com.oracle.objectfile.elf.dwarf.DwarfInfoSectionImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of objectfile Show documentation
Show all versions of objectfile Show documentation
SubstrateVM object file writing library
/*
* Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2020, Red Hat Inc. 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;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
import com.oracle.objectfile.elf.dwarf.constants.DwarfAccess;
import com.oracle.objectfile.elf.dwarf.constants.DwarfEncoding;
import com.oracle.objectfile.elf.dwarf.constants.DwarfExpressionOpcode;
import com.oracle.objectfile.elf.dwarf.constants.DwarfFlag;
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.DwarfVersion;
import org.graalvm.collections.EconomicSet;
import jdk.graal.compiler.debug.DebugContext;
import com.oracle.objectfile.debugentry.ArrayTypeEntry;
import com.oracle.objectfile.debugentry.ClassEntry;
import com.oracle.objectfile.debugentry.CompiledMethodEntry;
import com.oracle.objectfile.debugentry.FieldEntry;
import com.oracle.objectfile.debugentry.FileEntry;
import com.oracle.objectfile.debugentry.ForeignTypeEntry;
import com.oracle.objectfile.debugentry.HeaderTypeEntry;
import com.oracle.objectfile.debugentry.InterfaceClassEntry;
import com.oracle.objectfile.debugentry.MethodEntry;
import com.oracle.objectfile.debugentry.PrimitiveTypeEntry;
import com.oracle.objectfile.debugentry.StructureTypeEntry;
import com.oracle.objectfile.debugentry.TypeEntry;
import com.oracle.objectfile.debugentry.range.Range;
import com.oracle.objectfile.debugentry.range.SubRange;
import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalInfo;
import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLocalValueInfo;
import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugPrimitiveTypeInfo;
import com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.AbbrevCode;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.PrimitiveConstant;
/**
* 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;
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;
// initialize CU start to an invalid value
cuStart = -1;
}
@Override
public void createContent() {
assert !contentByteArrayCreated();
byte[] buffer = null;
int len = generateContent(null, buffer);
buffer = new byte[len];
super.setContent(buffer);
}
@Override
public void writeContent(DebugContext context) {
assert contentByteArrayCreated();
byte[] buffer = getContent();
int size = buffer.length;
int pos = 0;
enableLog(context, pos);
log(context, " [0x%08x] DEBUG_INFO", pos);
log(context, " [0x%08x] size = 0x%08x", pos, size);
pos = generateContent(context, buffer);
assert pos == size;
}
DwarfEncoding computeEncoding(int flags, int bitCount) {
assert bitCount > 0;
if ((flags & DebugPrimitiveTypeInfo.FLAG_NUMERIC) != 0) {
if (((flags & DebugPrimitiveTypeInfo.FLAG_INTEGRAL) != 0)) {
if ((flags & DebugPrimitiveTypeInfo.FLAG_SIGNED) != 0) {
switch (bitCount) {
case 8:
return DwarfEncoding.DW_ATE_signed_char;
default:
assert bitCount == 16 || bitCount == 32 || bitCount == 64;
return DwarfEncoding.DW_ATE_signed;
}
} else {
assert bitCount == 16;
return DwarfEncoding.DW_ATE_unsigned;
}
} else {
assert bitCount == 32 || bitCount == 64;
return DwarfEncoding.DW_ATE_float;
}
} else {
assert bitCount == 1;
return DwarfEncoding.DW_ATE_boolean;
}
}
public int generateContent(DebugContext context, byte[] buffer) {
int pos = 0;
/* Write CU 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.
*/
pos = writeInstanceClasses(context, buffer, pos);
/* Write CUs for array types. */
pos = writeArrays(context, buffer, pos);
return pos;
}
private int writeBuiltInTypes(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;
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);
String name = uniqueDebugString("JAVA");
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
pos = writeStrSectionOffset(name, buffer, pos);
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);
/*
* Write a terminating null attribute.
*/
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) {
assert primitiveTypeEntry.getBitCount() > 0;
int pos = 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);
byte byteSize = (byte) primitiveTypeEntry.getSize();
log(context, " [0x%08x] byte_size %d", pos, byteSize);
pos = writeAttrData1(byteSize, buffer, pos);
byte bitCount = (byte) primitiveTypeEntry.getBitCount();
log(context, " [0x%08x] bitCount %d", pos, bitCount);
pos = writeAttrData1(bitCount, buffer, pos);
DwarfEncoding encoding = computeEncoding(primitiveTypeEntry.getFlags(), bitCount);
log(context, " [0x%08x] encoding 0x%x", pos, encoding.value());
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);
}
public int writeVoidType(DebugContext context, PrimitiveTypeEntry primitiveTypeEntry, byte[] buffer, int p) {
assert primitiveTypeEntry.getBitCount() == 0;
int pos = 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);
}
public int writeHeaderType(DebugContext context, HeaderTypeEntry headerTypeEntry, byte[] buffer, int p) {
int pos = 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);
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 = writeAttrData1(size, buffer, pos);
pos = writeStructFields(context, headerTypeEntry.fields(), buffer, pos);
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
private int writeStructFields(DebugContext context, Stream fields, byte[] buffer, int p) {
Cursor cursor = new Cursor(p);
fields.forEach(fieldEntry -> {
cursor.set(writeStructField(context, fieldEntry, buffer, cursor.get()));
});
return cursor.get();
}
private int writeStructField(DebugContext context, FieldEntry fieldEntry, byte[] buffer, int p) {
int pos = p;
String fieldName = fieldEntry.fieldName();
TypeEntry valueType = fieldEntry.getValueType();
int valueTypeIdx;
if (fieldEntry.isEmbedded()) {
// the field type must be a foreign type
ForeignTypeEntry foreignValueType = (ForeignTypeEntry) valueType;
/* use the indirect layout type for the field */
/* handle special case when the field is an array */
int fieldSize = fieldEntry.getSize();
int valueSize = foreignValueType.getSize();
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;
pos = writeEmbeddedArrayDataType(context, foreignValueType, valueSize, fieldSize / valueSize, buffer, pos);
} else {
if (foreignValueType.isPointer()) {
TypeEntry pointerTo = foreignValueType.getPointerTo();
assert pointerTo != null : "ADDRESS field pointer type must have a known target type";
// type the array using the referent of the pointer type
//
// n.b it is critical for correctness to use the index of the referent rather
// than the layout type of the referring type even though the latter will
// (eventually) be set to the same value. the type index of the referent is
// guaranteed to be set on the first sizing pass before it is consumed here
// on the second writing pass.
// 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.
valueTypeIdx = getTypeIndex(pointerTo);
} else {
valueTypeIdx = getIndirectLayoutIndex(foreignValueType);
}
}
} else {
/* use the indirect type for the field so pointers get translated */
valueTypeIdx = getIndirectTypeIndex(valueType);
}
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);
short offset = (short) fieldEntry.getOffset();
int size = fieldEntry.getSize();
log(context, " [0x%08x] offset 0x%x (size 0x%x)", pos, offset, size);
pos = writeAttrData2(offset, buffer, pos);
int modifiers = fieldEntry.getModifiers();
log(context, " [0x%08x] modifiers %s", pos, fieldEntry.getModifiersString());
return writeAttrAccessibility(modifiers, buffer, pos);
}
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(writeInstanceClassInfo(context, classEntry, buffer, cursor.get()));
});
return cursor.get();
}
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);
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);
String name = classEntry.getFullFileName();
if (name == null) {
name = classEntry.getTypeName().replace('.', '/') + ".java";
}
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
pos = writeStrSectionOffset(uniqueDebugString(name), buffer, pos);
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) {
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
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 the class has a loader then embed the children in a namespace */
String loaderId = classEntry.getLoaderId();
if (!loaderId.isEmpty()) {
pos = writeNameSpace(context, loaderId, buffer, pos);
}
/* 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 */
/* Write all compiled code locations */
pos = writeMethodLocations(context, classEntry, buffer, pos);
/* Write abstract inline methods. */
pos = writeAbstractInlineMethods(context, classEntry, buffer, pos);
/* Write all static field definitions */
pos = writeStaticFieldLocations(context, classEntry, buffer, pos);
if (!loaderId.isEmpty()) {
pos = writeAttrNull(buffer, pos);
}
/*
* Write a terminating null attribute.
*/
pos = writeAttrNull(buffer, pos);
/* Fix up the CU length. */
patchLength(lengthPos, buffer, pos);
return pos;
}
private int writeNameSpace(DebugContext context, String id, byte[] buffer, int p) {
int pos = p;
String name = uniqueDebugString(id);
assert !id.isEmpty();
log(context, " [0x%08x] namespace %s", pos, name);
AbbrevCode abbrevCode = AbbrevCode.NAMESPACE;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
pos = writeStrSectionOffset(name, buffer, pos);
return pos;
}
private int writeClassConstantDeclaration(DebugContext context, TypeEntry typeEntry, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] class constant", pos);
long offset = typeEntry.getClassOffset();
if (offset < 0) {
return pos;
}
// Write a special static field declaration for the class object
// we use the abbrev code for a static field with no file or line location
AbbrevCode abbrevCode = AbbrevCode.CLASS_CONSTANT;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
String name = uniqueDebugString(typeEntry.getTypeName() + ".class");
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
pos = writeStrSectionOffset(name, buffer, pos);
/*
* This is a direct reference to the object rather than a compressed oop reference. So, we
* 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);
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);
/*
* We need to force encoding of this location as a heap base relative relocatable address
* rather than an offset from the heapbase register.
*/
log(context, " [0x%08x] location heapbase + 0x%x (class constant)", pos, offset);
pos = writeHeapLocationExprLoc(offset, false, buffer, pos);
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) {
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);
/* 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);
log(context, " [0x%08x] modifiers public", pos);
int modifiers = Modifier.PUBLIC;
pos = writeAttrAccessibility(modifiers, buffer, pos);
return pos;
}
private int writeFields(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
return classEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField).reduce(p,
(pos, fieldEntry) -> writeField(context, classEntry, fieldEntry, buffer, pos),
(oldPos, newPos) -> newPos);
}
private static boolean isManifestedField(FieldEntry fieldEntry) {
return fieldEntry.getOffset() >= 0;
}
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;
log(context, " [0x%08x] field definition", pos);
AbbrevCode abbrevCode;
boolean isStatic = Modifier.isStatic(modifiers);
if (!isStatic) {
if (!hasFile) {
abbrevCode = AbbrevCode.FIELD_DECLARATION_1;
} else {
abbrevCode = AbbrevCode.FIELD_DECLARATION_2;
}
} else {
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(entry, 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) {
assert entry instanceof ClassEntry;
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 */
int typeIdx = getIndirectTypeIndex(valueType);
log(context, " [0x%08x] type 0x%x (%s)", pos, typeIdx, valueType.getTypeName());
pos = writeInfoSectionOffset(typeIdx, buffer, pos);
if (!isStatic) {
int memberOffset = fieldEntry.getOffset();
log(context, " [0x%08x] member offset 0x%x", pos, memberOffset);
pos = writeAttrData2((short) memberOffset, 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. */
if (isStatic) {
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 writeMethodDeclarations(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 = writeMethodDeclaration(context, classEntry, method, buffer, pos);
}
}
return pos;
}
private int writeMethodDeclaration(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) {
int pos = p;
String methodKey = method.getSymbolName();
String linkageName = uniqueDebugString(methodKey);
setMethodDeclarationIndex(method, pos);
int modifiers = method.getModifiers();
boolean isStatic = Modifier.isStatic(modifiers);
log(context, " [0x%08x] method declaration %s::%s", pos, classEntry.getTypeName(), method.methodName());
AbbrevCode abbrevCode = (isStatic ? AbbrevCode.METHOD_DECLARATION_STATIC : AbbrevCode.METHOD_DECLARATION);
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);
FileEntry fileEntry = method.getFileEntry();
if (fileEntry == null) {
fileEntry = classEntry.getFileEntry();
}
assert fileEntry != null;
int fileIdx = classEntry.getFileIdx(fileEntry);
log(context, " [0x%08x] file 0x%x (%s)", pos, fileIdx, fileEntry.getFullName());
pos = writeAttrData2((short) fileIdx, buffer, pos);
int line = method.getLine();
log(context, " [0x%08x] line 0x%x", pos, line);
pos = writeAttrData2((short) line, buffer, pos);
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);
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);
if (abbrevCode == AbbrevCode.METHOD_DECLARATION) {
/* Record the current position so we can back patch the object pointer. */
int objectPointerIndex = pos;
/*
* Write a dummy ref address to move pos on to where the first parameter gets written.
*/
pos = writeAttrRef4(0, null, pos);
/*
* Now backpatch object pointer slot with current pos, identifying the first parameter.
*/
log(context, " [0x%08x] object_pointer 0x%x", objectPointerIndex, pos);
writeAttrRef4(pos, buffer, objectPointerIndex);
}
/* Write method parameter declarations. */
pos = writeMethodParameterDeclarations(context, classEntry, method, fileIdx, 3, buffer, pos);
/* write method local declarations */
pos = writeMethodLocalDeclarations(context, classEntry, method, fileIdx, 3, buffer, pos);
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
private int writeMethodParameterDeclarations(DebugContext context, ClassEntry classEntry, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) {
int pos = p;
int refAddr;
if (!Modifier.isStatic(method.getModifiers())) {
refAddr = pos;
DebugLocalInfo paramInfo = method.getThisParam();
setMethodLocalIndex(classEntry, method, paramInfo, refAddr);
pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, true, level, buffer, pos);
}
for (int i = 0; i < method.getParamCount(); i++) {
refAddr = pos;
DebugLocalInfo paramInfo = method.getParam(i);
setMethodLocalIndex(classEntry, method, paramInfo, refAddr);
pos = writeMethodParameterDeclaration(context, paramInfo, fileIdx, false, level, buffer, pos);
}
return pos;
}
private int writeMethodParameterDeclaration(DebugContext context, DebugLocalInfo paramInfo, int fileIdx, boolean artificial, int level, byte[] buffer,
int p) {
int pos = p;
log(context, " [0x%08x] method parameter declaration", pos);
AbbrevCode abbrevCode;
String paramName = paramInfo.name();
TypeEntry paramType = lookupType(paramInfo.valueType());
int line = paramInfo.line();
if (artificial) {
abbrevCode = AbbrevCode.METHOD_PARAMETER_DECLARATION_1;
} else if (line >= 0) {
abbrevCode = AbbrevCode.METHOD_PARAMETER_DECLARATION_2;
} else {
abbrevCode = AbbrevCode.METHOD_PARAMETER_DECLARATION_3;
}
log(context, " [0x%08x] <%d> Abbrev Number %d", pos, level, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] name %s", pos, paramName);
pos = writeStrSectionOffset(uniqueDebugString(paramName), buffer, pos);
if (abbrevCode == AbbrevCode.METHOD_PARAMETER_DECLARATION_2) {
log(context, " [0x%08x] file 0x%x", pos, fileIdx);
pos = writeAttrData2((short) fileIdx, buffer, pos);
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);
if (abbrevCode == AbbrevCode.METHOD_PARAMETER_DECLARATION_1) {
log(context, " [0x%08x] artificial true", pos);
pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos);
}
log(context, " [0x%08x] declaration true", pos);
pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos);
return pos;
}
private int writeMethodLocalDeclarations(DebugContext context, ClassEntry classEntry, MethodEntry method, int fileIdx, int level, byte[] buffer, int p) {
int pos = p;
int refAddr;
for (int i = 0; i < method.getLocalCount(); i++) {
refAddr = pos;
DebugLocalInfo localInfo = method.getLocal(i);
setMethodLocalIndex(classEntry, method, localInfo, refAddr);
pos = writeMethodLocalDeclaration(context, localInfo, fileIdx, level, buffer, pos);
}
return pos;
}
private int writeMethodLocalDeclaration(DebugContext context, DebugLocalInfo paramInfo, int fileIdx, int level, byte[] buffer,
int p) {
int pos = p;
log(context, " [0x%08x] method local declaration", pos);
AbbrevCode abbrevCode;
String paramName = paramInfo.name();
TypeEntry paramType = lookupType(paramInfo.valueType());
int line = paramInfo.line();
if (line >= 0) {
abbrevCode = AbbrevCode.METHOD_LOCAL_DECLARATION_1;
} else {
abbrevCode = AbbrevCode.METHOD_LOCAL_DECLARATION_2;
}
log(context, " [0x%08x] <%d> Abbrev Number %d", pos, level, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] name %s", pos, paramName);
pos = writeStrSectionOffset(uniqueDebugString(paramName), buffer, pos);
if (abbrevCode == AbbrevCode.METHOD_LOCAL_DECLARATION_1) {
log(context, " [0x%08x] file 0x%x", pos, fileIdx);
pos = writeAttrData2((short) fileIdx, buffer, pos);
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);
}
return pos;
}
private int writeInterfaceImplementors(DebugContext context, InterfaceClassEntry interfaceClassEntry, byte[] buffer, int p) {
return interfaceClassEntry.implementors().reduce(p,
(pos, classEntry) -> writeInterfaceImplementor(context, classEntry, buffer, pos),
(oldPos, newPos) -> newPos);
}
private int writeInterfaceImplementor(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] interface implementor", pos);
AbbrevCode abbrevCode = AbbrevCode.INTERFACE_IMPLEMENTOR;
log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
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);
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());
AbbrevCode abbrevCode = AbbrevCode.FOREIGN_STRUCT;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
String typedefName = foreignTypeEntry.getTypedefName();
if (typedefName == null) {
typedefName = "_" + foreignTypeEntry.getTypeName();
verboseLog(context, " [0x%08x] using synthetic typedef name %s", pos, typedefName);
}
if (typedefName.startsWith("struct ")) {
// log this before correcting it so we have some hope of clearing it up
log(context, " [0x%08x] typedefName includes redundant keyword struct %s", pos, typedefName);
typedefName = typedefName.substring("struct ".length());
}
typedefName = uniqueDebugString(typedefName);
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(typedefName), typedefName);
pos = writeStrSectionOffset(typedefName, buffer, pos);
log(context, " [0x%08x] byte_size 0x%x", pos, size);
pos = writeAttrData1((byte) size, buffer, pos);
// 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);
}
pos = writeStructFields(context, foreignTypeEntry.fields(), buffer, pos);
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
private int writeForeignWordLayout(DebugContext context, ForeignTypeEntry foreignTypeEntry, int size, boolean isSigned, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] foreign primitive word type for %s", pos, foreignTypeEntry.getTypeName());
/* Record the location of this type entry. */
AbbrevCode abbrevCode = AbbrevCode.PRIMITIVE_TYPE;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
assert size >= 0;
byte byteSize = (byte) (size > 0 ? size : dwarfSections.pointerSize());
log(context, " [0x%08x] byte_size %d", pos, byteSize);
pos = writeAttrData1(byteSize, buffer, pos);
byte bitCount = (byte) (byteSize * 8);
log(context, " [0x%08x] bitCount %d", pos, bitCount);
pos = writeAttrData1(bitCount, buffer, pos);
// treat the layout as a signed or unsigned word of the relevant size
DwarfEncoding encoding = (isSigned ? DwarfEncoding.DW_ATE_signed : DwarfEncoding.DW_ATE_unsigned);
log(context, " [0x%08x] encoding 0x%x", pos, encoding.value());
pos = writeAttrEncoding(encoding, buffer, pos);
String name = uniqueDebugString(integralTypeName(byteSize, isSigned));
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
return writeStrSectionOffset(name, buffer, pos);
}
private int writeForeignIntegerLayout(DebugContext context, ForeignTypeEntry foreignTypeEntry, int size, boolean isSigned, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] foreign primitive integral type for %s", pos, foreignTypeEntry.getTypeName());
/* Record the location of this type entry. */
AbbrevCode abbrevCode = AbbrevCode.PRIMITIVE_TYPE;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
assert size > 0;
byte byteSize = (byte) size;
log(context, " [0x%08x] byte_size %d", pos, byteSize);
pos = writeAttrData1(byteSize, buffer, pos);
byte bitCount = (byte) (byteSize * 8);
log(context, " [0x%08x] bitCount %d", pos, bitCount);
pos = writeAttrData1(bitCount, buffer, pos);
// treat the layout as a signed or unsigned word of the relevant size
DwarfEncoding encoding = (isSigned ? DwarfEncoding.DW_ATE_signed : DwarfEncoding.DW_ATE_unsigned);
log(context, " [0x%08x] encoding 0x%x", pos, encoding.value());
pos = writeAttrEncoding(encoding, buffer, pos);
String name = uniqueDebugString(integralTypeName(byteSize, isSigned));
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
return writeStrSectionOffset(name, buffer, pos);
}
private int writeForeignFloatLayout(DebugContext context, ForeignTypeEntry foreignTypeEntry, int size, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] foreign primitive float type for %s", pos, foreignTypeEntry.getTypeName());
/* Record the location of this type entry. */
AbbrevCode abbrevCode = AbbrevCode.PRIMITIVE_TYPE;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
assert size > 0;
byte byteSize = (byte) size;
log(context, " [0x%08x] byte_size %d", pos, byteSize);
pos = writeAttrData1(byteSize, buffer, pos);
byte bitCount = (byte) (byteSize * 8);
log(context, " [0x%08x] bitCount %d", pos, bitCount);
pos = writeAttrData1(bitCount, buffer, pos);
// treat the layout as a float of the relevant size
DwarfEncoding encoding = DwarfEncoding.DW_ATE_float;
log(context, " [0x%08x] encoding 0x%x", pos, encoding.value());
pos = writeAttrEncoding(encoding, buffer, pos);
String name = uniqueDebugString(size == 4 ? "float" : (size == 8 ? "double" : "long double"));
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
return writeStrSectionOffset(name, buffer, pos);
}
private static String integralTypeName(int byteSize, boolean isSigned) {
assert (byteSize & (byteSize - 1)) == 0 : "expecting a power of 2!";
StringBuilder stringBuilder = new StringBuilder();
if (!isSigned) {
stringBuilder.append('u');
}
stringBuilder.append("int");
stringBuilder.append(8 * byteSize);
stringBuilder.append("_t");
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.oopReferenceSize();
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.oopReferenceSize();
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
* 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(writeClassStaticFieldLocation(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 writeClassStaticFieldLocation(DebugContext context, ClassEntry classEntry, FieldEntry fieldEntry, byte[] buffer, int p) {
int pos = p;
String fieldName = fieldEntry.fieldName();
int fieldDefinitionOffset = getFieldDeclarationIndex(classEntry, fieldName);
log(context, " [0x%08x] static field location %s.%s", pos, classEntry.getTypeName(), fieldName);
AbbrevCode abbrevCode = AbbrevCode.STATIC_FIELD_LOCATION;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
// n.b. field definition offset gets written as a Ref4, relative to CU start
log(context, " [0x%08x] specification 0x%x", pos, fieldDefinitionOffset);
pos = writeAttrRef4(fieldDefinitionOffset, buffer, pos);
/* Field offset needs to be relocated relative to static primitive or static object base. */
int offset = fieldEntry.getOffset();
log(context, " [0x%08x] location heapbase + 0x%x (%s)", pos, offset, (fieldEntry.getValueType().isPrimitive() ? "primitive" : "object"));
pos = writeHeapLocationExprLoc(offset, buffer, pos);
return pos;
}
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(writeArray(context, arrayTypeEntry, buffer, cursor.get()));
});
return cursor.get();
}
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;
AbbrevCode 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");
pos = writeAttrLanguage(DwarfDebugInfo.LANG_ENCODING, buffer, pos);
log(context, " [0x%08x] use_UTF8", pos);
pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos);
String name = uniqueDebugString("JAVA");
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(name), name);
pos = writeStrSectionOffset(name, buffer, pos);
String compilationDirectory = dwarfSections.getCachePath();
log(context, " [0x%08x] comp_dir 0x%x (%s)", pos, debugStringIndex(compilationDirectory), compilationDirectory);
pos = writeStrSectionOffset(compilationDirectory, buffer, pos);
/* if the array base type is a class with a loader then embed the children in a namespace */
String loaderId = arrayTypeEntry.getLoaderId();
if (!loaderId.isEmpty()) {
pos = writeNameSpace(context, loaderId, buffer, pos);
}
/* 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);
/* if we opened a namespace then terminate its children */
if (!loaderId.isEmpty()) {
pos = writeAttrNull(buffer, pos);
}
/*
* Write a terminating null attribute.
*/
pos = writeAttrNull(buffer, pos);
/* Fix up the CU length. */
patchLength(lengthPos, buffer, pos);
return pos;
}
private int writeArrayLayout(DebugContext context, ArrayTypeEntry arrayTypeEntry, TypeEntry elementType, int size, byte[] buffer, int p) {
int pos = p;
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);
pos = writeArraySuperReference(context, buffer, pos);
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
private int writeFields(DebugContext context, ArrayTypeEntry arrayTypeEntry, byte[] buffer, int p) {
Cursor cursor = new Cursor(p);
arrayTypeEntry.fields().filter(DwarfInfoSectionImpl::isManifestedField)
.forEach(fieldEntry -> {
cursor.set(writeField(context, arrayTypeEntry, fieldEntry, buffer, cursor.get()));
});
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);
AbbrevCode abbrevCode = AbbrevCode.ARRAY_DATA_TYPE_1;
log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
// 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);
return pos;
}
private int writeEmbeddedArrayDataType(DebugContext context, ForeignTypeEntry foreignValueType, int valueSize, int arraySize, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] embedded array element data type", pos);
AbbrevCode abbrevCode = AbbrevCode.ARRAY_DATA_TYPE_2;
log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
// Foreign arrays have a fixed byte_size
int size = arraySize * valueSize;
log(context, " [0x%08x] byte_size 0x%x", pos, size);
pos = writeAttrData4(size, buffer, pos);
String elementTypeName = foreignValueType.getTypeName();
int elementTypeIdx;
if (foreignValueType.isPointer()) {
TypeEntry pointerTo = foreignValueType.getPointerTo();
assert pointerTo != null : "ADDRESS field pointer type must have a known target type";
// type the array using the referent of the pointer type
//
// n.b it is critical for correctness to use the index of the referent rather than
// the layout type of the referring type even though the latter will (eventually)
// be set to the same value. the type index of the referent is guaranteed to be set
// on the first sizing pass before it is consumed here on the second writing pass.
// 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);
} else {
// type the array using the layout type
elementTypeIdx = getIndirectLayoutIndex(foreignValueType);
}
log(context, " [0x%08x] type idx 0x%x (%s)", pos, elementTypeIdx, elementTypeName);
pos = writeInfoSectionOffset(elementTypeIdx, buffer, pos);
// write subrange child DIE
log(context, " [0x%08x] embedded array element range", pos);
abbrevCode = AbbrevCode.ARRAY_SUBRANGE;
log(context, " [0x%08x] <3> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] count 0x%x", pos, arraySize);
pos = writeAttrData4(arraySize, buffer, pos);
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
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;
log(context, " [0x%08x] <2> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
String fieldName = uniqueDebugString("data");
log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(fieldName), fieldName);
pos = writeStrSectionOffset(fieldName, buffer, pos);
log(context, " [0x%08x] type idx 0x%x", pos, arrayDataTypeIdx);
pos = writeInfoSectionOffset(arrayDataTypeIdx, buffer, pos);
int size = 0;
log(context, " [0x%08x] offset 0x%x (size 0x%x)", pos, offset, size);
pos = writeAttrData2((short) offset, buffer, pos);
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.oopReferenceSize();
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) {
Cursor cursor = new Cursor(p);
classEntry.compiledEntries().forEach(compiledMethodEntry -> {
cursor.set(writeMethodLocation(context, classEntry, compiledMethodEntry, buffer, cursor.get()));
});
return cursor.get();
}
private int writeMethodLocation(DebugContext context, ClassEntry classEntry, CompiledMethodEntry compiledEntry, byte[] buffer, int p) {
int pos = p;
Range primary = compiledEntry.getPrimary();
log(context, " [0x%08x] method location", pos);
AbbrevCode abbrevCode = AbbrevCode.METHOD_LOCATION;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] lo_pc 0x%08x", pos, primary.getLo());
pos = writeAttrAddress(primary.getLo(), buffer, pos);
log(context, " [0x%08x] hi_pc 0x%08x", pos, primary.getHi());
pos = writeAttrAddress(primary.getHi(), buffer, pos);
/*
* Should pass true only if method is non-private.
*/
log(context, " [0x%08x] external true", pos);
pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos);
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);
HashMap> varRangeMap = primary.getVarRangeMap();
pos = writeMethodParameterLocations(context, classEntry, varRangeMap, primary, 2, buffer, pos);
pos = writeMethodLocalLocations(context, classEntry, varRangeMap, primary, 2, buffer, pos);
if (primary.includesInlineRanges()) {
/*
* the method has inlined ranges so write concrete inlined method entries as its
* children
*/
pos = generateConcreteInlinedMethods(context, classEntry, compiledEntry, buffer, pos);
}
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
private int writeMethodParameterLocations(DebugContext context, ClassEntry classEntry, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) {
int pos = p;
MethodEntry methodEntry;
if (range.isPrimary()) {
methodEntry = range.getMethodEntry();
} else {
assert !range.isLeaf() : "should only be looking up var ranges for inlined calls";
methodEntry = range.getFirstCallee().getMethodEntry();
}
if (!Modifier.isStatic(methodEntry.getModifiers())) {
DebugLocalInfo thisParamInfo = methodEntry.getThisParam();
int refAddr = getMethodLocalIndex(classEntry, methodEntry, thisParamInfo);
List ranges = varRangeMap.get(thisParamInfo);
pos = writeMethodLocalLocation(context, range, thisParamInfo, refAddr, ranges, depth, true, buffer, pos);
}
for (int i = 0; i < methodEntry.getParamCount(); i++) {
DebugLocalInfo paramInfo = methodEntry.getParam(i);
int refAddr = getMethodLocalIndex(classEntry, methodEntry, paramInfo);
List ranges = varRangeMap.get(paramInfo);
pos = writeMethodLocalLocation(context, range, paramInfo, refAddr, ranges, depth, true, buffer, pos);
}
return pos;
}
private int writeMethodLocalLocations(DebugContext context, ClassEntry classEntry, HashMap> varRangeMap, Range range, int depth, byte[] buffer, int p) {
int pos = p;
MethodEntry methodEntry;
if (range.isPrimary()) {
methodEntry = range.getMethodEntry();
} else {
assert !range.isLeaf() : "should only be looking up var ranges for inlined calls";
methodEntry = range.getFirstCallee().getMethodEntry();
}
int count = methodEntry.getLocalCount();
for (int i = 0; i < count; i++) {
DebugLocalInfo localInfo = methodEntry.getLocal(i);
int refAddr = getMethodLocalIndex(classEntry, methodEntry, localInfo);
List ranges = varRangeMap.get(localInfo);
pos = writeMethodLocalLocation(context, range, localInfo, refAddr, ranges, depth, false, buffer, pos);
}
return pos;
}
private int writeMethodLocalLocation(DebugContext context, Range range, DebugLocalInfo localInfo, int refAddr, List ranges, int depth, boolean isParam, byte[] buffer,
int p) {
int pos = p;
log(context, " [0x%08x] method %s location %s:%s", pos, (isParam ? "parameter" : "local"), localInfo.name(), localInfo.typeName());
List localValues = new ArrayList<>();
for (SubRange subrange : ranges) {
DebugLocalValueInfo value = subrange.lookupValue(localInfo);
if (value != null) {
log(context, " [0x%08x] local %s:%s [0x%x, 0x%x] = %s", pos, value.name(), value.typeName(), subrange.getLo(), subrange.getHi(), formatValue(value));
switch (value.localKind()) {
case REGISTER:
case STACKSLOT:
localValues.add(value);
break;
case CONSTANT:
JavaConstant constant = value.constantValue();
// can only handle primitive or null constants just now
if (constant instanceof PrimitiveConstant || constant.getJavaKind() == JavaKind.Object) {
localValues.add(value);
}
break;
default:
break;
}
}
}
AbbrevCode abbrevCode;
if (localValues.isEmpty()) {
abbrevCode = (isParam ? AbbrevCode.METHOD_PARAMETER_LOCATION_1 : AbbrevCode.METHOD_LOCAL_LOCATION_1);
} else {
abbrevCode = (isParam ? AbbrevCode.METHOD_PARAMETER_LOCATION_2 : AbbrevCode.METHOD_LOCAL_LOCATION_2);
}
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);
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);
}
return pos;
}
/**
* Go through the subranges and generate concrete debug entries for inlined methods.
*/
private int generateConcreteInlinedMethods(DebugContext context, ClassEntry classEntry, CompiledMethodEntry compiledEntry, byte[] buffer, int p) {
Range primary = compiledEntry.getPrimary();
if (primary.isLeaf()) {
return p;
}
int pos = p;
log(context, " [0x%08x] concrete entries [0x%x,0x%x] %s", pos, primary.getLo(), primary.getHi(), primary.getFullMethodName());
int depth = 0;
Iterator iterator = compiledEntry.topDownRangeIterator();
while (iterator.hasNext()) {
SubRange subrange = iterator.next();
if (subrange.isLeaf()) {
// we only generate concrete methods for non-leaf entries
continue;
}
// if we just stepped out of a child range write nulls for each step up
while (depth > subrange.getDepth()) {
pos = writeAttrNull(buffer, pos);
depth--;
}
depth = subrange.getDepth();
pos = writeInlineSubroutine(context, classEntry, subrange, depth + 2, buffer, pos);
HashMap> varRangeMap = subrange.getVarRangeMap();
// increment depth to account for parameter and method locations
depth++;
pos = writeMethodParameterLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos);
pos = writeMethodLocalLocations(context, classEntry, varRangeMap, subrange, depth + 2, buffer, pos);
}
// if we just stepped out of a child range write nulls for each step up
while (depth > 0) {
pos = writeAttrNull(buffer, pos);
depth--;
}
return pos;
}
private int writeInlineSubroutine(DebugContext context, ClassEntry classEntry, SubRange caller, int depth, byte[] buffer, int p) {
assert !caller.isLeaf();
// the supplied range covers an inline call and references the caller method entry. its
// child ranges all reference the same inlined called method. leaf children cover code for
// that inlined method. non-leaf children cover code for recursively inlined methods.
// identify the inlined method by looking at the first callee
Range callee = caller.getFirstCallee();
MethodEntry methodEntry = callee.getMethodEntry();
String methodKey = methodEntry.getSymbolName();
/* the abstract index was written in the method's class entry */
int abstractOriginIndex = (classEntry == methodEntry.ownerType() ? getMethodDeclarationIndex(methodEntry) : getAbstractInlineMethodIndex(classEntry, methodEntry));
int pos = p;
log(context, " [0x%08x] concrete inline subroutine [0x%x, 0x%x] %s", pos, caller.getLo(), caller.getHi(), methodKey);
int callLine = caller.getLine();
assert callLine >= -1 : callLine;
int fileIndex;
if (callLine == -1) {
log(context, " Unable to retrieve call line for inlined method %s", callee.getFullMethodName());
/* continue with line 0 and fileIndex 1 as we must insert a tree node */
callLine = 0;
fileIndex = classEntry.getFileIdx();
} else {
FileEntry subFileEntry = caller.getFileEntry();
if (subFileEntry != null) {
fileIndex = classEntry.getFileIdx(subFileEntry);
} else {
log(context, " Unable to retrieve caller FileEntry for inlined method %s (caller method %s)", callee.getFullMethodName(), caller.getFullMethodName());
fileIndex = classEntry.getFileIdx();
}
}
final AbbrevCode abbrevCode = AbbrevCode.INLINED_SUBROUTINE_WITH_CHILDREN;
log(context, " [0x%08x] <%d> Abbrev Number %d", pos, depth, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] abstract_origin 0x%x", pos, abstractOriginIndex);
pos = writeAttrRef4(abstractOriginIndex, buffer, pos);
log(context, " [0x%08x] lo_pc 0x%08x", pos, caller.getLo());
pos = writeAttrAddress(caller.getLo(), buffer, pos);
log(context, " [0x%08x] hi_pc 0x%08x", pos, caller.getHi());
pos = writeAttrAddress(caller.getHi(), buffer, pos);
log(context, " [0x%08x] call_file %d", pos, fileIndex);
pos = writeAttrData4(fileIndex, buffer, pos);
log(context, " [0x%08x] call_line %d", pos, callLine);
pos = writeAttrData4(callLine, buffer, pos);
return pos;
}
private int writeAbstractInlineMethods(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) {
EconomicSet inlinedMethods = collectInlinedMethods(context, classEntry, p);
int pos = p;
for (MethodEntry methodEntry : inlinedMethods) {
// n.b. class entry used to index the method belongs to the inlining method
// not the inlined method
setAbstractInlineMethodIndex(classEntry, methodEntry, pos);
pos = writeAbstractInlineMethod(context, classEntry, methodEntry, buffer, pos);
}
return pos;
}
private EconomicSet collectInlinedMethods(DebugContext context, ClassEntry classEntry, int p) {
final EconomicSet methods = EconomicSet.create();
classEntry.compiledEntries().forEach(compiledEntry -> addInlinedMethods(context, compiledEntry, compiledEntry.getPrimary(), methods, p));
return methods;
}
private void addInlinedMethods(DebugContext context, CompiledMethodEntry compiledEntry, Range primary, EconomicSet hashSet, int p) {
if (primary.isLeaf()) {
return;
}
verboseLog(context, " [0x%08x] collect abstract inlined methods %s", p, primary.getFullMethodName());
Iterator iterator = compiledEntry.topDownRangeIterator();
while (iterator.hasNext()) {
SubRange subrange = iterator.next();
if (subrange.isLeaf()) {
// we only generate abstract inline methods for non-leaf entries
continue;
}
// the subrange covers an inline call and references the caller method entry. its
// child ranges all reference the same inlined called method. leaf children cover code
// for
// that inlined method. non-leaf children cover code for recursively inlined methods.
// identify the inlined method by looking at the first callee
Range callee = subrange.getFirstCallee();
MethodEntry methodEntry = callee.getMethodEntry();
if (hashSet.add(methodEntry)) {
verboseLog(context, " [0x%08x] add abstract inlined method %s", p, methodEntry.getSymbolName());
}
}
}
private int writeAbstractInlineMethod(DebugContext context, ClassEntry classEntry, MethodEntry method, byte[] buffer, int p) {
int pos = p;
log(context, " [0x%08x] abstract inline method %s::%s", pos, classEntry.getTypeName(), method.methodName());
AbbrevCode abbrevCode = AbbrevCode.ABSTRACT_INLINE_METHOD;
log(context, " [0x%08x] <1> Abbrev Number %d", pos, abbrevCode.ordinal());
pos = writeAbbrevCode(abbrevCode, buffer, pos);
log(context, " [0x%08x] inline 0x%x", pos, DwarfInline.DW_INL_inlined.value());
pos = writeAttrInline(DwarfInline.DW_INL_inlined, buffer, pos);
/*
* Should pass true only if method is non-private.
*/
log(context, " [0x%08x] external true", pos);
pos = writeFlag(DwarfFlag.DW_FLAG_true, buffer, pos);
int methodSpecOffset = getMethodDeclarationIndex(method);
log(context, " [0x%08x] specification 0x%x", pos, methodSpecOffset);
pos = writeInfoSectionOffset(methodSpecOffset, buffer, pos);
/*
* If the inline method exists in a different CU then write locals and params otherwise we
* can just reuse the locals and params in the declaration
*/
if (classEntry != method.ownerType()) {
FileEntry fileEntry = method.getFileEntry();
if (fileEntry == null) {
fileEntry = classEntry.getFileEntry();
}
assert fileEntry != null;
int fileIdx = classEntry.getFileIdx(fileEntry);
int level = 3;
// n.b. class entry used to index the params belongs to the inlining method
// not the inlined method
pos = writeMethodParameterDeclarations(context, classEntry, method, fileIdx, level, buffer, pos);
pos = writeMethodLocalDeclarations(context, classEntry, method, fileIdx, level, buffer, pos);
}
/*
* Write a terminating null attribute.
*/
return writeAttrNull(buffer, pos);
}
private int writeAttrRef4(int reference, byte[] buffer, int p) {
// make sure we have actually started writing a CU
assert cuStart >= 0;
// writes a CU-relative offset
return writeAttrData4(reference - cuStart, buffer, p);
}
private int writeCUHeader(byte[] buffer, int p) {
int pos = p;
/* CU length. */
pos = writeInt(0, buffer, pos);
/* DWARF version. */
pos = writeDwarfVersion(DwarfVersion.DW_VERSION_4, buffer, pos);
/* Abbrev offset. */
pos = writeAbbrevSectionOffset(0, buffer, pos);
/* Address size. */
return writeByte((byte) 8, buffer, pos);
}
@SuppressWarnings("unused")
public int writeAttrString(String value, byte[] buffer, int p) {
int pos = p;
return writeUTF8StringBytes(value, buffer, pos);
}
public int writeAttrLanguage(DwarfLanguage language, byte[] buffer, int p) {
int pos = p;
return writeByte(language.value(), buffer, pos);
}
public int writeAttrEncoding(DwarfEncoding encoding, byte[] buffer, int p) {
return writeByte(encoding.value(), buffer, p);
}
public int writeAttrInline(DwarfInline inline, byte[] buffer, int p) {
return writeByte(inline.value(), buffer, p);
}
public int writeAttrAccessibility(int modifiers, byte[] buffer, int p) {
DwarfAccess access;
if (Modifier.isPublic(modifiers)) {
access = DwarfAccess.DW_ACCESS_public;
} else if (Modifier.isProtected(modifiers)) {
access = DwarfAccess.DW_ACCESS_protected;
} else if (Modifier.isPrivate(modifiers)) {
access = DwarfAccess.DW_ACCESS_private;
} else {
/* Actually package private -- make it public for now. */
access = DwarfAccess.DW_ACCESS_public;
}
return writeByte(access.value(), buffer, p);
}
public int writeIndirectOopConversionExpression(boolean isHub, byte[] buffer, int p) {
int pos = p;
/*
* For an explanation of the conversion rules @see com.oracle.svm.core.heap.ReferenceAccess
*
* n.b.
*
* The setting for option -H:+/-SpawnIsolates is determined by useHeapBase == true/false.
*
*/
boolean useHeapBase = dwarfSections.useHeapBase();
int oopCompressShift = dwarfSections.oopCompressShift();
int oopTagsShift = dwarfSections.oopTagsShift();
int oopAlignShift = dwarfSections.oopAlignShift();
/* we may be able to use a mask or a right shift then a left shift or just a left shift */
int mask = 0;
int rightShift = 0;
int leftShift = 0;
int exprSize = 0;
/*
* First we compute the size of the locexpr and decide how to do any required bit-twiddling
*/
if (!useHeapBase) {
/* We must be compressing for a hub otherwise this call would not be needed. */
assert isHub == true;
mask = dwarfSections.oopTagsMask();
assert mask != 0;
/*-
* We don't need to care about zero oops just mask off the tag bits.
*
* required expression is
*
* .... push object address .. (1 byte) ..... [tagged oop]
* .... push mask ............ (1 byte) ..... [tagged oop, mask]
* .... NOT .................. (1 byte) ..... [tagged oop, ~mask]
* .... AND .................. (1 byte) ..... [raw oop]
*/
exprSize += 4;
} else {
/*-
* required expression will be one of these paths
*
* .... push object address .. (1 byte) ..... [offset]
* .... duplicate object base (1 byte) ..... [offset, offset]
* .... push 0 ............... (1 byte) ..... [offset, offset, 0]
* .... eq ................... (1 byte) ..... [offset]
* .... brtrue end ........... (3 bytes) .... [offset == oop == 0 if taken]
* IF mask != 0
* .... push mask ............ (1 byte) ..... [offset, mask]
* .... NOT .................. (1 byte) ..... [offset, ~mask]
* .... AND .................. (1 byte) ..... [offset]
* ELSE
* IF rightShift != 0
* .... push rightShift ...... (1 byte) ..... [offset, right shift]
* .... LSHR ................. (1 byte) ..... [offset]
* END IF
* IF leftShift != 0
* .... push leftShift ....... (1 byte) ..... [offset, left shift]
* .... LSHL ................. (1 byte) ..... [offset]
* END IF
* END IF
* .... push rheap+0 ......... (2 bytes) .... [offset, rheap]
* .... ADD .................. (1 byte) ..... [oop]
* end: ...................................... [oop]
*
*/
/* Count all bytes in common path */
exprSize += 10;
if (isHub) {
if (oopCompressShift == 0) {
/* We need to use oopAlignment for the shift. */
oopCompressShift = oopAlignShift;
}
if (oopCompressShift == oopTagsShift) {
/* We can use a mask to remove the bits. */
mask = dwarfSections.oopTagsMask();
exprSize += 3;
} else {
/* We need one or two shifts to remove the bits. */
if (oopTagsShift != 0) {
rightShift = oopTagsShift;
exprSize += 2;
}
leftShift = oopCompressShift;
exprSize += 2;
}
} else {
/* No flags to deal with, so we need either an uncompress or nothing. */
if (oopCompressShift != 0) {
leftShift = oopCompressShift;
exprSize += 2;
}
}
}
/* Write size followed by the expression and check the size comes out correct. */
pos = writeULEB(exprSize, buffer, pos);
int exprStart = pos;
if (!useHeapBase) {
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_push_object_address, buffer, pos);
pos = writeExprOpcodeLiteral(mask, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_not, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_and, buffer, pos);
} else {
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_push_object_address, buffer, pos);
/* skip to end if oop is null */
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_dup, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_lit0, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_eq, buffer, pos);
int skipStart = pos + 3; /* offset excludes BR op + 2 operand bytes */
short offsetToEnd = (short) (exprSize - (skipStart - exprStart));
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_bra, buffer, pos);
pos = writeShort(offsetToEnd, buffer, pos);
/* insert mask or shifts as necessary */
if (mask != 0) {
pos = writeExprOpcodeLiteral(mask, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_not, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_and, buffer, pos);
} else {
if (rightShift != 0) {
pos = writeExprOpcodeLiteral(rightShift, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_shr, buffer, pos);
}
if (leftShift != 0) {
pos = writeExprOpcodeLiteral(leftShift, buffer, pos);
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_shl, buffer, pos);
}
}
/* add the resulting offset to the heapbase register */
pos = writeExprOpcodeBReg(dwarfSections.getHeapbaseRegister(), buffer, pos);
pos = writeSLEB(0, buffer, pos); /* 1 byte. */
pos = writeExprOpcode(DwarfExpressionOpcode.DW_OP_plus, buffer, pos);
assert pos == skipStart + offsetToEnd;
/* make sure we added up correctly */
assert pos == exprStart + exprSize;
}
return pos;
}
}