diff --git a/substratevm/CHANGELOG.md b/substratevm/CHANGELOG.md index 9ec2cb840d08..3674950592ab 100644 --- a/substratevm/CHANGELOG.md +++ b/substratevm/CHANGELOG.md @@ -12,6 +12,7 @@ At runtime, premain runtime options are set along with main class' arguments in * (GR-57384) Preserve the origin of a resource included in a native image. The information is included in the report produced by -H:+GenerateEmbeddedResourcesFile. * (GR-58000) Support for `GetStringUTFLengthAsLong` added in JNI_VERSION_24 ([JDK-8328877](https://bugs.openjdk.org/browse/JDK-8328877)) * (GR-58383) The length of the printed stack trace when using `-XX:MissingRegistrationReportingMode=Warn` can now be set with `-XX:MissingRegistrationWarnContextLines=` and its default length is now 8. +* (GR-56599) Update native image debuginfo from DWARF4 to DWARF5 and store type information for debugging in DWARF type units. ## GraalVM for JDK 23 (Internal Version 24.1.0) * (GR-51520) The old class initialization strategy, which was deprecated in GraalVM for JDK 22, is removed. The option `StrictImageHeap` no longer has any effect. diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 677ef89796ce..6b80d9c30efd 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -795,10 +795,10 @@ "cflags": ["-Zi", "-O2", "-D_LITTLE_ENDIAN"], }, "linux": { - "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], + "cflags": ["-g", "-gdwarf-5", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], }, "": { - "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], + "cflags": ["-g", "-gdwarf-5", "-fPIC", "-O2", "-D_LITTLE_ENDIAN", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0"], }, }, "jacoco" : "exclude", @@ -856,7 +856,7 @@ "cflags": ["-g", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden"], }, "linux": { - "cflags": ["-g", "-gdwarf-4", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0", "-D_GNU_SOURCE"], + "cflags": ["-g", "-gdwarf-5", "-fPIC", "-O2", "-ffunction-sections", "-fdata-sections", "-fvisibility=hidden", "-D_FORTIFY_SOURCE=0", "-D_GNU_SOURCE"], }, "": { "ignore": "only darwin and linux are supported", diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java index 2df914597394..114c585637ea 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ArrayTypeEntry.java @@ -29,8 +29,9 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugArrayTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; -import jdk.vm.ci.meta.ResolvedJavaType; + import jdk.graal.compiler.debug.DebugContext; +import jdk.vm.ci.meta.ResolvedJavaType; public class ArrayTypeEntry extends StructureTypeEntry { private TypeEntry elementType; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java index a840414838f6..f9747acaf638 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java @@ -30,14 +30,11 @@ import java.util.List; import java.util.stream.Stream; +import org.graalvm.collections.EconomicMap; + import com.oracle.objectfile.debugentry.range.PrimaryRange; import com.oracle.objectfile.debugentry.range.Range; import com.oracle.objectfile.debugentry.range.SubRange; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; -import org.graalvm.collections.EconomicMap; -import jdk.graal.compiler.debug.DebugContext; - import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFieldInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugInstanceTypeInfo; @@ -47,6 +44,10 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; +import jdk.graal.compiler.debug.DebugContext; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + /** * Track debug info associated with a Java class. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java index f012843e1910..47a68ad22445 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DebugInfoBase.java @@ -737,8 +737,8 @@ public String getCachePath() { return cachePath; } - public boolean isHubClassEntry(ClassEntry classEntry) { - return classEntry.getTypeName().equals(DwarfDebugInfo.HUB_TYPE_NAME); + public boolean isHubClassEntry(StructureTypeEntry typeEntry) { + return typeEntry.getTypeName().equals(DwarfDebugInfo.HUB_TYPE_NAME); } public ClassEntry getHubClassEntry() { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java index 9511fd54ca9e..f46378d57486 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/EnumClassEntry.java @@ -26,9 +26,10 @@ package com.oracle.objectfile.debugentry; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugEnumTypeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; + import jdk.graal.compiler.debug.DebugContext; public class EnumClassEntry extends ClassEntry { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ForeignTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ForeignTypeEntry.java index 349b755edebf..cb886d89ed50 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ForeignTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ForeignTypeEntry.java @@ -27,10 +27,11 @@ package com.oracle.objectfile.debugentry; import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugForeignTypeInfo; -import jdk.vm.ci.meta.ResolvedJavaType; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; + import jdk.graal.compiler.debug.DebugContext; +import jdk.vm.ci.meta.ResolvedJavaType; public class ForeignTypeEntry extends ClassEntry { private static final int FLAG_WORD = 1 << 0; @@ -57,6 +58,10 @@ public DebugInfoProvider.DebugTypeInfo.DebugTypeKind typeKind() { return DebugInfoProvider.DebugTypeInfo.DebugTypeKind.FOREIGN; } + public void setLayoutTypeSignature(long typeSignature) { + this.layoutTypeSignature = typeSignature; + } + @Override public void addDebugInfo(DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, DebugContext debugContext) { assert debugTypeInfo instanceof DebugForeignTypeInfo; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java index b1836039a441..4ececbccd8bf 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/HeaderTypeEntry.java @@ -26,12 +26,12 @@ package com.oracle.objectfile.debugentry; -import jdk.graal.compiler.debug.DebugContext; - import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugHeaderTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; +import jdk.graal.compiler.debug.DebugContext; + public class HeaderTypeEntry extends StructureTypeEntry { public HeaderTypeEntry(String typeName, int size) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java index cb87c014c44c..42b2e7ac2d03 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/InterfaceClassEntry.java @@ -26,14 +26,15 @@ package com.oracle.objectfile.debugentry; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugInterfaceTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; -import jdk.graal.compiler.debug.DebugContext; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; +import jdk.graal.compiler.debug.DebugContext; public class InterfaceClassEntry extends ClassEntry { private final List implementors; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java index d663ac552099..a60ed3b1b1fd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimitiveTypeEntry.java @@ -26,14 +26,15 @@ package com.oracle.objectfile.debugentry; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_INTEGRAL; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_NUMERIC; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_SIGNED; + import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; -import jdk.graal.compiler.debug.DebugContext; -import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_INTEGRAL; -import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_NUMERIC; -import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo.FLAG_SIGNED; +import jdk.graal.compiler.debug.DebugContext; public class PrimitiveTypeEntry extends TypeEntry { private char typeChar; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java index 7556cf759a5f..0331b410ba9d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StructureTypeEntry.java @@ -26,15 +26,18 @@ package com.oracle.objectfile.debugentry; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFieldInfo; -import jdk.vm.ci.meta.ResolvedJavaType; -import jdk.graal.compiler.debug.DebugContext; - import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFieldInfo; +import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo; + +import jdk.graal.compiler.debug.DebugContext; +import jdk.vm.ci.meta.ResolvedJavaType; + /** * An intermediate type that provides behaviour for managing fields. This unifies code for handling * header structures and Java instance and array classes that both support data members. @@ -45,9 +48,25 @@ public abstract class StructureTypeEntry extends TypeEntry { */ protected final List fields; + /** + * The type signature of this types' layout. + */ + protected long layoutTypeSignature; + protected long indirectLayoutTypeSignature; + public StructureTypeEntry(String typeName, int size) { super(typeName, size); this.fields = new ArrayList<>(); + this.layoutTypeSignature = 0; + this.indirectLayoutTypeSignature = 0; + } + + public long getLayoutTypeSignature() { + return layoutTypeSignature; + } + + public long getIndirectLayoutTypeSignature() { + return indirectLayoutTypeSignature; } public Stream fields() { @@ -118,4 +137,21 @@ String memberModifiers(int modifiers) { return builder.toString(); } + + @Override + public void addDebugInfo(@SuppressWarnings("unused") DebugInfoBase debugInfoBase, DebugInfoProvider.DebugTypeInfo debugTypeInfo, @SuppressWarnings("unused") DebugContext debugContext) { + super.addDebugInfo(debugInfoBase, debugTypeInfo, debugContext); + // header type does not have a separate layout type + if (this instanceof HeaderTypeEntry) { + this.layoutTypeSignature = typeSignature; + } else { + this.layoutTypeSignature = debugTypeInfo.typeSignature(DwarfDebugInfo.LAYOUT_PREFIX); + } + // header and foreign types are never stored compressed + if (!debugInfoBase.useHeapBase() || this instanceof HeaderTypeEntry || this instanceof ForeignTypeEntry) { + this.indirectLayoutTypeSignature = layoutTypeSignature; + } else { + this.indirectLayoutTypeSignature = debugTypeInfo.typeSignature(DwarfDebugInfo.INDIRECT_PREFIX + DwarfDebugInfo.LAYOUT_PREFIX); + } + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java index b6e870ee3d69..c704c347ed87 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/TypeEntry.java @@ -26,10 +26,6 @@ package com.oracle.objectfile.debugentry; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; -import jdk.graal.compiler.debug.DebugContext; - import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind.ARRAY; import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind.ENUM; import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind.FOREIGN; @@ -38,12 +34,24 @@ import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind.INTERFACE; import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind.PRIMITIVE; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo.DebugTypeKind; +import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo; + +import jdk.graal.compiler.debug.DebugContext; + public abstract class TypeEntry { /** * The name of this type. */ protected final String typeName; + /** + * The type signature of this type. + */ + protected long typeSignature; + protected long indirectTypeSignature; + /** * The offset of the java.lang.Class instance for this class in the image heap or -1 if no such * object exists. @@ -59,6 +67,16 @@ protected TypeEntry(String typeName, int size) { this.typeName = typeName; this.size = size; this.classOffset = -1; + this.typeSignature = 0; + this.indirectTypeSignature = 0; + } + + public long getTypeSignature() { + return typeSignature; + } + + public long getIndirectTypeSignature() { + return indirectTypeSignature; } public long getClassOffset() { @@ -127,5 +145,12 @@ public boolean isStructure() { public void addDebugInfo(@SuppressWarnings("unused") DebugInfoBase debugInfoBase, DebugTypeInfo debugTypeInfo, @SuppressWarnings("unused") DebugContext debugContext) { /* Record the location of the Class instance in the heap if there is one */ this.classOffset = debugTypeInfo.classOffset(); + this.typeSignature = debugTypeInfo.typeSignature(""); + // primitives, header and foreign types are never stored compressed + if (!debugInfoBase.useHeapBase() || this instanceof PrimitiveTypeEntry || this instanceof HeaderTypeEntry || this instanceof ForeignTypeEntry) { + this.indirectTypeSignature = typeSignature; + } else { + this.indirectTypeSignature = debugTypeInfo.typeSignature(DwarfDebugInfo.INDIRECT_PREFIX); + } } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java index 2c7be7251690..e8488c87b4f0 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -129,6 +129,11 @@ public String toString() { */ String typeName(); + /** + * @return a 64bit type signature to uniquely identify the type + */ + long typeSignature(String prefix); + DebugTypeKind typeKind(); /** diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java index d6ba23b7f019..c7b345f4b6fe 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -26,20 +26,21 @@ package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.AbbrevCode; import com.oracle.objectfile.elf.dwarf.constants.DwarfAttribute; import com.oracle.objectfile.elf.dwarf.constants.DwarfForm; import com.oracle.objectfile.elf.dwarf.constants.DwarfHasChildren; import com.oracle.objectfile.elf.dwarf.constants.DwarfSectionName; import com.oracle.objectfile.elf.dwarf.constants.DwarfTag; + import jdk.graal.compiler.debug.DebugContext; -import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.AbbrevCode; /** * Section generator for debug_abbrev section. That section defines the layout of the * DWARF Information Entries (DIEs) used to model Java debug info. Top level DIEs define Java - * Compile Units (CUs). Embedded DIEs describe the content of the CU: types, code, variable, etc. - * These definitions are used to interpret the DIE content inserted into the debug_info - * section. + * Compile Units (CUs) and Type Units (TUs). Embedded DIEs describe the content of the CU/TU: types, + * code, variable, etc. These definitions are used to interpret the DIE content inserted into the + * debug_info section. *

* * An abbrev table contains abbrev entries for one or more DIEs, the last one being a null entry. @@ -62,7 +63,7 @@ *

  • LEB128 tag; .............. defines the type of the DIE (class, subprogram, var * etc) * - *
  • uint8 has_chldren; ....... is the DIE followed by child DIEs or a sibling + *
  • uint8 has_children; ....... is the DIE followed by child DIEs or a sibling * DIE * *
  • attribute_spec* .......... zero or more attributes @@ -81,19 +82,22 @@ * * * - * For the moment we only use one abbrev table with two types of CU. There is one occurrence of the - * BUILTIN_UNIT CU which includes definitions of Java primitive value types and the - * struct type used to model a Java object header. There are multiple occurrences of the - * CLASS_UNIT CU, one for each Java class, interface or array class included in the - * generated native image binary. The latter describes the class, array or interface layout and - * defines a class, interface or array reference pointer type. It provides declarations for instance - * and static methods and static fields of a class, and methods of an interface. In the case of a - * class it may also include definitions of static fields (i.e. location info) and for a class or - * interface definitions of compiled methods (i.e. code address locations). The latter may include - * details of inlined method frames and top level or inlined parameter or local variable locations. + * For the moment we only use one abbrev table with three types of CU and one type of TU. There is + * one occurrence of the CLASS_CONSTANT_UNIT CU which contains class constant objects + * for all Java types that are defined in the debug info section. There are multiple occurrences of + * the CLASS_UNIT_1 and CLASS_UNIT_2 CUs, one for each Java class, + * interface or array class included in the generated native image binary. The latter differentiate + * of whether they contain compiled methods or not. It provides declarations for instance and static + * methods and static fields of a class, and methods of an interface. In the case of a class it may + * also include definitions of static fields (i.e. location info) and for a class or interface + * definitions of compiled methods (i.e. code address locations). The latter may include details of + * inlined method frames and top level or inlined parameter or local variable locations. There are + * also multiple occurrences of the TYPE_UNIT TU, one up to four for each Java class, + * interface or array class included in the generated native image binary. A type unit describes the + * class, array or interface layout or defines a class, interface or array reference pointer type *

    * - * These two CUs include the following top level and nested DIES + * These CUs and TU include the following top level and nested DIES *

    * * Level 0 DIEs @@ -102,11 +106,18 @@ * *

  • abbrev_code == null, tag == null - empty terminator * - *
  • abbrev_code == BUILTIN_UNIT, tag == DW_TAG_compilation_unit - CU that defines - * the Java object header struct and all Java primitive types. + *
  • abbrev_code == CLASS_CONSTANT_UNIT, tag == DW_TAG_compile_unit - CU that defines + * class constant objects. + * + *
  • abbrev_code == CLASS_UNIT_1, tag == DW_TAG_compile_unit - CU that defines + * declarations and locations for a specific Java object, interface or array type without + * compilations. * - *
  • abbrev_code == CLASS_UNIT, tag == DW_TAG_compilation_unit - CU that defines a - * specific Java object, interface or array type. + *
  • abbrev_code == CLASS_UNIT_2, tag == DW_TAG_compile_unit - CU that defines + * declarations and locations for a specific Java object, interface or array type with compilations. + * + *
  • abbrev_code == TYPE_UNIT, tag == DW_TAG_type_unit - TU that defines a specific + * Java object, interface or array type. * * * @@ -114,56 +125,67 @@ * *
      * - *
    • abbrev_code == PRIMITIVE_TYPE, tag == DW_TAG_base_type, parent = BUILTIN_UNIT - + *
    • abbrev_code == PRIMITIVE_TYPE, tag == DW_TAG_base_type, parent = TYPE_UNIT - * Java primitive type (non-void) * - *
    • abbrev_code == VOID_TYPE, tag == DW_TAG_unspecified_type, parent = BUILTIN_UNIT - * - Java void type + *
    • abbrev_code == VOID_TYPE, tag == DW_TAG_unspecified_type, parent = TYPE_UNIT - + * Java void type + * + *
    • abbrev_code == OBJECT_HEADER, tag == DW_TAG_structure_type, parent = TYPE_UNIT - + * Java object header * - *
    • abbrev_code == OBJECT_HEADER, tag == DW_TAG_structure_type, parent = BUILTIN_UNIT - * - Java object header + *
    • abbrev_code == CLASS_CONSTANT, tag == DW_TAG_constant, parent = CLASS_CONSTANT_UNIT + * - class constant object * - *
    • abbrev_code == CLASS_LAYOUT, tag == DW_TAG_class_type, parent = CLASS_UNIT - - * Java instance type structure definition + *
    • abbrev_code == CLASS_LAYOUT_1/CLASS_LAYOUT_2, tag == DW_TAG_class_type, parent = TYPE_UNIT + * - Java instance type structure definition * - *
    • abbrev_code == CLASS_POINTER, tag == DW_TAG_pointer_type, parent = CLASS_UNIT - - * Java instance ref type + *
    • abbrev_code == CLASS_LAYOUT_3, tag == DW_TAG_class_type, parent = CLASS_UNIT_1/2 + * - Skeleton Java instance type structure definition for compilation units * - *
    • abbrev_code == METHOD_LOCATION, tag == DW_TAG_subprogram , parent = CLASS_UNIT - - * Java method code definition (i.e. location of code) + *
    • abbrev_code == TYPE_POINTER, tag == DW_TAG_pointer_type, parent = TYPE_UNIT - Is + * either of + *
        + *
      • Java instance ref type
      • + *
      • Java interface ref type
      • + *
      • Java array ref type
      • + *
      • Java indirect ref type
      • - used to type indirect oops that encode the address of an + * object, whether by adding tag bits or representing the address as an offset from some base + * address. these are used to type object references stored in static and instance fields. They are + * not needed when typing local vars and parameters held in registers or on the stack as they appear + * as raw addresses. + *
      * - *
    • abbrev_code == STATIC_FIELD_LOCATION, tag == DW_TAG_variable, parent = CLASS_UNIT + *
    • abbrev_code == METHOD_LOCATION, tag == DW_TAG_subprogram , parent = CLASS_UNIT_2 + * - Java method code definition (i.e. location of code) + * + *
    • abbrev_code == STATIC_FIELD_LOCATION, tag == DW_TAG_variable, parent = CLASS_UNIT_1/2 * - Java static field definition (i.e. location of data) * - *
    • abbrev_code == ARRAY_LAYOUT, tag == DW_TAG_structure_type, parent = CLASS_UNIT - - * Java array type structure definition + *
    • abbrev_code == FOREIGN_TYPEDEF, tag == DW_TAG_typedef_type, parent = TYPE_UNIT - + * Definition of a typedef for foreign types * - *
    • abbrev_code == ARRAY_POINTER, tag == DW_TAG_pointer_type, parent = CLASS_UNIT - - * Java array ref type + *
    • abbrev_code == FOREIGN_STRUCT, tag == DW_TAG_structure_type, parent = TYPE_UNIT + * - Foreign structure type definition * - *
    • abbrev_code == INTERFACE_LAYOUT, tag == DW_TAG_union_type, parent = CLASS_UNIT - + *
    • abbrev_code == ARRAY_LAYOUT, tag == DW_TAG_structure_type, parent = TYPE_UNIT - * Java array type structure definition * - *
    • abbrev_code == INTERFACE_POINTER, tag == DW_TAG_pointer_type, parent = CLASS_UNIT - * - Java interface ref type + *
    • abbrev_code == INTERFACE_LAYOUT, tag == DW_TAG_union_type, parent = TYPE_UNIT - + * Java array type structure definition * - *
    • abbrev_code == INDIRECT_LAYOUT, tag == DW_TAG_class_type, parent = CLASS_UNIT - + *
    • abbrev_code == INDIRECT_LAYOUT, tag == DW_TAG_class_type, parent = TYPE_UNIT - * wrapper layout attaches address rewriting logic to the layout types that it wraps using a * data_location attribute * - *
    • abbrev_code == INDIRECT_POINTER, tag == DW_TAG_pointer_type, parent = CLASS_UNIT - * - indirect ref type used to type indirect oops that encode the address of an object, whether by - * adding tag bits or representing the address as an offset from some base address. these are used - * to type object references stored in static and instance fields. They are not needed when typing - * local vars and parameters held in registers or on the stack as they appear as raw addresses. - * - *
    • abbrev_code == NAMESPACE, tag == DW_TAG_namespace, parent = CLASS_UNIT - a - * wrap-around DIE that is used to embed all the normal level 1 DIEs of a CLASS_UNIT in - * a namespace. This is needed when the corresponding class/interface or array base element type - * have been loaded by a loader with a non-empty loader in order to ensure that mangled names for - * the class and its members can legitimately employ the loader id as a namespace prefix. Note that - * use of a namespace wrapper DIE causes all the embedded level 1+ DIEs documented above and all - * their children to be generated at a level one greater than documented here. + *
    • abbrev_code == NAMESPACE, tag == DW_TAG_namespace, parent = TYPE_UNIT, CLASS_UNIT_1/2 + * - a wrap-around DIE that is used to embed all the normal level 1 DIEs of a + * CLASS_UNIT in a namespace. This is needed when the corresponding class/interface or + * array base element type have been loaded by a loader with a non-empty loader in order to ensure + * that mangled names for the class and its members can legitimately employ the loader id as a + * namespace prefix. Note that use of a namespace wrapper DIE causes all the embedded level 1+ DIEs + * documented above and all their children to be generated at a level one greater than documented + * here. * *
    * @@ -175,12 +197,16 @@ * object/array header field * *
  • abbrev_code == METHOD_DECLARATION/METHOD_DECLARATION_STATIC, tag == DW_TAG_subprogram, - * parent = CLASS_LAYOUT, INTERFACE_LAYOUT + * parent = CLASS_LAYOUT_3 + * + *
  • abbrev_code == METHOD_DECLARATION_SKELETON, tag == DW_TAG_subprogram, + * parent = CLASS_LAYOUT_1/2, INTERFACE_LAYOUT - a minimal method declaration to avoid + * unnecessary duplication of debug info * *
  • abbrev_code == FIELD_DECLARATION_1/2/3/4, tag == DW_TAG_member, parent = CLASS_LAYOUT * - instance field declaration (i.e. specification of properties) * - *
  • abbrev_code == SUPER_REFERENCE, tag == DW_TAG_inheritance, parent = CLASS_LAYOUT, + *
  • abbrev_code == SUPER_REFERENCE, tag == DW_TAG_inheritance, parent = CLASS_LAYOUT_1/2, * ARRAY_LAYOUT - reference to super class layout or to appropriate header struct for {code * java.lang.Object} or arrays. * @@ -191,7 +217,7 @@ * parent = METHOD_LOCATION/INLINED_SUBROUTINE_WITH_CHILDREN - provides range and * abstract origin for an inlined subroutine * - *
  • abbrev_code == METHOD_PARAMETER_DECLARATION_1/2/3, tag == DW_TAG_formal_parameter, parent = + *
  • abbrev_code == METHOD_PARAMETER_DECLARATION_1/2/3/4/5, tag == DW_TAG_formal_parameter, parent = * METHOD_DECLARATION/METHOD_DECLARATION_STATIC - details of method parameters * *
  • abbrev_code == METHOD_LOCAL_DECLARATION_1/2, tag == DW_TAG_variable, parent = @@ -203,27 +229,32 @@ * *
      * - *
    • abbrev_code == METHOD_LOCAL_LOCATION, tag == DW_TAG_formal_parameter, parent = - * METHOD_LOCATION - details of method parameter or local locations + *
    • abbrev_code == METHOD_PARAMETER_LOCATION_1/2, tag == DW_TAG_formal_parameter, parent = + * METHOD_LOCATION - details of method parameter locations + * + *
    • abbrev_code == METHOD_LOCAL_LOCATION_1/2, tag == DW_TAG_variable, parent = + * METHOD_LOCATION - details of method local locations * *
    * * Detailed layouts of the DIEs listed above are as follows: *

    * - * A single instance of the level 0 BUILTIN_UNIT compile unit provide details of all - * Java primitive types and the struct type used to model a Java object header + * A single instance of the level 0 CLASS_CONSTANT_UNIT CU provides a class constant + * object for all types in the image * *

      * - *
    • abbrev_code == BUILTIN_UNIT, tag == DW_TAG_compilation_unit, + *
    • abbrev_code == CLASS_CONSTANT_UNIT, tag == DW_TAG_compile_unit, * has_children * *
    • DW_AT_language : ... DW_FORM_data1 * + *
    • DW_AT_use_UTF8 : ... DW_FORM_flag + * *
    • DW_AT_name : ....... DW_FORM_strp * - *
    • DW_AT_use_UTF8 : ... DW_FORM_flag + *
    • DW_AT_comp_dir : ... DW_FORM_strp * *
    * @@ -232,25 +263,43 @@ * *
      * - *
    • abbrev_code == CLASS_UNIT1/2, tag == DW_TAG_compilation_unit, + *
    • abbrev_code == CLASS_UNIT_1/2, tag == DW_TAG_compile_unit, * has_children * - *
    • DW_AT_language : ... DW_FORM_data1 + *
    • DW_AT_language : ....... DW_FORM_data1 * - *
    • DW_AT_name : ....... DW_FORM_strp + *
    • DW_AT_use_UTF8 : ....... DW_FORM_flag * - *
    • DW_AT_comp_dir : ... DW_FORM_strp + *
    • DW_AT_name : ........... DW_FORM_strp * - *
    • DW_AT_low_pc : ..... DW_FORM_address only for CLASS_UNIT1 + *
    • DW_AT_comp_dir : ....... DW_FORM_strp * - *
    • DW_AT_hi_pc : ...... DW_FORM_address only for CLASS_UNIT1 + *
    • DW_AT_ranges : ......... DW_FORM_sec_offset only for CLASS_UNIT_2 * - *
    • DW_AT_use_UTF8 : ... DW_FORM_flag + *
    • DW_AT_low_pc : ......... DW_FORM_address only for CLASS_UNIT_2 + * + *
    • DW_AT_stmt_list : ...... DW_FORM_sec_offset only for CLASS_UNIT_2 + * + *
    • DW_AT_loclists_base : .. DW_FORM_sec_offset only for CLASS_UNIT_2 + * + *
    + * + * Instances of the level 0 TYPE_UNIT type unit provide details of all Java object + * types. + * + *
      * - *
    • DW_AT_stmt_list : .. DW_FORM_sec_offset + *
    • abbrev_code == TYPE_UNIT, tag == DW_TAG_type_unit, + * has_children + * + *
    • DW_AT_language : ....... DW_FORM_data1 + * + *
    • DW_AT_use_UTF8 : ....... DW_FORM_flag * *
    * + * + * * Primitive Types: For each non-void Java primitive type there is a level 1 DIE defining a base * type * @@ -300,13 +349,13 @@ * *
  • abbrev_code = HEADER_FIELD, tag == DW_TAG_member, no_children * - *
  • Dw_AT_name : ................... DW_FORM_strp + *
  • DW_AT_name : ................... DW_FORM_strp * - *
  • Dw_AT_type : ................... DW_FORM_ref_addr + *
  • DW_AT_type : ................... DW_FORM_ref_addr * - *
  • Dw_AT_data_member_location : ... DW_FORM_data1 + *
  • DW_AT_data_member_location : ... DW_FORM_data1 * - *
  • Dw_AT_accessibility : .......... DW_FORM_data1 + *
  • DW_AT_accessibility : .......... DW_FORM_data1 * * * @@ -341,18 +390,20 @@ * *
      * - *
    • abbrev_code == CLASS_LAYOUT1/CLASS_LAYOUT2, tag == DW_TAG_class_type, + *
    • abbrev_code == CLASS_LAYOUT1/2/3, tag == DW_TAG_class_type, * has_children * - *
    • Dw_AT_name : ........ DW_FORM_strp + *
    • DW_AT_name : ........ DW_FORM_strp + * + *
    • DW_AT_declaration : . DW_FORM_flag only for CLASS_LAYOUT_3 * - *
    • Dw_AT_byte_size : ... DW_FORM_data1/2 + *
    • DW_AT_signature : ... DW_FORM_ref_sig8 only for CLASS_LAYOUT_3 * - *
    • Dw_AT_decl_file : ... DW_FORM_data1/2 + *
    • DW_AT_byte_size : ... DW_FORM_data1/2 only for CLASS_LAYOUT_1/2 * - *
    • Dw_AT_decl_line : ... DW_FORM_data1/2 + *
    • DW_AT_decl_file : ... DW_FORM_data1/2 only for CLASS_LAYOUT_1/2 * - *
    • Dw_AT_data_location : ... DW_FORM_expr_loc n.b. only for CLASS_LAYOUT2 + *
    • DW_AT_data_location : ... DW_FORM_expr_loc n.b. only for CLASS_LAYOUT_2 * *
    * @@ -373,20 +424,21 @@ * *
      * - *
    • abbrev_code == METHOD_DECLARATION/METHOD_DECLARATION_STATIC, tag == DW_TAG_subprogram, + *
    • abbrev_code == METHOD_DECLARATION/METHOD_DECLARATION_STATIC/METHOD_DECLARATION_SKELETON, tag == DW_TAG_subprogram, * has_children * *
    • DW_AT_external : .......... DW_FORM_flag * - *
    • Dw_AT_name : .............. DW_FORM_strp + *
    • DW_AT_name : .............. DW_FORM_strp * - *
    • DW_AT_decl_file : ......... DW_FORM_data1/2 + *
    • DW_AT_decl_file : ......... DW_FORM_data1/2 only for + * METHOD_DECLARATION/METHOD_DECLARATION_STATIC * - *
    • DW_AT_decl_line : ......... DW_FORM_data1/2 + *
    • DW_AT_decl_line : ......... DW_FORM_data1/2 only for METHOD_DECLARATION/METHOD_DECLARATION_STATIC * - *
    • Dw_AT_linkage_name : ...... DW_FORM_strp + *
    • DW_AT_linkage_name : ...... DW_FORM_strp * - *
    • Dw_AT_type : .............. DW_FORM_ref_addr (optional!!) + *
    • DW_AT_type : .............. DW_FORM_ref_sig8 (optional!!) * *
    • DW_AT_artificial : ........ DW_FORM_flag * @@ -394,12 +446,13 @@ * *
    • DW_AT_declaration : ....... DW_FORM_flag * - *
    • Dw_AT_object_pointer : .... DW_FORM_ref4 n.b. only for METHOD_DECLARATION, - * points to param 0 DIE + *
    • DW_AT_object_pointer : .... DW_FORM_ref4 only for METHOD_DECLARATION, points to + * param 0 DIE * - *
    • DW_AT_virtuality : ........ DW_FORM_data1 (for override methods) + *
    • DW_AT_virtuality : ........ DW_FORM_data1 (for override methods) only for METHOD_DECLARATION/METHOD_DECLARATION_STATIC * - *
    • DW_AT_containing_type : ... DW_FORM_ref4 (for override methods) + *
    • DW_AT_containing_type : ... DW_FORM_ref_sig8 (for override methods) only for + * METHOD_DECLARATION/METHOD_DECLARATION_STATIC * *
    * @@ -407,7 +460,7 @@ * *
  • abbrev_code == FIELD_DECLARATION_1/2/3/4, tag == DW_TAG_member, no_children * - *
  • Dw_AT_name : ................... DW_FORM_strp + *
  • DW_AT_name : ................... DW_FORM_strp * *
  • DW_AT_decl_file : .............. DW_FORM_data1/2 n.b. only for * FIELD_DECLARATION_2/4 @@ -415,19 +468,19 @@ *
  • DW_AT_decl_line : .............. DW_FORM_data1/2 n.b. only for * FIELD_DECLARATION_2/4 * - *
  • Dw_AT_type : ................... DW_FORM_ref_addr + *
  • DW_AT_type : ................... DW_FORM_ref_sig8 * - *
  • Dw_AT_data_member_location : ... DW_FORM_data1/2 (n.b. nly for + *
  • DW_AT_data_member_location : ... DW_FORM_data1/2 (n.b. nly for * FIELD_DECLARATION_1/2 instance * - *
  • Dw_AT_artificial : ............. DW_FORM_flag + *
  • DW_AT_artificial : ............. DW_FORM_flag * - *
  • Dw_AT_accessibility : .......... DW_FORM_data1 + *
  • DW_AT_accessibility : .......... DW_FORM_data1 * - *
  • Dw_AT_external : ............... DW_FORM_flag (n.b. only for + *
  • DW_AT_external : ............... DW_FORM_flag (n.b. only for * FIELD_DECLARATION_3/4 static * - *
  • Dw_AT_declaration : ............ DW_FORM_flag n.b. only for + *
  • DW_AT_declaration : ............ DW_FORM_flag n.b. only for * FIELD_DECLARATION_3/4 static * * @@ -436,11 +489,11 @@ * *
  • abbrev_code == SUPER_REFERENCE, tag == DW_TAG_inheritance, no_children * - *
  • Dw_AT_type : ................... DW_FORM_ref_addr + *
  • DW_AT_type : ................... DW_FORM_ref_sig8 * - *
  • Dw_AT_data_member_location : ... DW_FORM_data1/2 + *
  • DW_AT_data_member_location : ... DW_FORM_data1/2 * - *
  • Dw_AT_accessibility :........... DW_FORM_data1 + *
  • DW_AT_accessibility :........... DW_FORM_data1 * * * @@ -450,36 +503,37 @@ * *
      * - *
    • abbrev_code == METHOD_PARAMETER_DECLARATION_1/2/3, tag == + *
    • abbrev_code == METHOD_PARAMETER_DECLARATION_1/2/3/4/5, tag == * DW_TAG_formal_parameter, no_children * - *
    • Dw_AT_name : ... DW_FORM_strp (may be empty string) + *
    • DW_AT_name : ... DW_FORM_strp (may be empty string) only for + * METHOD_PARAMETER_DECLARATION_1/2/3 * - *
    • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for METHOD_PARAMETER_DECLARATION_2 + *
    • DW_AT_file : ... DW_FORM_data1/2 only for METHOD_PARAMETER_DECLARATION_2 * - *
    • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for METHOD_PARAMETER_DECLARATION_2 + *
    • DW_AT_line : ... DW_FORM_data1/2 only for METHOD_PARAMETER_DECLARATION_2 * - *
    • Dw_AT_type : ... DW_FORM_ref_addr + *
    • DW_AT_type : ... DW_FORM_ref_sig8 * - *
    • Dw_AT_artificial : ... DW_FORM_flag n.b. only for METHOD_PARAMETER_DECLARATION_1 + *
    • DW_AT_artificial : ... DW_FORM_flag only for METHOD_PARAMETER_DECLARATION_1/4 * used for this and access vars * - *
    • Dw_AT_declaration : ... DW_FORM_flag + *
    • DW_AT_declaration : ... DW_FORM_flag * *
    * *
  • abbrev_code == METHOD_LOCAL_DECLARATION_1/2, tag == DW_TAG_variable, * no_children * - *
  • Dw_AT_name : ... DW_FORM_strp (may be empty string) + *
  • DW_AT_name : ... DW_FORM_strp (may be empty string) * - *
  • Dw_AT_file : ... DW_FORM_data1/2 n.b. only for METHOD_PARAMETER_DECLARATION_1 + *
  • DW_AT_file : ... DW_FORM_data1/2 n.b. only for METHOD_PARAMETER_DECLARATION_1 * - *
  • Dw_AT_line : ... DW_FORM_data1/2 n.b. only for METHOD_PARAMETER_DECLARATION_1 + *
  • DW_AT_line : ... DW_FORM_data1/2 n.b. only for METHOD_PARAMETER_DECLARATION_1 * - *
  • Dw_AT_type : ... DW_FORM_ref_addr + *
  • DW_AT_type : ... DW_FORM_ref_sig8 * - *
  • Dw_AT_declaration : ... DW_FORM_flag + *
  • DW_AT_declaration : ... DW_FORM_flag * * * @@ -499,20 +553,20 @@ * *
  • abbrev_code == INDIRECT_LAYOUT, tag == DW_TAG_class_type, has_children * - *
  • Dw_AT_name : ........ DW_FORM_strp + *
  • DW_AT_name : ........ DW_FORM_strp * - *
  • Dw_AT_byte_size : ... DW_FORM_data1/2 + *
  • DW_AT_byte_size : ... DW_FORM_data1/2 * - *
  • Dw_AT_data_location : ... DW_FORM_expr_loc + *
  • DW_AT_data_location : ... DW_FORM_expr_loc * * * * Instance Class Reference Types: The level 1 CLASS_LAYOUT and * INDIRECT_LAYOUT DIEs are followed by level 1 DIEs defining pointers to the - * respective class layouts. A CLASS_POINTER DIE defines a pointer type for the + * respective class layouts. A TYPE_POINTER DIE defines a pointer type for the * CLASS_LAYOUT type and is used to type pointers which directly address an instance. * It is used to type local and parameter var references whether located in a register or on the - * stack. It may be followed by an INDIRECT_POINTER DIE which defines a pointer type + * stack. It may be followed by another TYPE_POINTER DIE which defines a pointer type * for the class's INDIRECT_LAYOUT type. This is used to type references to instances * of the class located in a static or instance field. These latter references require address * translation by masking off tag bits and/or rebasing from an offset to a raw address. The logic @@ -521,21 +575,11 @@ * *
      * - *
    • abbrev_code == CLASS_POINTER, tag == DW_TAG_pointer_type, no_children + *
    • abbrev_code == TYPE_POINTER, tag == DW_TAG_pointer_type, no_children * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 + *
    • DW_AT_byte_size : ... DW_FORM_data1 * - *
    • Dw_AT_type : ........ DW_FORM_ref4 - * - *
    - * - *
      - * - *
    • abbrev_code == INDIRECT_POINTER, tag == DW_TAG_pointer_type, no_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • Dw_AT_type : ........ DW_FORM_ref4 + *
    • DW_AT_type : ........ DW_FORM_ref_sig8 * *
    * @@ -566,7 +610,7 @@ * *
      * - *
    • abbrev_code == DW_ABBREV_CODE_METHOD_LOCATION, tag == DW_TAG_subprogram, + *
    • abbrev_code == METHOD_LOCATION, tag == DW_TAG_subprogram, * has_children * *
    • DW_AT_low_pc : .......... DW_FORM_addr @@ -575,28 +619,42 @@ * *
    • DW_AT_external : ........ DW_FORM_flag * - *
    • DW_AT_specification : ... DW_FORM_ref4 + *
    • DW_AT_specification : ... DW_FORM_ref_addr * *
    * * Method local locations: A method location may be followed by zero or more - * METHOD_LOCAL_LOCATION DIEs which identify the in-memory location of parameter and/or - * local values during execution of the compiled code. A METHOD_LOCAL_LOCATION DIE - * references the corresponding METHOD_PARAMETER_DECLARATION or * - * METHOD_LOCAL_DECLARATION. It also specifies a location list which defines address - * ranges where the parameter or local is valid and provides details of where to find the value of - * the parameter or local in memory. Likewise, an inlined subroutine DIE is followed by zero or more + * METHOD_PARAMETER_LOCATION DIEs which identify the in-memory location of parameter + * values METHOD_LOCAL_LOCATION DIEs which identify the in-memory location of local + * values during execution of the compiled code. A + * METHOD_PARAMETER_LOCATION/METHOD_LOCAL_LOCATION DIE references the + * corresponding METHOD_PARAMETER_DECLARATION/METHOD_LOCAL_DECLARATION. It + * also specifies a location list which defines address ranges where the parameter or local is valid + * and provides details of where to find the value of the parameter or local in memory. Likewise, an + * inlined subroutine DIE is followed by zero or more METHOD_PARAMETER_LOCATION and * METHOD_LOCAL_LOCATION DIEs, providing details of where to find the specification of * inlined parameters or locals and their value in memory. * *
      * - *
    • abbrev_code == DW_ABBREV_CODE_METHOD_LOCAL_LOCATION1/2, tag == + *
    • abbrev_code == METHOD_PARAMETER_LOCATION1/2, tag == * DW_TAG_formal_parameter, no_children * - *
    • DW_AT_specification : .......... DW_FORM_ref4 + *
    • DW_AT_abstract_origin : ........ DW_FORM_ref_addr + * + *
    • DW_AT_location: ................ DW_FORM_loclistx only for + * METHOD_PARAMETER_LOCATION2 + * + *
    + * + *
      + * + *
    • abbrev_code == METHOD_LOCAL_LOCATION1/2, tag == + * DW_TAG_variable, no_children * - *
    • DW_AT_location: ................ DW_FORM_sec_offset n.b. only for + *
    • DW_AT_abstract_origin : ........ DW_FORM_ref_addr + * + *
    • DW_AT_location: ................ DW_FORM_loclistx only for * METHOD_LOCAL_LOCATION2 * *
    @@ -618,7 +676,7 @@ * *
      * - *
    • abbrev_code == DW_ABBREV_CODE_abstract_inline_method, tag == DW_TAG_subprogram, + *
    • abbrev_code == ABSTRACT_INLINE_METHOD, tag == DW_TAG_subprogram, * has_children * *
    • DW_AT_inline : .......... DW_FORM_data1 @@ -645,10 +703,10 @@ * *
        * - *
      • abbrev_code == DW_ABBREV_CODE_INLINED_SUBROUTINE, tag == DW_TAG_subprogram, + *
      • abbrev_code == INLINED_SUBROUTINE, tag == DW_TAG_subprogram, * no_children * - *
      • abbrev_code == DW_ABBREV_CODE_INLINED_SUBROUTINE_WITH_CHILDREN, tag == + *
      • abbrev_code == INLINED_SUBROUTINE_WITH_CHILDREN, tag == * DW_TAG_subprogram, has_children * *
      • DW_AT_abstract_origin : ... DW_FORM_ref4 @@ -703,9 +761,9 @@ * *
      • abbrev_code == ARRAY_LAYOUT, tag == DW_TAG_class_type, has_children * - *
      • Dw_AT_name : ........ DW_FORM_strp + *
      • DW_AT_name : ........ DW_FORM_strp * - *
      • Dw_AT_byte_size : ... DW_FORM_data1/2 + *
      • DW_AT_byte_size : ... DW_FORM_data1/2 * *
      * @@ -720,19 +778,9 @@ *

      * * The third and fourth DIEs define array reference types as a pointers to the underlying structure - * layout types. As with classes, there is an ARRAY_POINTER type for raw address references used to - * type local and param vars and an INDIRECT_POINTER type (see above) for array references stored in - * static and instance fields. - * - *

        - * - *
      • abbrev_code == ARRAY_POINTER, tag == DW_TAG_pointer_type, no_children - * - *
      • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
      • Dw_AT_type : ........ DW_FORM_ref4 - * - *
      + * layout types. As with classes, there is a TYPE_POINTER type for raw address references used to + * type local and param vars and a (indirect) TYPE_POINTER type (see above) for array references + * stored in static and instance fields. * * n.b. the name used in the ARRAY_LAYOUT DIE is the Java array name. This is deliberately * inconsistent with the Java naming where the name refers to the pointer type. As with normal @@ -745,11 +793,13 @@ * *
        * - *
      • abbrev_code == array_data_type, tag == DW_TAG_array_type, no_children + *
      • abbrev_code == ARRAY_DATA_TYPE_1, tag == DW_TAG_array_type, no_children * - *
      • Dw_AT_byte_size : ... DW_FORM_data1 + *
      • abbrev_code == ARRAY_DATA_TYPE_2, tag == DW_TAG_array_type, children * - *
      • Dw_AT_type : ........ DW_FORM_ref_addr + *
      • DW_AT_byte_size : ... DW_FORM_data4 only ARRAY_DATA_TYPE_2 + * + *
      • DW_AT_type : ........ DW_FORM_ref_sig8 * *
      * @@ -767,7 +817,7 @@ * *
    • abbrev_code == INTERFACE_LAYOUT, DW_TAG_union_type, has_children * - *
    • Dw_AT_name : ....... DW_FORM_strp + *
    • DW_AT_name : ....... DW_FORM_strp * *
    * @@ -781,9 +831,9 @@ * indirect layout is the same as the size of the interface layout. * * The third and fourth DIEs define interface reference types as a pointers to the underlying - * structure layout types. As with classes, there is an INTERFACE_POINTER type for raw address - * references used to type local and param vars and an INDIRECT_POINTER type (see above) for - * interface references stored in static and instance fields. + * structure layout types. As with classes, there is an TYPE_POINTER type for raw address references + * used to type local and param vars and an (indirect) TYPE_POINTER type (see above) for interface + * references stored in static and instance fields. * * A second level 1 defines a pointer to this layout type. * @@ -792,16 +842,6 @@ * normal objects an interface reference in a Java signature appears as a pointer to an interface * layout when printed by gdb. * - *
      - * - *
    • abbrev_code == INTERFACE_POINTER, tag == DW_TAG_pointer_type, has_children - * - *
    • Dw_AT_byte_size : ... DW_FORM_data1 - * - *
    • DW_AT_TYPE : ....... DW_FORM_ref4 - * - *
    - * * The union type embeds level 2 DIEs with tag member. There is a member for each implementing * class, typed using the layout. * @@ -809,11 +849,11 @@ * *
  • abbrev_code == INTERFACE_IMPLEMENTOR, tag == DW_TAG_member, no_children * - *
  • Dw_AT_name : ................... DW_FORM_strp + *
  • DW_AT_name : ................... DW_FORM_strp * - *
  • Dw_AT_type : ................... DW_FORM_ref_addr + *
  • DW_AT_type : ................... DW_FORM_ref_sig8 * - *
  • Dw_AT_accessibility : .......... DW_FORM_data1 + *
  • DW_AT_accessibility : .......... DW_FORM_data1 * * * @@ -834,7 +874,7 @@ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { public DwarfAbbrevSectionImpl(DwarfDebugInfo dwarfSections) { // abbrev section depends on ranges section - super(dwarfSections, DwarfSectionName.DW_ABBREV_SECTION, DwarfSectionName.DW_RANGES_SECTION); + super(dwarfSections, DwarfSectionName.DW_ABBREV_SECTION, DwarfSectionName.DW_RNGLISTS_SECTION); } @Override @@ -868,10 +908,12 @@ public void writeContent(DebugContext context) { public int writeAbbrevs(DebugContext context, byte[] buffer, int p) { int pos = p; pos = writeCompileUnitAbbrevs(context, buffer, pos); + pos = writeTypeUnitAbbrev(context, buffer, pos); pos = writePrimitiveTypeAbbrev(context, buffer, pos); pos = writeVoidTypeAbbrev(context, buffer, pos); pos = writeObjectHeaderAbbrev(context, buffer, pos); + pos = writeClassConstantAbbrev(context, buffer, pos); pos = writeNamespaceAbbrev(context, buffer, pos); @@ -879,19 +921,16 @@ public int writeAbbrevs(DebugContext context, byte[] buffer, int p) { pos = writeClassReferenceAbbrev(context, buffer, pos); pos = writeMethodDeclarationAbbrevs(context, buffer, pos); pos = writeFieldDeclarationAbbrevs(context, buffer, pos); - pos = writeClassConstantAbbrev(context, buffer, pos); pos = writeArrayLayoutAbbrev(context, buffer, pos); - pos = writeArrayReferenceAbbrev(context, buffer, pos); pos = writeInterfaceLayoutAbbrev(context, buffer, pos); - pos = writeInterfaceReferenceAbbrev(context, buffer, pos); - pos = writeForeignReferenceAbbrev(context, buffer, pos); pos = writeForeignTypedefAbbrev(context, buffer, pos); pos = writeForeignStructAbbrev(context, buffer, pos); pos = writeHeaderFieldAbbrev(context, buffer, pos); + pos = writeArrayElementFieldAbbrev(context, buffer, pos); pos = writeArrayDataTypeAbbrevs(context, buffer, pos); pos = writeArraySubrangeTypeAbbrev(context, buffer, pos); pos = writeMethodLocationAbbrev(context, buffer, pos); @@ -914,7 +953,6 @@ public int writeAbbrevs(DebugContext context, byte[] buffer, int p) { */ if (dwarfSections.useHeapBase()) { pos = writeIndirectLayoutAbbrev(context, buffer, pos); - pos = writeIndirectReferenceAbbrev(context, buffer, pos); } pos = writeParameterDeclarationAbbrevs(context, buffer, pos); @@ -942,9 +980,10 @@ private int writeHasChildren(DwarfHasChildren hasChildren, byte[] buffer, int po private int writeCompileUnitAbbrevs(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; - pos = writeCompileUnitAbbrev(context, AbbrevCode.BUILTIN_UNIT, buffer, pos); + pos = writeCompileUnitAbbrev(context, AbbrevCode.CLASS_CONSTANT_UNIT, buffer, pos); pos = writeCompileUnitAbbrev(context, AbbrevCode.CLASS_UNIT_1, buffer, pos); pos = writeCompileUnitAbbrev(context, AbbrevCode.CLASS_UNIT_2, buffer, pos); + pos = writeCompileUnitAbbrev(context, AbbrevCode.CLASS_UNIT_3, buffer, pos); return pos; } @@ -961,13 +1000,17 @@ private int writeCompileUnitAbbrev(@SuppressWarnings("unused") DebugContext cont pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_comp_dir, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); - if (abbrevCode == AbbrevCode.CLASS_UNIT_2) { + if (abbrevCode == AbbrevCode.CLASS_UNIT_2 || abbrevCode == AbbrevCode.CLASS_UNIT_3) { pos = writeAttrType(DwarfAttribute.DW_AT_ranges, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_sec_offset, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_low_pc, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_addr, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_stmt_list, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_sec_offset, buffer, pos); + if (abbrevCode == AbbrevCode.CLASS_UNIT_3) { + pos = writeAttrType(DwarfAttribute.DW_AT_loclists_base, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_sec_offset, buffer, pos); + } } /* * Now terminate. @@ -977,6 +1020,23 @@ private int writeCompileUnitAbbrev(@SuppressWarnings("unused") DebugContext cont return pos; } + private int writeTypeUnitAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { + int pos = p; + pos = writeAbbrevCode(AbbrevCode.TYPE_UNIT, buffer, pos); + pos = writeTag(DwarfTag.DW_TAG_type_unit, buffer, pos); + pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_yes, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_language, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_use_UTF8, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); + /* + * Now terminate. + */ + pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); + return pos; + } + private int writePrimitiveTypeAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; pos = writeAbbrevCode(AbbrevCode.PRIMITIVE_TYPE, buffer, pos); @@ -1048,6 +1108,7 @@ private int writeNamespaceAbbrev(@SuppressWarnings("unused") DebugContext contex private int writeClassLayoutAbbrevs(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; pos = writeClassLayoutAbbrev(context, AbbrevCode.CLASS_LAYOUT_1, buffer, pos); + pos = writeClassLayoutAbbrev(context, AbbrevCode.CLASS_LAYOUT_3, buffer, pos); if (!dwarfSections.useHeapBase()) { pos = writeClassLayoutAbbrev(context, AbbrevCode.CLASS_LAYOUT_2, buffer, pos); } @@ -1062,18 +1123,25 @@ private int writeClassLayoutAbbrev(@SuppressWarnings("unused") DebugContext cont pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_yes, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_name, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_decl_file, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); - /*- - * At present we definitely don't have a line number for the class itself. - pos = writeAttrType(DwarfDebugInfo.DW_AT_decl_line, buffer, pos); - pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data2, buffer, pos); - */ - if (abbrevCode == AbbrevCode.CLASS_LAYOUT_2) { - pos = writeAttrType(DwarfAttribute.DW_AT_data_location, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_expr_loc, buffer, pos); + if (abbrevCode == AbbrevCode.CLASS_LAYOUT_3) { + pos = writeAttrType(DwarfAttribute.DW_AT_declaration, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_signature, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); + } else { + pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_decl_file, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); + /*- + * At present we definitely don't have a line number for the class itself. + pos = writeAttrType(DwarfDebugInfo.DW_AT_decl_line, buffer, pos); + pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data2, buffer, pos); + */ + if (abbrevCode == AbbrevCode.CLASS_LAYOUT_2) { + pos = writeAttrType(DwarfAttribute.DW_AT_data_location, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_expr_loc, buffer, pos); + } } /* * Now terminate. @@ -1088,13 +1156,13 @@ private int writeClassReferenceAbbrev(@SuppressWarnings("unused") DebugContext c int pos = p; /* A pointer to the class struct type. */ - pos = writeAbbrevCode(AbbrevCode.CLASS_POINTER, buffer, pos); + pos = writeAbbrevCode(AbbrevCode.TYPE_POINTER, buffer, pos); pos = writeTag(DwarfTag.DW_TAG_pointer_type, buffer, pos); pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); /* * Now terminate. */ @@ -1107,6 +1175,7 @@ private int writeMethodDeclarationAbbrevs(@SuppressWarnings("unused") DebugConte int pos = p; pos = writeMethodDeclarationAbbrev(context, AbbrevCode.METHOD_DECLARATION, buffer, pos); pos = writeMethodDeclarationAbbrev(context, AbbrevCode.METHOD_DECLARATION_STATIC, buffer, pos); + pos = writeMethodDeclarationAbbrev(context, AbbrevCode.METHOD_DECLARATION_SKELETON, buffer, pos); return pos; } @@ -1119,25 +1188,29 @@ private int writeMethodDeclarationAbbrev(@SuppressWarnings("unused") DebugContex pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_name, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_decl_file, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_decl_line, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); + if (abbrevCode == AbbrevCode.METHOD_DECLARATION || abbrevCode == AbbrevCode.METHOD_DECLARATION_STATIC) { + pos = writeAttrType(DwarfAttribute.DW_AT_decl_file, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_decl_line, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); + } pos = writeAttrType(DwarfAttribute.DW_AT_linkage_name, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_artificial, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_accessibility, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_declaration, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); - /* This is not in DWARF2 */ - // pos = writeAttrType(DW_AT_virtuality, buffer, pos); - // pos = writeAttrForm(DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_containing_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); + if (abbrevCode == AbbrevCode.METHOD_DECLARATION || abbrevCode == AbbrevCode.METHOD_DECLARATION_STATIC) { + /* This is not in DWARF2 */ + // pos = writeAttrType(DW_AT_virtuality, buffer, pos); + // pos = writeAttrForm(DW_FORM_data1, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_containing_type, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); + } if (abbrevCode == AbbrevCode.METHOD_DECLARATION) { pos = writeAttrType(DwarfAttribute.DW_AT_object_pointer, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); @@ -1179,7 +1252,7 @@ private int writeFieldDeclarationAbbrev(@SuppressWarnings("unused") DebugContext // pos = writeAttrForm(DwarfDebugInfo.DW_FORM_data2, buffer, pos); } pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); if (abbrevCode == AbbrevCode.FIELD_DECLARATION_1 || abbrevCode == AbbrevCode.FIELD_DECLARATION_2) { /* Instance fields have a member offset relocated relative to the heap base register. */ pos = writeAttrType(DwarfAttribute.DW_AT_data_member_location, buffer, pos); @@ -1211,13 +1284,11 @@ private int writeClassConstantAbbrev(@SuppressWarnings("unused") DebugContext co pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); /* We may not have a file and line for a field. */ pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_accessibility, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_external, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_declaration, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_location, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_expr_loc, buffer, pos); /* @@ -1246,24 +1317,6 @@ private int writeArrayLayoutAbbrev(@SuppressWarnings("unused") DebugContext cont return pos; } - private int writeArrayReferenceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - - pos = writeAbbrevCode(AbbrevCode.ARRAY_POINTER, buffer, pos); - pos = writeTag(DwarfTag.DW_TAG_pointer_type, buffer, pos); - pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); - return pos; - } - private int writeInterfaceLayoutAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; @@ -1280,24 +1333,6 @@ private int writeInterfaceLayoutAbbrev(@SuppressWarnings("unused") DebugContext return pos; } - private int writeInterfaceReferenceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - - pos = writeAbbrevCode(AbbrevCode.INTERFACE_POINTER, buffer, pos); - pos = writeTag(DwarfTag.DW_TAG_pointer_type, buffer, pos); - pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); - return pos; - } - private int writeInterfaceImplementorAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; @@ -1307,7 +1342,7 @@ private int writeInterfaceImplementorAbbrev(@SuppressWarnings("unused") DebugCon pos = writeAttrType(DwarfAttribute.DW_AT_name, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_accessibility, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); /* @@ -1318,28 +1353,6 @@ private int writeInterfaceImplementorAbbrev(@SuppressWarnings("unused") DebugCon return pos; } - private int writeForeignReferenceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - - /* A pointer to the class struct type. */ - pos = writeAbbrevCode(AbbrevCode.FOREIGN_POINTER, buffer, pos); - pos = writeTag(DwarfTag.DW_TAG_pointer_type, buffer, pos); - pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); - // n.b we use a (relocatable) ref_addr here rather than a (CU-relative) ref4 - // because an unknown foreign pointer type will reference void which is not - // local to the current CU. - pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); - return pos; - } - private int writeForeignTypedefAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; @@ -1387,6 +1400,28 @@ private int writeHeaderFieldAbbrev(@SuppressWarnings("unused") DebugContext cont pos = writeAttrType(DwarfAttribute.DW_AT_name, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_data_member_location, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_accessibility, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); + /* + * Now terminate. + */ + pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); + return pos; + } + + private int writeArrayElementFieldAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { + int pos = p; + + pos = writeAbbrevCode(AbbrevCode.ARRAY_ELEMENT_FIELD, buffer, pos); + pos = writeTag(DwarfTag.DW_TAG_member, buffer, pos); + pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_name, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_strp, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_data_member_location, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); @@ -1422,7 +1457,7 @@ private int writeArrayDataTypeAbbrev(@SuppressWarnings("unused") DebugContext co // because a foreign array type can reference another foreign type which is // not in the current CU. pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); /* * Now terminate. */ @@ -1460,7 +1495,7 @@ private int writeMethodLocationAbbrev(@SuppressWarnings("unused") DebugContext c pos = writeAttrType(DwarfAttribute.DW_AT_external, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_specification, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); /* * Now terminate. */ @@ -1510,12 +1545,11 @@ private int writeStaticFieldLocationAbbrev(@SuppressWarnings("unused") DebugCont private int writeSuperReferenceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { int pos = p; - pos = writeAbbrevCode(AbbrevCode.SUPER_REFERENCE, buffer, pos); pos = writeTag(DwarfTag.DW_TAG_inheritance, buffer, pos); pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_data_member_location, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_accessibility, buffer, pos); @@ -1525,6 +1559,7 @@ private int writeSuperReferenceAbbrev(@SuppressWarnings("unused") DebugContext c */ pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); + return pos; } @@ -1558,30 +1593,13 @@ private int writeIndirectLayoutAbbrev(@SuppressWarnings("unused") DebugContext c return pos; } - private int writeIndirectReferenceAbbrev(@SuppressWarnings("unused") DebugContext context, byte[] buffer, int p) { - int pos = p; - - /* The type for a pointer to the indirect layout type. */ - pos = writeAbbrevCode(AbbrevCode.INDIRECT_POINTER, buffer, pos); - pos = writeTag(DwarfTag.DW_TAG_pointer_type, buffer, pos); - pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_byte_size, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_data1, buffer, pos); - pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); - /* - * Now terminate. - */ - pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); - return pos; - } - private int writeParameterDeclarationAbbrevs(DebugContext context, byte[] buffer, int p) { int pos = p; pos = writeParameterDeclarationAbbrev(context, AbbrevCode.METHOD_PARAMETER_DECLARATION_1, buffer, pos); pos = writeParameterDeclarationAbbrev(context, AbbrevCode.METHOD_PARAMETER_DECLARATION_2, buffer, pos); pos = writeParameterDeclarationAbbrev(context, AbbrevCode.METHOD_PARAMETER_DECLARATION_3, buffer, pos); + pos = writeSkeletonParameterDeclarationAbbrev(context, AbbrevCode.METHOD_PARAMETER_DECLARATION_4, buffer, pos); + pos = writeSkeletonParameterDeclarationAbbrev(context, AbbrevCode.METHOD_PARAMETER_DECLARATION_5, buffer, pos); return pos; } @@ -1600,7 +1618,7 @@ private int writeParameterDeclarationAbbrev(@SuppressWarnings("unused") DebugCon pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); } pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); if (abbrevCode == AbbrevCode.METHOD_PARAMETER_DECLARATION_1) { /* Only this parameter is artificial and it has no line. */ pos = writeAttrType(DwarfAttribute.DW_AT_artificial, buffer, pos); @@ -1616,6 +1634,26 @@ private int writeParameterDeclarationAbbrev(@SuppressWarnings("unused") DebugCon return pos; } + private int writeSkeletonParameterDeclarationAbbrev(@SuppressWarnings("unused") DebugContext context, AbbrevCode abbrevCode, byte[] buffer, int p) { + int pos = p; + pos = writeAbbrevCode(abbrevCode, buffer, pos); + pos = writeTag(DwarfTag.DW_TAG_formal_parameter, buffer, pos); + pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); + pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); + if (abbrevCode == AbbrevCode.METHOD_PARAMETER_DECLARATION_4) { + /* Only this parameter is artificial and it has no line. */ + pos = writeAttrType(DwarfAttribute.DW_AT_artificial, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); + } + /* + * Now terminate. + */ + pos = writeAttrType(DwarfAttribute.DW_AT_null, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_null, buffer, pos); + return pos; + } + private int writeLocalDeclarationAbbrevs(DebugContext context, byte[] buffer, int p) { int pos = p; pos = writeLocalDeclarationAbbrev(context, AbbrevCode.METHOD_LOCAL_DECLARATION_1, buffer, pos); @@ -1638,7 +1676,7 @@ private int writeLocalDeclarationAbbrev(@SuppressWarnings("unused") DebugContext pos = writeAttrForm(DwarfForm.DW_FORM_data2, buffer, pos); } pos = writeAttrType(DwarfAttribute.DW_AT_type, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_sig8, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_declaration, buffer, pos); pos = writeAttrForm(DwarfForm.DW_FORM_flag, buffer, pos); /* @@ -1669,10 +1707,10 @@ private int writeParameterLocationAbbrev(@SuppressWarnings("unused") DebugContex pos = writeTag(DwarfTag.DW_TAG_formal_parameter, buffer, pos); pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_abstract_origin, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); if (abbrevCode == AbbrevCode.METHOD_PARAMETER_LOCATION_2) { pos = writeAttrType(DwarfAttribute.DW_AT_location, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_sec_offset, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_loclistx, buffer, pos); } /* * Now terminate. @@ -1688,10 +1726,10 @@ private int writeLocalLocationAbbrev(@SuppressWarnings("unused") DebugContext co pos = writeTag(DwarfTag.DW_TAG_variable, buffer, pos); pos = writeHasChildren(DwarfHasChildren.DW_CHILDREN_no, buffer, pos); pos = writeAttrType(DwarfAttribute.DW_AT_abstract_origin, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_ref4, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_ref_addr, buffer, pos); if (abbrevCode == AbbrevCode.METHOD_LOCAL_LOCATION_2) { pos = writeAttrType(DwarfAttribute.DW_AT_location, buffer, pos); - pos = writeAttrForm(DwarfForm.DW_FORM_sec_offset, buffer, pos); + pos = writeAttrForm(DwarfForm.DW_FORM_loclistx, buffer, pos); } /* * Now terminate. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java index aee6600eeb85..3f6871052b2c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfDebugInfo.java @@ -28,17 +28,17 @@ import java.nio.ByteOrder; +import org.graalvm.collections.EconomicMap; + import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.DebugInfoBase; - import com.oracle.objectfile.debugentry.MethodEntry; -import com.oracle.objectfile.debugentry.range.Range; import com.oracle.objectfile.debugentry.StructureTypeEntry; import com.oracle.objectfile.debugentry.TypeEntry; +import com.oracle.objectfile.debugentry.range.Range; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalInfo; import com.oracle.objectfile.elf.ELFMachine; import com.oracle.objectfile.elf.dwarf.constants.DwarfLanguage; -import org.graalvm.collections.EconomicMap; /** * A class that models the debug info in an organization that facilitates generation of the required @@ -56,37 +56,38 @@ enum AbbrevCode { /* null marker which must come first as its ordinal has to equal zero */ NULL, /* Level 0 DIEs. */ - BUILTIN_UNIT, + CLASS_CONSTANT_UNIT, CLASS_UNIT_1, CLASS_UNIT_2, + CLASS_UNIT_3, + TYPE_UNIT, /* Level 1 DIEs. */ PRIMITIVE_TYPE, VOID_TYPE, OBJECT_HEADER, + CLASS_CONSTANT, NAMESPACE, CLASS_LAYOUT_1, CLASS_LAYOUT_2, - CLASS_POINTER, - FOREIGN_POINTER, + CLASS_LAYOUT_3, + TYPE_POINTER, FOREIGN_TYPEDEF, FOREIGN_STRUCT, METHOD_LOCATION, STATIC_FIELD_LOCATION, ARRAY_LAYOUT, - ARRAY_POINTER, INTERFACE_LAYOUT, - INTERFACE_POINTER, INDIRECT_LAYOUT, - INDIRECT_POINTER, /* Level 2 DIEs. */ METHOD_DECLARATION, METHOD_DECLARATION_STATIC, + METHOD_DECLARATION_SKELETON, FIELD_DECLARATION_1, FIELD_DECLARATION_2, FIELD_DECLARATION_3, FIELD_DECLARATION_4, - CLASS_CONSTANT, HEADER_FIELD, + ARRAY_ELEMENT_FIELD, ARRAY_DATA_TYPE_1, ARRAY_DATA_TYPE_2, ARRAY_SUBRANGE, @@ -100,6 +101,8 @@ enum AbbrevCode { METHOD_PARAMETER_DECLARATION_1, METHOD_PARAMETER_DECLARATION_2, METHOD_PARAMETER_DECLARATION_3, + METHOD_PARAMETER_DECLARATION_4, + METHOD_PARAMETER_DECLARATION_5, METHOD_LOCAL_DECLARATION_1, METHOD_LOCAL_DECLARATION_2, METHOD_PARAMETER_LOCATION_1, @@ -126,6 +129,11 @@ enum AbbrevCode { * address translation */ public static final String INDIRECT_PREFIX = "_z_."; + /* + * A prefix used for type signature generation to generate unique type signatures for type + * layout type units + */ + public static final String LAYOUT_PREFIX = "_layout_."; /* * The name of the type for header field hub which needs special case processing to remove tag * bits @@ -155,7 +163,7 @@ enum AbbrevCode { * n.b. this collection includes entries for the structure types used to define the object and * array headers which do not have an associated TypeEntry. */ - private final EconomicMap typePropertiesIndex = EconomicMap.create(); + private final EconomicMap classPropertiesIndex = EconomicMap.create(); /** * A collection of method properties associated with each generated method record. @@ -231,80 +239,26 @@ public byte getThreadRegister() { } /** - * A class used to associate properties with a specific type, the most important one being its - * index in the info section. + * A class used to associate extra properties with an instance class type. */ - static class DwarfTypeProperties { - /** - * Index in debug_info section of type declaration for this class. - */ - private int typeInfoIndex; - /** - * Index in debug_info section of indirect type declaration for this class. - * - * this is normally just the same as the index of the normal type declaration, however, when - * oops are stored in static and instance fields as offsets from the heapbase register gdb - * needs to be told how to convert these oops to raw addresses and this requires attaching a - * data_location address translation expression to an indirect type that wraps the object - * layout type. so, with that encoding this field will identify the wrapper type whenever - * the original type is an object, interface or array layout. primitive types and header - * types do not need translating. - */ - private int indirectTypeInfoIndex; + + static class DwarfClassProperties { /** * The type entry with which these properties are associated. */ - private final TypeEntry typeEntry; - - public int getTypeInfoIndex() { - return typeInfoIndex; - } - - public void setTypeInfoIndex(int typeInfoIndex) { - this.typeInfoIndex = typeInfoIndex; - } - - public int getIndirectTypeInfoIndex() { - return indirectTypeInfoIndex; - } - - public void setIndirectTypeInfoIndex(int typeInfoIndex) { - this.indirectTypeInfoIndex = typeInfoIndex; - } - - public TypeEntry getTypeEntry() { - return typeEntry; - } - - DwarfTypeProperties(TypeEntry typeEntry) { - this.typeEntry = typeEntry; - this.typeInfoIndex = -1; - this.indirectTypeInfoIndex = -1; - } - - } - - /** - * A class used to associate extra properties with an instance class type. - */ - - static class DwarfClassProperties extends DwarfTypeProperties { + private final StructureTypeEntry typeEntry; /** * Index of the class entry's compile unit in the debug_info section. */ private int cuIndex; /** - * Index of the class entry's class_layout DIE in the debug_info section. - */ - private int layoutIndex; - /** - * Index of the class entry's indirect layout DIE in the debug_info section. + * Index of the class entry's code ranges data in the debug_rnglists section. */ - private int indirectLayoutIndex; + private int codeRangesIndex; /** - * Index of the class entry's code ranges data in the debug_ranges section. + * Index of the class entry's code location data in the debug_loclists section. */ - private int codeRangesIndex; + private int locationListIndex; /** * Index of the class entry's line data in the debug_line section. */ @@ -318,12 +272,15 @@ static class DwarfClassProperties extends DwarfTypeProperties { */ private EconomicMap fieldDeclarationIndex; - DwarfClassProperties(StructureTypeEntry entry) { - super(entry); + public StructureTypeEntry getTypeEntry() { + return typeEntry; + } + + DwarfClassProperties(StructureTypeEntry typeEntry) { + this.typeEntry = typeEntry; this.cuIndex = -1; - this.layoutIndex = -1; - this.indirectLayoutIndex = -1; this.codeRangesIndex = -1; + this.locationListIndex = 0; this.lineIndex = -1; this.linePrologueSize = -1; fieldDeclarationIndex = null; @@ -393,19 +350,9 @@ public int getAbstractInlineMethodIndex(ClassEntry classEntry) { } } - private DwarfTypeProperties addTypeProperties(TypeEntry typeEntry) { - assert typeEntry != null; - assert !typeEntry.isClass(); - assert typePropertiesIndex.get(typeEntry) == null; - DwarfTypeProperties typeProperties = new DwarfTypeProperties(typeEntry); - this.typePropertiesIndex.put(typeEntry, typeProperties); - return typeProperties; - } - private DwarfClassProperties addClassProperties(StructureTypeEntry entry) { - assert typePropertiesIndex.get(entry) == null; DwarfClassProperties classProperties = new DwarfClassProperties(entry); - this.typePropertiesIndex.put(entry, classProperties); + this.classPropertiesIndex.put(entry, classProperties); return classProperties; } @@ -416,22 +363,8 @@ private DwarfMethodProperties addMethodProperties(MethodEntry methodEntry) { return methodProperties; } - private DwarfTypeProperties lookupTypeProperties(TypeEntry typeEntry) { - if (typeEntry instanceof ClassEntry) { - return lookupClassProperties((ClassEntry) typeEntry); - } else { - DwarfTypeProperties typeProperties = typePropertiesIndex.get(typeEntry); - if (typeProperties == null) { - typeProperties = addTypeProperties(typeEntry); - } - return typeProperties; - } - } - private DwarfClassProperties lookupClassProperties(StructureTypeEntry entry) { - DwarfTypeProperties typeProperties = typePropertiesIndex.get(entry); - assert typeProperties == null || typeProperties instanceof DwarfClassProperties; - DwarfClassProperties classProperties = (DwarfClassProperties) typeProperties; + DwarfClassProperties classProperties = classPropertiesIndex.get(entry); if (classProperties == null) { classProperties = addClassProperties(entry); } @@ -446,40 +379,6 @@ private DwarfMethodProperties lookupMethodProperties(MethodEntry methodEntry) { return methodProperties; } - void setTypeIndex(TypeEntry typeEntry, int idx) { - assert idx >= 0; - DwarfTypeProperties typeProperties = lookupTypeProperties(typeEntry); - assert typeProperties.getTypeInfoIndex() == -1 || typeProperties.getTypeInfoIndex() == idx; - typeProperties.setTypeInfoIndex(idx); - } - - int getTypeIndex(TypeEntry typeEntry) { - DwarfTypeProperties typeProperties = lookupTypeProperties(typeEntry); - return getTypeIndex(typeProperties); - } - - int getTypeIndex(DwarfTypeProperties typeProperties) { - assert typeProperties.getTypeInfoIndex() >= 0; - return typeProperties.getTypeInfoIndex(); - } - - void setIndirectTypeIndex(TypeEntry typeEntry, int idx) { - assert idx >= 0; - DwarfTypeProperties typeProperties = lookupTypeProperties(typeEntry); - assert typeProperties.getIndirectTypeInfoIndex() == -1 || typeProperties.getIndirectTypeInfoIndex() == idx; - typeProperties.setIndirectTypeInfoIndex(idx); - } - - int getIndirectTypeIndex(TypeEntry typeEntry) { - DwarfTypeProperties typeProperties = lookupTypeProperties(typeEntry); - return getIndirectTypeIndex(typeProperties); - } - - int getIndirectTypeIndex(DwarfTypeProperties typeProperties) { - assert typeProperties.getIndirectTypeInfoIndex() >= 0; - return typeProperties.getIndirectTypeInfoIndex(); - } - public void setCUIndex(ClassEntry classEntry, int idx) { assert idx >= 0; DwarfClassProperties classProperties = lookupClassProperties(classEntry); @@ -496,64 +395,35 @@ public int getCUIndex(ClassEntry classEntry) { return classProperties.cuIndex; } - void setLayoutIndex(ClassEntry classEntry, int idx) { - assert idx >= 0 || idx == -1; - DwarfClassProperties classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.layoutIndex == -1 || classProperties.layoutIndex == idx; - classProperties.layoutIndex = idx; - } - - int getLayoutIndex(ClassEntry classEntry) { - DwarfClassProperties classProperties; - classProperties = lookupClassProperties(classEntry); - assert classProperties.getTypeEntry() == classEntry; - assert classProperties.layoutIndex >= 0; - return classProperties.layoutIndex; - } - - void setIndirectLayoutIndex(ClassEntry classEntry, int idx) { - // The layout index of a POINTER type is set to the type index of its referent. - // If the pointer type is generated before its referent that means it can be set - // with value -1 (unset) on the first sizing pass. The indirect layout will - // be reset to a positive offset on the second pass before it is used to write - // the referent of the pointer type. Hence the condition in the following assert. - assert idx >= 0 || idx == -1; - // Note however, that this possibility needs to be finessed when writing - // a foreign struct ADDRESS field of POINTER type (i.e. an embedded field). - // If the struct is generated before the POINTER type then the layout index will - // still be -1 during the second write pass when the field type needs to be - // written. This possibility is handled by typing the field using the typeIdx - // of the referent. the latter is guaranteed to have been set during the first pass. - + public void setCodeRangesIndex(ClassEntry classEntry, int idx) { + assert idx >= 0; DwarfClassProperties classProperties = lookupClassProperties(classEntry); assert classProperties.getTypeEntry() == classEntry; - assert classProperties.indirectLayoutIndex == -1 || classProperties.indirectLayoutIndex == idx; - classProperties.indirectLayoutIndex = idx; + assert classProperties.codeRangesIndex == -1 || classProperties.codeRangesIndex == idx; + classProperties.codeRangesIndex = idx; } - int getIndirectLayoutIndex(ClassEntry classEntry) { + public int getCodeRangesIndex(ClassEntry classEntry) { DwarfClassProperties classProperties; classProperties = lookupClassProperties(classEntry); assert classProperties.getTypeEntry() == classEntry; - assert classProperties.indirectLayoutIndex >= 0; - return classProperties.indirectLayoutIndex; + assert classProperties.codeRangesIndex >= 0; + return classProperties.codeRangesIndex; } - public void setCodeRangesIndex(ClassEntry classEntry, int idx) { + public void setLocationListIndex(ClassEntry classEntry, int idx) { assert idx >= 0; DwarfClassProperties classProperties = lookupClassProperties(classEntry); assert classProperties.getTypeEntry() == classEntry; - assert classProperties.codeRangesIndex == -1 || classProperties.codeRangesIndex == idx; - classProperties.codeRangesIndex = idx; + assert classProperties.locationListIndex == 0 || classProperties.locationListIndex == idx; + classProperties.locationListIndex = idx; } - public int getCodeRangesIndex(ClassEntry classEntry) { + public int getLocationListIndex(ClassEntry classEntry) { DwarfClassProperties classProperties; classProperties = lookupClassProperties(classEntry); assert classProperties.getTypeEntry() == classEntry; - assert classProperties.codeRangesIndex >= 0; - return classProperties.codeRangesIndex; + return classProperties.locationListIndex; } public void setLineIndex(ClassEntry classEntry, int idx) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java index e38565863930..780f05fff985 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -60,6 +60,7 @@ import com.oracle.objectfile.elf.dwarf.constants.DwarfInline; import com.oracle.objectfile.elf.dwarf.constants.DwarfLanguage; import com.oracle.objectfile.elf.dwarf.constants.DwarfSectionName; +import com.oracle.objectfile.elf.dwarf.constants.DwarfUnitHeader; import com.oracle.objectfile.elf.dwarf.constants.DwarfVersion; import jdk.graal.compiler.debug.DebugContext; @@ -71,42 +72,28 @@ * Section generator for debug_info section. */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { - /** - * The name of a special DWARF struct type used to model an object header. - */ - private static final String OBJECT_HEADER_STRUCT_NAME = "_objhdr"; - /** * An info header section always contains a fixed number of bytes. */ - private static final int DIE_HEADER_SIZE = 11; - /** - * Normally the offset of DWARF type declarations are tracked using the type/class entry - * properties but that means they are only available to be read during the second pass when - * filling in type cross-references. However, we need to use the offset of the void type during - * the first pass as the target of later-generated foreign pointer types. So, this field saves - * it up front. - */ - private int voidOffset; - private int cuStart; + private static final int CU_DIE_HEADER_SIZE = 12; + private static final int TU_DIE_HEADER_SIZE = 24; + + private int unitStart; public DwarfInfoSectionImpl(DwarfDebugInfo dwarfSections) { // debug_info section depends on loc section - super(dwarfSections, DwarfSectionName.DW_INFO_SECTION, DwarfSectionName.DW_LOC_SECTION); - // initialize to an invalid value - voidOffset = -1; + super(dwarfSections, DwarfSectionName.DW_INFO_SECTION, DwarfSectionName.DW_LOCLISTS_SECTION); // initialize CU start to an invalid value - cuStart = -1; + unitStart = -1; } @Override public void createContent() { assert !contentByteArrayCreated(); - byte[] buffer = null; - int len = generateContent(null, buffer); + int len = generateContent(null, null); - buffer = new byte[len]; + byte[] buffer = new byte[len]; super.setContent(buffer); } @@ -154,33 +141,74 @@ DwarfEncoding computeEncoding(int flags, int bitCount) { public int generateContent(DebugContext context, byte[] buffer) { int pos = 0; - /* Write CU for primitive types and header struct. */ - + /* Write TUs for primitive types and header struct. */ pos = writeBuiltInTypes(context, buffer, pos); /* - * Write CUs for all instance classes, which includes interfaces and enums. That also - * incorporates interfaces that model foreign types. + * Write TUs and CUs for all instance classes, which includes interfaces and enums. That + * also incorporates interfaces that model foreign types. */ - pos = writeInstanceClasses(context, buffer, pos); - /* Write CUs for array types. */ - + /* Write TUs and CUs for array types. */ pos = writeArrays(context, buffer, pos); + /* Write CU for class constant objects. */ + pos = writeClassConstantObjects(context, buffer, pos); + return pos; } + private int writeSkeletonClassLayout(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + log(context, " [0x%08x] class layout", pos); + AbbrevCode abbrevCode = AbbrevCode.CLASS_LAYOUT_3; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + String name = classEntry.getTypeName(); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + log(context, " [0x%08x] declaration true", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + long typeSignature = classEntry.getLayoutTypeSignature(); + log(context, " [0x%08x] type specification 0x%x", pos, typeSignature); + pos = writeTypeSignature(typeSignature, buffer, pos); + + pos = writeStaticFieldDeclarations(context, classEntry, buffer, pos); + pos = writeMethodDeclarations(context, classEntry, buffer, pos); + /* + * Write a terminating null attribute. + */ + return writeAttrNull(buffer, pos); + } + private int writeBuiltInTypes(DebugContext context, byte[] buffer, int p) { int pos = p; + + log(context, " [0x%08x] primitive types", pos); + Cursor cursor = new Cursor(pos); + primitiveTypeStream().forEach(primitiveTypeEntry -> { + if (primitiveTypeEntry.getBitCount() > 0) { + cursor.set(writePrimitiveType(context, primitiveTypeEntry, buffer, cursor.get())); + } else { + cursor.set(writeVoidType(context, primitiveTypeEntry, buffer, cursor.get())); + } + }); + pos = cursor.get(); + + log(context, " [0x%08x] header type", pos); + return writeHeaderType(context, headerType(), buffer, pos); + } + + private int writeClassConstantObjects(DebugContext context, byte[] buffer, int p) { + int pos = p; + // Write the single Java builtin unit header int lengthPos = pos; log(context, " [0x%08x] <0> Java Builtin Compile Unit", pos); - cuStart = p; pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DIE_HEADER_SIZE; - AbbrevCode abbrevCode = AbbrevCode.BUILTIN_UNIT; + assert pos == lengthPos + CU_DIE_HEADER_SIZE; + AbbrevCode abbrevCode = AbbrevCode.CLASS_CONSTANT_UNIT; log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); @@ -193,27 +221,13 @@ private int writeBuiltInTypes(DebugContext context, byte[] buffer, int p) { String compilationDirectory = dwarfSections.getCachePath(); log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - /* Write child entries for primitive Java types. */ - - pos = primitiveTypeStream().reduce(pos, - (pos1, primitiveTypeEntry) -> { - if (primitiveTypeEntry.getBitCount() > 0) { - return writePrimitiveType(context, primitiveTypeEntry, buffer, pos1); - } else { - return writeVoidType(context, primitiveTypeEntry, buffer, pos1); - } - }, - (oldpos, newpos) -> newpos); - - /* Write child entry for object/array header struct. */ - pos = writeHeaderType(context, headerType(), buffer, pos); - - /* write class constants for primitive type classes */ - - pos = primitiveTypeStream().reduce(pos, - (pos1, primitiveTypeEntry) -> writeClassConstantDeclaration(context, primitiveTypeEntry, buffer, pos1), - (oldpos, newpos) -> newpos); + Cursor cursor = new Cursor(pos); + /* Write the location for the special Class object pseudo-static field for all types */ + typeStream().forEach(typeEntry -> { + cursor.set(writeClassConstantDeclaration(context, typeEntry, buffer, cursor.get())); + }); + pos = cursor.get(); /* * Write a terminating null attribute. @@ -221,22 +235,19 @@ private int writeBuiltInTypes(DebugContext context, byte[] buffer, int p) { pos = writeAttrNull(buffer, pos); /* Fix up the CU length. */ - patchLength(lengthPos, buffer, pos); return pos; } - public int writePrimitiveType(DebugContext context, PrimitiveTypeEntry primitiveTypeEntry, byte[] buffer, int p) { + private int writePrimitiveType(DebugContext context, PrimitiveTypeEntry primitiveTypeEntry, byte[] buffer, int p) { assert primitiveTypeEntry.getBitCount() > 0; int pos = p; + + // Write a type unit header + int lengthPos = pos; + pos = writeTUPreamble(context, primitiveTypeEntry.getTypeSignature(), "", buffer, p); + log(context, " [0x%08x] primitive type %s", pos, primitiveTypeEntry.getTypeName()); - /* Record the location of this type entry. */ - setTypeIndex(primitiveTypeEntry, pos); - /* - * primitive fields never need an indirection so use the same index for places where we - * might want an indirect type - */ - setIndirectTypeIndex(primitiveTypeEntry, pos); AbbrevCode abbrevCode = AbbrevCode.PRIMITIVE_TYPE; log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); @@ -251,44 +262,50 @@ public int writePrimitiveType(DebugContext context, PrimitiveTypeEntry primitive pos = writeAttrEncoding(encoding, buffer, pos); String name = primitiveTypeEntry.getTypeName(); log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); - return writeStrSectionOffset(name, buffer, pos); + pos = writeStrSectionOffset(name, buffer, pos); + + /* Write a terminating null attribute. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the type offset. */ + patchLength(lengthPos, buffer, pos); + return pos; } - public int writeVoidType(DebugContext context, PrimitiveTypeEntry primitiveTypeEntry, byte[] buffer, int p) { + private int writeVoidType(DebugContext context, PrimitiveTypeEntry primitiveTypeEntry, byte[] buffer, int p) { assert primitiveTypeEntry.getBitCount() == 0; int pos = p; + + // Write a type unit header + int lengthPos = pos; + pos = writeTUPreamble(context, primitiveTypeEntry.getTypeSignature(), "", buffer, p); + log(context, " [0x%08x] primitive type void", pos); - /* Record the location of this type entry. */ - setTypeIndex(primitiveTypeEntry, pos); - /* - * Type void never needs an indirection so use the same index for places where we might want - * an indirect type. - */ - setIndirectTypeIndex(primitiveTypeEntry, pos); - // specially record void type offset for immediate use during first pass of info generation - // we need to use it as the base layout for foreign types - assert voidOffset == -1 || voidOffset == pos; - voidOffset = pos; AbbrevCode abbrevCode = AbbrevCode.VOID_TYPE; log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); String name = primitiveTypeEntry.getTypeName(); log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); - return writeStrSectionOffset(name, buffer, pos); + pos = writeStrSectionOffset(name, buffer, pos); + + /* Write a terminating null attribute. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the type offset. */ + patchLength(lengthPos, buffer, pos); + return pos; } - public int writeHeaderType(DebugContext context, HeaderTypeEntry headerTypeEntry, byte[] buffer, int p) { + private int writeHeaderType(DebugContext context, HeaderTypeEntry headerTypeEntry, byte[] buffer, int p) { int pos = p; + + // Write a type unit header + int lengthPos = pos; + pos = writeTUPreamble(context, headerTypeEntry.getTypeSignature(), "", buffer, p); + String name = headerTypeEntry.getTypeName(); byte size = (byte) headerTypeEntry.getSize(); log(context, " [0x%08x] header type %s", pos, name); - /* Record the location of this type entry. */ - setTypeIndex(headerTypeEntry, pos); - /* - * Header records don't need an indirection so use the same index for places where we might - * want an indirect type. - */ - setIndirectTypeIndex(headerTypeEntry, pos); AbbrevCode abbrevCode = AbbrevCode.OBJECT_HEADER; log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); @@ -297,10 +314,16 @@ public int writeHeaderType(DebugContext context, HeaderTypeEntry headerTypeEntry log(context, " [0x%08x] byte_size 0x%x", pos, size); pos = writeAttrData1(size, buffer, pos); pos = writeStructFields(context, headerTypeEntry.fields(), buffer, pos); - /* - * Write a terminating null attribute. - */ - return writeAttrNull(buffer, pos); + + /* Write a terminating null attribute. */ + pos = writeAttrNull(buffer, pos); + + /* Write a terminating null attribute. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the type offset. */ + patchLength(lengthPos, buffer, pos); + return pos; } private int writeStructFields(DebugContext context, Stream fields, byte[] buffer, int p) { @@ -315,7 +338,9 @@ private int writeStructField(DebugContext context, FieldEntry fieldEntry, byte[] int pos = p; String fieldName = fieldEntry.fieldName(); TypeEntry valueType = fieldEntry.getValueType(); - int valueTypeIdx; + long typeSignature = 0; + int typeIdx = 0; + AbbrevCode abbrevCode = AbbrevCode.HEADER_FIELD; if (fieldEntry.isEmbedded()) { // the field type must be a foreign type ForeignTypeEntry foreignValueType = (ForeignTypeEntry) valueType; @@ -326,7 +351,8 @@ private int writeStructField(DebugContext context, FieldEntry fieldEntry, byte[] if (fieldEntry.getSize() != foreignValueType.getSize()) { assert (fieldSize % valueSize == 0) : "embedded field size is not a multiple of value type size!"; // declare a local array of the embedded type and use it as the value type - valueTypeIdx = pos; + typeIdx = pos; + abbrevCode = AbbrevCode.ARRAY_ELEMENT_FIELD; pos = writeEmbeddedArrayDataType(context, foreignValueType, valueSize, fieldSize / valueSize, buffer, pos); } else { if (foreignValueType.isPointer()) { @@ -343,23 +369,27 @@ private int writeStructField(DebugContext context, FieldEntry fieldEntry, byte[] // of the referring type and the latter precedes the definition of the // referent type then the layout index of the referring type may still be unset // at this point. - valueTypeIdx = getTypeIndex(pointerTo); + typeSignature = pointerTo.getTypeSignature(); } else { - valueTypeIdx = getIndirectLayoutIndex(foreignValueType); + typeSignature = foreignValueType.getIndirectLayoutTypeSignature(); } } } else { /* use the indirect type for the field so pointers get translated */ - valueTypeIdx = getIndirectTypeIndex(valueType); + typeSignature = valueType.getIndirectTypeSignature(); } log(context, " [0x%08x] struct field", pos); - AbbrevCode abbrevCode = AbbrevCode.HEADER_FIELD; log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(fieldName), fieldName); pos = writeStrSectionOffset(fieldName, buffer, pos); - log(context, " [0x%08x] type 0x%x (%s)", pos, valueTypeIdx, valueType.getTypeName()); - pos = writeInfoSectionOffset(valueTypeIdx, buffer, pos); + if (abbrevCode == AbbrevCode.HEADER_FIELD) { + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, valueType.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); + } else { + log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, valueType.getTypeName()); + pos = writeInfoSectionOffset(typeIdx, buffer, pos); + } short offset = (short) fieldEntry.getOffset(); int size = fieldEntry.getSize(); log(context, " [0x%08x] offset 0x%x (size 0x%x)", pos, offset, size); @@ -373,22 +403,388 @@ private int writeInstanceClasses(DebugContext context, byte[] buffer, int pos) { log(context, " [0x%08x] instance classes", pos); Cursor cursor = new Cursor(pos); instanceClassStream().forEach(classEntry -> { - // save current CU start so we can write Ref4 attributes as CU offsets - cuStart = cursor.get(); - setCUIndex(classEntry, cuStart); + cursor.set(writeTypeUnits(context, classEntry, buffer, cursor.get())); + setCUIndex(classEntry, cursor.get()); cursor.set(writeInstanceClassInfo(context, classEntry, buffer, cursor.get())); }); return cursor.get(); } + private int writeTypeUnits(DebugContext context, StructureTypeEntry typeEntry, byte[] buffer, int p) { + int pos = p; + + if (typeEntry.isForeign()) { + ForeignTypeEntry foreignTypeEntry = (ForeignTypeEntry) typeEntry; + pos = writeForeignLayoutTypeUnit(context, foreignTypeEntry, buffer, pos); + pos = writeForeignTypeUnit(context, foreignTypeEntry, buffer, pos); + } else { + if (typeEntry.isArray()) { + pos = writeArrayLayoutTypeUnit(context, (ArrayTypeEntry) typeEntry, buffer, pos); + } else if (typeEntry.isInterface()) { + pos = writeInterfaceLayoutTypeUnit(context, (InterfaceClassEntry) typeEntry, buffer, pos); + } else { + assert typeEntry instanceof ClassEntry; + pos = writeClassLayoutTypeUnit(context, (ClassEntry) typeEntry, buffer, pos); + } + pos = writePointerTypeUnit(context, typeEntry, false, buffer, pos); + if (dwarfSections.useHeapBase()) { + pos = writeIndirectLayoutTypeUnit(context, typeEntry, buffer, pos); + pos = writePointerTypeUnit(context, typeEntry, true, buffer, pos); + } + } + return pos; + } + + private int writeTUPreamble(DebugContext context, long typeSignature, String loaderId, byte[] buffer, int p) { + int pos = p; + + // Write a type unit header + pos = writeTUHeader(typeSignature, buffer, pos); + int typeOffsetPos = pos - 4; + assert pos == p + TU_DIE_HEADER_SIZE; + AbbrevCode abbrevCode = AbbrevCode.TYPE_UNIT; + log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); + pos = writeAttrLanguage(DwarfDebugInfo.LANG_ENCODING, buffer, pos); + log(context, " [0x%08x] use_UTF8", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + + /* if the class has a loader then embed the children in a namespace */ + if (!loaderId.isEmpty()) { + pos = writeNameSpace(context, loaderId, buffer, pos); + } + + /* Fix up the type offset. */ + writeInt(pos - p, buffer, typeOffsetPos); + return pos; + } + + private int writePointerTypeUnit(DebugContext context, StructureTypeEntry typeEntry, boolean indirect, byte[] buffer, int p) { + int pos = p; + + String loaderId = ""; + if (typeEntry.isArray()) { + loaderId = ((ArrayTypeEntry) typeEntry).getLoaderId(); + } else if (typeEntry.isClass()) { + loaderId = ((ClassEntry) typeEntry).getLoaderId(); + } + int lengthPos = pos; + long typeSignature = indirect ? typeEntry.getIndirectTypeSignature() : typeEntry.getTypeSignature(); + pos = writeTUPreamble(context, typeSignature, loaderId, buffer, p); + + /* Define a pointer type referring to the underlying layout. */ + log(context, " [0x%08x] %s%s pointer type", pos, typeEntry.isInterface() ? "interface" : "class", indirect ? " indirect" : ""); + AbbrevCode abbrevCode = AbbrevCode.TYPE_POINTER; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + int pointerSize = indirect ? dwarfSections.referenceSize() : dwarfSections.pointerSize(); + log(context, " [0x%08x] byte_size 0x%x", pos, pointerSize); + pos = writeAttrData1((byte) pointerSize, buffer, pos); + long layoutTypeSignature = indirect ? typeEntry.getIndirectLayoutTypeSignature() : typeEntry.getLayoutTypeSignature(); + log(context, " [0x%08x] type 0x%x", pos, layoutTypeSignature); + pos = writeTypeSignature(layoutTypeSignature, buffer, pos); + + if (!loaderId.isEmpty()) { + /* Write a terminating null attribute for the namespace. */ + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the TU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + + private int writeIndirectLayoutTypeUnit(DebugContext context, StructureTypeEntry typeEntry, byte[] buffer, int p) { + int pos = p; + + String loaderId = ""; + if (typeEntry.isArray()) { + loaderId = ((ArrayTypeEntry) typeEntry).getLoaderId(); + } else if (typeEntry.isClass()) { + loaderId = ((ClassEntry) typeEntry).getLoaderId(); + } + int lengthPos = pos; + pos = writeTUPreamble(context, typeEntry.getIndirectLayoutTypeSignature(), loaderId, buffer, pos); + + /* + * Write a wrapper type with a data_location attribute that can act as a target for an + * indirect pointer. + */ + log(context, " [0x%08x] indirect %s layout", pos, typeEntry.isInterface() ? "interface" : "class"); + AbbrevCode abbrevCode = AbbrevCode.INDIRECT_LAYOUT; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + String indirectName = uniqueDebugString(DwarfDebugInfo.INDIRECT_PREFIX + typeEntry.getTypeName()); + String name = uniqueDebugString(typeEntry.getTypeName()); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(indirectName), name); + pos = writeStrSectionOffset(indirectName, buffer, pos); + int size = typeEntry.getSize(); + log(context, " [0x%08x] byte_size 0x%x", pos, size); + pos = writeAttrData2((short) size, buffer, pos); + /* Write a data location expression to mask and/or rebase oop pointers. */ + log(context, " [0x%08x] data_location", pos); + pos = writeIndirectOopConversionExpression(dwarfSections.isHubClassEntry(typeEntry), buffer, pos); + + /* Now write the child field. */ + pos = writeSuperReference(context, typeEntry.getLayoutTypeSignature(), name, buffer, pos); + + /* Write a terminating null attribute for the indirect layout. */ + pos = writeAttrNull(buffer, pos); + + if (!loaderId.isEmpty()) { + /* Write a terminating null attribute for the namespace. */ + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the TU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + + private int writeInterfaceLayoutTypeUnit(DebugContext context, InterfaceClassEntry interfaceClassEntry, byte[] buffer, int p) { + int pos = p; + + String loaderId = interfaceClassEntry.getLoaderId(); + int lengthPos = pos; + pos = writeTUPreamble(context, interfaceClassEntry.getLayoutTypeSignature(), loaderId, buffer, pos); + + log(context, " [0x%08x] interface layout", pos); + AbbrevCode abbrevCode = AbbrevCode.INTERFACE_LAYOUT; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + String name = interfaceClassEntry.getTypeName(); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + + /* Now write references to all class layouts that implement this interface. */ + pos = writeInterfaceImplementors(context, interfaceClassEntry, buffer, pos); + pos = writeSkeletonMethodDeclarations(context, interfaceClassEntry, buffer, pos); + + /* Write a terminating null attribute for the interface layout. */ + pos = writeAttrNull(buffer, pos); + + if (!loaderId.isEmpty()) { + /* Write a terminating null attribute for the namespace. */ + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the TU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + + private int writeClassLayoutTypeUnit(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + + String loaderId = classEntry.getLoaderId(); + int lengthPos = pos; + pos = writeTUPreamble(context, classEntry.getLayoutTypeSignature(), loaderId, buffer, pos); + + log(context, " [0x%08x] type layout", pos); + AbbrevCode abbrevCode = AbbrevCode.CLASS_LAYOUT_1; + /* + * when we don't have a separate indirect type then hub layouts need an extra data_location + * attribute + */ + if (!dwarfSections.useHeapBase() && dwarfSections.isHubClassEntry(classEntry)) { + abbrevCode = AbbrevCode.CLASS_LAYOUT_2; + } + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + String name = classEntry.getTypeName(); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + int size = classEntry.getSize(); + log(context, " [0x%08x] byte_size 0x%x", pos, size); + pos = writeAttrData2((short) size, buffer, pos); + int fileIdx = classEntry.getFileIdx(); + log(context, " [0x%08x] file 0x%x (%s)", pos, fileIdx, classEntry.getFileName()); + pos = writeAttrData2((short) fileIdx, buffer, pos); + if (abbrevCode == AbbrevCode.CLASS_LAYOUT_2) { + /* Write a data location expression to mask and/or rebase oop pointers. */ + log(context, " [0x%08x] data_location", pos); + pos = writeIndirectOopConversionExpression(true, buffer, pos); + } + + StructureTypeEntry superClassEntry = classEntry.getSuperClass(); + if (superClassEntry == null) { + superClassEntry = headerType(); + } + + /* Now write the child fields. */ + pos = writeSuperReference(context, superClassEntry.getLayoutTypeSignature(), superClassEntry.getTypeName(), buffer, pos); + pos = writeFields(context, classEntry, buffer, pos); + pos = writeSkeletonMethodDeclarations(context, classEntry, buffer, pos); + + /* Write a terminating null attribute for the class layout. */ + pos = writeAttrNull(buffer, pos); + + if (!loaderId.isEmpty()) { + /* Write a terminating null attribute for the namespace. */ + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the TU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + + private int writeForeignTypeUnit(DebugContext context, ForeignTypeEntry foreignTypeEntry, byte[] buffer, int p) { + int pos = p; + long typeSignature = foreignTypeEntry.getTypeSignature(); + + // Unlike with Java we use the Java name for the pointer type rather than the + // underlying base type, or rather for a typedef that targets the pointer type. + // That ensures that e.g. CCharPointer is a typedef for char*. + + // Write a type unit header + int lengthPos = pos; + pos = writeTUHeader(typeSignature, buffer, pos); + int typeOffsetPos = pos - 4; + assert pos == lengthPos + TU_DIE_HEADER_SIZE; + AbbrevCode abbrevCode = AbbrevCode.TYPE_UNIT; + log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); + pos = writeAttrLanguage(DwarfDebugInfo.LANG_ENCODING, buffer, pos); + log(context, " [0x%08x] use_UTF8", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + + /* if the class has a loader then embed the children in a namespace */ + String loaderId = foreignTypeEntry.getLoaderId(); + if (!loaderId.isEmpty()) { + pos = writeNameSpace(context, loaderId, buffer, pos); + } + + /* Define a pointer type referring to the base type */ + int refTypeIdx = pos; + log(context, " [0x%08x] foreign pointer type", pos); + abbrevCode = AbbrevCode.TYPE_POINTER; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + int pointerSize = dwarfSections.pointerSize(); + log(context, " [0x%08x] byte_size 0x%x", pos, pointerSize); + pos = writeAttrData1((byte) pointerSize, buffer, pos); + long layoutTypeSignature = foreignTypeEntry.getLayoutTypeSignature(); + log(context, " [0x%08x] type 0x%x", pos, layoutTypeSignature); + pos = writeTypeSignature(layoutTypeSignature, buffer, pos); + + /* Fix up the type offset. */ + writeInt(pos - lengthPos, buffer, typeOffsetPos); + + /* Define a typedef for the layout type using the Java name. */ + log(context, " [0x%08x] foreign typedef", pos); + abbrevCode = AbbrevCode.FOREIGN_TYPEDEF; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + String name = uniqueDebugString(foreignTypeEntry.getTypeName()); + log(context, " [0x%08x] name %s", pos, name); + pos = writeStrSectionOffset(name, buffer, pos); + log(context, " [0x%08x] type 0x%x", pos, refTypeIdx); + pos = writeAttrRef4(refTypeIdx, buffer, pos); + + if (!loaderId.isEmpty()) { + /* Write a terminating null attribute for the namespace. */ + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the TU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + + private int writeForeignLayoutTypeUnit(DebugContext context, ForeignTypeEntry foreignTypeEntry, byte[] buffer, int p) { + int pos = p; + + String loaderId = foreignTypeEntry.getLoaderId(); + int lengthPos = pos; + pos = writeTUPreamble(context, foreignTypeEntry.getLayoutTypeSignature(), loaderId, buffer, pos); + + int size = foreignTypeEntry.getSize(); + if (foreignTypeEntry.isWord()) { + // define the type as a typedef for a signed or unsigned word i.e. we don't have a + // layout type + pos = writeForeignWordLayout(context, foreignTypeEntry, size, foreignTypeEntry.isSigned(), buffer, pos); + } else if (foreignTypeEntry.isIntegral()) { + // use a suitably sized signed or unsigned integral type as the layout type + pos = writeForeignIntegerLayout(context, foreignTypeEntry, size, foreignTypeEntry.isSigned(), buffer, pos); + } else if (foreignTypeEntry.isFloat()) { + // use a suitably sized float type as the layout type + pos = writeForeignFloatLayout(context, foreignTypeEntry, size, buffer, pos); + } else if (foreignTypeEntry.isStruct()) { + // define this type using a structure layout + pos = writeForeignStructLayout(context, foreignTypeEntry, size, buffer, pos); + } else { + // this must be a pointer. if the target type is known use it to declare the pointer + // type, otherwise default to 'void *' + TypeEntry targetType = voidType(); + if (foreignTypeEntry.isPointer()) { + TypeEntry pointerTo = foreignTypeEntry.getPointerTo(); + if (pointerTo != null) { + targetType = pointerTo; + } + } + log(context, " [0x%08x] foreign pointer type %s referent 0x%x (%s)", pos, foreignTypeEntry.getTypeName(), targetType.getTypeSignature(), targetType.getTypeName()); + // set layout type as alias for pointer type + foreignTypeEntry.setLayoutTypeSignature(targetType.getTypeSignature()); + // do not write this type unit + return p; + } + + /* + * Write declarations for methods of the foreign types as functions + * + * n.b. these appear as standalone declarations rather than as children of a class layout + * DIE, so we don't need a terminating attribute. + */ + pos = writeSkeletonMethodDeclarations(context, foreignTypeEntry, buffer, pos); + + if (!loaderId.isEmpty()) { + /* Write a terminating null attribute for the namespace. */ + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the TU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; // Write a Java class unit header int lengthPos = pos; log(context, " [0x%08x] Instance class unit", pos); pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DIE_HEADER_SIZE; - AbbrevCode abbrevCode = (classEntry.hasCompiledEntries() ? AbbrevCode.CLASS_UNIT_2 : AbbrevCode.CLASS_UNIT_1); + assert pos == lengthPos + CU_DIE_HEADER_SIZE; + AbbrevCode abbrevCode; + if (classEntry.hasCompiledEntries()) { + if (getLocationListIndex(classEntry) == 0) { + abbrevCode = AbbrevCode.CLASS_UNIT_2; + } else { + abbrevCode = AbbrevCode.CLASS_UNIT_3; + } + } else { + abbrevCode = AbbrevCode.CLASS_UNIT_1; + } log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); @@ -404,17 +800,22 @@ private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, String compilationDirectory = dwarfSections.getCachePath(); log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory); pos = writeStrSectionOffset(compilationDirectory, buffer, pos); - if (abbrevCode == AbbrevCode.CLASS_UNIT_2) { + if (abbrevCode == AbbrevCode.CLASS_UNIT_2 || abbrevCode == AbbrevCode.CLASS_UNIT_3) { int codeRangesIndex = getCodeRangesIndex(classEntry); log(context, " [0x%08x] ranges 0x%x", pos, codeRangesIndex); - pos = writeRangesSectionOffset(codeRangesIndex, buffer, pos); - // write low_pc as well as ranges so that lcoation lists can default the base address + pos = writeRangeListsSectionOffset(codeRangesIndex, buffer, pos); + // write low_pc as well as ranges so that location lists can default the base address int lo = classEntry.lowpc(); log(context, " [0x%08x] low_pc 0x%x", pos, codeRangesIndex); pos = writeAttrAddress(lo, buffer, pos); int lineIndex = getLineIndex(classEntry); log(context, " [0x%08x] stmt_list 0x%x", pos, lineIndex); pos = writeLineSectionOffset(lineIndex, buffer, pos); + if (abbrevCode == AbbrevCode.CLASS_UNIT_3) { + int locationListIndex = getLocationListIndex(classEntry); + log(context, " [0x%08x] loclists_base 0x%x", pos, locationListIndex); + pos = writeLocSectionOffset(locationListIndex, buffer, pos); + } } /* if the class has a loader then embed the children in a namespace */ String loaderId = classEntry.getLoaderId(); @@ -424,23 +825,9 @@ private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, /* Now write the child DIEs starting with the layout and pointer type. */ - if (classEntry.isInterface()) { - InterfaceClassEntry interfaceClassEntry = (InterfaceClassEntry) classEntry; - pos = writeInterfaceLayout(context, interfaceClassEntry, buffer, pos); - pos = writeInterfaceType(context, interfaceClassEntry, buffer, pos); - } else if (classEntry.isForeign()) { - ForeignTypeEntry foreignTypeEntry = (ForeignTypeEntry) classEntry; - pos = writeForeignLayout(context, foreignTypeEntry, buffer, pos); - pos = writeForeignType(context, foreignTypeEntry, buffer, pos); - } else { - pos = writeClassLayout(context, classEntry, buffer, pos); - pos = writeClassType(context, classEntry, buffer, pos); - } - - /* Write a declaration for the special Class object pseudo-static field */ - pos = writeClassConstantDeclaration(context, classEntry, buffer, pos); - - /* if we opened a namespace then terminate its children */ + // this works for interfaces, foreign types and classes, entry kind specifics are in the + // type units + pos = writeSkeletonClassLayout(context, classEntry, buffer, pos); /* Write all compiled code locations */ @@ -454,6 +841,7 @@ private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, pos = writeStaticFieldLocations(context, classEntry, buffer, pos); + /* if we opened a namespace then terminate its children */ if (!loaderId.isEmpty()) { pos = writeAttrNull(buffer, pos); } @@ -464,7 +852,6 @@ private int writeInstanceClassInfo(DebugContext context, ClassEntry classEntry, pos = writeAttrNull(buffer, pos); /* Fix up the CU length. */ - patchLength(lengthPos, buffer, pos); return pos; } @@ -503,15 +890,13 @@ private int writeClassConstantDeclaration(DebugContext context, TypeEntry typeEn * need to use the direct layout type for hub class to type it. */ ClassEntry valueType = dwarfSections.getHubClassEntry(); - int typeIdx = (valueType == null ? -1 : getLayoutIndex(valueType)); - log(context, " [0x%08x] type 0x%x ()", pos, typeIdx); - pos = writeInfoSectionOffset(typeIdx, buffer, pos); + long typeSignature = valueType == null ? lookupObjectClass().getLayoutTypeSignature() : valueType.getLayoutTypeSignature(); + log(context, " [0x%08x] type 0x%x ()", pos, typeSignature); + pos = writeTypeSignature(typeSignature, buffer, pos); log(context, " [0x%08x] accessibility public static final", pos); pos = writeAttrAccessibility(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, buffer, pos); log(context, " [0x%08x] external(true)", pos); pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); - log(context, " [0x%08x] definition(true)", pos); - pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); /* * Encode this location as a relative relocatable address or an offset from the heapbase * register. @@ -521,98 +906,14 @@ private int writeClassConstantDeclaration(DebugContext context, TypeEntry typeEn return pos; } - private int writeClassLayout(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - int layoutIndex = pos; - setLayoutIndex(classEntry, layoutIndex); - log(context, " [0x%08x] class layout", pos); - AbbrevCode abbrevCode = AbbrevCode.CLASS_LAYOUT_1; - /* - * when we don't have a separate indirect type then hub layouts need an extra data_location - * attribute - */ - if (!dwarfSections.useHeapBase() && dwarfSections.isHubClassEntry(classEntry)) { - abbrevCode = AbbrevCode.CLASS_LAYOUT_2; - } - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - String name = classEntry.getTypeName(); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); - pos = writeStrSectionOffset(name, buffer, pos); - int size = classEntry.getSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, size); - pos = writeAttrData2((short) size, buffer, pos); - int fileIdx = classEntry.getFileIdx(); - log(context, " [0x%08x] file 0x%x (%s)", pos, fileIdx, classEntry.getFileName()); - pos = writeAttrData2((short) fileIdx, buffer, pos); - if (abbrevCode == AbbrevCode.CLASS_LAYOUT_2) { - /* Write a data location expression to mask and/or rebase oop pointers. */ - log(context, " [0x%08x] data_location", pos); - pos = writeIndirectOopConversionExpression(true, buffer, pos); - } - int superTypeOffset; - String superName; - ClassEntry superClassEntry = classEntry.getSuperClass(); - if (superClassEntry != null) { - /* Inherit layout from super class. */ - superName = superClassEntry.getTypeName(); - superTypeOffset = getLayoutIndex(superClassEntry); - } else { - /* Inherit layout from object header. */ - superName = OBJECT_HEADER_STRUCT_NAME; - TypeEntry headerType = headerType(); - superTypeOffset = getTypeIndex(headerType); - } - /* Now write the child fields. */ - pos = writeSuperReference(context, superTypeOffset, superName, buffer, pos); - pos = writeFields(context, classEntry, buffer, pos); - pos = writeMethodDeclarations(context, classEntry, buffer, pos); - /* - * Write a terminating null attribute. - */ - pos = writeAttrNull(buffer, pos); - - if (dwarfSections.useHeapBase()) { - /* - * Write a wrapper type with a data_location attribute that can act as a target for an - * indirect pointer. - */ - setIndirectLayoutIndex(classEntry, pos); - log(context, " [0x%08x] indirect class layout", pos); - abbrevCode = AbbrevCode.INDIRECT_LAYOUT; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - String indirectName = uniqueDebugString(DwarfDebugInfo.INDIRECT_PREFIX + classEntry.getTypeName()); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(indirectName), name); - pos = writeStrSectionOffset(indirectName, buffer, pos); - log(context, " [0x%08x] byte_size 0x%x", pos, size); - pos = writeAttrData2((short) size, buffer, pos); - /* Write a data location expression to mask and/or rebase oop pointers. */ - log(context, " [0x%08x] data_location", pos); - pos = writeIndirectOopConversionExpression(dwarfSections.isHubClassEntry(classEntry), buffer, pos); - superTypeOffset = layoutIndex; - /* Now write the child field. */ - pos = writeSuperReference(context, superTypeOffset, superName, buffer, pos); - /* - * Write a terminating null attribute. - */ - pos = writeAttrNull(buffer, pos); - } else { - log(context, " [0x%08x] setIndirectLayoutIndex %s 0x%x", pos, classEntry.getTypeName(), pos); - setIndirectLayoutIndex(classEntry, layoutIndex); - } - - return pos; - } - - private int writeSuperReference(DebugContext context, int superTypeOffset, String superName, byte[] buffer, int p) { + private int writeSuperReference(DebugContext context, long typeSignature, String superName, byte[] buffer, int p) { int pos = p; log(context, " [0x%08x] super reference", pos); AbbrevCode abbrevCode = AbbrevCode.SUPER_REFERENCE; log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); - log(context, " [0x%08x] type 0x%x (%s)", pos, superTypeOffset, superName); - pos = writeInfoSectionOffset(superTypeOffset, buffer, pos); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, superName); + pos = writeTypeSignature(typeSignature, buffer, pos); /* Parent layout is embedded at start of object. */ log(context, " [0x%08x] data_member_location (super) 0x%x", pos, 0); pos = writeAttrData1((byte) 0, buffer, pos); @@ -635,7 +936,7 @@ private static boolean isManifestedField(FieldEntry fieldEntry) { private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntry fieldEntry, byte[] buffer, int p) { int pos = p; int modifiers = fieldEntry.getModifiers(); - boolean hasFile = fieldEntry.getFileName().length() > 0; + boolean hasFile = !fieldEntry.getFileName().isEmpty(); log(context, " [0x%08x] field definition", pos); AbbrevCode abbrevCode; boolean isStatic = Modifier.isStatic(modifiers); @@ -651,8 +952,6 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr } else { abbrevCode = AbbrevCode.FIELD_DECLARATION_4; } - /* Record the position of the declaration to use when we write the definition. */ - setFieldDeclarationIndex(entry, fieldEntry.fieldName(), pos); } log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); @@ -671,9 +970,9 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr } TypeEntry valueType = fieldEntry.getValueType(); /* use the indirect type for the field so pointers get translated if needed */ - int typeIdx = getIndirectTypeIndex(valueType); - log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, valueType.getTypeName()); - pos = writeInfoSectionOffset(typeIdx, buffer, pos); + long typeSignature = valueType.getIndirectTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, valueType.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); if (!isStatic) { int memberOffset = fieldEntry.getOffset(); log(context, " [0x%08x] member offset 0x%x", pos, memberOffset); @@ -691,6 +990,89 @@ private int writeField(DebugContext context, StructureTypeEntry entry, FieldEntr return pos; } + private int writeSkeletonMethodDeclarations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + for (MethodEntry method : classEntry.getMethods()) { + if (method.isInRange() || method.isInlined()) { + /* + * Declare all methods whether or not they have been compiled or inlined. + */ + pos = writeSkeletonMethodDeclaration(context, classEntry, method, buffer, pos); + } + } + + return pos; + } + + private int writeSkeletonMethodDeclaration(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) { + int pos = p; + log(context, " [0x%08x] method declaration %s::%s", pos, classEntry.getTypeName(), method.methodName()); + AbbrevCode abbrevCode = AbbrevCode.METHOD_DECLARATION_SKELETON; + log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + log(context, " [0x%08x] external true", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + String name = uniqueDebugString(method.methodName()); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + String linkageName = uniqueDebugString(method.getSymbolName()); + log(context, " [0x%08x] linkage_name %s", pos, linkageName); + pos = writeStrSectionOffset(linkageName, buffer, pos); + TypeEntry returnType = method.getValueType(); + long retTypeSignature = returnType.getTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, retTypeSignature, returnType.getTypeName()); + pos = writeTypeSignature(retTypeSignature, buffer, pos); + log(context, " [0x%08x] artificial %s", pos, method.isDeopt() ? "true" : "false"); + pos = writeFlag((method.isDeopt() ? DwarfFlag.DW_FLAG_true : DwarfFlag.DW_FLAG_false), buffer, pos); + int modifiers = method.getModifiers(); + log(context, " [0x%08x] accessibility %s", pos, method.getModifiersString()); + pos = writeAttrAccessibility(modifiers, buffer, pos); + log(context, " [0x%08x] declaration true", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + + /* Write method parameter declarations. */ + pos = writeSkeletonMethodParameterDeclarations(context, method, buffer, pos); + + /* Write a terminating null attribute. */ + return writeAttrNull(buffer, pos); + } + + private int writeSkeletonMethodParameterDeclarations(DebugContext context, MethodEntry method, byte[] buffer, int p) { + int pos = p; + if (!Modifier.isStatic(method.getModifiers())) { + DebugLocalInfo paramInfo = method.getThisParam(); + pos = writeSkeletonMethodParameterDeclaration(context, paramInfo, true, buffer, pos); + } + for (int i = 0; i < method.getParamCount(); i++) { + DebugLocalInfo paramInfo = method.getParam(i); + pos = writeSkeletonMethodParameterDeclaration(context, paramInfo, false, buffer, pos); + } + return pos; + } + + private int writeSkeletonMethodParameterDeclaration(DebugContext context, DebugLocalInfo paramInfo, boolean artificial, byte[] buffer, + int p) { + int pos = p; + log(context, " [0x%08x] method parameter declaration", pos); + AbbrevCode abbrevCode; + TypeEntry paramType = lookupType(paramInfo.valueType()); + if (artificial) { + abbrevCode = AbbrevCode.METHOD_PARAMETER_DECLARATION_4; + } else { + abbrevCode = AbbrevCode.METHOD_PARAMETER_DECLARATION_5; + } + log(context, " [0x%08x] <3> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + long typeSignature = paramType.getTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, paramType.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); + if (abbrevCode == AbbrevCode.METHOD_PARAMETER_DECLARATION_4) { + log(context, " [0x%08x] artificial true", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + } + return pos; + } + private int writeMethodDeclarations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; for (MethodEntry method : classEntry.getMethods()) { @@ -735,18 +1117,18 @@ private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry, log(context, " [0x%08x] linkage_name %s", pos, linkageName); pos = writeStrSectionOffset(linkageName, buffer, pos); TypeEntry returnType = method.getValueType(); - int retTypeIdx = getTypeIndex(returnType); - log(context, " [0x%08x] type 0x%x (%s)", pos, retTypeIdx, returnType.getTypeName()); - pos = writeInfoSectionOffset(retTypeIdx, buffer, pos); + long retTypeSignature = returnType.getTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, retTypeSignature, returnType.getTypeName()); + pos = writeTypeSignature(retTypeSignature, buffer, pos); log(context, " [0x%08x] artificial %s", pos, method.isDeopt() ? "true" : "false"); pos = writeFlag((method.isDeopt() ? DwarfFlag.DW_FLAG_true : DwarfFlag.DW_FLAG_false), buffer, pos); log(context, " [0x%08x] accessibility %s", pos, "public"); pos = writeAttrAccessibility(modifiers, buffer, pos); log(context, " [0x%08x] declaration true", pos); pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); - int typeIdx = getLayoutIndex(classEntry); - log(context, " [0x%08x] containing_type 0x%x (%s)", pos, typeIdx, classEntry.getTypeName()); - pos = writeAttrRef4(typeIdx, buffer, pos); + long typeSignature = classEntry.getLayoutTypeSignature(); + log(context, " [0x%08x] containing_type 0x%x (%s)", pos, typeSignature, classEntry.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); if (abbrevCode == AbbrevCode.METHOD_DECLARATION) { /* Record the current position so we can back patch the object pointer. */ int objectPointerIndex = pos; @@ -813,9 +1195,9 @@ private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo log(context, " [0x%08x] line 0x%x", pos, line); pos = writeAttrData2((short) line, buffer, pos); } - int typeIdx = getTypeIndex(paramType); - log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, paramType.getTypeName()); - pos = writeInfoSectionOffset(typeIdx, buffer, pos); + long typeSignature = paramType.getTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, paramType.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); if (abbrevCode == AbbrevCode.METHOD_PARAMETER_DECLARATION_1) { log(context, " [0x%08x] artificial true", pos); pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); @@ -860,65 +1242,11 @@ private int writeMethodLocalDeclaration(DebugContext context, DebugLocalInfo par log(context, " [0x%08x] line 0x%x", pos, line); pos = writeAttrData2((short) line, buffer, pos); } - int typeIdx = getTypeIndex(paramType); - log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, paramType.getTypeName()); - pos = writeInfoSectionOffset(typeIdx, buffer, pos); - log(context, " [0x%08x] declaration true", pos); - pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); - return pos; - } - - private int writeInterfaceLayout(DebugContext context, InterfaceClassEntry interfaceClassEntry, byte[] buffer, int p) { - int pos = p; - int layoutOffset = pos; - setLayoutIndex(interfaceClassEntry, layoutOffset); - log(context, " [0x%08x] interface layout", pos); - AbbrevCode abbrevCode = AbbrevCode.INTERFACE_LAYOUT; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - String name = interfaceClassEntry.getTypeName(); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); - pos = writeStrSectionOffset(name, buffer, pos); - /* - * Now write references to all class layouts that implement this interface. - */ - pos = writeInterfaceImplementors(context, interfaceClassEntry, buffer, pos); - pos = writeMethodDeclarations(context, interfaceClassEntry, buffer, pos); - - /* - * Write a terminating null attribute. - */ - pos = writeAttrNull(buffer, pos); - - if (dwarfSections.useHeapBase()) { - /* - * Write a wrapper type with a data_location attribute that can act as a target for an - * indirect pointer. - */ - setIndirectLayoutIndex(interfaceClassEntry, pos); - log(context, " [0x%08x] indirect class layout", pos); - abbrevCode = AbbrevCode.INDIRECT_LAYOUT; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - String indirectName = uniqueDebugString(DwarfDebugInfo.INDIRECT_PREFIX + interfaceClassEntry.getTypeName()); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(indirectName), name); - pos = writeStrSectionOffset(indirectName, buffer, pos); - int size = interfaceClassEntry.getSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, size); - pos = writeAttrData2((short) size, buffer, pos); - /* Write a data location expression to mask and/or rebase oop pointers. */ - log(context, " [0x%08x] data_location", pos); - pos = writeIndirectOopConversionExpression(false, buffer, pos); - /* Now write the child field. */ - pos = writeSuperReference(context, layoutOffset, name, buffer, pos); - /* - * Write a terminating null attribute. - */ - pos = writeAttrNull(buffer, pos); - } else { - setIndirectLayoutIndex(interfaceClassEntry, layoutOffset); - } - + long typeSignature = paramType.getTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, paramType.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); + log(context, " [0x%08x] declaration true", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); return pos; } @@ -937,63 +1265,15 @@ private int writeInterfaceImplementor(DebugContext context, ClassEntry classEntr String name = uniqueDebugString("_" + classEntry.getTypeName()); log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); pos = writeStrSectionOffset(name, buffer, pos); - int layoutOffset = getLayoutIndex(classEntry); - log(context, " [0x%08x] type 0x%x (%s)", pos, layoutOffset, classEntry.getTypeName()); - pos = writeInfoSectionOffset(layoutOffset, buffer, pos); + long typeSignature = classEntry.getLayoutTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, classEntry.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); int modifiers = Modifier.PUBLIC; log(context, " [0x%08x] modifiers %s", pos, "public"); pos = writeAttrAccessibility(modifiers, buffer, pos); return pos; } - private int writeForeignLayout(DebugContext context, ForeignTypeEntry foreignTypeEntry, byte[] buffer, int p) { - int pos = p; - int size = foreignTypeEntry.getSize(); - int layoutOffset = pos; - if (foreignTypeEntry.isWord()) { - // define the type as a typedef for a signed or unsigned word i.e. we don't have a - // layout type - pos = writeForeignWordLayout(context, foreignTypeEntry, size, foreignTypeEntry.isSigned(), buffer, pos); - } else if (foreignTypeEntry.isIntegral()) { - // use a suitably sized signed or unsigned integral type as the layout type - pos = writeForeignIntegerLayout(context, foreignTypeEntry, size, foreignTypeEntry.isSigned(), buffer, pos); - } else if (foreignTypeEntry.isFloat()) { - // use a suitably sized float type as the layout type - pos = writeForeignFloatLayout(context, foreignTypeEntry, size, buffer, pos); - } else if (foreignTypeEntry.isStruct()) { - // define this type using a structure layout - pos = writeForeignStructLayout(context, foreignTypeEntry, size, buffer, pos); - } else { - // this must be a pointer. if the target type is known use it to declare the pointer - // type, otherwise default to 'void *' - layoutOffset = voidOffset; - String referentName = "void"; - if (foreignTypeEntry.isPointer()) { - TypeEntry pointerTo = foreignTypeEntry.getPointerTo(); - if (pointerTo != null) { - layoutOffset = getTypeIndex(foreignTypeEntry.getPointerTo()); - referentName = foreignTypeEntry.getTypeName(); - } - } - log(context, " [0x%08x] foreign pointer type %s referent 0x%x (%s)", pos, foreignTypeEntry.getTypeName(), layoutOffset, referentName); - } - setLayoutIndex(foreignTypeEntry, layoutOffset); - - /* - * Write declarations for methods of the foreign types as functions - * - * n.b. these appear as standalone declarations rather than as children of a class layout - * DIE so we don't need a terminating attribute. - */ - pos = writeMethodDeclarations(context, foreignTypeEntry, buffer, pos); - /* - * We don't need an indirect type because foreign pointers are never compressed - */ - setIndirectLayoutIndex(foreignTypeEntry, layoutOffset); - - return pos; - } - private int writeForeignStructLayout(DebugContext context, ForeignTypeEntry foreignTypeEntry, int size, byte[] buffer, int p) { int pos = p; log(context, " [0x%08x] foreign struct type for %s", pos, foreignTypeEntry.getTypeName()); @@ -1018,8 +1298,8 @@ private int writeForeignStructLayout(DebugContext context, ForeignTypeEntry fore // if we have a parent write a super attribute ForeignTypeEntry parent = foreignTypeEntry.getParent(); if (parent != null) { - int parentOffset = getLayoutIndex(parent); - pos = writeSuperReference(context, parentOffset, parent.getTypedefName(), buffer, pos); + long typeSignature = parent.getLayoutTypeSignature(); + pos = writeSuperReference(context, typeSignature, parent.getTypedefName(), buffer, pos); } pos = writeStructFields(context, foreignTypeEntry.fields(), buffer, pos); /* @@ -1109,121 +1389,6 @@ private static String integralTypeName(int byteSize, boolean isSigned) { return stringBuilder.toString(); } - private int writeClassType(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - - /* Define a pointer type referring to the underlying layout. */ - int typeIdx = pos; - setTypeIndex(classEntry, typeIdx); - log(context, " [0x%08x] class pointer type", pos); - AbbrevCode abbrevCode = AbbrevCode.CLASS_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int pointerSize = dwarfSections.pointerSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, pointerSize); - pos = writeAttrData1((byte) pointerSize, buffer, pos); - int layoutOffset = getLayoutIndex(classEntry); - log(context, " [0x%08x] type 0x%x", pos, layoutOffset); - pos = writeAttrRef4(layoutOffset, buffer, pos); - - if (dwarfSections.useHeapBase()) { - /* Define an indirect pointer type referring to the indirect layout. */ - setIndirectTypeIndex(classEntry, pos); - log(context, " [0x%08x] class indirect pointer type", pos); - abbrevCode = AbbrevCode.INDIRECT_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int oopReferenceSize = dwarfSections.referenceSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, oopReferenceSize); - pos = writeAttrData1((byte) oopReferenceSize, buffer, pos); - layoutOffset = getIndirectLayoutIndex(classEntry); - log(context, " [0x%08x] type 0x%x", pos, layoutOffset); - pos = writeAttrRef4(layoutOffset, buffer, pos); - } else { - setIndirectTypeIndex(classEntry, typeIdx); - } - - return pos; - } - - private int writeInterfaceType(DebugContext context, InterfaceClassEntry interfaceClassEntry, byte[] buffer, int p) { - int pos = p; - - /* Define a pointer type referring to the underlying layout. */ - int typeIdx = pos; - setTypeIndex(interfaceClassEntry, typeIdx); - log(context, " [0x%08x] interface pointer type", pos); - AbbrevCode abbrevCode = AbbrevCode.INTERFACE_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int pointerSize = dwarfSections.pointerSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, pointerSize); - pos = writeAttrData1((byte) pointerSize, buffer, pos); - int layoutOffset = getLayoutIndex(interfaceClassEntry); - log(context, " [0x%08x] type 0x%x", pos, layoutOffset); - pos = writeAttrRef4(layoutOffset, buffer, pos); - - if (dwarfSections.useHeapBase()) { - /* Define an indirect pointer type referring to the indirect layout. */ - setIndirectTypeIndex(interfaceClassEntry, pos); - log(context, " [0x%08x] interface indirect pointer type", pos); - abbrevCode = AbbrevCode.INDIRECT_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int byteSize = dwarfSections.referenceSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, byteSize); - pos = writeAttrData1((byte) byteSize, buffer, pos); - layoutOffset = getIndirectLayoutIndex(interfaceClassEntry); - log(context, " [0x%08x] type 0x%x", pos, layoutOffset); - pos = writeAttrRef4(layoutOffset, buffer, pos); - } else { - setIndirectTypeIndex(interfaceClassEntry, typeIdx); - } - - return pos; - } - - private int writeForeignType(DebugContext context, ForeignTypeEntry foreignTypeEntry, byte[] buffer, int p) { - int pos = p; - int layoutOffset = getLayoutIndex(foreignTypeEntry); - - // Unlike with Java we use the Java name for the pointer type rather than the - // underlying base type, or rather for a typedef that targets the pointer type. - // That ensures that e.g. CCharPointer is a typedef for char*. - - /* Define a pointer type referring to the base type */ - int refTypeIdx = pos; - log(context, " [0x%08x] foreign pointer type", pos); - AbbrevCode abbrevCode = AbbrevCode.FOREIGN_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int pointerSize = dwarfSections.pointerSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, pointerSize); - pos = writeAttrData1((byte) pointerSize, buffer, pos); - // Note that we write a ref_addr offset here because an unknown (void *) - // foreign type can have a layout offset that is not in its CU - log(context, " [0x%08x] type 0x%x", pos, layoutOffset); - pos = writeInfoSectionOffset(layoutOffset, buffer, pos); - - /* Define a typedef for the layout type using the Java name. */ - int typedefIdx = pos; - log(context, " [0x%08x] foreign typedef", pos); - abbrevCode = AbbrevCode.FOREIGN_TYPEDEF; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - String name = uniqueDebugString(foreignTypeEntry.getTypeName()); - log(context, " [0x%08x] name %s", pos, name); - pos = writeStrSectionOffset(name, buffer, pos); - log(context, " [0x%08x] type 0x%x", pos, refTypeIdx); - pos = writeAttrRef4(refTypeIdx, buffer, pos); - - setTypeIndex(foreignTypeEntry, typedefIdx); - // foreign pointers are never stored compressed so don't need a separate indirect type - setIndirectTypeIndex(foreignTypeEntry, typedefIdx); - - return pos; - } - private int writeStaticFieldLocations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { /* * Only write locations for static fields that have an offset greater than 0. A negative @@ -1237,10 +1402,66 @@ private int writeStaticFieldLocations(DebugContext context, ClassEntry classEntr return cursor.get(); } + private int writeStaticFieldDeclarations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + /* + * Only write locations for static fields that have an offset greater than 0. A negative + * offset indicates that the field has been folded into code as an unmaterialized constant. + */ + Cursor cursor = new Cursor(p); + classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedStaticField) + .forEach(fieldEntry -> { + cursor.set(writeClassStaticFieldDeclaration(context, classEntry, fieldEntry, buffer, cursor.get())); + }); + return cursor.get(); + } + private static boolean isManifestedStaticField(FieldEntry fieldEntry) { return Modifier.isStatic(fieldEntry.getModifiers()) && fieldEntry.getOffset() >= 0; } + private int writeClassStaticFieldDeclaration(DebugContext context, ClassEntry classEntry, FieldEntry fieldEntry, byte[] buffer, int p) { + assert Modifier.isStatic(fieldEntry.getModifiers()); + + int pos = p; + boolean hasFile = !fieldEntry.getFileName().isEmpty(); + log(context, " [0x%08x] field definition", pos); + AbbrevCode abbrevCode; + if (!hasFile) { + abbrevCode = AbbrevCode.FIELD_DECLARATION_3; + } else { + abbrevCode = AbbrevCode.FIELD_DECLARATION_4; + } + /* Record the position of the declaration to use when we write the definition. */ + setFieldDeclarationIndex(classEntry, fieldEntry.fieldName(), pos); + log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + + String name = fieldEntry.fieldName(); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + /* We may not have a file and line for a field. */ + if (hasFile) { + int fileIdx = fieldEntry.getFileIdx(); + assert fileIdx > 0; + log(context, " [0x%08x] filename 0x%x (%s)", pos, fileIdx, fieldEntry.getFileName()); + pos = writeAttrData2((short) fileIdx, buffer, pos); + /* At present we definitely don't have line numbers. */ + } + TypeEntry valueType = fieldEntry.getValueType(); + /* use the indirect type for the field so pointers get translated if needed */ + long typeSignature = valueType.getIndirectTypeSignature(); + log(context, " [0x%08x] type 0x%x (%s)", pos, typeSignature, valueType.getTypeName()); + pos = writeTypeSignature(typeSignature, buffer, pos); + log(context, " [0x%08x] accessibility %s", pos, fieldEntry.getModifiersString()); + pos = writeAttrAccessibility(fieldEntry.getModifiers(), buffer, pos); + /* Static fields are only declared here and are external. */ + log(context, " [0x%08x] external(true)", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + log(context, " [0x%08x] definition(true)", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + return pos; + } + private int writeClassStaticFieldLocation(DebugContext context, ClassEntry classEntry, FieldEntry fieldEntry, byte[] buffer, int p) { int pos = p; String fieldName = fieldEntry.fieldName(); @@ -1263,19 +1484,71 @@ private int writeArrays(DebugContext context, byte[] buffer, int p) { log(context, " [0x%08x] array classes", p); Cursor cursor = new Cursor(p); arrayTypeStream().forEach(arrayTypeEntry -> { - cuStart = cursor.get(); + cursor.set(writeTypeUnits(context, arrayTypeEntry, buffer, cursor.get())); cursor.set(writeArray(context, arrayTypeEntry, buffer, cursor.get())); }); return cursor.get(); } + private int writeArrayLayoutTypeUnit(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { + int pos = p; + + String loaderId = arrayTypeEntry.getLoaderId(); + int lengthPos = pos; + pos = writeTUPreamble(context, arrayTypeEntry.getLayoutTypeSignature(), loaderId, buffer, pos); + + /* Write the array layout and array reference DIEs. */ + TypeEntry elementType = arrayTypeEntry.getElementType(); + int size = arrayTypeEntry.getSize(); + log(context, " [0x%08x] array layout", pos); + AbbrevCode abbrevCode = AbbrevCode.ARRAY_LAYOUT; + log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); + pos = writeAbbrevCode(abbrevCode, buffer, pos); + String name = arrayTypeEntry.getTypeName(); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + pos = writeStrSectionOffset(name, buffer, pos); + log(context, " [0x%08x] byte_size 0x%x", pos, size); + pos = writeAttrData2((short) size, buffer, pos); + + /* Now the child DIEs. */ + + /* write a type definition for the element array field. */ + int arrayDataTypeIdx = pos; + pos = writeArrayDataType(context, elementType, buffer, pos); + pos = writeFields(context, arrayTypeEntry, buffer, pos); + + /* Write a zero length element array field. */ + pos = writeArrayElementField(context, size, arrayDataTypeIdx, buffer, pos); + + /* All arrays inherit from java.lang.Object */ + ClassEntry objectType = lookupObjectClass(); + String superName = objectType.getTypeName(); + long typeSignature = objectType.getLayoutTypeSignature(); + pos = writeSuperReference(context, typeSignature, superName, buffer, pos); + + /* Write a terminating null attribute for the array layout. */ + pos = writeAttrNull(buffer, pos); + + /* if we opened a namespace then terminate its children */ + if (!loaderId.isEmpty()) { + pos = writeAttrNull(buffer, pos); + } + + /* Write a terminating null attribute for the top level TU DIE. */ + pos = writeAttrNull(buffer, pos); + + /* Fix up the CU length. */ + patchLength(lengthPos, buffer, pos); + return pos; + } + private int writeArray(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { int pos = p; // Write a Java class unit header int lengthPos = pos; log(context, " [0x%08x] Array class unit", pos); pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DIE_HEADER_SIZE; + assert pos == lengthPos + CU_DIE_HEADER_SIZE; AbbrevCode abbrevCode = AbbrevCode.CLASS_UNIT_1; log(context, " [0x%08x] <0> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); @@ -1297,18 +1570,7 @@ private int writeArray(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte } /* Write the array layout and array reference DIEs. */ - TypeEntry elementType = arrayTypeEntry.getElementType(); - int size = arrayTypeEntry.getSize(); - int layoutIdx = pos; - pos = writeArrayLayout(context, arrayTypeEntry, elementType, size, buffer, pos); - int indirectLayoutIdx = pos; - if (dwarfSections.useHeapBase()) { - pos = writeIndirectArrayLayout(context, arrayTypeEntry, size, layoutIdx, buffer, pos); - } - pos = writeArrayTypes(context, arrayTypeEntry, layoutIdx, indirectLayoutIdx, buffer, pos); - - /* Write a declaration for the special Class object pseudo-static field */ - pos = writeClassConstantDeclaration(context, arrayTypeEntry, buffer, pos); + pos = writeSkeletonArrayLayout(context, arrayTypeEntry, buffer, pos); /* if we opened a namespace then terminate its children */ if (!loaderId.isEmpty()) { @@ -1326,27 +1588,20 @@ private int writeArray(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte return pos; } - private int writeArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry, TypeEntry elementType, int size, byte[] buffer, int p) { + private int writeSkeletonArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) { int pos = p; log(context, " [0x%08x] array layout", pos); - AbbrevCode abbrevCode = AbbrevCode.ARRAY_LAYOUT; + AbbrevCode abbrevCode = AbbrevCode.CLASS_LAYOUT_3; log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); String name = arrayTypeEntry.getTypeName(); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name); pos = writeStrSectionOffset(name, buffer, pos); - log(context, " [0x%08x] byte_size 0x%x", pos, size); - pos = writeAttrData2((short) size, buffer, pos); - - /* Now the child DIEs. */ - - /* write a type definition for the element array field. */ - int arrayDataTypeIdx = pos; - pos = writeArrayDataType(context, elementType, buffer, pos); - pos = writeFields(context, arrayTypeEntry, buffer, pos); - /* Write a zero length element array field. */ - pos = writeArrayElementField(context, size, arrayDataTypeIdx, buffer, pos); - pos = writeArraySuperReference(context, buffer, pos); + log(context, " [0x%08x] declaration true", pos); + pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos); + long typeSignature = arrayTypeEntry.getLayoutTypeSignature(); + log(context, " [0x%08x] type 0x%x", pos, typeSignature); + pos = writeTypeSignature(typeSignature, buffer, pos); /* * Write a terminating null attribute. */ @@ -1362,34 +1617,6 @@ private int writeFields(DebugContext context, ArrayTypeEntry arrayTypeEntry, byt return cursor.get(); } - private int writeIndirectArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry, int size, int layoutOffset, byte[] buffer, int p) { - int pos = p; - - /* - * write a wrapper type with a data_location attribute that can act as a target for an - * indirect pointer - */ - log(context, " [0x%08x] indirect class layout", pos); - AbbrevCode abbrevCode = AbbrevCode.INDIRECT_LAYOUT; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - String name = arrayTypeEntry.getTypeName(); - String indirectName = uniqueDebugString(DwarfDebugInfo.INDIRECT_PREFIX + name); - log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(indirectName), name); - pos = writeStrSectionOffset(indirectName, buffer, pos); - log(context, " [0x%08x] byte_size 0x%x", pos, size); - pos = writeAttrData2((short) size, buffer, pos); - /* Write a data location expression to mask and/or rebase oop pointers. */ - log(context, " [0x%08x] data_location", pos); - pos = writeIndirectOopConversionExpression(false, buffer, pos); - /* Now write the child field. */ - pos = writeSuperReference(context, layoutOffset, name, buffer, pos); - /* - * Write a terminating null attribute. - */ - return writeAttrNull(buffer, pos); - } - private int writeArrayDataType(DebugContext context, TypeEntry elementType, byte[] buffer, int p) { int pos = p; log(context, " [0x%08x] array element data type", pos); @@ -1399,9 +1626,9 @@ private int writeArrayDataType(DebugContext context, TypeEntry elementType, byte // Java arrays don't have a fixed byte_size String elementTypeName = elementType.getTypeName(); /* use the indirect type for the element type so pointers get translated */ - int elementTypeIdx = getIndirectTypeIndex(elementType); - log(context, " [0x%08x] type idx 0x%x (%s)", pos, elementTypeIdx, elementTypeName); - pos = writeInfoSectionOffset(elementTypeIdx, buffer, pos); + long elementTypeSignature = elementType.getIndirectTypeSignature(); + log(context, " [0x%08x] type idx 0x%x (%s)", pos, elementTypeSignature, elementTypeName); + pos = writeTypeSignature(elementTypeSignature, buffer, pos); return pos; } @@ -1416,7 +1643,7 @@ private int writeEmbeddedArrayDataType(DebugContext context, ForeignTypeEntry fo log(context, " [0x%08x] byte_size 0x%x", pos, size); pos = writeAttrData4(size, buffer, pos); String elementTypeName = foreignValueType.getTypeName(); - int elementTypeIdx; + long elementTypeSignature; if (foreignValueType.isPointer()) { TypeEntry pointerTo = foreignValueType.getPointerTo(); assert pointerTo != null : "ADDRESS field pointer type must have a known target type"; @@ -1429,13 +1656,13 @@ private int writeEmbeddedArrayDataType(DebugContext context, ForeignTypeEntry fo // However, if this embedded struct field definition precedes the definition of the // referring type and the latter precedes the definition of the referent type then // the layout index of the referring type may still be unset at this point. - elementTypeIdx = getTypeIndex(pointerTo); + elementTypeSignature = pointerTo.getTypeSignature(); } else { // type the array using the layout type - elementTypeIdx = getIndirectLayoutIndex(foreignValueType); + elementTypeSignature = foreignValueType.getIndirectLayoutTypeSignature(); } - log(context, " [0x%08x] type idx 0x%x (%s)", pos, elementTypeIdx, elementTypeName); - pos = writeInfoSectionOffset(elementTypeIdx, buffer, pos); + log(context, " [0x%08x] type idx 0x%x (%s)", pos, elementTypeSignature, elementTypeName); + pos = writeTypeSignature(elementTypeSignature, buffer, pos); // write subrange child DIE log(context, " [0x%08x] embedded array element range", pos); abbrevCode = AbbrevCode.ARRAY_SUBRANGE; @@ -1452,7 +1679,7 @@ private int writeEmbeddedArrayDataType(DebugContext context, ForeignTypeEntry fo private int writeArrayElementField(DebugContext context, int offset, int arrayDataTypeIdx, byte[] buffer, int p) { int pos = p; log(context, " [0x%08x] array element data field", pos); - AbbrevCode abbrevCode = AbbrevCode.HEADER_FIELD; + AbbrevCode abbrevCode = AbbrevCode.ARRAY_ELEMENT_FIELD; log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); String fieldName = uniqueDebugString("data"); @@ -1466,54 +1693,6 @@ private int writeArrayElementField(DebugContext context, int offset, int arrayDa int modifiers = Modifier.PUBLIC; log(context, " [0x%08x] modifiers %s", pos, "public"); return writeAttrAccessibility(modifiers, buffer, pos); - - } - - private int writeArraySuperReference(DebugContext context, byte[] buffer, int p) { - int pos = p; - /* Arrays all inherit from java.lang.Object */ - TypeEntry objectType = lookupObjectClass(); - String superName = objectType.getTypeName(); - assert objectType != null; - assert objectType instanceof ClassEntry; - int superOffset = getLayoutIndex((ClassEntry) objectType); - return writeSuperReference(context, superOffset, superName, buffer, pos); - } - - private int writeArrayTypes(DebugContext context, ArrayTypeEntry arrayTypeEntry, int layoutOffset, int indirectLayoutOffset, byte[] buffer, int p) { - int pos = p; - String name = uniqueDebugString(arrayTypeEntry.getTypeName()); - - int typeIdx = pos; - setTypeIndex(arrayTypeEntry, pos); - /* Define a pointer type referring to the underlying layout. */ - log(context, " [0x%08x] array pointer type", pos); - AbbrevCode abbrevCode = AbbrevCode.ARRAY_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int pointerSize = dwarfSections.pointerSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, pointerSize); - pos = writeAttrData1((byte) pointerSize, buffer, pos); - log(context, " [0x%08x] type (pointer) 0x%x (%s)", pos, layoutOffset, name); - pos = writeAttrRef4(layoutOffset, buffer, pos); - - if (dwarfSections.useHeapBase()) { - setIndirectTypeIndex(arrayTypeEntry, pos); - /* Define an indirect pointer type referring to the underlying indirect layout. */ - log(context, " [0x%08x] array indirect pointer type", pos); - abbrevCode = AbbrevCode.INDIRECT_POINTER; - log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal()); - pos = writeAbbrevCode(abbrevCode, buffer, pos); - int byteSize = dwarfSections.referenceSize(); - log(context, " [0x%08x] byte_size 0x%x", pos, byteSize); - pos = writeAttrData1((byte) byteSize, buffer, pos); - log(context, " [0x%08x] type (pointer) 0x%x (%s)", pos, indirectLayoutOffset, name); - pos = writeAttrRef4(indirectLayoutOffset, buffer, pos); - } else { - setIndirectTypeIndex(arrayTypeEntry, typeIdx); - } - - return pos; } private int writeMethodLocations(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { @@ -1543,7 +1722,7 @@ private int writeMethodLocation(DebugContext context, ClassEntry classEntry, Com String methodKey = primary.getSymbolName(); int methodSpecOffset = getMethodDeclarationIndex(primary.getMethodEntry()); log(context, " [0x%08x] specification 0x%x (%s)", pos, methodSpecOffset, methodKey); - pos = writeAttrRef4(methodSpecOffset, buffer, pos); + pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos); HashMap> varRangeMap = primary.getVarRangeMap(); pos = writeMethodParameterLocations(context, classEntry, varRangeMap, primary, 2, buffer, pos); pos = writeMethodLocalLocations(context, classEntry, varRangeMap, primary, 2, buffer, pos); @@ -1638,12 +1817,12 @@ private int writeMethodLocalLocation(DebugContext context, Range range, DebugLoc log(context, " [0x%08x] <%d> Abbrev Number %d", pos, depth, abbrevCode.ordinal()); pos = writeAbbrevCode(abbrevCode, buffer, pos); log(context, " [0x%08x] specification 0x%x", pos, refAddr); - pos = writeAttrRef4(refAddr, buffer, pos); + pos = writeInfoSectionOffset(refAddr, buffer, pos); if (abbrevCode == AbbrevCode.METHOD_LOCAL_LOCATION_2 || abbrevCode == AbbrevCode.METHOD_PARAMETER_LOCATION_2) { - int locRefAddr = getRangeLocalIndex(range, localInfo); - log(context, " [0x%08x] loc list 0x%x", pos, locRefAddr); - pos = writeLocSectionOffset(locRefAddr, buffer, pos); + int locRefOffset = getRangeLocalIndex(range, localInfo); + log(context, " [0x%08x] loc list 0x%x", pos, locRefOffset); + pos = writeULEB(locRefOffset, buffer, pos); } return pos; } @@ -1819,32 +1998,54 @@ private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntr private int writeAttrRef4(int reference, byte[] buffer, int p) { // make sure we have actually started writing a CU - assert cuStart >= 0; + assert unitStart >= 0; // writes a CU-relative offset - return writeAttrData4(reference - cuStart, buffer, p); + return writeAttrData4(reference - unitStart, buffer, p); } private int writeCUHeader(byte[] buffer, int p) { int pos = p; + /* save current CU start, so we can write Ref4 attributes as CU offsets. */ + unitStart = pos; /* CU length. */ pos = writeInt(0, buffer, pos); /* DWARF version. */ - pos = writeDwarfVersion(DwarfVersion.DW_VERSION_4, buffer, pos); + pos = writeDwarfVersion(DwarfVersion.DW_VERSION_5, buffer, pos); + /* unit type */ + pos = writeDwarfUnitHeader(DwarfUnitHeader.DW_UT_compile, buffer, pos); + /* Address size. */ + pos = writeByte((byte) 8, buffer, pos); /* Abbrev offset. */ - pos = writeAbbrevSectionOffset(0, buffer, pos); + return writeAbbrevSectionOffset(0, buffer, pos); + } + + private int writeTUHeader(long typeSignature, byte[] buffer, int p) { + int pos = p; + /* save current TU start, so we can write Ref4 attributes as CU offsets. */ + unitStart = pos; + /* CU length. */ + pos = writeInt(0, buffer, pos); + /* DWARF version. */ + pos = writeDwarfVersion(DwarfVersion.DW_VERSION_5, buffer, pos); + /* Unit type */ + pos = writeDwarfUnitHeader(DwarfUnitHeader.DW_UT_type, buffer, pos); /* Address size. */ - return writeByte((byte) 8, buffer, pos); + pos = writeByte((byte) 8, buffer, pos); + /* Abbrev offset. */ + pos = writeAbbrevSectionOffset(0, buffer, pos); + /* Type signature */ + pos = writeTypeSignature(typeSignature, buffer, pos); + /* Type offset */ + return writeInt(0, buffer, pos); } @SuppressWarnings("unused") public int writeAttrString(String value, byte[] buffer, int p) { - int pos = p; - return writeUTF8StringBytes(value, buffer, pos); + return writeUTF8StringBytes(value, buffer, p); } public int writeAttrLanguage(DwarfLanguage language, byte[] buffer, int p) { - int pos = p; - return writeByte(language.value(), buffer, pos); + return writeByte(language.value(), buffer, p); } public int writeAttrEncoding(DwarfEncoding encoding, byte[] buffer, int p) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java index c348cc2dd2ed..bdc82370dbc8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLocSectionImpl.java @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -39,7 +38,6 @@ import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debugentry.ClassEntry; -import com.oracle.objectfile.debugentry.CompiledMethodEntry; import com.oracle.objectfile.debugentry.range.Range; import com.oracle.objectfile.debugentry.range.SubRange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalInfo; @@ -47,7 +45,9 @@ import com.oracle.objectfile.elf.ELFMachine; import com.oracle.objectfile.elf.ELFObjectFile; import com.oracle.objectfile.elf.dwarf.constants.DwarfExpressionOpcode; +import com.oracle.objectfile.elf.dwarf.constants.DwarfLocationListEntry; import com.oracle.objectfile.elf.dwarf.constants.DwarfSectionName; +import com.oracle.objectfile.elf.dwarf.constants.DwarfVersion; import jdk.graal.compiler.debug.DebugContext; import jdk.vm.ci.aarch64.AArch64; @@ -79,7 +79,7 @@ public class DwarfLocSectionImpl extends DwarfSectionImpl { public DwarfLocSectionImpl(DwarfDebugInfo dwarfSections) { // debug_loc section depends on text section - super(dwarfSections, DwarfSectionName.DW_LOC_SECTION, DwarfSectionName.TEXT_SECTION, targetLayoutKinds); + super(dwarfSections, DwarfSectionName.DW_LOCLISTS_SECTION, DwarfSectionName.TEXT_SECTION, targetLayoutKinds); initDwarfRegMap(); } @@ -102,10 +102,9 @@ public Set getDependencies(Map { - classEntry.compiledEntries().forEachOrdered(compiledMethodEntry -> { - cursor.set(writeCompiledMethodLocations(context, compiledMethodEntry, buffer, cursor.get())); - }); + List locationListEntries = getLocationListEntries(classEntry); + if (locationListEntries.isEmpty()) { + // no need to emit empty location list + // location list index can never be 0 as there is at least a header before + setLocationListIndex(classEntry, 0); + } else { + int entryCount = locationListEntries.size(); + + int lengthPos = cursor.get(); + cursor.set(writeLocationListsHeader(entryCount, buffer, cursor.get())); + + int baseOffset = cursor.get(); + setLocationListIndex(classEntry, baseOffset); + cursor.add(entryCount * 4); // space for offset array + + int index = 0; + for (LocationListEntry entry : locationListEntries) { + setRangeLocalIndex(entry.range(), entry.local(), index); + writeInt(cursor.get() - baseOffset, buffer, baseOffset + index * 4); + index++; + cursor.set(writeVarLocations(context, entry.local(), entry.base(), entry.rangeList(), buffer, cursor.get())); + } + + /* Fix up location list length */ + patchLength(lengthPos, buffer, cursor.get()); + } }); + return cursor.get(); } - private int writeCompiledMethodLocations(DebugContext context, CompiledMethodEntry compiledEntry, byte[] buffer, int p) { + private int writeLocationListsHeader(int offsetEntries, byte[] buffer, int p) { int pos = p; - Range primary = compiledEntry.getPrimary(); - /* - * Note that offsets are written relative to the primary range base. This requires writing a - * base address entry before each of the location list ranges. It is possible to default the - * base address to the low_pc value of the compile unit for the compiled method's owning - * class, saving two words per location list. However, that forces the debugger to do a lot - * more up-front cross-referencing of CUs when it needs to resolve code addresses e.g. to - * set a breakpoint, leading to a very slow response for the user. - */ - int base = primary.getLo(); - log(context, " [0x%08x] top level locations [0x%x, 0x%x] method %s", pos, primary.getLo(), primary.getHi(), primary.getFullMethodNameWithParams()); - pos = writeTopLevelLocations(context, compiledEntry, base, buffer, pos); - if (!primary.isLeaf()) { - log(context, " [0x%08x] inline locations %s", pos, primary.getFullMethodNameWithParams()); - pos = writeInlineLocations(context, compiledEntry, base, buffer, pos); - } - return pos; + /* Loclists length. */ + pos = writeInt(0, buffer, pos); + /* DWARF version. */ + pos = writeDwarfVersion(DwarfVersion.DW_VERSION_5, buffer, pos); + /* Address size. */ + pos = writeByte((byte) 8, buffer, pos); + /* Segment selector size. */ + pos = writeByte((byte) 0, buffer, pos); + /* Offset entry count */ + return writeInt(offsetEntries, buffer, pos); } - private int writeTopLevelLocations(DebugContext context, CompiledMethodEntry compiledEntry, int base, byte[] buffer, int p) { - int pos = p; - Range primary = compiledEntry.getPrimary(); - HashMap> varRangeMap = primary.getVarRangeMap(); - for (DebugLocalInfo local : varRangeMap.keySet()) { - List rangeList = varRangeMap.get(local); - if (!rangeList.isEmpty()) { - setRangeLocalIndex(primary, local, pos); - pos = writeVarLocations(context, local, base, rangeList, buffer, pos); - } - } - return pos; + private record LocationListEntry(Range range, int base, DebugLocalInfo local, List rangeList) { } - private int writeInlineLocations(DebugContext context, CompiledMethodEntry compiledEntry, int base, byte[] buffer, int p) { - int pos = p; - Range primary = compiledEntry.getPrimary(); - assert !primary.isLeaf(); - Iterator iterator = compiledEntry.topDownRangeIterator(); - while (iterator.hasNext()) { - SubRange subrange = iterator.next(); - if (subrange.isLeaf()) { - continue; - } - HashMap> varRangeMap = subrange.getVarRangeMap(); - for (DebugLocalInfo local : varRangeMap.keySet()) { - List rangeList = varRangeMap.get(local); - if (!rangeList.isEmpty()) { - setRangeLocalIndex(subrange, local, pos); - pos = writeVarLocations(context, local, base, rangeList, buffer, pos); + private static List getLocationListEntries(ClassEntry classEntry) { + List locationListEntries = new ArrayList<>(); + + classEntry.compiledEntries().forEachOrdered(compiledEntry -> { + Range primary = compiledEntry.getPrimary(); + /* + * Note that offsets are written relative to the primary range base. This requires + * writing a base address entry before each of the location list ranges. It is possible + * to default the base address to the low_pc value of the compile unit for the compiled + * method's owning class, saving two words per location list. However, that forces the + * debugger to do a lot more up-front cross-referencing of CUs when it needs to resolve + * code addresses e.g. to set a breakpoint, leading to a very slow response for the + * user. + */ + int base = primary.getLo(); + // location list entries for primary range + locationListEntries.addAll(getRangeLocationListEntries(primary, base)); + // location list entries for inlined calls + if (!primary.isLeaf()) { + Iterator iterator = compiledEntry.topDownRangeIterator(); + while (iterator.hasNext()) { + SubRange subrange = iterator.next(); + if (subrange.isLeaf()) { + continue; + } + locationListEntries.addAll(getRangeLocationListEntries(subrange, base)); } } + }); + return locationListEntries; + } + + private static List getRangeLocationListEntries(Range range, int base) { + List locationListEntries = new ArrayList<>(); + + for (Map.Entry> entry : range.getVarRangeMap().entrySet()) { + if (!entry.getValue().isEmpty()) { + locationListEntries.add(new LocationListEntry(range, base, entry.getKey(), entry.getValue())); + } } - return pos; + + return locationListEntries; } private int writeVarLocations(DebugContext context, DebugLocalInfo local, int base, List rangeList, byte[] buffer, int p) { @@ -204,15 +232,16 @@ private int writeVarLocations(DebugContext context, DebugLocalInfo local, int ba // write start of primary range as base address - see comment above for reasons why // we choose ot do this rather than use the relevant compile unit low_pc - pos = writeAttrData8(-1L, buffer, pos); + pos = writeLocationListEntry(DwarfLocationListEntry.DW_LLE_base_address, buffer, pos); pos = writeAttrAddress(base, buffer, pos); // write ranges as offsets from base for (LocalValueExtent extent : extents) { DebugLocalValueInfo value = extent.value; assert (value != null); log(context, " [0x%08x] local %s:%s [0x%x, 0x%x] = %s", pos, value.name(), value.typeName(), extent.getLo(), extent.getHi(), formatValue(value)); - pos = writeAttrData8(extent.getLo() - base, buffer, pos); - pos = writeAttrData8(extent.getHi() - base, buffer, pos); + pos = writeLocationListEntry(DwarfLocationListEntry.DW_LLE_offset_pair, buffer, pos); + pos = writeULEB(extent.getLo() - base, buffer, pos); + pos = writeULEB(extent.getHi() - base, buffer, pos); switch (value.localKind()) { case REGISTER: pos = writeRegisterLocation(context, value.regIndex(), buffer, pos); @@ -236,10 +265,7 @@ private int writeVarLocations(DebugContext context, DebugLocalInfo local, int ba } } // write list terminator - pos = writeAttrData8(0, buffer, pos); - pos = writeAttrData8(0, buffer, pos); - - return pos; + return writeLocationListEntry(DwarfLocationListEntry.DW_LLE_end_of_list, buffer, pos); } private int writeRegisterLocation(DebugContext context, int regIndex, byte[] buffer, int p) { @@ -248,31 +274,31 @@ private int writeRegisterLocation(DebugContext context, int regIndex, byte[] buf int pos = p; if (targetIdx < 0x20) { // can write using DW_OP_reg - short byteCount = 1; + int byteCount = 1; byte reg = (byte) targetIdx; - pos = writeShort(byteCount, buffer, pos); + pos = writeULEB(byteCount, buffer, pos); pos = writeExprOpcodeReg(reg, buffer, pos); verboseLog(context, " [0x%08x] REGOP count %d op 0x%x", pos, byteCount, DwarfExpressionOpcode.DW_OP_reg0.value() + reg); } else { // have to write using DW_OP_regx + LEB operand assert targetIdx < 128 : "unexpectedly high reg index!"; - short byteCount = 2; - pos = writeShort(byteCount, buffer, pos); + int byteCount = 2; + pos = writeULEB(byteCount, buffer, pos); pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_regx, buffer, pos); pos = writeULEB(targetIdx, buffer, pos); verboseLog(context, " [0x%08x] REGOP count %d op 0x%x reg %d", pos, byteCount, DwarfExpressionOpcode.DW_OP_regx.value(), targetIdx); - // target idx written as ULEB should fit in one byte - assert pos == p + 4 : "wrote the wrong number of bytes!"; + // byte count and target idx written as ULEB should fit in one byte + assert pos == p + 3 : "wrote the wrong number of bytes!"; } return pos; } private int writeStackLocation(DebugContext context, int offset, byte[] buffer, int p) { int pos = p; - short byteCount = 0; + int byteCount = 0; byte sp = (byte) getDwarfStackRegister(); int patchPos = pos; - pos = writeShort(byteCount, buffer, pos); + pos = writeULEB(byteCount, buffer, pos); int zeroPos = pos; if (sp < 0x20) { // fold the base reg index into the op @@ -284,12 +310,12 @@ private int writeStackLocation(DebugContext context, int offset, byte[] buffer, } pos = writeSLEB(offset, buffer, pos); // now backpatch the byte count - byteCount = (byte) (pos - zeroPos); - writeShort(byteCount, buffer, patchPos); + byteCount = (pos - zeroPos); + writeULEB(byteCount, buffer, patchPos); if (sp < 0x20) { - verboseLog(context, " [0x%08x] STACKOP count %d op 0x%x offset %d", pos, byteCount, (DwarfExpressionOpcode.DW_OP_breg0.value() + sp), 0 - offset); + verboseLog(context, " [0x%08x] STACKOP count %d op 0x%x offset %d", pos, byteCount, (DwarfExpressionOpcode.DW_OP_breg0.value() + sp), -offset); } else { - verboseLog(context, " [0x%08x] STACKOP count %d op 0x%x reg %d offset %d", pos, byteCount, DwarfExpressionOpcode.DW_OP_bregx.value(), sp, 0 - offset); + verboseLog(context, " [0x%08x] STACKOP count %d op 0x%x reg %d offset %d", pos, byteCount, DwarfExpressionOpcode.DW_OP_bregx.value(), sp, -offset); } return pos; } @@ -302,7 +328,7 @@ private int writePrimitiveConstantLocation(DebugContext context, JavaConstant co int dataByteCount = kind.getByteCount(); // total bytes is op + uleb + dataByteCount int byteCount = 1 + 1 + dataByteCount; - pos = writeShort((short) byteCount, buffer, pos); + pos = writeULEB(byteCount, buffer, pos); pos = writeExprOpcode(op, buffer, pos); pos = writeULEB(dataByteCount, buffer, pos); if (dataByteCount == 1) { @@ -331,7 +357,7 @@ private int writeNullConstantLocation(DebugContext context, JavaConstant constan int dataByteCount = 8; // total bytes is op + uleb + dataByteCount int byteCount = 1 + 1 + dataByteCount; - pos = writeShort((short) byteCount, buffer, pos); + pos = writeULEB(byteCount, buffer, pos); pos = writeExprOpcode(op, buffer, pos); pos = writeULEB(dataByteCount, buffer, pos); pos = writeAttrData8(0, buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfRangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfRangesSectionImpl.java index 155efe12feba..1d289c6307c8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfRangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfRangesSectionImpl.java @@ -26,35 +26,32 @@ package com.oracle.objectfile.elf.dwarf; +import java.util.Map; + import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.elf.dwarf.constants.DwarfRangeListEntry; import com.oracle.objectfile.elf.dwarf.constants.DwarfSectionName; -import jdk.graal.compiler.debug.DebugContext; +import com.oracle.objectfile.elf.dwarf.constants.DwarfVersion; -import java.util.Map; +import jdk.graal.compiler.debug.DebugContext; public class DwarfRangesSectionImpl extends DwarfSectionImpl { public DwarfRangesSectionImpl(DwarfDebugInfo dwarfSections) { - // debug_ranges section depends on debug_aranges section - super(dwarfSections, DwarfSectionName.DW_RANGES_SECTION, DwarfSectionName.DW_ARANGES_SECTION); + // debug_rnglists section depends on debug_aranges section + super(dwarfSections, DwarfSectionName.DW_RNGLISTS_SECTION, DwarfSectionName.DW_ARANGES_SECTION); } @Override public void createContent() { assert !contentByteArrayCreated(); - Cursor cursor = new Cursor(); - instanceClassStream().filter(ClassEntry::hasCompiledEntries).forEachOrdered(classEntry -> { - setCodeRangesIndex(classEntry, cursor.get()); - // base address - cursor.add(2 * 8); - // per method lo and hi offsets - cursor.add(2 * 8 * classEntry.compiledEntryCount()); - // end marker - cursor.add(2 * 8); - }); - byte[] buffer = new byte[cursor.get()]; + + byte[] buffer = null; + int len = generateContent(null, buffer); + + buffer = new byte[len]; super.setContent(buffer); } @@ -78,39 +75,82 @@ public byte[] getOrDecideContent(Map alre @Override public void writeContent(DebugContext context) { assert contentByteArrayCreated(); + byte[] buffer = getContent(); int size = buffer.length; - Cursor cursor = new Cursor(); + int pos = 0; + + enableLog(context, pos); + log(context, " [0x%08x] DEBUG_RANGES", pos); + log(context, " [0x%08x] size = 0x%08x", pos, size); + + pos = generateContent(context, buffer); + assert pos == size; + } + + private int generateContent(DebugContext context, byte[] buffer) { + int pos = 0; + + int lengthPos = pos; + pos = writeRangeListsHeader(buffer, pos); + + pos = writeRangeLists(context, buffer, pos); + + patchLength(lengthPos, buffer, pos); + return pos; + } - enableLog(context, cursor.get()); - log(context, " [0x%08x] DEBUG_RANGES", cursor.get()); + private int writeRangeListsHeader(byte[] buffer, int p) { + int pos = p; + /* Rnglists length. */ + pos = writeInt(0, buffer, pos); + /* DWARF version. */ + pos = writeDwarfVersion(DwarfVersion.DW_VERSION_5, buffer, pos); + /* Address size. */ + pos = writeByte((byte) 8, buffer, pos); + /* Segment selector size. */ + pos = writeByte((byte) 0, buffer, pos); + /* + * Offset entry count. Not needed because we just use ranges in top level compile unit DIEs + */ + return writeInt(0, buffer, pos); + } + + private int writeRangeLists(DebugContext context, byte[] buffer, int p) { + Cursor entryCursor = new Cursor(p); instanceClassStream().filter(ClassEntry::hasCompiledEntries).forEachOrdered(classEntry -> { - int pos = cursor.get(); - int start = pos; + int pos = entryCursor.get(); setCodeRangesIndex(classEntry, pos); - log(context, " [0x%08x] ranges start for class %s", pos, classEntry.getTypeName()); - int base = classEntry.compiledEntriesBase(); - log(context, " [0x%08x] base 0x%x", pos, base); - pos = writeLong(-1L, buffer, pos); - pos = writeRelocatableCodeOffset(base, buffer, pos); - cursor.set(pos); - classEntry.compiledEntries().forEach(compiledMethodEntry -> { - int lo = compiledMethodEntry.getPrimary().getLo(); - int hi = compiledMethodEntry.getPrimary().getHi(); - log(context, " [0x%08x] lo 0x%x (%s)", cursor.get(), lo - base, compiledMethodEntry.getPrimary().getFullMethodNameWithParams()); - cursor.set(writeLong(lo - base, buffer, cursor.get())); - log(context, " [0x%08x] hi 0x%x", cursor.get(), hi - base); - cursor.set(writeLong(hi - base, buffer, cursor.get())); - }); - pos = cursor.get(); - // write end marker - pos = writeLong(0, buffer, pos); - pos = writeLong(0, buffer, pos); - log(context, " [0x%08x] ranges size 0x%x for class %s", pos, pos - start, classEntry.getTypeName()); - cursor.set(pos); + /* Write range list for a class */ + entryCursor.set(writeRangeList(context, classEntry, buffer, pos)); }); + return entryCursor.get(); + } - assert cursor.get() == size; + private int writeRangeList(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + log(context, " [0x%08x] ranges start for class %s", pos, classEntry.getTypeName()); + int base = classEntry.compiledEntriesBase(); + log(context, " [0x%08x] base 0x%x", pos, base); + pos = writeRangeListEntry(DwarfRangeListEntry.DW_RLE_base_address, buffer, pos); + pos = writeRelocatableCodeOffset(base, buffer, pos); + + Cursor cursor = new Cursor(pos); + classEntry.compiledEntries().forEach(compiledMethodEntry -> { + cursor.set(writeRangeListEntry(DwarfRangeListEntry.DW_RLE_offset_pair, buffer, cursor.get())); + + int loOffset = compiledMethodEntry.getPrimary().getLo() - base; + int hiOffset = compiledMethodEntry.getPrimary().getHi() - base; + log(context, " [0x%08x] lo 0x%x (%s)", cursor.get(), loOffset, compiledMethodEntry.getPrimary().getFullMethodNameWithParams()); + cursor.set(writeULEB(loOffset, buffer, cursor.get())); + log(context, " [0x%08x] hi 0x%x", cursor.get(), hiOffset); + cursor.set(writeULEB(hiOffset, buffer, cursor.get())); + }); + pos = cursor.get(); + // write end marker + pos = writeRangeListEntry(DwarfRangeListEntry.DW_RLE_end_of_list, buffer, pos); + log(context, " [0x%08x] ranges size 0x%x for class %s", pos, pos - p, classEntry.getTypeName()); + return pos; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java index cf6139d5cd00..6f4c2650af28 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -55,8 +55,11 @@ import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.AbbrevCode; import com.oracle.objectfile.elf.dwarf.constants.DwarfExpressionOpcode; import com.oracle.objectfile.elf.dwarf.constants.DwarfFlag; +import com.oracle.objectfile.elf.dwarf.constants.DwarfLocationListEntry; +import com.oracle.objectfile.elf.dwarf.constants.DwarfRangeListEntry; import com.oracle.objectfile.elf.dwarf.constants.DwarfSectionName; import com.oracle.objectfile.elf.dwarf.constants.DwarfTag; +import com.oracle.objectfile.elf.dwarf.constants.DwarfUnitHeader; import com.oracle.objectfile.elf.dwarf.constants.DwarfVersion; import jdk.graal.compiler.debug.DebugContext; @@ -485,6 +488,14 @@ protected int writeAbbrevCode(AbbrevCode code, byte[] buffer, int pos) { return writeSLEB(code.ordinal(), buffer, pos); } + protected int writeRangeListEntry(DwarfRangeListEntry rangeListEntry, byte[] buffer, int pos) { + return writeByte(rangeListEntry.value(), buffer, pos); + } + + protected int writeLocationListEntry(DwarfLocationListEntry locationListEntry, byte[] buffer, int pos) { + return writeByte(locationListEntry.value(), buffer, pos); + } + protected int writeTag(DwarfTag dwarfTag, byte[] buffer, int pos) { int code = dwarfTag.value(); if (code == 0) { @@ -498,6 +509,14 @@ protected int writeDwarfVersion(DwarfVersion dwarfVersion, byte[] buffer, int po return writeShort(dwarfVersion.value(), buffer, pos); } + protected int writeDwarfUnitHeader(DwarfUnitHeader dwarfUnitHeader, byte[] buffer, int pos) { + return writeByte((byte) dwarfUnitHeader.value(), buffer, pos); + } + + protected int writeTypeSignature(long typeSignature, byte[] buffer, int pos) { + return writeLong(typeSignature, buffer, pos); + } + protected int writeFlag(DwarfFlag flag, byte[] buffer, int pos) { return writeByte(flag.value(), buffer, pos); } @@ -531,8 +550,8 @@ protected int writeLineSectionOffset(int offset, byte[] buffer, int pos) { return writeDwarfSectionOffset(offset, buffer, DwarfSectionName.DW_LINE_SECTION, pos); } - protected int writeRangesSectionOffset(int offset, byte[] buffer, int pos) { - return writeDwarfSectionOffset(offset, buffer, DwarfSectionName.DW_RANGES_SECTION, pos); + protected int writeRangeListsSectionOffset(int offset, byte[] buffer, int pos) { + return writeDwarfSectionOffset(offset, buffer, DwarfSectionName.DW_RNGLISTS_SECTION, pos); } protected int writeAbbrevSectionOffset(int offset, byte[] buffer, int pos) { @@ -550,7 +569,7 @@ private int writeStrSectionOffset(int offset, byte[] buffer, int pos) { } protected int writeLocSectionOffset(int offset, byte[] buffer, int pos) { - return writeDwarfSectionOffset(offset, buffer, DwarfSectionName.DW_LOC_SECTION, pos); + return writeDwarfSectionOffset(offset, buffer, DwarfSectionName.DW_LOCLISTS_SECTION, pos); } protected int writeDwarfSectionOffset(int offset, byte[] buffer, DwarfSectionName referencedSectionName, int pos) { @@ -597,15 +616,16 @@ protected int writeHeapLocationExprLoc(long offset, byte[] buffer, int p) { */ protected int writeHeapLocationLocList(long offset, byte[] buffer, int p) { int pos = p; - short len = 0; + int len = 0; int lenPos = pos; // write dummy length - pos = writeShort(len, buffer, pos); + pos = writeULEB(len, buffer, pos); + int zeroPos = pos; pos = writeHeapLocation(offset, buffer, pos); pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_stack_value, buffer, pos); // backpatch length - len = (short) (pos - (lenPos + 2)); - writeShort(len, buffer, lenPos); + len = pos - zeroPos; + writeULEB(len, buffer, lenPos); return pos; } @@ -841,28 +861,6 @@ protected ClassEntry lookupObjectClass() { return dwarfSections.lookupObjectClass(); } - protected int getTypeIndex(TypeEntry typeEntry) { - if (!contentByteArrayCreated()) { - return -1; - } - return dwarfSections.getTypeIndex(typeEntry); - } - - protected void setTypeIndex(TypeEntry typeEntry, int pos) { - dwarfSections.setTypeIndex(typeEntry, pos); - } - - protected int getIndirectTypeIndex(TypeEntry typeEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getIndirectTypeIndex(typeEntry); - } - - protected void setIndirectTypeIndex(TypeEntry typeEntry, int pos) { - dwarfSections.setIndirectTypeIndex(typeEntry, pos); - } - protected int getCUIndex(ClassEntry classEntry) { if (!contentByteArrayCreated()) { return 0; @@ -874,28 +872,6 @@ protected void setCUIndex(ClassEntry classEntry, int idx) { dwarfSections.setCUIndex(classEntry, idx); } - protected void setLayoutIndex(ClassEntry classEntry, int pos) { - dwarfSections.setLayoutIndex(classEntry, pos); - } - - protected int getLayoutIndex(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getLayoutIndex(classEntry); - } - - protected void setIndirectLayoutIndex(ClassEntry classEntry, int pos) { - dwarfSections.setIndirectLayoutIndex(classEntry, pos); - } - - protected int getIndirectLayoutIndex(ClassEntry classEntry) { - if (!contentByteArrayCreated()) { - return 0; - } - return dwarfSections.getIndirectLayoutIndex(classEntry); - } - protected void setCodeRangesIndex(ClassEntry classEntry, int pos) { dwarfSections.setCodeRangesIndex(classEntry, pos); } @@ -907,6 +883,14 @@ protected int getCodeRangesIndex(ClassEntry classEntry) { return dwarfSections.getCodeRangesIndex(classEntry); } + protected void setLocationListIndex(ClassEntry classEntry, int pos) { + dwarfSections.setLocationListIndex(classEntry, pos); + } + + protected int getLocationListIndex(ClassEntry classEntry) { + return dwarfSections.getLocationListIndex(classEntry); + } + protected void setLineIndex(ClassEntry classEntry, int pos) { dwarfSections.setLineIndex(classEntry, pos); } @@ -998,7 +982,7 @@ protected int getMethodLocalIndex(ClassEntry classEntry, MethodEntry methodEntry * @param range the top level (primary) or inline range to which the local (or parameter) * belongs. * @param localInfo the local or param whose index is to be recorded. - * @param index the info section offset to be recorded. + * @param index the info section offset index to be recorded. */ protected void setRangeLocalIndex(Range range, DebugLocalInfo localInfo, int index) { dwarfSections.setRangeLocalIndex(range, localInfo, index); @@ -1014,9 +998,6 @@ protected void setRangeLocalIndex(Range range, DebugLocalInfo localInfo, int ind * @return the associated info section offset. */ protected int getRangeLocalIndex(Range range, DebugLocalInfo localInfo) { - if (!contentByteArrayCreated()) { - return 0; - } return dwarfSections.getRangeLocalIndex(range, localInfo); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfAttribute.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfAttribute.java index 10c87e6b0715..050b9e9c726d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfAttribute.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfAttribute.java @@ -66,7 +66,9 @@ public enum DwarfAttribute { DW_AT_call_file(0x58), DW_AT_call_line(0x59), DW_AT_object_pointer(0x64), - DW_AT_linkage_name(0x6e); + DW_AT_signature(0x69), + DW_AT_linkage_name(0x6e), + DW_AT_loclists_base(0x8c); private final int value; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfForm.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfForm.java index 0dc5b3aedad3..1855bb16850e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfForm.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfForm.java @@ -52,7 +52,9 @@ public enum DwarfForm { DW_FORM_data1(0x0b), DW_FORM_flag(0xc), DW_FORM_strp(0xe), - DW_FORM_expr_loc(0x18); + DW_FORM_expr_loc(0x18), + DW_FORM_ref_sig8(0x20), + DW_FORM_loclistx(0x22); private final int value; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfLocationListEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfLocationListEntry.java new file mode 100644 index 000000000000..128506075fdc --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfLocationListEntry.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.objectfile.elf.dwarf.constants; + +/** + * All the Dwarf range list entry tags needed to range list entries generated by GraalVM. + */ +public enum DwarfLocationListEntry { + DW_LLE_end_of_list((byte) 0), + DW_LLE_offset_pair((byte) 0x04), + DW_LLE_base_address((byte) 0x06); + + private final byte value; + + DwarfLocationListEntry(byte i) { + value = i; + } + + public byte value() { + return value; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfRangeListEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfRangeListEntry.java new file mode 100644 index 000000000000..949dd610427b --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfRangeListEntry.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.objectfile.elf.dwarf.constants; + +/** + * All the Dwarf range list entry tags needed to range list entries generated by GraalVM. + */ +public enum DwarfRangeListEntry { + DW_RLE_end_of_list((byte) 0), + DW_RLE_offset_pair((byte) 0x04), + DW_RLE_base_address((byte) 0x05); + + private final byte value; + + DwarfRangeListEntry(byte i) { + value = i; + } + + public byte value() { + return value; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfSectionName.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfSectionName.java index bb12f38edf89..9d91ebf24437 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfSectionName.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfSectionName.java @@ -37,9 +37,9 @@ public enum DwarfSectionName { DW_FRAME_SECTION(".debug_frame"), DW_ABBREV_SECTION(".debug_abbrev"), DW_INFO_SECTION(".debug_info"), - DW_LOC_SECTION(".debug_loc"), + DW_LOCLISTS_SECTION(".debug_loclists"), DW_ARANGES_SECTION(".debug_aranges"), - DW_RANGES_SECTION(".debug_ranges"); + DW_RNGLISTS_SECTION(".debug_rnglists"); private final String value; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfTag.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfTag.java index c15b59bd5938..77527e493900 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfTag.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfTag.java @@ -41,6 +41,7 @@ public enum DwarfTag { DW_TAG_typedef(0x16), DW_TAG_union_type(0x17), DW_TAG_inheritance(0x1c), + DW_TAG_inlined_subroutine(0x1d), DW_TAG_subrange_type(0x21), DW_TAG_base_type(0x24), DW_TAG_constant(0x27), @@ -48,7 +49,7 @@ public enum DwarfTag { DW_TAG_variable(0x34), DW_TAG_namespace(0x39), DW_TAG_unspecified_type(0x3b), - DW_TAG_inlined_subroutine(0x1d); + DW_TAG_type_unit(0x41); private final int value; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfUnitHeader.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfUnitHeader.java new file mode 100644 index 000000000000..8255aae1e669 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfUnitHeader.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.oracle.objectfile.elf.dwarf.constants; + +/** + * All the Dwarf unit headers needed in the debug info section. + */ +public enum DwarfUnitHeader { + DW_UT_compile(0x1), + DW_UT_type(0x2); + + private final int value; + + DwarfUnitHeader(int i) { + value = i; + } + + public int value() { + return value; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfVersion.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfVersion.java index d646f501499c..de98c7e83fb2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfVersion.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/constants/DwarfVersion.java @@ -36,7 +36,8 @@ public enum DwarfVersion { * still need to be generated as version 2. */ DW_VERSION_2((short) 2), - DW_VERSION_4((short) 4); + DW_VERSION_4((short) 4), + DW_VERSION_5((short) 5); private final short value; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java index 58b921752dba..e7e5cea367a8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java @@ -93,6 +93,7 @@ import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.graph.NodeSourcePosition; import jdk.graal.compiler.java.StableMethodNameFormatter; +import jdk.graal.compiler.util.Digest; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.BytecodeFrame; @@ -248,6 +249,11 @@ public void debugContext(Consumer action) { } } + @Override + public long typeSignature(String prefix) { + return Digest.digestAsUUID(prefix + typeName()).getLeastSignificantBits(); + } + public String toJavaName(@SuppressWarnings("hiding") HostedType hostedType) { return getDeclaringClass(hostedType, true).toJavaName(); } @@ -335,6 +341,11 @@ public String typeName() { return typeName; } + @Override + public long typeSignature(String prefix) { + return Digest.digestAsUUID(typeName).getLeastSignificantBits(); + } + @Override public DebugTypeKind typeKind() { return DebugTypeKind.HEADER; @@ -469,6 +480,11 @@ private class NativeImageDebugInstanceTypeInfo extends NativeImageDebugTypeInfo super(hostedType); } + @Override + public long typeSignature(String prefix) { + return super.typeSignature(prefix + loaderName()); + } + @Override public DebugTypeKind typeKind() { return DebugTypeKind.INSTANCE; @@ -476,7 +492,6 @@ public DebugTypeKind typeKind() { @Override public String loaderName() { - return UniqueShortNameProvider.singleton().uniqueShortLoaderName(hostedType.getJavaClass().getClassLoader()); } @@ -824,6 +839,19 @@ void addField(String name, ResolvedJavaType valueType, int offset, @SuppressWarn fieldInfos.add(fieldinfo); } + @Override + public long typeSignature(String prefix) { + HostedType elementType = hostedType.getComponentType(); + while (elementType.isArray()) { + elementType = elementType.getComponentType(); + } + String loaderId = ""; + if (elementType.isInstanceClass() || elementType.isInterface() || elementType.isEnum()) { + loaderId = UniqueShortNameProvider.singleton().uniqueShortLoaderName(elementType.getJavaClass().getClassLoader()); + } + return super.typeSignature(prefix + loaderId); + } + @Override public DebugTypeKind typeKind() { return DebugTypeKind.ARRAY; @@ -859,6 +887,15 @@ private class NativeImageDebugPrimitiveTypeInfo extends NativeImageDebugTypeInfo this.primitiveType = primitiveType; } + @Override + public long typeSignature(String prefix) { + /* + * primitive types never need an indirection so use the same signature for places where + * we might want a special type + */ + return super.typeSignature(""); + } + @Override public DebugTypeKind typeKind() { return DebugTypeKind.PRIMITIVE; @@ -2218,9 +2255,7 @@ public boolean usesStack() { public class NativeImageDebugLocalInfo implements DebugLocalInfo { protected final String name; - protected final ResolvedJavaType type; - protected final ResolvedJavaType valueType; - protected final String typeName; + protected ResolvedJavaType type; protected final JavaKind kind; protected int slot; protected int line; @@ -2233,14 +2268,14 @@ public class NativeImageDebugLocalInfo implements DebugLocalInfo { // if we don't have a type default it for the JavaKind // it may still end up null when kind is Undefined. this.type = (resolvedType != null ? resolvedType : hostedTypeForKind(kind)); - - this.valueType = (type != null && type instanceof HostedType) ? getOriginal((HostedType) type) : type; - this.typeName = valueType == null ? "" : valueType().toJavaName(); } @Override public ResolvedJavaType valueType() { - return valueType; + if (type != null && type instanceof HostedType) { + return getOriginal((HostedType) type); + } + return type; } @Override @@ -2250,7 +2285,8 @@ public String name() { @Override public String typeName() { - return typeName; + ResolvedJavaType valueType = valueType(); + return (valueType == null ? "" : valueType().toJavaName()); } @Override