From 393b17be7d6c24c21cc7bff4e0ad04cd20472dba Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:11:44 +0000 Subject: [PATCH 001/130] define interfaces used to communicate debug info to object file and provide API method to install it --- .../src/com/oracle/objectfile/ObjectFile.java | 7 ++ .../debuginfo/DebugInfoProvider.java | 68 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index a574faa9a9aa..b6564b8db39e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -45,6 +45,7 @@ import java.util.TreeSet; import java.util.stream.StreamSupport; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.elf.ELFObjectFile; import com.oracle.objectfile.macho.MachOObjectFile; import com.oracle.objectfile.pecoff.PECoffObjectFile; @@ -1079,6 +1080,12 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // flag compatibility } + // support for consuming debug info + + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + // do nothing by default + } + protected static Iterable allDecisions(final Map decisions) { return () -> StreamSupport.stream(decisions.values().spliterator(), false) .flatMap(layoutDecisionMap -> StreamSupport.stream(layoutDecisionMap.spliterator(), false)).iterator(); 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 new file mode 100644 index 000000000000..8d9c097a60c6 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -0,0 +1,68 @@ +package com.oracle.objectfile.debuginfo; +import java.util.List; + +// class defining interfaces used to allow a native image +// to communicate details of types, code and data to +// the underlying object file so that the object file +// can insert appropriate debug info +public interface DebugInfoProvider { + // access details of a specific type + interface DebugTypeInfo { + } + + // access details of a specific compiled method + interface DebugCodeInfo { + String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); + DebugLineInfoProvider lineInfoProvider(); + String paramNames(); + String returnTypeName(); + int getFrameSize(); + List getFrameSizeChanges(); + } + + // access details of a specific heap object + interface DebugDataInfo { + } + + // access details of a specific outer or inlined method at a given line number + interface DebugLineInfo { + String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); + } + + interface DebugFrameSizeChange + { + enum Type {EXTEND, CONTRACT}; + int getOffset(); + DebugFrameSizeChange.Type getType(); + } + + // convenience interface defining iterator type + interface DebugTypeInfoProvider extends Iterable { + } + + // convenience interface defining iterator type + interface DebugCodeInfoProvider extends Iterable { + } + + // convenience interface defining iterator type + interface DebugLineInfoProvider extends Iterable{ + } + + // convenience interface defining iterator type + interface DebugDataInfoProvider extends Iterable { + } + + DebugTypeInfoProvider typeInfoProvider(); + DebugCodeInfoProvider codeInfoProvider(); + DebugDataInfoProvider dataInfoProvider(); +} From cab2bc9c198b7d8642ae32a34db8e62c52f7b47b Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:15:39 +0000 Subject: [PATCH 002/130] implement generation of basic DWARF sections in ELF object files --- .../oracle/objectfile/elf/ELFObjectFile.java | 38 + .../objectfile/elf/dwarf/ClassEntry.java | 159 ++ .../oracle/objectfile/elf/dwarf/DirEntry.java | 28 + .../objectfile/elf/dwarf/DwarfSections.java | 2267 +++++++++++++++++ .../objectfile/elf/dwarf/FileEntry.java | 28 + .../objectfile/elf/dwarf/PrimaryEntry.java | 106 + .../oracle/objectfile/elf/dwarf/Range.java | 135 + .../objectfile/elf/dwarf/StringEntry.java | 51 + .../objectfile/elf/dwarf/StringTable.java | 48 + 9 files changed, 2860 insertions(+) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index a63057f7dc85..b2ec0e5fa7d6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -42,6 +42,8 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.StringTable; import com.oracle.objectfile.SymbolTable; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.elf.dwarf.DwarfSections; import com.oracle.objectfile.io.AssemblyBuffer; import com.oracle.objectfile.io.OutputAssembler; @@ -1155,4 +1157,40 @@ public SymbolTable getSymbolTable() { protected int getMinimumFileSize() { return 0; } + + @Override + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + DwarfSections dwarfSections = new DwarfSections(getMachine()); + // we need an implementation for each section + DwarfSections.DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); + DwarfSections.DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); + DwarfSections.DwarfFrameSectionImpl frameSectionImpl = dwarfSections.getFrameSectionImpl(); + DwarfSections.DwarfInfoSectionImpl elfInfoSectionImpl = dwarfSections.getInfoSectionImpl(); + DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); + DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); + // now we can create the section elements with empty content + ELFSection strSection = (ELFSection)newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + ELFSection abbrevSection = (ELFSection)newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + ELFSection locSection= (ELFSection)newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + ELFSection infoSection = (ELFSection)newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + ELFSection aRangesSection = (ELFSection)newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + ELFSection debugSection = (ELFSection)newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + // the byte[] for each implementation's content are created and + // written under getOrDecideContent. doing that ensures that all + // dependent sections are filled in and then sized according to the + // declared dependencies. however, if we leave it at that then + // associated reloc sections only get created when the first reloc + // is inserted during content write that's too late for them to have + // layout constraints included in the layout decision set and causes + // an NPE during reloc section write. so we need to create the relevant + // reloc sections here in advance + elfStrSectionImpl.getOrCreateRelocationElement(false); + elfAbbrevSectionImpl.getOrCreateRelocationElement(false); + frameSectionImpl.getOrCreateRelocationElement(false); + elfInfoSectionImpl.getOrCreateRelocationElement(false); + elfARangesSectionImpl.getOrCreateRelocationElement(false); + elfLineSectionImpl.getOrCreateRelocationElement(false); + // ok now we can populate the implementations + dwarfSections.installDebugInfo(debugInfoProvider); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java new file mode 100644 index 000000000000..f70b5cd387d8 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -0,0 +1,159 @@ +package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ClassEntry + { + // the name of the associated class + private String className; + // the associated file + FileEntry fileEntry; + // a list recording details of all primary ranges included in + // this class sorted by ascending address range + private LinkedList primaryEntries; + // an index identifying primary ranges which have already been encountered + private Map primaryIndex; + // an index of all primary and secondary files referenced from this class's CU + private Map localFilesIndex; + // a list of the same files + private LinkedList localFiles; + // an index of all primary and secondary dirs referenced from this class's CU + private HashMap localDirsIndex; + // a list of the same dirs + private LinkedList localDirs; + // index of debug_info section compilation unit for this class + private int cuIndex; + // index into debug_line section for associated CU + private int lineIndex; + // size of line number info prologue region for associated CU + private int linePrologueSize; + // total size of line number info region for associated CU + private int totalSize; + + public ClassEntry(String className, FileEntry fileEntry) + { + this.className = className; + this.fileEntry = fileEntry; + this.primaryEntries = new LinkedList<>(); + this.primaryIndex = new HashMap<>(); + this.localFiles = new LinkedList<>(); + this.localFilesIndex = new HashMap<>(); + this.localDirs = new LinkedList<>(); + this.localDirsIndex = new HashMap<>(); + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.dirEntry; + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + this.cuIndex = -1; + this.lineIndex = -1; + this.linePrologueSize = -1; + this.totalSize = -1; + } + + PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) + { + if(primaryIndex.get(primary) == null) { + PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); + primaryEntries.add(primaryEntry); + primaryIndex.put(primary, primaryEntry); + return primaryEntry; + } + return null; + } + void addSubRange(Range subrange, FileEntry subFileEntry) { + Range primary = subrange.getPrimary(); + // the subrange should belong to a primary range + assert primary != null; + PrimaryEntry primaryEntry = primaryIndex.get(primary); + // we should already have seen the primary range + assert primaryEntry != null; + assert primaryEntry.getClassEntry() == this; + primaryEntry.addSubRange(subrange, subFileEntry); + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.dirEntry; + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + } + public int localDirsIdx(DirEntry dirEntry) { + if (dirEntry != null) { + return localDirsIndex.get(dirEntry); + } else { + return 0; + } + } + + public int localFilesIdx(FileEntry fileEntry) { + return localFilesIndex.get(fileEntry); + } + + String getFileName() + { + return fileEntry.getFileName(); + } + + String getDirName() { + return fileEntry.getDirName(); + } + + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + return lineIndex; + } + void setLineIndex(int lineIndex) { + this.lineIndex = lineIndex; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + public FileEntry getFileEntry() { + return fileEntry; + } + public String getClassName() { + return className; + } + public LinkedList getPrimaryEntries() { + return primaryEntries; + } + public Object primaryIndexFor(Range primaryRange) { + return primaryIndex.get(primaryRange); + } + public LinkedList getLocalDirs() + { + return localDirs; + } + public LinkedList getLocalFiles() + { + return localFiles; + } + } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java new file mode 100644 index 000000000000..45ad9a44b088 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -0,0 +1,28 @@ +package com.oracle.objectfile.elf.dwarf; + +// files may be located in a source directory associated +// with a well known substratevm or compiler root package +// in that case the the file's directory path will be something +// like "foo.bar.baz/src/foo/bar/baz/mumble/grumble/bletch" +// i.e. the root package and "src" will be inserted as a prefix +// before the dirs derived from the actual package +// files whose package does not match a well-known root package +// will be listed using the dirs derived from the package +// i.e. simply "foo/bar/baz/mumble/grumble/bletch" + +public class DirEntry +{ + private String path; + + // create an entry for a root package path + // or a user path not under a root package + public DirEntry(String path) { + this.path = path; + } + + public String getPath() + { + return path; + } +} + diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java new file mode 100644 index 000000000000..8ba6c884aca9 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -0,0 +1,2267 @@ +package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; +import com.oracle.objectfile.ObjectFile.Element; +import com.oracle.objectfile.elf.ELFMachine; +import com.oracle.objectfile.elf.ELFObjectFile.ELFSection; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DwarfSections +{ + // names of the different sections we create or reference + // in reverse dependency order + public static final String TEXT_SECTION_NAME = ".text"; + public static final String DW_STR_SECTION_NAME = ".debug_str"; + public static final String DW_LINE_SECTION_NAME = ".debug_line"; + public static final String DW_FRAME_SECTION_NAME = ".debug_frame"; + public static final String DW_ABBREV_SECTION_NAME = ".debug_abbrev"; + public static final String DW_INFO_SECTION_NAME = ".debug_info"; + public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; + + // dwarf version 2 is all we need for debug info + private static final short DW_VERSION_2 = 2; + + // define all the abbrev section codes we need for our DIEs + private static final int DW_ABBREV_CODE_null = 0; + private static final int DW_ABBREV_CODE_compile_unit = 1; + private static final int DW_ABBREV_CODE_subprogram = 2; + + // define all the Dwarf tags we need for our DIEs + private static final int DW_TAG_compile_unit = 0x11; + private static final int DW_TAG_subprogram = 0x2e; + // define all the Dwarf attributes we need for our DIEs + private static final int DW_AT_null = 0x0; + private static final int DW_AT_name = 0x3; + private static final int DW_AT_comp_dir = 0x1b; + private static final int DW_AT_stmt_list = 0x10; + private static final int DW_AT_low_pc = 0x11; + private static final int DW_AT_hi_pc = 0x12; + private static final int DW_AT_language = 0x13; + private static final int DW_AT_external = 0x3f; + // private static final int DW_AT_return_addr = 0x2a; + private static final int DW_AT_frame_base = 0x40; + // define all the Dwarf attribute forms we need for our DIEs + private static final int DW_FORM_null = 0x0; + private static final int DW_FORM_string = 0x8; + private static final int DW_FORM_strp = 0xe; // not currently used + private static final int DW_FORM_addr = 0x1; + private static final int DW_FORM_data1 = 0x0b; // use flag instead + private static final int DW_FORM_data4 = 0x6; + private static final int DW_FORM_data8 = 0x7; + private static final int DW_FORM_block1 = 0x0a; + private static final int DW_FORM_flag = 0xc; + + // define specific attribute values for given attribute or form types + // DIE header has_children attribute values + private static final byte DW_CHILDREN_no = 0; + private static final byte DW_CHILDREN_yes = 1; + // DW_FORM_flag attribute values + private static final byte DW_FLAG_false = 0; + private static final byte DW_FLAG_true = 1; + // value for DW_AT_language attribute with form DATA1 + private final static byte DW_LANG_Java = 0xb; + // access not needed until we make functions members + // DW_AT_Accessibility attribute values + // private static final byte DW_ACCESS_public = 1; + // private static final byte DW_ACCESS_protected = 2; + // private static final byte DW_ACCESS_private = 3; + + + // not yet needed + // private static final int DW_AT_type = 0; // only present for non-void functions + // private static final int DW_AT_accessibility = 0; + + // CIE and FDE entries + + public final static int DW_CFA_CIE_id = -1; + public final static int DW_CFA_FDE_id = 0; + + public final static byte DW_CFA_CIE_version = 1; + + // values for high 2 bits + public final static byte DW_CFA_advance_loc = 0x1; + public final static byte DW_CFA_offset = 0x2; + public final static byte DW_CFA_restore = 0x3; + + // values for low 6 bits + public final static byte DW_CFA_nop = 0x0; + public final static byte DW_CFA_set_loc1 = 0x1; + public final static byte DW_CFA_advance_loc1 = 0x2; + public final static byte DW_CFA_advance_loc2 = 0x3; + public final static byte DW_CFA_advance_loc4 = 0x4; + public final static byte DW_CFA_offset_extended = 0x5; + public final static byte DW_CFA_restore_extended = 0x6; + public final static byte DW_CFA_undefined = 0x7; + public final static byte DW_CFA_same_value = 0x8; + public final static byte DW_CFA_register = 0x9; + public final static byte DW_CFA_def_cfa = 0xc; + public final static byte DW_CFA_def_cfa_register = 0xd; + public final static byte DW_CFA_def_cfa_offset = 0xe; + + private ELFMachine elfMachine; + private DwarfStrSectionImpl dwarfStrSection; + private DwarfAbbrevSectionImpl dwarfAbbrevSection; + private DwarfInfoSectionImpl dwarfInfoSection; + private DwarfARangesSectionImpl dwarfARangesSection; + private DwarfLineSectionImpl dwarfLineSection; + private DwarfFrameSectionImpl dwarfFameSection; + + public DwarfSections(ELFMachine elfMachine) { + this.elfMachine = elfMachine; + dwarfStrSection = new DwarfStrSectionImpl(); + dwarfAbbrevSection = new DwarfAbbrevSectionImpl(); + dwarfInfoSection = new DwarfInfoSectionImpl(); + dwarfARangesSection = new DwarfARangesSectionImpl(); + dwarfLineSection = new DwarfLineSectionImpl(); + dwarfFameSection = (elfMachine == ELFMachine.AArch64 + ? new DwarfFrameSectionImplAArch64() + : new DwarfFrameSectionImplX86_64()); + } + + public DwarfStrSectionImpl getStrSectionImpl() { + return dwarfStrSection; + } + + public DwarfAbbrevSectionImpl getAbbrevSectionImpl() { + return dwarfAbbrevSection; + } + + public DwarfFrameSectionImpl getFrameSectionImpl() { + return dwarfFameSection; + } + + public DwarfInfoSectionImpl getInfoSectionImpl() { + return dwarfInfoSection; + } + + public DwarfARangesSectionImpl getARangesSectionImpl() { + return dwarfARangesSection; + } + + public DwarfLineSectionImpl getLineSectionImpl() { + return dwarfLineSection; + } + + public ELFMachine getElfMachine() { + return elfMachine; + } + + // a scratch buffer used during computation of a section's size + protected final static byte[] scratch = new byte[10]; + + // table listing all known strings + private StringTable stringTable = new StringTable(); + + // list detailing all dirs in which files are found to reside + // either as part of substrate/compiler or user code + private LinkedList dirs = new LinkedList(); + // index of already seen dirs + private Map dirsIndex = new HashMap<>(); + + // The obvious traversal structure for debug records is + // 1) by top level compiled method (primary Range) ordered by ascending address + // 2) by inlined method (sub range) within top level method ordered by ascending address + // this ensures that all debug records are generated in increasing address order + + // a list recording details of all primary ranges included in + // this file sorted by ascending address range + private LinkedList primaryEntries = new LinkedList(); + + // An alternative traversal option is + // 1) by top level class (String id) + // 2) by top level compiled method (primary Range) within a class ordered by ascending address + // 3) by inlined method (sub range) within top level method ordered by ascending address + // + // this relies on the (current) fact that methods of a given class always appear + // in a single continuous address range with no intervening code from other methods + // or data values. this means we can treat each class as a compilation unit, allowing + // data common to all methods of the class to be shared. + // + // Unfortunately, files cannot be treated as the compilation unit. A file F may contain + // multiple classes, say C1 and C2. There is no guarantee that methods for some other + // class C' in file F' will not be compiled into the address space interleaved between + // methods of C1 and C2. That is a shame because generating debug info records one file at a + // time would allow more sharing e.g. enabling all classes in a file to share a single copy + // of the file and dir tables. + + // list of class entries detailing class info for primary ranges + private LinkedList primaryClasses = new LinkedList(); + // index of already seen classes + private Map primaryClassesIndex = new HashMap<>(); + + // List of files which contain primary ranges + private LinkedList primaryFiles = new LinkedList(); + // List of files which contain primary or secondary ranges + private LinkedList files = new LinkedList(); + // index of already seen files + private Map filesIndex = new HashMap<>(); + + private static String[] root_pkgs = { + // substrate root packages + "com.oracle.graal.pointsto", + "com.oracle.objectfile", + "com.oracle.svm.agent", + "com.oracle.svm.configure", + "com.oracle.svm.core", + "com.oracle.svm.core.genscavenge", + "com.oracle.svm.core.graal", + "com.oracle.svm.core.graal.aarch64", + "com.oracle.svm.core.graal.amd64", + "com.oracle.svm.core.graal.llvm", + "com.oracle.svm.core.jdk11", + "com.oracle.svm.core.jdk8", + "com.oracle.svm.core.posix", + "com.oracle.svm.core.posix.jdk11", + "com.oracle.svm.core.windows", + "com.oracle.svm.driver", + "com.oracle.svm.graal", + "com.oracle.svm.graal.hotspot.libgraal", + "com.oracle.svm.hosted", + "com.oracle.svm.jline", + "com.oracle.svm.jni", + "com.oracle.svm.junit", + "com.oracle.svm.libffi", + "com.oracle.svm.native.jvm.posix", + "com.oracle.svm.native.jvm.windows", + "com.oracle.svm.native.libchelper", + "com.oracle.svm.native.strictmath", + "com.oracle.svm.polyglot", + "com.oracle.svm.reflect", + "com.oracle.svm.test", + "com.oracle.svm.test.jdk11", + "com.oracle.svm.thirdparty", + "com.oracle.svm.truffle", + "com.oracle.svm.truffle.nfi", + "com.oracle.svm.truffle.nfi.posix", + "com.oracle.svm.truffle.nfi.windows", + "com.oracle.svm.tutorial", + "com.oracle.svm.util", + "com.oracle.svm.util.jdk11", + "org.graalvm.polyglot.nativeapi", + // compiler root packages + "jdk.tools.jaotc", + "jdk.tools.jaotc.binformat", + "jdk.tools.jaotc", + "org.graalvm.compiler.api.directives", + "org.graalvm.compiler.api.replacements", + "org.graalvm.compiler.api.runtime", + "org.graalvm.compiler.asm", + "org.graalvm.compiler.asm.aarch64", + "org.graalvm.compiler.asm.amd64", + "org.graalvm.compiler.asm.sparc", + "org.graalvm.compiler.bytecode", + "org.graalvm.compiler.code", + "org.graalvm.compiler.core", + "org.graalvm.compiler.core.aarch64", + "org.graalvm.compiler.core.amd64", + "org.graalvm.compiler.core.common", + "org.graalvm.compiler.core.llvm", + "org.graalvm.compiler.core.match.processor", + "org.graalvm.compiler.core.sparc", + "org.graalvm.compiler.debug", + "org.graalvm.compiler.graph", + "org.graalvm.compiler.hotspot", + "org.graalvm.compiler.hotspot.aarch64", + "org.graalvm.compiler.hotspot.amd64", + "org.graalvm.compiler.hotspot.jdk8", + "org.graalvm.compiler.hotspot.management", + "org.graalvm.compiler.hotspot.sparc", + "org.graalvm.compiler.java", + "org.graalvm.compiler.jtt", + "org.graalvm.compiler.lir", + "org.graalvm.compiler.lir.aarch64", + "org.graalvm.compiler.lir.amd64", + "org.graalvm.compiler.lir.jtt", + "org.graalvm.compiler.lir.sparc", + "org.graalvm.compiler.loop", + "org.graalvm.compiler.loop.phases", + "org.graalvm.compiler.microbenchmarks", + "org.graalvm.compiler.nodeinfo", + "org.graalvm.compiler.nodeinfo.processor", + "org.graalvm.compiler.nodes", + "org.graalvm.compiler.options", + "org.graalvm.compiler.options.processor", + "org.graalvm.compiler.phases", + "org.graalvm.compiler.phases.common", + "org.graalvm.compiler.printer", + "org.graalvm.compiler.processor", + "org.graalvm.compiler.replacements", + "org.graalvm.compiler.replacements.aarch64", + "org.graalvm.compiler.replacements.amd64", + "org.graalvm.compiler.replacements.processor", + "org.graalvm.compiler.replacements.sparc", + "org.graalvm.compiler.runtime", + "org.graalvm.compiler.serviceprovider", + "org.graalvm.compiler.serviceprovider.jdk8", + "org.graalvm.compiler.serviceprovider.processor", + "org.graalvm.compiler.truffle.common", + "org.graalvm.compiler.truffle.common.hotspot", + "org.graalvm.compiler.truffle.common.hotspot.libgraal", + "org.graalvm.compiler.truffle.common.processor", + "org.graalvm.compiler.truffle.compiler", + "org.graalvm.compiler.truffle.compiler.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot", + "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", + "org.graalvm.compiler.truffle.compiler.hotspot.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", + "org.graalvm.compiler.truffle.compiler.hotspot.sparc", + "org.graalvm.compiler.truffle.runtime", + "org.graalvm.compiler.truffle.runtime.hotspot", + "org.graalvm.compiler.truffle.runtime.hotspot.java", + "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", + "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", + "org.graalvm.compiler.truffle.runtime.serviceprovider", + "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", + "org.graalvm.compiler.virtual", + "org.graalvm.compiler.virtual.bench", + "org.graalvm.compiler.word", + "org.graalvm.graphio", + "org.graalvm.libgraal", + "org.graalvm.libgraal.jdk8", + "org.graalvm.micro.benchmarks", + "org.graalvm.util", + // sdk root packages + "org.graalvm.collections", + "org.graalvm.launcher", + "org.graalvm.options", + "org.graalvm.polyglot", + "org.graalvm.home", + "org.graalvm.nativeimage", + "org.graalvm.polyglot.tck", + "org.graalvm.word", + }; + + public String uniqueString(String string) { + return stringTable.uniqueString(string); + } + + public String uniqueDebugString(String string) { + return stringTable.uniqueDebugString(string); + } + + private int debugStringIndex(String string) { + return stringTable.debugStringIndex(string); + } + + public void installDebugInfo(DebugInfoProvider debugInfoProvider) + { + DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); + for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { + // install types + } + + // ensure we have a null string in the string section + uniqueDebugString(""); + + DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); + for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { + // primary file name and full method name need to be written to the debug_str section + // + String fileName = debugCodeInfo.fileName(); + String className = debugCodeInfo.className(); + String methodName = debugCodeInfo.methodName(); + String paramNames = debugCodeInfo.paramNames(); + String returnTypeName = debugCodeInfo.returnTypeName(); + int lo = debugCodeInfo.addressLo(); + int hi = debugCodeInfo.addressHi(); + int primaryLine = debugCodeInfo.line(); + Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); + // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, returnTypeName, className, methodName, paramNames, fileName); + // create an infoSection entry for the method + addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); + for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { + String fileNameAtLine = debugLineInfo.fileName(); + String classNameAtLine = debugLineInfo.className(); + String methodNameAtLine = debugLineInfo.methodName(); + int loAtLine = lo + debugLineInfo.addressLo(); + int hiAtLine = lo + debugLineInfo.addressHi(); + int line = debugLineInfo.line(); + // record all subranges even if they have no line or file so we at least get a symbol for them + Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); + addSubRange(primaryRange, subRange); + } + } + DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + for (DebugDataInfo debugDataInfo : dataInfoProvider) { + // install details of heap elements + String name = debugDataInfo.toString(); + } + } + + public ClassEntry ensureClassEntry(Range range) { + String className = range.getClassName(); + // see if we already have an entry + ClassEntry classEntry = primaryClassesIndex.get(className); + if (classEntry == null) { + // create and index the entry associating it with the right file + FileEntry fileEntry = ensureFileEntry(range); + classEntry = new ClassEntry(className, fileEntry); + primaryClasses.add(classEntry); + primaryClassesIndex.put(className, classEntry); + } + assert classEntry.getClassName().equals(className); + return classEntry; + } + + public FileEntry ensureFileEntry(Range range) { + String fileName = range.getFileName(); + // ensure we have an entry + FileEntry fileEntry = filesIndex.get(fileName); + if(fileEntry == null) { + DirEntry dirEntry = ensureDirEntry(fileName); + String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); + fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), + stringTable.uniqueString(baseName), + dirEntry); + files.add(fileEntry); + filesIndex.put(fileName, fileEntry); + // if this is a primary entry then add it to the primary list + if(range.isPrimary()) { + primaryFiles.add(fileEntry); + } else { + Range primaryRange = range.getPrimary(); + FileEntry primaryEntry = filesIndex.get(primaryRange.getFileName()); + assert primaryEntry != null; + } + } + return fileEntry; + } + + public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) + { + assert primaryRange.isPrimary(); + ClassEntry classEntry = ensureClassEntry(primaryRange); + PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); + if (entry != null) { + // track the entry for this range in address order + primaryEntries.add(entry); + } + } + + public void addSubRange(Range primaryRange, Range subrange) + { + assert primaryRange.isPrimary(); + assert !subrange.isPrimary(); + String className = primaryRange.getClassName(); + ClassEntry classEntry = primaryClassesIndex.get(className); + FileEntry subrangeEntry = ensureFileEntry(subrange); + // the primary range should already have been seen + // and associated with a primary class entry + assert classEntry.primaryIndexFor(primaryRange) != null; + classEntry.addSubRange(subrange, subrangeEntry); + } + + private DirEntry ensureDirEntry(String file) + { + int pathLength = file.lastIndexOf('/'); + if(pathLength < 0) { + // no path/package means use dir entry 0 + return null; + } + String filePath = file.substring(0, pathLength); + DirEntry dirEntry = dirsIndex.get(filePath); + if (dirEntry == null) { + dirEntry = new DirEntry(stringTable.uniqueString(filePath)); + dirsIndex.put(filePath, dirEntry); + dirs.add(dirEntry); + } + return dirEntry; + } + + // shared implementation methods to manage content creation + public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { + public boolean debug = false; + public long debug_text_base = 0; + public long debug_address = 0; + public int debug_base = 0; + + public DwarfSectionImpl() { + } + + public abstract void createContent(); + public abstract void writeContent(); + public void checkDebug(int pos) { + // if the env var relevant to this element + // type is set then switch on debugging + String name = getSectionName(); + String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); + if (System.getenv(envVarName) != null) { + debug = true; + debug_base = pos; + debug_address = debug_text_base; + } + } + + protected void debug(String format, Object ... args) + { + if(debug) { + System.out.format(format, args); + } + } + + // base level put methods that assume a non-null buffer + public int putByte(byte b, byte[] buffer, int pos) { + buffer[pos++] = b; + return pos; + } + public int putShort(short s, byte[] buffer, int pos) { + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + return pos; + } + public int putInt(int i, byte[] buffer, int pos) { + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + return pos; + } + public int putLong(long l, byte[] buffer, int pos) { + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + return pos; + } + public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { + // mark address so it is relocated relative to the start of the text segment + markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); + pos = putLong(0, buffer, pos); + return pos; + } + public int putULEB(long l, byte[] buffer, int pos) { + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >>> 7; + boolean done = (l == 0); + if(!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if(done) { + break; + } + } + return pos; + } + public int putSLEB(long l, byte[] buffer, int pos) { + boolean negative = l < 0; + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >> 7; + boolean bIsSigned = (b & 0x40) != 0; + boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); + if(!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if(done) { + break; + } + } + return pos; + } + public int putAsciiStringBytes(String s, byte[] buffer, int pos) { + return putAsciiStringBytes(s, 0, buffer, pos); + } + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { + for (int l = startChar; l < s.length(); l++) { + char c = s.charAt(l); + if(c > 127) { + throw new RuntimeException("oops : expected ASCII string! " + s); + } + buffer[pos++] = (byte) c; + } + buffer[pos++] = '\0'; + return pos; + } + + // common write methods that check for a null buffer + + public void patchLength(int lengthPos, byte[] buffer, int pos) { + if (buffer != null) { + int length = pos - (lengthPos + 4); + putInt(length, buffer, lengthPos); + } + } + + public int writeAbbrevCode(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeTag(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + public int writeFlag(byte flag, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(flag, scratch, 0); + } else { + return putByte(flag, buffer, pos); + } + } + + public int writeAttr_addr(long address, byte[] buffer, int pos) { + if (buffer == null) { + return pos + 8; + } else { + return putRelocatableCodeOffset(address, buffer, pos); + } + } + + public int writeAttr_data8(long value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putLong(value, scratch, 0); + } else { + return putLong(value, buffer, pos); + } + } + + public int writeAttr_data4(int value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putInt(value, scratch, 0); + } else { + return putInt(value, buffer, pos); + } + } + + public int writeAttr_data1(byte value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(value, scratch, 0); + } else { + return putByte(value, buffer, pos); + } + } + + public int writeAttr_null(byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(0, scratch, 0); + } else { + return putSLEB(0, buffer, pos); + } + } + + public abstract String targetSectionName(); + public abstract LayoutDecision.Kind[] targetSectionKinds(); + + public abstract String getSectionName(); + + /* + @Override + public int getOrDecideSize(Map alreadyDecided, int sizeHint) { + return super.getOrDecideSize(alreadyDecided, sizeHint); + } + */ + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + // ensure content byte[] has been created before calling super method + createContent(); + + // ensure content byte[] has been written before calling super method + writeContent(); + + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public Set getDependencies(Map decisions) + { + Set deps = super.getDependencies(decisions); + String targetName = targetSectionName(); + ELFSection targetSection = (ELFSection)getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + // make our content depend on the size and content of the target + for (LayoutDecision.Kind targetKind : targetKinds) { + LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + } + // make our size depend on our content + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + + return deps; + } + } + + public class DwarfStrSectionImpl extends DwarfSectionImpl { + public DwarfStrSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_STR_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + for (StringEntry stringEntry : stringTable) { + if (stringEntry.isAddToStrSection()){ + stringEntry.setOffset(pos); + String string = stringEntry.getString(); + pos += string.length() + 1; + } + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + for (StringEntry stringEntry : stringTable) { + if (stringEntry.isAddToStrSection()){ + assert stringEntry.getOffset() == pos; + String string = stringEntry.getString(); + pos = putAsciiStringBytes(string, buffer, pos); + } + } + assert pos == size; + } + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_str section content depends on text section content and offset + public final static String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { + + public DwarfAbbrevSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_ABBREV_SECTION_NAME; + } + + @Override + public void createContent() + { + int pos = 0; + // an abbrev table contains abbrev entries for one or + // more CUs. the table includes a sequence of abbrev + // entries each of which defines a specific DIE layout + // employed to describe some DIE in a CU. a table is + // terminated by a null entry + // + // a null entry has consists of just a 0 abbrev code + // LEB128 abbrev_code; // == 0 + // + // non-null entries have the following format + // LEB128 abbrev_code; // unique noncode for this layout != 0 + // 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 DIE + // * // zero or more attributes + // // terminator + // + // An attribute_spec consists of an attribute name and form + // LEB128 attr_name; // 0 for the null attribute name + // LEB128 attr_form; // 0 for the null attribute form + // + // For the moment we only use one abbrev table for all CUs. + // It contains two DIEs, the first to describe the compilation + // unit itself and the second to describe each method within + // that compilation unit. + // + // The DIE layouts are as follows: + // + // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + // DW_AT_language : DW_FORM_data1 + // DW_AT_name : DW_FORM_strp + // DW_AT_low_pc : DW_FORM_address + // DW_AT_hi_pc : DW_FORM_address + // DW_AT_stmt_list : DW_FORM_data4 + // + // abbrev_code == 2, tag == DW_TAG_subprogram, no_children + // DW_AT_name : DW_FORM_strp + // DW_AT_low_pc : DW_FORM_addr + // DW_AT_hi_pc : DW_FORM_addr + // DW_AT_external : DW_FORM_flag + + pos = writeAbbrev1(null, pos); + pos = writeAbbrev2(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + pos = writeAbbrev1(buffer, pos); + pos = writeAbbrev2(buffer, pos); + assert pos == size; + } + + public int writeAttrType(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAttrForm(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAbbrev1(byte[] buffer, int pos) { + // abbrev 1 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + pos = writeTag(DW_TAG_compile_unit, buffer, pos); + pos = writeFlag(DW_CHILDREN_yes, buffer, pos); + pos = writeAttrType(DW_AT_language, buffer, pos); + pos = writeAttrForm(DW_FORM_data1, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_stmt_list, buffer, pos); + pos = writeAttrForm(DW_FORM_data4, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + public int writeAbbrev2(byte[] buffer, int pos) { + // abbrev 2 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + pos = writeTag(DW_TAG_subprogram, buffer, pos); + pos = writeFlag(DW_CHILDREN_no, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_external, buffer, pos); + pos = writeAttrForm(DW_FORM_flag, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_abbrev section content depends on .debug_frame section content and offset + public final static String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { + + public DwarfFrameSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_FRAME_SECTION_NAME; + } + + @Override + public void createContent() + { + int pos = 0; + + // the frame section contains one CIE at offset 0 + // followed by an FIE for each method + pos = writeCIE(null, pos); + pos = writeMethodFrames(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + // there are entries for the prologue region where the + // stack is being built, the method body region(s) where + // the code executes with a fixed size frame and the + // epilogue region(s) where the stack is torn down + pos = writeCIE(buffer, pos); + pos = writeMethodFrames(buffer, pos); + + assert pos == size; + } + + public int writeCIE(byte[] buffer, int pos) { + // we only need a vanilla CIE with default fields + // because we have to have at least one + // the layout is + // + // uint32 : length // length of remaining fields in this CIE + // uint32 : CIE_id // unique id for CIE == 0xffffff + // uint8 : version // == 1 + // uint8[] : augmentation // == "" so always 1 byte + // ULEB : code_alignment_factor // 1 (could use 4 for Aarch64) + // ULEB : data_alignment_factor // -8 + // byte : ret_addr reg id // x86_64 => 16 AArch64 => 32 + // byte[] : initial_instructions // includes pad to 8-byte boundary + if (buffer == null) { + pos += putInt(0, scratch, 0); // don't care about length + pos += putInt(DW_CFA_CIE_id, scratch, 0); + pos += putByte(DW_CFA_CIE_version, scratch, 0); + pos += putAsciiStringBytes("", scratch, 0); + pos += putULEB(1, scratch, 0); + pos += putULEB(-8, scratch, 0); + pos += putByte((byte)getPCIdx(), scratch, 0); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + // no need to write length + return pos; + } else { + int lengthPos = pos; + pos = putInt(0, buffer, pos); + pos = putInt(DW_CFA_CIE_id, buffer, pos); + pos = putByte(DW_CFA_CIE_version, buffer, pos); + pos = putAsciiStringBytes("", buffer, pos); + pos = putULEB(1, buffer, pos); + pos = putSLEB(-8, buffer, pos); + pos = putByte((byte)getPCIdx(), buffer, pos); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + return pos; + } + } + + public int writeMethodFrames(byte[] buffer, int pos) { + for (ClassEntry classEntry : primaryClasses) { + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + long lo = primaryEntry.getPrimary().getLo(); + long hi = primaryEntry.getPrimary().getHi(); + int frameSize = primaryEntry.getFrameSize(); + int currentOffset = 0; + int lengthPos = pos; + pos = writeFDEHeader((int)lo, (int)hi, buffer, pos); + for (DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { + int advance = debugFrameSizeInfo.getOffset() - currentOffset; + currentOffset += advance; + pos = writeAdvanceLoc(advance, buffer, pos); + if (debugFrameSizeInfo.getType() == DebugFrameSizeChange.Type.EXTEND) { + // SP has been extended so rebase CFA using full frame + pos = writeDefCFAOffset(frameSize, buffer, pos); + } else { + // SP has been contracted so rebase CFA using empty frame + pos = writeDefCFAOffset(8, buffer, pos); + } + } + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + } + } + return pos; + } + + public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { + // we only need a vanilla FDE header with default fields + // the layout is + // + // uint32 : length // length of remaining fields in this FDE + // uint32 : CIE_offset // alwasy 0 i.e. identifies our only CIE header + // uint64 : initial_location // i.e. method lo address + // uint64 : address_range // i.e. method hi - lo + // byte[] : instructions // includes pad to 8-byte boundary + + int lengthPos = pos; + if (buffer == null) { + pos += putInt(0, scratch, 0); // dummy length + pos += putInt(0, scratch, 0); // CIE_offset + pos += putLong(lo, scratch, 0); // initial address + return pos + putLong(hi - lo, scratch, 0); // address range + } else { + pos = putInt(0, buffer, pos); // dummy length + pos = putInt(0, buffer, pos); // CIE_offset + pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address + return putLong(hi - lo, buffer, pos); // address range + } + } + + public int writePaddingNops(int alignment, byte[] buffer, int pos) { + assert (alignment & (alignment - 1)) == 0; + while ((pos & (alignment - 1)) != 0) { + if (buffer == null) { + pos++; + } else { + pos = putByte(DW_CFA_nop, buffer, pos); + } + } + return pos; + } + + public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa, scratch, 0); + pos += putSLEB(register, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa, buffer, pos); + pos = putULEB(register, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa_offset, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { + if (offset <= 0x3f) { + return writeAdvanceLoc0((byte) offset, buffer, pos); + } else if(offset <= 0xff) { + return writeAdvanceLoc1((byte) offset, buffer, pos); + } else if(offset <= 0xffff) { + return writeAdvanceLoc2((short) offset, buffer, pos); + } else { + return writeAdvanceLoc4(offset, buffer, pos); + } + } + public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { + byte op = advanceLoc0Op(offset); + if (buffer == null) { + return pos + putByte(op, scratch, 0); + } else { + return putByte(op, buffer, pos); + } + } + public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { + byte op = DW_CFA_advance_loc1; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putByte(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putByte(offset, buffer, pos); + } + } + public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { + byte op = DW_CFA_advance_loc2; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putShort(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putShort(offset, buffer, pos); + } + } + public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { + byte op = DW_CFA_advance_loc4; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putInt(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putInt(offset, buffer, pos); + } + } + public int writeOffset(int register, int offset, byte[] buffer, int pos) { + byte op = offsetOp(register); + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { + if (buffer == null) { + pos += putByte(DW_CFA_register, scratch, 0); + pos += putULEB(savedReg, scratch, 0); + return pos + putULEB(savedToReg, scratch, 0); + } else { + pos = putByte(DW_CFA_register, buffer, pos); + pos = putULEB(savedReg, buffer, pos); + return putULEB(savedToReg, buffer, pos); + } + } + + public abstract int getPCIdx(); + public abstract int getSPIdx(); + public abstract int writeInitialInstructions(byte[] buffer, int pos); + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + // .debug_frame section content depends on .debug_line section content and offset + public final static String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + private byte offsetOp(int register) { + assert (register >> 6) == 0; + return (byte)((DW_CFA_offset << 6) | register); + } + private byte advanceLoc0Op(int offset) { + assert (offset >= 0 && offset <= 0x3f); + return (byte)((DW_CFA_advance_loc << 6) | offset); + } + } + public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl + { + public final static int DW_CFA_RSP_IDX = 7; + public final static int DW_CFA_RIP_IDX = 16; + + public DwarfFrameSectionImplX86_64() { + super(); + } + @Override + public int getPCIdx() { + return DW_CFA_RIP_IDX; + } + @Override + public int getSPIdx() { + return DW_CFA_RSP_IDX; + } + @Override + public int writeInitialInstructions(byte[] buffer, int pos) + { + // rsp points at the word containing the saved rip + // so the frame base (cfa) is at rsp + 8 (why not - ???) + // def_cfa r7 (sp) offset 8 + pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); + // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa (why not -1 ???) + // offset r16 (rip) cfa - 8 + pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); + return pos; + } + } + public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl + { + public final static int DW_CFA_FP_IDX = 29; + public final static int DW_CFA_LR_IDX = 30; + public final static int DW_CFA_SP_IDX = 31; + public final static int DW_CFA_PC_IDX = 32; + + public DwarfFrameSectionImplAArch64() { + super(); + } + @Override + public int getPCIdx(){ + return DW_CFA_PC_IDX; + } + @Override + public int getSPIdx(){ + return DW_CFA_SP_IDX; + } + @Override + public int writeInitialInstructions(byte[] buffer, int pos) + { + // rsp has not been updated + // caller pc is in lr + // register r32 (rpc), r30 (lr) + pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); + return pos; + } + } + + public class DwarfInfoSectionImpl extends DwarfSectionImpl + { + // header section always contains fixed number of bytes + private static final int DW_DIE_HEADER_SIZE = 11; + + public DwarfInfoSectionImpl() + { + super(); + } + + @Override + public String getSectionName() + { + return DW_INFO_SECTION_NAME; + } + + @Override + public void createContent() + { + // we need a single level 0 DIE for each compilation unit (CU) + // Each CU's Level 0 DIE is preceded by a fixed header: + // and terminated by a null DIE + // uint32 length // excluding this length field + // uint16 dwarf_version // always 2 ?? + // uint32 abbrev offset // always 0 ?? + // uint8 address_size // always 8 + // * // sequence of top-level and nested child entries + // // == 0 + // + // a DIE is a recursively defined structure + // it starts with a code for the associated + // abbrev entry followed by a series of attribute + // values as determined by the entry terminated by + // a null value and followed by zero or more child + // DIEs (zero iff has_children == no_children) + // + // LEB128 abbrev_code != 0 // non-zero value indexes tag + attr layout of DIE + // * // value sequence as determined by abbrev entry + // * // sequence of child DIEs (if appropriate) + // // == 0 + // + // note that a null_DIE looks like + // LEB128 abbrev_code == 0 + // i.e. it also looks like a null_value + + byte[] buffer = null; + int pos = 0; + + for (ClassEntry classEntry : primaryClasses) { + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // no need to backpatch length at lengthPos + } + buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_INFO\n", pos); + debug(" [0x%08x] size = 0x%08x\n", pos, size); + for (ClassEntry classEntry : primaryClasses) { + // save the offset of this file's CU so it can + // be used when writing the aranges section + classEntry.setCUIndex(pos); + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + debug(" [0x%08x] Compilation Unit\n", pos, size); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // backpatch length at lengthPos (excluding length field) + patchLength(lengthPos, buffer, pos); + } + assert pos == size; + } + + public int writeCUHeader(byte[] buffer, int pos) { + if (buffer == null) { + pos += putInt(0, scratch, 0); // CU length + pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version + pos += putInt(0, scratch, 0); // abbrev offset + return pos + putByte((byte)8, scratch, 0); // address size + } else { + pos = putInt(0, buffer, pos); // CU length + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version + pos = putInt(0, buffer, pos); // abbrev offset + return putByte((byte)8, buffer, pos); // address size + } + } + public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) + { + LinkedList primaryEntries = classEntry.getPrimaryEntries(); + debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); + pos = writeAttr_data1(DW_LANG_Java, buffer, pos); + debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); + pos = writeAttr_strp(classEntry.getFileName(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, primaryEntries.getFirst().getPrimary().getLo()); + pos = writeAttr_addr(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + debug(" [0x%08x] hi_pc 0x%08x\n", pos, primaryEntries.getLast().getPrimary().getHi()); + pos = writeAttr_addr(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); + debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); + pos = writeAttr_data4(classEntry.getLineIndex(), buffer, pos); + for (PrimaryEntry primary : primaryEntries) { + pos = writePrimary(primary, buffer, pos); + } + // write a terminating null attribute for the the level 2 primaries + return writeAttr_null(buffer, pos); + + } + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) + { + Range primary = primaryEntry.getPrimary(); + debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getClassAndMethodNameWithParams()), primary.getClassAndMethodNameWithParams()); + pos = writeAttr_strp(primary.getClassAndMethodNameWithParams(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); + pos = writeAttr_addr(primary.getLo(), buffer, pos); + debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); + pos = writeAttr_addr(primary.getHi(), buffer, pos); + // need to pass true only if method is public + debug(" [0x%08x] external true\n", pos); + return writeFlag(DW_FLAG_true, buffer, pos); + } + public int writeAttr_strp(String value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putInt(0, scratch, 0); + } else { + int idx = debugStringIndex(value); + return putInt(idx, buffer, pos); + } + } + public int writeAttr_string(String value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + value.length() + 1; + } else { + return putAsciiStringBytes(value, buffer, pos); + } + } + protected void debug(String format, Object... args) { + if (((int) args[0] - debug_base) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + // .debug_info section content depends on abbrev section content and offset + public final static String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public class DwarfARangesSectionImpl extends DwarfSectionImpl { + private static final int DW_AR_HEADER_SIZE = 12; + private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size + + public DwarfARangesSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_ARANGES_SECTION_NAME; + } + + public void createContent() + { + int pos = 0; + // we need an entry for each compilation unit + // + // uint32 length // in bytes (not counting these 4 bytes) + // uint16 dwarf_version // always 2 + // uint32 info_offset // offset of compilation unit on debug_info + // uint8 address_size // always 8 + // uint8 segment_desc_size // ??? + // + // i.e. 12 bytes followed by padding + // aligning up to 2 * address size + // + // uint8 pad[4] + // + // followed by N + 1 times + // + // uint64 lo // lo address of range + // uint64 length // number of bytes in range + // + // where N is the number of ranges belonging to the compilation unit + // and the last range contains two zeroes + + for(ClassEntry classEntry : primaryClasses) { + pos += DW_AR_HEADER_SIZE; + // align to 2 * address size + pos += DW_AR_HEADER_PAD_SIZE; + pos += classEntry.getPrimaryEntries().size() * 2 * 8; + pos += 2 * 8; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) + { + Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debug_text_base = ((Number)valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_ARANGES\n", pos); + for(ClassEntry classEntry : primaryClasses) { + int lastpos = pos; + int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; + int cuIndex = classEntry.getCUIndex(); + LinkedList primaryEntries = classEntry.getPrimaryEntries(); + // add room for each entry into length count + length += primaryEntries.size() * 2 * 8; + length += 2 * 8; + debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); + pos = putInt(length, buffer, pos); + pos = putShort(DW_VERSION_2,buffer, pos); // dwarf version is always 2 + pos = putInt(cuIndex, buffer, pos); + pos = putByte((byte)8, buffer, pos); // address size is always 8 + pos = putByte((byte)0, buffer, pos); // segment size is always 0 + assert (pos - lastpos) == DW_AR_HEADER_SIZE; + // align to 2 * address size + for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { + pos = putByte((byte)0, buffer, pos); + } + debug(" [0x%08x] Address Length Name\n", pos); + for (PrimaryEntry primaryEntry : primaryEntries) { + Range primary = primaryEntry.getPrimary(); + debug(" [0x%08x] %016x %016x %s\n", pos, debug_text_base + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); + pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); + pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); + } + pos = putLong(0, buffer, pos); + pos = putLong(0, buffer, pos); + } + + assert pos == size; + } + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_aranges section content depends on .debug_info section content and offset + public final static String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public class DwarfLineSectionImpl extends DwarfSectionImpl { + // header section always contains fixed number of bytes + private static final int DW_LN_HEADER_SIZE = 27; + // line base is -5 + private static final int DW_LN_LINE_BASE = -5; + // opcode line range is 14 giving full range -5 to 8 + private static final int DW_LN_LINE_RANGE = 14; + // opcode base should equal DW_LNS_define_file + 1 + private static final int DW_LN_OPCODE_BASE = 13; + + /* + * standard opcodes defined by Dwarf 2 + */ + private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an invalid opcode + private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for extended opcodes + private static final byte DW_LNS_copy = 1; // append current state as matrix row 0 args + private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg + private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg + private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg + private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg + private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args + private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row + private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode 255 0 args + private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg + + /* + * extended opcodes defined by Dwarf 2 + */ + private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 + private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses + private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 + private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 + + DwarfLineSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_LINE_SECTION_NAME; + } + + public void createContent() { + // we need to create a header, dir table, file table and line + // number table encoding for each CU + + // write entries for each file listed in the primary list + int pos = 0; + for (ClassEntry classEntry : primaryClasses) { + int startPos = pos; + classEntry.setLineIndex(startPos); + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(classEntry); + int fileTableSize = computeFileTableSize(classEntry); + int prologueSize = headerSize + dirTableSize + fileTableSize; + classEntry.setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(classEntry); + int totalSize = prologueSize + lineNumberTableSize; + classEntry.setTotalSize(totalSize); + pos += totalSize; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + public int headerSize() { + // header size is standard 31 bytes + // uint32 total_length + // uint16 version + // uint32 prologue_length + // uint8 min_insn_length + // uint8 default_is_stmt + // int8 line_base + // uint8 line_range + // uint8 opcode_base + // uint8 li_opcode_base + // uint8[opcode_base-1] standard_opcode_lengths + + return DW_LN_HEADER_SIZE; + } + + public int computeDirTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int dirSize = 0; + for (DirEntry dir : classEntry.getLocalDirs()) { + dirSize += dir.getPath().length() + 1; + } + // allow for separator nul + dirSize++; + return dirSize; + } + + public int computeFileTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int fileSize = 0; + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we want the file base name excluding path + String baseName = localEntry.getBaseName(); + int length = baseName.length(); + fileSize += length + 1; + DirEntry dirEntry = localEntry.dirEntry; + int idx = classEntry.localDirsIdx(dirEntry); + fileSize += putULEB(idx, scratch, 0); + // the two zero timestamps require 1 byte each + fileSize += 2; + } + // allow for terminator nul + fileSize++; + return fileSize; + } + + public int computeLineNUmberTableSize(ClassEntry classEntry) { + // sigh -- we have to do this by generating the + // content even though we cannot write it into a byte[] + return writeLineNumberTable(classEntry,null, 0); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) + { + Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debug_text_base = ((Number)valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + public void writeContent() { + byte[] buffer = getContent(); + + int pos = 0; + checkDebug(pos); + debug(" [0x%08x] DEBUG_LINE\n", pos); + + for (ClassEntry classEntry : primaryClasses) { + int startPos = pos; + assert classEntry.getLineIndex() == startPos; + debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + pos = writeHeader(classEntry, buffer, pos); + debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + int dirTablePos = pos; + pos = writeDirTable(classEntry, buffer, pos); + debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(classEntry, buffer, pos); + debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(classEntry, buffer, pos); + debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); + debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + } + assert pos == buffer.length; + } + + public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) + { + // 4 ubyte length field + pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); + // 2 ubyte version is always 2 + pos = putShort(DW_VERSION_2, buffer, pos); + // 4 ubyte prologue length includes rest of header and + // dir + file table section + int prologueSize = classEntry.getLinePrologueSize() - 6; + pos = putInt(prologueSize, buffer, pos); + // 1 ubyte min instruction length is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte default is_stmt is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte line base is always -5 + pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); + // 1 ubyte line range is always 14 giving range -5 to 8 + pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); + // 1 ubyte opcode base is always 13 + pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); + // specify opcode arg sizes for the standard opcodes + putByte((byte) 0, buffer, pos); // DW_LNS_copy + putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc + putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line + putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file + putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column + putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt + putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block + putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc + putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc + putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence + putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address + pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file + return pos; + } + + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) + { + debug(" [0x%08x] Dir Name\n", pos); + // write out the list of dirs referenced form this file entry + int dirIdx = 1; + for (DirEntry dir : classEntry.getLocalDirs()) { + // write nul terminated string text. + debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); + pos = putAsciiStringBytes(dir.getPath(), buffer, pos); + dirIdx++; + } + // separate dirs from files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) + { + int fileIdx = 1; + debug(" [0x%08x] Entry Dir Name\n", pos); + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we need the file name minus path, the associated dir index, and 0 for time stamps + String baseName = localEntry.getBaseName(); + DirEntry dirEntry = localEntry.dirEntry; + int dirIdx = classEntry.localDirsIdx(dirEntry); + debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); + pos = putAsciiStringBytes(baseName, buffer, pos); + pos = putULEB(dirIdx, buffer, pos); + pos = putULEB(0, buffer, pos); + pos = putULEB(0, buffer, pos); + fileIdx++; + } + // terminate files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int debug_line = 1; + public int debug_copy_count = 0; + + + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) + { + // the primary file entry should always be first in the local files list + assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; + String primaryClassName = classEntry.getClassName(); + String primaryFileName = classEntry.getFileName(); + String file = primaryFileName; + int fileIdx = 1; + debug(" [0x%08x] primary class %s\n", pos, primaryClassName); + debug(" [0x%08x] primary file %s\n", pos, primaryFileName); + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + Range primaryRange = primaryEntry.getPrimary(); + assert primaryRange.getFileName().equals(primaryFileName); + // each primary represents a method i.e. a contiguous + // sequence of subranges. we assume the default state + // at the start of each sequence because we always post an + // end_sequence when we finish all the subranges in the method + long line = primaryRange.getLine(); + if(line < 0 && primaryEntry.getSubranges().size() > 0) { + line = primaryEntry.getSubranges().get(0).getLine(); + } + if(line < 0) { + line = 0; + } + long address = primaryRange.getLo(); + long hiAddress = address; + // int column = 0; + // boolean is_stmt = true; + // boolean is_basic_block = false; + // boolean end_sequence = false; + // set state for primary + + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + primaryRange.getLo(), debug_text_base + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); + + // initialize and write a row for the start of the primary method + pos = putSetFile(file, fileIdx, buffer, pos); + pos = putSetBasicBlock(buffer, pos); + // address is currently 0 + pos = putSetAddress(address, buffer, pos); + // state machine value of line is currently 1 + // increment to desired line + if(line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putCopy(buffer, pos); + + // now write a row for each subrange lo and hi + + for (Range subrange : primaryEntry.getSubranges()) { + assert subrange.getLo() >= primaryRange.getLo(); + assert subrange.getHi() <= primaryRange.getHi(); + FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); + String subfile = subFileEntry.getFileName(); + int subFileIdx = classEntry.localFilesIdx(subFileEntry); + long subLine = subrange.getLine(); + long subAddressLo = subrange.getLo(); + long subAddressHi = subrange.getHi(); + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + subAddressLo, debug_text_base + subAddressHi, subrange.getClassAndMethodName(), subLine); + if(subLine < 0) { + // no line info so stay at previous file:line + subLine = line; + subfile = file; + subFileIdx = fileIdx; + debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); + } + /* + // there is a temptation to append end sequence at here + // when the hiAddress lies strictly between the current + // address and the start of the next subrange because, + // ostensibly, we have void space between the end of + // the current subrange and the start of the next one. + // however, debug works better if we treat all the insns up + // to the next range start as belonging to the current line + // so the code below is not actually needed. it is left in + // to clarify i) that this is a deliberate choice and ii) what + // that deliberate choice is avoiding. + if(address < hiAddress && hiAddress < subAddressLo) { + long addressDelta = hiAddress - address; + // increment address to hi address, write an + // end sequence and update state to new range + pos = putAdvancePC(addressDelta, buffer, pos); + pos = putEndSequence(buffer, pos); + file = subfile; + fileIdx = subFileIdx; + pos = putSetFile(file, fileIdx, buffer, pos); + line = subLine; + // state machine value of line is currently 1 + // increment to desired line + if (line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putSetBasicBlock(buffer, pos); + // use a reloc to ensure address is relative to text base + address = hiAddress; + pos = putSetAddress(hiAddress, buffer, pos); + } + */ + // if we have to update to a new file then do so + if(subFileIdx != fileIdx) { + // update the current file + pos = putSetFile(subfile, (long) subFileIdx, buffer, pos); + file = subfile; + fileIdx = subFileIdx; + } + // check if we can advance line and/or address in + // one byte with a special opcode + long lineDelta = subLine - line; + long addressDelta = subAddressLo - address; + byte opcode = isSpecialOpcode(addressDelta, lineDelta); + if(opcode != DW_LNS_undefined) { + // ignore pointless write when addressDelta == lineDelta == 0 + if(addressDelta != 0 || lineDelta != 0) { + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // does it help to divide and conquer using + // a fixed address increment + int remainder = isConstAddPC(addressDelta); + if(remainder > 0) { + pos = putConstAddPC(buffer, pos); + // the remaining address can be handled with a + // special opcode but what about the line delta + opcode = isSpecialOpcode(remainder, lineDelta); + if(opcode != DW_LNS_undefined) { + // address remainder and line now fit + pos = putSpecialOpcode(opcode, buffer, pos); + } else { + // ok, bump the line separately then use a + // special opcode for the address remainder + opcode = isSpecialOpcode(remainder, 0); + assert opcode != DW_LNS_undefined; + pos = putAdvanceLine(lineDelta, buffer, pos); + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // increment line and pc separately + if(lineDelta != 0) { + pos = putAdvanceLine(lineDelta, buffer, pos); + } + // n.b. we might just have had an out of range line increment + // with a zero address increment + if(addressDelta > 0) { + // see if we can use a ushort for the increment + if(isFixedAdvancePC(addressDelta)) { + pos = putFixedAdvancePC((short) addressDelta, buffer, pos); + } else { + pos = putAdvancePC(addressDelta, buffer, pos); + } + } + pos = putCopy(buffer, pos); + } + } + // move line and address range on + line += lineDelta; + address += addressDelta; + hiAddress = subAddressHi; + } + // append a final end sequence just below the next primary range + if(address < primaryRange.getHi()) { + long addressDelta = primaryRange.getHi() - address; + // increment address before we write the end sequence + pos = putAdvancePC(addressDelta, buffer, pos); + } + pos = putEndSequence(buffer, pos); + } + debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); + + return pos; + } + + protected void debug(String format, Object... args) + { + if (((int) args[0] - debug_base) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + public int putCopy(byte[] buffer, int pos) + { + byte opcode = DW_LNS_copy; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debug_copy_count++; + debug(" [0x%08x] Copy %d\n", pos, debug_copy_count); + return putByte(opcode, buffer, pos); + } + } + + public int putAdvancePC(long uleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_advance_pc; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debug_address += uleb; + debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debug_address); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putAdvanceLine(long sleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_advance_line; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putSLEB(sleb, scratch, 0); + } else { + debug_line += sleb; + debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debug_line); + pos = putByte(opcode, buffer, pos); + return putSLEB(sleb, buffer, pos); + } + } + + public int putSetFile(String file, long uleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_set_file; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putSetColumn(long uleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_set_column; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putNegateStmt(byte[] buffer, int pos) + { + byte opcode = DW_LNS_negate_stmt; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + return putByte(opcode, buffer, pos); + } + } + + public int putSetBasicBlock(byte[] buffer, int pos) + { + byte opcode = DW_LNS_set_basic_block; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Set basic block\n", pos); + return putByte(opcode, buffer, pos); + } + } + + public int putConstAddPC(byte[] buffer, int pos) + { + byte opcode = DW_LNS_const_add_pc; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + int advance = opcodeAddress((byte) 255); + debug_address += advance; + debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debug_address); + return putByte(opcode, buffer, pos); + } + } + + public int putFixedAdvancePC(short arg, byte[] buffer, int pos) + { + byte opcode = DW_LNS_fixed_advance_pc; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putShort(arg, scratch, 0); + } else { + debug_address += arg; + debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debug_address); + pos = putByte(opcode, buffer, pos); + return putShort(arg, buffer, pos); + } + } + + public int putEndSequence(byte[] buffer, int pos) + { + byte opcode = DW_LNE_end_sequence; + if(buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(1, scratch, 0); + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); + debug_address = debug_text_base; + debug_line = 1; + debug_copy_count = 0; + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(1, buffer, pos); + return putByte(opcode, buffer, pos); + } + } + + public int putSetAddress(long arg, byte[] buffer, int pos) + { + byte opcode = DW_LNE_set_address; + if(buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(9, scratch, 0); + pos = pos + putByte(opcode, scratch, 0); + return pos + putLong(arg, scratch, 0); + } else { + debug_address = debug_text_base + (int) arg; + debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debug_address); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(9, buffer, pos); + pos = putByte(opcode, buffer, pos); + return putRelocatableCodeOffset(arg, buffer, pos); + } + } + + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) + { + byte opcode = DW_LNE_define_file; + // calculate bytes needed for opcode + args + int fileBytes = file.length() + 1; + long insnBytes = 1; + insnBytes += fileBytes; + insnBytes += putULEB(uleb1, scratch, 0); + insnBytes += putULEB(uleb2, scratch, 0); + insnBytes += putULEB(uleb3, scratch, 0); + if(buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // write insnBytes as a ULEB + pos += putULEB(insnBytes, scratch, 0); + return pos + (int) insnBytes; + } else { + debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert insn length as uleb + pos = putULEB(insnBytes, buffer, pos); + // insert opcode and args + pos = putByte(opcode, buffer, pos); + pos = putAsciiStringBytes(file, buffer, pos); + pos = putULEB(uleb1, buffer, pos); + pos = putULEB(uleb2, buffer, pos); + return putULEB(uleb3, buffer, pos); + } + } + + public int opcodeId(byte opcode) + { + int iopcode = opcode & 0xff; + return iopcode - DW_LN_OPCODE_BASE; + } + + public int opcodeAddress(byte opcode) + { + int iopcode = opcode & 0xff; + return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + } + + public int opcodeLine(byte opcode) + { + int iopcode = opcode & 0xff; + return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; + } + + public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) + { + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + if (debug && opcode== 0) { + debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debug_address, debug_line); + } + debug_address += opcodeAddress(opcode); + debug_line += opcodeLine(opcode); + debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", + pos, opcodeId(opcode), opcodeAddress(opcode), debug_address, opcodeLine(opcode), debug_line); + return putByte(opcode, buffer, pos); + } + } + + private final static int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + private final static int MAX_ADDPC_DELTA= MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); + + public byte isSpecialOpcode(long addressDelta, long lineDelta) + { + if(addressDelta < 0) { + return DW_LNS_undefined; + } + if(lineDelta >= DW_LN_LINE_BASE) { + long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; + if(offsetLineDelta < DW_LN_LINE_RANGE) { + // line_delta can be encoded + // check if address is ok + if(addressDelta <= MAX_ADDRESS_ONLY_DELTA) { + long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; + if(opcode <= 255) { + return (byte) opcode; + } + } + } + } + + // return invalid opcode + return DW_LNS_undefined; + } + + public int isConstAddPC(long addressDelta) + { + if(addressDelta < MAX_ADDRESS_ONLY_DELTA) { + return 0; + } + if(addressDelta <= MAX_ADDPC_DELTA) { + return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); + } else { + return 0; + } + } + + public boolean isFixedAdvancePC(long addressDiff) + { + return addressDiff >= 0 && addressDiff < 0xffff; + } + + // .debug_line section content depends on .debug_str section content and offset + public final static String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java new file mode 100644 index 000000000000..982305ac9015 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -0,0 +1,28 @@ +package com.oracle.objectfile.elf.dwarf; + +public class FileEntry +{ + // the name of the associated file including path + private String fileName; + // the name of the associated file excluding path + private String baseName; + // the directory entry associated with this file entry + DirEntry dirEntry; + + public FileEntry(String fileName, String baseName, DirEntry dirEntry) + { + this.fileName = fileName; + this.baseName = baseName; + this.dirEntry = dirEntry; + } + + public String getFileName() { + return fileName; + } + public String getBaseName() { + return baseName; + } + String getDirName() { + return (dirEntry != null ? dirEntry.getPath() : ""); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java new file mode 100644 index 000000000000..963e71714957 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -0,0 +1,106 @@ +package com.oracle.objectfile.elf.dwarf; + +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +public class PrimaryEntry + { + // the primary range detailed by this object + Range primary; + // details of the class owning this range + ClassEntry classEntry; + // a list of subranges associated with the primary range + List subranges; + // a mapping from subranges to their associated file entry + HashMap subrangeIndex; + // details of of compiled method frame size changes + private List frameSizeInfos; + // size of compiled method frame + private int frameSize; + // index of debug_info section compilation unit for this file + private int cuIndex; + // index into debug_line section for associated compilation unit + private int lineIndex; + // size of line number info prologue region for associated compilation unit + private int linePrologueSize; + // total size of line number info region for associated compilation unit + private int totalSize; + + public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { + this.primary = primary; + this.classEntry = classEntry; + this.subranges = new LinkedList<>(); + this.subrangeIndex = new HashMap<>(); + this.frameSizeInfos = frameSizeInfos; + this.frameSize = frameSize; + // initialize indices into other sections to illegal values + this.cuIndex = -1; + this.lineIndex = -1; + } + public void addSubRange(Range subrange, FileEntry subFileEntry) { + // we should not see a subrange more than once + assert !subranges.contains(subrange); + assert subrangeIndex.get(subrange) == null; + // we need to generate a file table entry + // for all ranges + subranges.add(subrange); + subrangeIndex.put(subrange, subFileEntry); + } + public Range getPrimary() { + return primary; + } + public ClassEntry getClassEntry() { + return classEntry; + } + public FileEntry getFileEntry() { + return classEntry.getFileEntry(); + } + public List getSubranges() { + return subranges; + } + public FileEntry getSubrangeFileEntry(Range subrange) { + return subrangeIndex.get(subrange); + } + List getFrameSizeInfos() { + return frameSizeInfos; + } + int getFrameSize() { + return frameSize; + } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + // should have been set before being read + assert lineIndex >= 0; + return lineIndex; + } + void setLineIndex(int lineIndex) { + // should only get set once to a non-negative value + assert lineIndex >= 0; + assert this.lineIndex == -1; + this.lineIndex = lineIndex; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java new file mode 100644 index 000000000000..7fc543efd256 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -0,0 +1,135 @@ +package com.oracle.objectfile.elf.dwarf; + +// details of a specific address range in a compiled method +// either a primary range identifying a whole method +// or a sub-range identifying a sequence of +// instructions that belong to an inlined method + +public class Range { + private String fileName; + private String className; + private String methodName; + private String paramNames; + private String returnTypeName; + private String fullMethodName; + private int lo; + private int hi; + private int line; + // this is null for a primary range + private Range primary; + + // create a primary range + Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { + this(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); + } + + // create a primary or secondary range + Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { + // currently file name and full method name need to go into the debug_str section + // other strings just need to be deduplicated to save space + this.fileName = stringTable.uniqueDebugString(fileName); + this.className = stringTable.uniqueString(className); + this.methodName = stringTable.uniqueString(methodName); + this.paramNames = stringTable.uniqueString(paramNames); + this.returnTypeName = stringTable.uniqueString(returnTypeName); + this.fullMethodName = stringTable.uniqueDebugString(getClassAndMethodNameWithParams()); + this.lo = lo; + this.hi = hi; + this.line = line; + this.primary = primary; + } + + + public boolean sameClassName(Range other) { + return className.equals(other.className); + } + + public boolean sameMethodName(Range other) { + return methodName.equals(other.methodName); + } + + public boolean sameParamNames(Range other) { + return paramNames.equals(other.paramNames); + } + + public boolean sameReturnTypeName(Range other) { + return returnTypeName.equals(other.returnTypeName); + } + + public boolean sameFileName(Range other) { + return fileName.equals(other.fileName); + } + + public boolean sameMethod(Range other) { + return sameClassName(other) && + sameMethodName(other) && + sameParamNames(other) && + sameReturnTypeName(other); + } + + public boolean contains(Range other) { + return (lo <= other.lo && hi >= other.hi); + } + + public boolean isPrimary() { + return getPrimary() == null; + } + + public Range getPrimary() { + return primary; + } + + public String getFileName() { + return fileName; + } + public String getClassName() { + return className; + } + public String getMethodName() { + return methodName; + } + public String getParamNames() { + return paramNames; + } + public String getReturnTypeName() { + return returnTypeName; + } + public int getHi() { + return hi; + } + public int getLo() { + return lo; + } + public int getLine() { + return line; + } + public String getClassAndMethodName() { + return getExtendedMethodName(false, false); + } + public String getClassAndMethodNameWithParams() { + return getExtendedMethodName(true, false); + } + + public String getFullMethodName() { + return getExtendedMethodName(true, true); + } + + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { + StringBuilder builder = new StringBuilder(); + if (includeReturnType && returnTypeName.length() > 0) { + builder.append(returnTypeName); + builder.append(' '); + } + if (className != null) { + builder.append(className); + builder.append("::"); + } + builder.append(methodName); + if (includeParams && !paramNames.isEmpty()) { + builder.append('('); + builder.append(paramNames); + builder.append(')'); + } + return builder.toString(); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java new file mode 100644 index 000000000000..ec564851e641 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -0,0 +1,51 @@ +package com.oracle.objectfile.elf.dwarf; + +// class used to ensure we keep only one copy of a String +// amd track it's locations in the string section should +// it need to be entered +public class StringEntry { + private String string; + private int offset; + private boolean addToStrSection; + + StringEntry(String string) { + this.string = string; + this.offset = -1; + } + public String getString() { + return string; + } + public int getOffset() { + // offset must be set before this can be fetched + assert offset >= 0; + return offset; + } + public void setOffset(int offset) { + assert this.offset < 0; + assert offset >= 0; + this.offset = offset; + } + public boolean isAddToStrSection() { + return addToStrSection; + } + public void setAddToStrSection() { + this.addToStrSection = true; + } + public boolean equals(Object object) { + if (object == null || !(object instanceof StringEntry)) { + return false; + } else { + StringEntry other = (StringEntry)object; + return this == other || string.equals(other.string); + } + } + public int hashCode() { + return string.hashCode() + 37; + } + public String toString() { + return string; + } + public boolean isEmpty() { + return string.length() == 0; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java new file mode 100644 index 000000000000..ba7285bdb1aa --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -0,0 +1,48 @@ +package com.oracle.objectfile.elf.dwarf; + +import java.util.HashMap; +import java.util.Iterator; + +// class which reduces incoming strings to unique +// instances and also marks strings which need +// to be written to the debug_str section +public class StringTable implements Iterable { + + private final HashMap table; + + public StringTable() { + this.table = new HashMap(); + } + + public String uniqueString(String string) { + return ensureString(string, false); + } + + public String uniqueDebugString(String string) { + return ensureString(string, true); + } + + private String ensureString(String string, boolean addToStrSection) { + StringEntry stringEntry = table.get(string); + if (stringEntry == null) { + stringEntry = new StringEntry(string); + table.put(string, stringEntry); + } + if (addToStrSection && !stringEntry.isAddToStrSection()) { + stringEntry.setAddToStrSection(); + } + return stringEntry.getString(); + } + + public int debugStringIndex(String string) { + StringEntry stringEntry = table.get(string); + assert stringEntry != null; + if (stringEntry == null) { + return -1; + } + return stringEntry.getOffset(); + } + public Iterator iterator() { + return table.values().iterator(); + } +} From c447f4d2dfcab93af285e126955535fd3a25cc4f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:23:46 +0000 Subject: [PATCH 003/130] drive native image debug info generation when -H:+TrackNodeSourcePosition is enabled --- .../svm/hosted/image/NativeBootImage.java | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 34e09f145e07..9a669a3f5ddf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.image; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.CONTRACT; import static com.oracle.svm.core.SubstrateUtil.mangleName; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; @@ -44,18 +46,27 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.hosted.meta.HostedType; +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.serviceprovider.BufferUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -67,6 +78,10 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; import com.oracle.objectfile.ObjectFile.RelocationKind; @@ -458,6 +473,12 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { cGlobals.writeData(rwDataBuffer, (offset, symbolName) -> defineDataSymbol(symbolName, rwDataSection, offset + RWDATA_CGLOBALS_PARTITION_OFFSET)); defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET); + // if we have constructed any debug info then + // give the object file a chance to install it + if (GraalOptions.TrackNodeSourcePosition.getValue(HostedOptionValues.singleton())) { + DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); + objectFile.installDebugInfo(provider); + } // - Write the heap, either to its own section, or to the ro and rw data sections. RelocatableBuffer heapSectionBuffer = null; ProgbitsSectionImpl heapSectionImpl = null; @@ -952,4 +973,261 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final ObjectFile objectFile; protected final NativeImageCodeCache codeCache; } + + private class NativeImageDebugInfoProvider implements DebugInfoProvider { + private final NativeImageCodeCache codeCache; + private final NativeImageHeap heap; + private final Iterator> codeCacheIterator; + private final Iterator> heapIterator; + + public NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { + super(); + this.codeCache = codeCache; + this.heap = heap; + this.codeCacheIterator = codeCache.compilations.entrySet().iterator(); + this.heapIterator = heap.objects.entrySet().iterator(); + } + @Override + public DebugTypeInfoProvider typeInfoProvider() + { + return () -> new Iterator() { + @Override + public boolean hasNext() { + return false; + } + @Override + public DebugTypeInfo next() { + return null; + } + }; + } + @Override + public DebugCodeInfoProvider codeInfoProvider() { + return () -> new Iterator() { + @Override + public boolean hasNext() { + return codeCacheIterator.hasNext(); + } + @Override + public DebugCodeInfo next() { + Map.Entry entry = codeCacheIterator.next(); + return new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue()); + } + }; + } + @Override + public DebugDataInfoProvider dataInfoProvider() + { + return () -> new Iterator() { + @Override + public boolean hasNext() { + return false; + } + @Override + public DebugDataInfo next() { + return null; + } + }; + } + } + + private class NativeImageDebugCodeInfo implements DebugCodeInfo + { + private final HostedMethod method; + private final CompilationResult compilation; + public NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { + this.method = method; + this.compilation = compilation; + } + @Override + public String fileName() { + HostedType declaringClass = method.getDeclaringClass(); + String name = declaringClass.getSourceFileName(); + if (name != null) { + // the file name will not include any path + // use the package to create a path prefix + Package pkg = declaringClass.getJavaClass().getPackage(); + if (pkg != null) { + String prefix = pkg.getName(); + prefix = prefix.replace('.', '/'); + name = prefix + "/" + name; + } + } else { + // build file name from the class name which includes the package + name = className(); + // try to map inner classes back to their parent class's file + int idx = name.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + return ""; + } + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + name = name.substring(0, idx); + } + name = name.replace('.','/') + ".java"; + } + return name; + } + @Override + public String className() + { + return method.format("%H"); + } + @Override + public String methodName() { + return method.format("%n"); + } + @Override + public String paramNames() { + return method.format("%P"); + } + @Override + public String returnTypeName() { + return method.format("%R"); + } + @Override + public int addressLo() { + return method.getCodeAddressOffset(); + } + @Override + public int addressHi() { + return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); + } + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(0); + } + return -1; + } + @Override + public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { + if (fileName().length() == 0) { + return () -> new Iterator() + { + @Override + public boolean hasNext() + { + return false; + } + @Override + public DebugLineInfo next() + { + return null; + } + }; + } + return () -> new Iterator() { + final Iterator sourceIterator = compilation.getSourceMappings().iterator(); + @Override + public boolean hasNext() + { + return sourceIterator.hasNext(); + } + @Override + public DebugLineInfo next() + { + return new NativeImageDebugLineInfo(sourceIterator.next()); + } + }; + } + public int getFrameSize() { + return compilation.getTotalFrameSize(); + } + public List getFrameSizeChanges() { + List frameSizeChanges = new LinkedList<>(); + for (Mark mark : compilation.getMarks()) { + // we only need to observe stack increment or decrement points + if(mark.id.equals("PROLOGUE_DECD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); + frameSizeChanges.add(sizeChange); + // } else if (mark.id.equals("PROLOGUE_END")) { + // can ignore these + // } else if (mark.id.equals("EPILOGUE_START")) { + // can ignore these + } else if(mark.id.equals("EPILOGUE_INCD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); + frameSizeChanges.add(sizeChange); + // } else if(mark.id.equals("EPILOGUE_END")) { + } + } + return frameSizeChanges; + } + } + private class NativeImageDebugLineInfo implements DebugLineInfo { + private final int bci; + private final ResolvedJavaMethod method; + private final int lo; + private final int hi; + public NativeImageDebugLineInfo(SourceMapping sourceMapping) { + NodeSourcePosition position = sourceMapping.getSourcePosition(); + int bci = position.getBCI(); + this.bci = (bci >= 0 ? bci : 0); + this.method = position.getMethod(); + this.lo = sourceMapping.getStartOffset(); + this.hi = sourceMapping.getEndOffset(); + } + @Override + public String fileName() { + String name = className(); + int idx = name.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + return ""; + } + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + name = name.substring(0, idx); + } + return name.replace('.','/') + ".java"; + } + @Override + public String className() + { + return method.format("%H"); + } + @Override + public String methodName() + { + return method.format("%n"); + } + @Override + public int addressLo() + { + return lo; + } + @Override + public int addressHi() + { + return hi; + } + @Override + public int line() + { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(bci); + } + return -1; + } + } + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange + { + private int offset; + private Type type; + public NativeImageDebugFrameSizeChange(int offset, Type type) { + this.offset = offset; + this.type = type; + } + @Override + public int getOffset() { + return offset; + } + @Override + public Type getType() { + return type; + } + } } From f38669e53f58a3d4d1f9d1a4cd40698a6f30c95f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:26:06 +0000 Subject: [PATCH 004/130] script that writes a 'set directories' command into file .gdbsourcepath for use when debugging native image with gdb --- substratevm/write_gdbsourcepath | 199 ++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 substratevm/write_gdbsourcepath diff --git a/substratevm/write_gdbsourcepath b/substratevm/write_gdbsourcepath new file mode 100644 index 000000000000..2cf9c728e1a4 --- /dev/null +++ b/substratevm/write_gdbsourcepath @@ -0,0 +1,199 @@ +#!/bin/bash + + +function usage() +{ + echo "write_gdbsourcepath [-h | -v]" + echo "writes command to set source path to .gdbsourcepath" + echo "set GRAAL_SRC_ROOT to graal git repo root" + echo " defaults to .. when . = sdk, compile, substratevm, truffle" + echo "set GRAAL_JDK_SRC_ROOT to unzipped src.zip root" + echo " defaults to JAVA_HOME/src" + exit $1 +} + +function check_args() +{ + while [ $# -ge 1 ]; do + if [ "$1" == "-v" ]; then + VERBOSE=1 + shift + elif [ "$1" == "-h" ]; then + usage 0 + else + usage 1 + fi + done +} + +typeset -i VERBOSE +VERBOSE=0 + +# debug +function verbose() +{ + if [ $VERBOSE -eq 1 ]; then + echo $* + fi +} + +# check which java we are using and set up JAVA_VERSION +function check_java_version() +{ + JAVA_VERSION_STRING=$(java -version |& grep version | cut -d' ' -f3) + if [ "${JAVA_VERSION_STRING#\"1.8.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=8 + elif [ "${JAVA_VERSION_STRING#\"9.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=9 + elif [ "${JAVA_VERSION_STRING#\"11.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=11 + elif [ "${JAVA_VERSION_STRING#\"14.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=14 + else + echo "Unrecognized java version : $JAVA_VERSION_STRING" + exit 1 + fi +} + +# check for the required source trees and +# set up GRAAL_SRC_ROOT and GRAAL_JDK_SRC_ROOT +function check_source_dirs() +{ + if [ -z "$GRAAL_SRC_ROOT" ]; then + # see if we are in one of the Graal trees + if [ "${PWD#*/sdk}" != "$PWD" -o \ + "${PWD#*/compiler}" != "$PWD" -o \ + "${PWD#*/substratevm}" != "$PWD" -o \ + "${PWD#*/truffle}" != "$PWD" ]; then + GRAAL_SRC_ROOT=$(cd ..; pwd) + echo "defaulting GRAAL_SRC_ROOT to .. : $GRAAL_SRC_ROOT" + else + echo "Please set GRAAL_SRC_ROOT to git repo checkout dir" + exit 1 + fi + fi + + if [ -z "$GRAAL_JDK_SRC_ROOT" ]; then + if [ ! -z "$JAVA_HOME" ]; then + GRAAL_JDK_SRC_ROOT=$JAVA_HOME/src + echo "defaulting GRAAL_JDK_SRC_ROOT to JAVA_HOME : $GRAAL_JDK_SRC_ROOT" + else + JAVA_EXE=`which java` + GRAAL_JDK_SRC_ROOT=${JAVA_EXE%/bin/java}/src + fi + fi +} + +# add sources from a supplied graal source dir +function add_sources() +{ + # sanity check + if [ ! -d $1 ]; then + echo "hmm, was expecting a graal component directory, not this : $1" + fi + if [ ! -d $1/src ]; then + echo "hmm, was expecting to find a graal component source tree, not this : $1/src" + fi + root=$1 + for dir in $1/src/* + do + typeset -i ignore + ignore=0 + verbose "considering $dir" + set -x + if [ ! -d ${dir}/src ]; then + ignore=1 + else + # look for test or jdk in the trailing path + tail=${dir#$root} + if [ "${tail%*test}" != "$tail" -o \ + "${tail#*test}" != "$tail" ] ; then + # ignore test dirs + ignore=1 + elif [ "${tail#*jdk}" != "$tail" ]; then + # check for a specific jdk release + if [ "${tail#jdk.}" != "$tail" ]; then + # jdk. as part of a package name is ok + echo '+++' + if ["${tail#jdk.}" != "$tail" ]; then + echo allow $dir + fi + echo /// + ignore=0 + elif [ "${tail#*jdk}" != "${JAVA_VERSION}" ]; then + # jdk must match JAVA_VERSION + echo '+++' + if [ "${dir#jdk.}" != "$dir" ]; then + echo disallow $dir + fi + echo /// + ignore=1 + fi + fi + fi + set +x + if [ $ignore -eq 1 ] ; then + verbose "ignoring $dir" + else + verbose "including $dir" + SOURCEPATH=${SOURCEPATH}:$dir/src + fi + done +} + +# add sources from a supplied java source dir +function add_java_sources() +{ + # sanity check + if [ ! -d $1 ]; then + echo "hmm, was expecting to find a JDK source dir, not this : $1" + fi + SOURCEPATH=${SOURCEPATH}:$1 +} + +check_args $* + +check_java_version + +check_source_dirs + +GRAAL_SDK_SRC_ROOT=${GRAAL_SRC_ROOT}/sdk +GRAAL_COMPILER_SRC_ROOT=${GRAAL_SRC_ROOT}/compiler +GRAAL_SUBSTRATEVM_SRC_ROOT=${GRAAL_SRC_ROOT}/substratevm +GRAAL_TRUFFLE_SRC_ROOT=${GRAAL_SRC_ROOT}/truffle + +SOURCEPATH= + +if [ -d ${GRAAL_SDK_SRC_ROOT} ]; then + add_sources ${GRAAL_SDK_SRC_ROOT} +else + echo "Unable to find sdk sources in ${GRAAL_SDK_SRC_ROOT}" +fi +if [ -d ${GRAAL_COMPILER_SRC_ROOT} ]; then + add_sources ${GRAAL_COMPILER_SRC_ROOT} +else + echo "Unable to find compiler sources in ${GRAAL_COMPILER_SRC_ROOT}" +fi +if [ -d ${GRAAL_SUBSTRATEVM_SRC_ROOT} ]; then + add_sources ${GRAAL_SUBSTRATEVM_SRC_ROOT} +else + echo "Unable to find substratevm sources in ${GRAAL_SUBSTRATEVM_SRC_ROOT}" +fi +if [ -d ${GRAAL_TRUFFLE_SRC_ROOT} ]; then + add_sources ${GRAAL_TRUFFLE_SRC_ROOT} +else + echo "Unable to find truffle sources in ${GRAAL_TRUFFLE_SRC_ROOT}" +fi + +if [ -d ${GRAAL_JDK_SRC_ROOT} ]; then + add_java_sources ${GRAAL_JDK_SRC_ROOT} +else + echo "Unable to find JDK sources in ${GRAAL_JDK_SRC_ROOT}/src" + echo "unzip src.zip into \${GRAAL_JDK_SRC_ROOT}/src" +fi + +SOURCEPATH=${SOURCEPATH#:*} +echo "set directories $SOURCEPATH" > .gdbsourcepath +if [ $VERBOSE -gt 0 ]; then + cat .gdbsourcepath +fi From 476b9090b9031cd2a5cb52d537be56789809ee5e Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 10:32:26 +0000 Subject: [PATCH 005/130] instructions for using debug info prototype --- substratevm/DEBUGINFO.md | 127 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 substratevm/DEBUGINFO.md diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md new file mode 100644 index 000000000000..5b859cd3cd7a --- /dev/null +++ b/substratevm/DEBUGINFO.md @@ -0,0 +1,127 @@ +Using the ptototype debug info feature +-------------------------------------- + +To add debug info to a generated native image add flag +-H:+TrackNodeSourcePosition to the native image command line. + + mx native-image -H:+TrackNodeSourcePosition Hello.java + +The resulting image should contain code (method) debug symbols. + +What is currently implemented +----------------------------- + +The currently implemented features include: + + - break points configured by file and line or by method name + - single stepping by line including both into and over function calls + - stack backtraces (not including frames detailing inlined code) + +Note that single stepping within a compiled method includes file and +line number info for inlined code, including inlined Graal methods. +So, gdb may switch files even though you are still in the same +compiled method. + +Identifying the location of source code +--------------------------------------- + +In order for gdb to be able to locate the source files for your app +methods, Graal methods and JDK runtime methods you need to provide gdb +with a list of source root dirs a 'set directories' command: + + (gdb) set directories /home/adinn/hello/src:/home/adinn/graal/sdk/src/org/graalvm.word/src:/home/adinn/graal/sdk/src/org.graalvm.options/src:... + +The argument is a comma separated list of source roots. It needs to +identify: + + - sources for your app + - sources under the Graal sdk, compiler, substratevm and truffle trees + - sources in the JDK src.zip file + +Needless to say the list for Graal is long and complex. Also, the JDK +sources are in a zip file and gdb does not understand zip sources. So +you need to extract the JDK sources as a preparatory step, + +You can use shell script write_gdbsourcepath (added to Graal dir +substratevm) to auto-generate settings for the GRaal and JDK sources. + + $ bash write_gdbsourcepath + +It creates a local file .gdbsourcepath which sets the relevant +directories. Before running it you can set two env vars to tell it +where to locate the source trees it needs to include: + + - GRAAL_JAVA_SRC_ROOT should point to the dir into which you have + unzipped the src.zip from your Graal JDK release + - GRAAL_SRC_ROOT should point to the dir in which your Graal git + tree checkout is located + +Note that the script ignores test source dirs and jdk dirs that do not +match the release level of the JDK (i.e. if you use jdk8 it will ony +include jdk8 src dirs). The script runs the java command available via +JAVA_HOME to idenitfy which JDK is in use). + +If you run the script from the substratevm dir of your Graal git repo +checkout the script will default GRAAL_SRC_ROOT to the parent dir. + +If JAVA_HOME is set the script will default GRAAL_JAVA_SRC_ROOT to +$JAVA_HOME/src + +Checking debug info +------------------- + +The objdump command can be used to display the dbeug info embedded +into a native image. The following commands (which all assume the +target binary is called hello) can be used to display all currentyl +generated content: + + $ objdump --dwarf=info hello > info + $ objdump --dwarf=abbrev hello > abbrev + $ objdump --dwarf=ranges hello > ranges + $ objdump --dwarf=decodedline hello > decodedline + $ objdump --dwarf=rawline hello > rawline + $ objdump --dwarf=str hello > str + $ objdump --dwarf=frames hello > frames + +The *info* section includes details of all compiled Java methods. + +The *abbrev* sectio defines the layout of records in the info section +that describe Java files (compilation units) and methods. + +The *ranges* section details the start and end addresses of method +code segments + +The *decodedline* section maps subsegments of method code range +segments to files and line numbers. This mapping includes entries +for files and line numbers for inlined methods. + +The *rawline* segment provides deatails of how the line table is +generated using DWARF state machine instuctions that encode file, +line and address transitions. + +The *str* section provides a lookup table for strings referenced +from records in the info section + +The *frames* section lists transition points in compiled methods +where a (fixed size) stack frame is pushed or popped, allowing +the debugger to identify each frame's current and previous stack +pointers and it's return address. + +Note that some of the content embedded in the debug records is +generated by the C compiler and belongs to code that is either in +libraries or the C lib bootstrap code that is bundled in with the +Java method code. + +Currently supported targets +--------------------------- + +The prototype is currently implemented only for gdb on Linux. + + - Linux/x86_64 suppoort has been tested and should work + correctly. + + - Linux/AArch64 support is present but has not yet been fully + verified (break points should work ok but stack backtraces + may be incorrect). + +Windows support is still under development. From 55ab5bdb6c8e99fa27acfb7324b0e176a788311d Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 12:12:28 +0000 Subject: [PATCH 006/130] fix check-style errors --- .../debuginfo/DebugInfoProvider.java | 29 +- .../oracle/objectfile/elf/ELFObjectFile.java | 12 +- .../objectfile/elf/dwarf/ClassEntry.java | 304 ++++---- .../oracle/objectfile/elf/dwarf/DirEntry.java | 32 +- .../objectfile/elf/dwarf/DwarfSections.java | 653 +++++++----------- .../objectfile/elf/dwarf/FileEntry.java | 32 +- .../objectfile/elf/dwarf/PrimaryEntry.java | 219 +++--- .../oracle/objectfile/elf/dwarf/Range.java | 26 + .../objectfile/elf/dwarf/StringEntry.java | 28 +- .../objectfile/elf/dwarf/StringTable.java | 26 + .../svm/hosted/image/NativeBootImage.java | 61 +- 11 files changed, 722 insertions(+), 700 deletions(-) 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 8d9c097a60c6..3a4cc6eac521 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 @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.debuginfo; import java.util.List; @@ -39,8 +65,7 @@ interface DebugLineInfo { int line(); } - interface DebugFrameSizeChange - { + interface DebugFrameSizeChange { enum Type {EXTEND, CONTRACT}; int getOffset(); DebugFrameSizeChange.Type getType(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index b2ec0e5fa7d6..85c9fbb16d42 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1169,12 +1169,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - ELFSection strSection = (ELFSection)newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - ELFSection abbrevSection = (ELFSection)newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - ELFSection locSection= (ELFSection)newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - ELFSection infoSection = (ELFSection)newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - ELFSection aRangesSection = (ELFSection)newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - ELFSection debugSection = (ELFSection)newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index f70b5cd387d8..90fc7a8d6318 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -6,154 +32,148 @@ import java.util.List; import java.util.Map; -public class ClassEntry - { - // the name of the associated class - private String className; - // the associated file - FileEntry fileEntry; - // a list recording details of all primary ranges included in - // this class sorted by ascending address range - private LinkedList primaryEntries; - // an index identifying primary ranges which have already been encountered - private Map primaryIndex; - // an index of all primary and secondary files referenced from this class's CU - private Map localFilesIndex; - // a list of the same files - private LinkedList localFiles; - // an index of all primary and secondary dirs referenced from this class's CU - private HashMap localDirsIndex; - // a list of the same dirs - private LinkedList localDirs; - // index of debug_info section compilation unit for this class - private int cuIndex; - // index into debug_line section for associated CU - private int lineIndex; - // size of line number info prologue region for associated CU - private int linePrologueSize; - // total size of line number info region for associated CU - private int totalSize; +public class ClassEntry { + // the name of the associated class + private String className; + // the associated file + FileEntry fileEntry; + // a list recording details of all primary ranges included in + // this class sorted by ascending address range + private LinkedList primaryEntries; + // an index identifying primary ranges which have already been encountered + private Map primaryIndex; + // an index of all primary and secondary files referenced from this class's CU + private Map localFilesIndex; + // a list of the same files + private LinkedList localFiles; + // an index of all primary and secondary dirs referenced from this class's CU + private HashMap localDirsIndex; + // a list of the same dirs + private LinkedList localDirs; + // index of debug_info section compilation unit for this class + private int cuIndex; + // index into debug_line section for associated CU + private int lineIndex; + // size of line number info prologue region for associated CU + private int linePrologueSize; + // total size of line number info region for associated CU + private int totalSize; - public ClassEntry(String className, FileEntry fileEntry) - { - this.className = className; - this.fileEntry = fileEntry; - this.primaryEntries = new LinkedList<>(); - this.primaryIndex = new HashMap<>(); - this.localFiles = new LinkedList<>(); - this.localFilesIndex = new HashMap<>(); - this.localDirs = new LinkedList<>(); - this.localDirsIndex = new HashMap<>(); - localFiles.add(fileEntry); - localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.dirEntry; - if (dirEntry != null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } - this.cuIndex = -1; - this.lineIndex = -1; - this.linePrologueSize = -1; - this.totalSize = -1; - } + public ClassEntry(String className, FileEntry fileEntry) { + this.className = className; + this.fileEntry = fileEntry; + this.primaryEntries = new LinkedList<>(); + this.primaryIndex = new HashMap<>(); + this.localFiles = new LinkedList<>(); + this.localFilesIndex = new HashMap<>(); + this.localDirs = new LinkedList<>(); + this.localDirsIndex = new HashMap<>(); + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.dirEntry; + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + this.cuIndex = -1; + this.lineIndex = -1; + this.linePrologueSize = -1; + this.totalSize = -1; + } - PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) - { - if(primaryIndex.get(primary) == null) { - PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); - primaryEntries.add(primaryEntry); - primaryIndex.put(primary, primaryEntry); - return primaryEntry; - } - return null; - } - void addSubRange(Range subrange, FileEntry subFileEntry) { - Range primary = subrange.getPrimary(); - // the subrange should belong to a primary range - assert primary != null; - PrimaryEntry primaryEntry = primaryIndex.get(primary); - // we should already have seen the primary range - assert primaryEntry != null; - assert primaryEntry.getClassEntry() == this; - primaryEntry.addSubRange(subrange, subFileEntry); - if (localFilesIndex.get(subFileEntry) == null) { - localFiles.add(subFileEntry); - localFilesIndex.put(subFileEntry, localFiles.size()); - } - DirEntry dirEntry = subFileEntry.dirEntry; - if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } + PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { + if (primaryIndex.get(primary) == null) { + PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); + primaryEntries.add(primaryEntry); + primaryIndex.put(primary, primaryEntry); + return primaryEntry; + } + return null; + } + void addSubRange(Range subrange, FileEntry subFileEntry) { + Range primary = subrange.getPrimary(); + // the subrange should belong to a primary range + assert primary != null; + PrimaryEntry primaryEntry = primaryIndex.get(primary); + // we should already have seen the primary range + assert primaryEntry != null; + assert primaryEntry.getClassEntry() == this; + primaryEntry.addSubRange(subrange, subFileEntry); + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.dirEntry; + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); } - public int localDirsIdx(DirEntry dirEntry) { - if (dirEntry != null) { - return localDirsIndex.get(dirEntry); - } else { - return 0; - } + } + public int localDirsIdx(DirEntry dirEntry) { + if (dirEntry != null) { + return localDirsIndex.get(dirEntry); + } else { + return 0; } + } - public int localFilesIdx(FileEntry fileEntry) { - return localFilesIndex.get(fileEntry); - } + public int localFilesIdx(FileEntry fileEntry) { + return localFilesIndex.get(fileEntry); + } - String getFileName() - { - return fileEntry.getFileName(); - } + String getFileName() { + return fileEntry.getFileName(); + } - String getDirName() { - return fileEntry.getDirName(); - } + String getDirName() { + return fileEntry.getDirName(); + } - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - int getLineIndex() { - return lineIndex; - } - void setLineIndex(int lineIndex) { - this.lineIndex = lineIndex; - } - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - public int getLinePrologueSize() { - return linePrologueSize; - } - public int getTotalSize() { - return totalSize; - } - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } - public FileEntry getFileEntry() { - return fileEntry; - } - public String getClassName() { - return className; - } - public LinkedList getPrimaryEntries() { - return primaryEntries; - } - public Object primaryIndexFor(Range primaryRange) { - return primaryIndex.get(primaryRange); - } - public LinkedList getLocalDirs() - { - return localDirs; - } - public LinkedList getLocalFiles() - { - return localFiles; - } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + return lineIndex; + } + void setLineIndex(int lineIndex) { + this.lineIndex = lineIndex; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + public FileEntry getFileEntry() { + return fileEntry; + } + public String getClassName() { + return className; + } + public LinkedList getPrimaryEntries() { + return primaryEntries; + } + public Object primaryIndexFor(Range primaryRange) { + return primaryIndex.get(primaryRange); + } + public LinkedList getLocalDirs() { + return localDirs; + } + public LinkedList getLocalFiles() { + return localFiles; } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 45ad9a44b088..1ce68980f93a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; // files may be located in a source directory associated @@ -10,8 +36,7 @@ // will be listed using the dirs derived from the package // i.e. simply "foo/bar/baz/mumble/grumble/bletch" -public class DirEntry -{ +public class DirEntry { private String path; // create an entry for a root package path @@ -20,8 +45,7 @@ public DirEntry(String path) { this.path = path; } - public String getPath() - { + public String getPath() { return path; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 8ba6c884aca9..c668f92c0785 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.BasicProgbitsSectionImpl; import com.oracle.objectfile.BuildDependency; @@ -23,8 +49,7 @@ import java.util.Map; import java.util.Set; -public class DwarfSections -{ +public class DwarfSections { // names of the different sections we create or reference // in reverse dependency order public static final String TEXT_SECTION_NAME = ".text"; @@ -76,7 +101,7 @@ public class DwarfSections private static final byte DW_FLAG_false = 0; private static final byte DW_FLAG_true = 1; // value for DW_AT_language attribute with form DATA1 - private final static byte DW_LANG_Java = 0xb; + private static final byte DW_LANG_Java = 0xb; // access not needed until we make functions members // DW_AT_Accessibility attribute values // private static final byte DW_ACCESS_public = 1; @@ -90,30 +115,30 @@ public class DwarfSections // CIE and FDE entries - public final static int DW_CFA_CIE_id = -1; - public final static int DW_CFA_FDE_id = 0; + public static final int DW_CFA_CIE_id = -1; + public static final int DW_CFA_FDE_id = 0; - public final static byte DW_CFA_CIE_version = 1; + public static final byte DW_CFA_CIE_version = 1; // values for high 2 bits - public final static byte DW_CFA_advance_loc = 0x1; - public final static byte DW_CFA_offset = 0x2; - public final static byte DW_CFA_restore = 0x3; + public static final byte DW_CFA_advance_loc = 0x1; + public static final byte DW_CFA_offset = 0x2; + public static final byte DW_CFA_restore = 0x3; // values for low 6 bits - public final static byte DW_CFA_nop = 0x0; - public final static byte DW_CFA_set_loc1 = 0x1; - public final static byte DW_CFA_advance_loc1 = 0x2; - public final static byte DW_CFA_advance_loc2 = 0x3; - public final static byte DW_CFA_advance_loc4 = 0x4; - public final static byte DW_CFA_offset_extended = 0x5; - public final static byte DW_CFA_restore_extended = 0x6; - public final static byte DW_CFA_undefined = 0x7; - public final static byte DW_CFA_same_value = 0x8; - public final static byte DW_CFA_register = 0x9; - public final static byte DW_CFA_def_cfa = 0xc; - public final static byte DW_CFA_def_cfa_register = 0xd; - public final static byte DW_CFA_def_cfa_offset = 0xe; + public static final byte DW_CFA_nop = 0x0; + public static final byte DW_CFA_set_loc1 = 0x1; + public static final byte DW_CFA_advance_loc1 = 0x2; + public static final byte DW_CFA_advance_loc2 = 0x3; + public static final byte DW_CFA_advance_loc4 = 0x4; + public static final byte DW_CFA_offset_extended = 0x5; + public static final byte DW_CFA_restore_extended = 0x6; + public static final byte DW_CFA_undefined = 0x7; + public static final byte DW_CFA_same_value = 0x8; + public static final byte DW_CFA_register = 0x9; + public static final byte DW_CFA_def_cfa = 0xc; + public static final byte DW_CFA_def_cfa_register = 0xd; + public static final byte DW_CFA_def_cfa_offset = 0xe; private ELFMachine elfMachine; private DwarfStrSectionImpl dwarfStrSection; @@ -164,7 +189,7 @@ public ELFMachine getElfMachine() { } // a scratch buffer used during computation of a section's size - protected final static byte[] scratch = new byte[10]; + protected static final byte[] scratch = new byte[10]; // table listing all known strings private StringTable stringTable = new StringTable(); @@ -213,142 +238,6 @@ public ELFMachine getElfMachine() { // index of already seen files private Map filesIndex = new HashMap<>(); - private static String[] root_pkgs = { - // substrate root packages - "com.oracle.graal.pointsto", - "com.oracle.objectfile", - "com.oracle.svm.agent", - "com.oracle.svm.configure", - "com.oracle.svm.core", - "com.oracle.svm.core.genscavenge", - "com.oracle.svm.core.graal", - "com.oracle.svm.core.graal.aarch64", - "com.oracle.svm.core.graal.amd64", - "com.oracle.svm.core.graal.llvm", - "com.oracle.svm.core.jdk11", - "com.oracle.svm.core.jdk8", - "com.oracle.svm.core.posix", - "com.oracle.svm.core.posix.jdk11", - "com.oracle.svm.core.windows", - "com.oracle.svm.driver", - "com.oracle.svm.graal", - "com.oracle.svm.graal.hotspot.libgraal", - "com.oracle.svm.hosted", - "com.oracle.svm.jline", - "com.oracle.svm.jni", - "com.oracle.svm.junit", - "com.oracle.svm.libffi", - "com.oracle.svm.native.jvm.posix", - "com.oracle.svm.native.jvm.windows", - "com.oracle.svm.native.libchelper", - "com.oracle.svm.native.strictmath", - "com.oracle.svm.polyglot", - "com.oracle.svm.reflect", - "com.oracle.svm.test", - "com.oracle.svm.test.jdk11", - "com.oracle.svm.thirdparty", - "com.oracle.svm.truffle", - "com.oracle.svm.truffle.nfi", - "com.oracle.svm.truffle.nfi.posix", - "com.oracle.svm.truffle.nfi.windows", - "com.oracle.svm.tutorial", - "com.oracle.svm.util", - "com.oracle.svm.util.jdk11", - "org.graalvm.polyglot.nativeapi", - // compiler root packages - "jdk.tools.jaotc", - "jdk.tools.jaotc.binformat", - "jdk.tools.jaotc", - "org.graalvm.compiler.api.directives", - "org.graalvm.compiler.api.replacements", - "org.graalvm.compiler.api.runtime", - "org.graalvm.compiler.asm", - "org.graalvm.compiler.asm.aarch64", - "org.graalvm.compiler.asm.amd64", - "org.graalvm.compiler.asm.sparc", - "org.graalvm.compiler.bytecode", - "org.graalvm.compiler.code", - "org.graalvm.compiler.core", - "org.graalvm.compiler.core.aarch64", - "org.graalvm.compiler.core.amd64", - "org.graalvm.compiler.core.common", - "org.graalvm.compiler.core.llvm", - "org.graalvm.compiler.core.match.processor", - "org.graalvm.compiler.core.sparc", - "org.graalvm.compiler.debug", - "org.graalvm.compiler.graph", - "org.graalvm.compiler.hotspot", - "org.graalvm.compiler.hotspot.aarch64", - "org.graalvm.compiler.hotspot.amd64", - "org.graalvm.compiler.hotspot.jdk8", - "org.graalvm.compiler.hotspot.management", - "org.graalvm.compiler.hotspot.sparc", - "org.graalvm.compiler.java", - "org.graalvm.compiler.jtt", - "org.graalvm.compiler.lir", - "org.graalvm.compiler.lir.aarch64", - "org.graalvm.compiler.lir.amd64", - "org.graalvm.compiler.lir.jtt", - "org.graalvm.compiler.lir.sparc", - "org.graalvm.compiler.loop", - "org.graalvm.compiler.loop.phases", - "org.graalvm.compiler.microbenchmarks", - "org.graalvm.compiler.nodeinfo", - "org.graalvm.compiler.nodeinfo.processor", - "org.graalvm.compiler.nodes", - "org.graalvm.compiler.options", - "org.graalvm.compiler.options.processor", - "org.graalvm.compiler.phases", - "org.graalvm.compiler.phases.common", - "org.graalvm.compiler.printer", - "org.graalvm.compiler.processor", - "org.graalvm.compiler.replacements", - "org.graalvm.compiler.replacements.aarch64", - "org.graalvm.compiler.replacements.amd64", - "org.graalvm.compiler.replacements.processor", - "org.graalvm.compiler.replacements.sparc", - "org.graalvm.compiler.runtime", - "org.graalvm.compiler.serviceprovider", - "org.graalvm.compiler.serviceprovider.jdk8", - "org.graalvm.compiler.serviceprovider.processor", - "org.graalvm.compiler.truffle.common", - "org.graalvm.compiler.truffle.common.hotspot", - "org.graalvm.compiler.truffle.common.hotspot.libgraal", - "org.graalvm.compiler.truffle.common.processor", - "org.graalvm.compiler.truffle.compiler", - "org.graalvm.compiler.truffle.compiler.amd64", - "org.graalvm.compiler.truffle.compiler.hotspot", - "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", - "org.graalvm.compiler.truffle.compiler.hotspot.amd64", - "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", - "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", - "org.graalvm.compiler.truffle.compiler.hotspot.sparc", - "org.graalvm.compiler.truffle.runtime", - "org.graalvm.compiler.truffle.runtime.hotspot", - "org.graalvm.compiler.truffle.runtime.hotspot.java", - "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", - "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", - "org.graalvm.compiler.truffle.runtime.serviceprovider", - "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", - "org.graalvm.compiler.virtual", - "org.graalvm.compiler.virtual.bench", - "org.graalvm.compiler.word", - "org.graalvm.graphio", - "org.graalvm.libgraal", - "org.graalvm.libgraal.jdk8", - "org.graalvm.micro.benchmarks", - "org.graalvm.util", - // sdk root packages - "org.graalvm.collections", - "org.graalvm.launcher", - "org.graalvm.options", - "org.graalvm.polyglot", - "org.graalvm.home", - "org.graalvm.nativeimage", - "org.graalvm.polyglot.tck", - "org.graalvm.word", - }; - public String uniqueString(String string) { return stringTable.uniqueString(string); } @@ -361,8 +250,7 @@ private int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } - public void installDebugInfo(DebugInfoProvider debugInfoProvider) - { + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { // install types @@ -370,11 +258,10 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) // ensure we have a null string in the string section uniqueDebugString(""); - + DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { // primary file name and full method name need to be written to the debug_str section - // String fileName = debugCodeInfo.fileName(); String className = debugCodeInfo.className(); String methodName = debugCodeInfo.methodName(); @@ -425,7 +312,7 @@ public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); // ensure we have an entry FileEntry fileEntry = filesIndex.get(fileName); - if(fileEntry == null) { + if (fileEntry == null) { DirEntry dirEntry = ensureDirEntry(fileName); String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), @@ -434,7 +321,7 @@ public FileEntry ensureFileEntry(Range range) { files.add(fileEntry); filesIndex.put(fileName, fileEntry); // if this is a primary entry then add it to the primary list - if(range.isPrimary()) { + if (range.isPrimary()) { primaryFiles.add(fileEntry); } else { Range primaryRange = range.getPrimary(); @@ -445,8 +332,7 @@ public FileEntry ensureFileEntry(Range range) { return fileEntry; } - public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) - { + public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); @@ -456,8 +342,7 @@ public void addRange(Range primaryRange, List frameSizeInf } } - public void addSubRange(Range primaryRange, Range subrange) - { + public void addSubRange(Range primaryRange, Range subrange) { assert primaryRange.isPrimary(); assert !subrange.isPrimary(); String className = primaryRange.getClassName(); @@ -469,10 +354,9 @@ public void addSubRange(Range primaryRange, Range subrange) classEntry.addSubRange(subrange, subrangeEntry); } - private DirEntry ensureDirEntry(String file) - { + private DirEntry ensureDirEntry(String file) { int pathLength = file.lastIndexOf('/'); - if(pathLength < 0) { + if (pathLength < 0) { // no path/package means use dir entry 0 return null; } @@ -489,9 +373,9 @@ private DirEntry ensureDirEntry(String file) // shared implementation methods to manage content creation public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { public boolean debug = false; - public long debug_text_base = 0; - public long debug_address = 0; - public int debug_base = 0; + public long debugTextBase = 0; + public long debugAddress = 0; + public int debugBase = 0; public DwarfSectionImpl() { } @@ -505,14 +389,13 @@ public void checkDebug(int pos) { String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { debug = true; - debug_base = pos; - debug_address = debug_text_base; + debugBase = pos; + debugAddress = debugTextBase; } } - protected void debug(String format, Object ... args) - { - if(debug) { + protected void debug(String format, Object ... args) { + if (debug) { System.out.format(format, args); } } @@ -556,11 +439,11 @@ public int putULEB(long l, byte[] buffer, int pos) { byte b = (byte) (l & 0x7f); l = l >>> 7; boolean done = (l == 0); - if(!done) { + if (!done) { b = (byte) (b | 0x80); } pos = putByte(b, buffer, pos); - if(done) { + if (done) { break; } } @@ -573,11 +456,11 @@ public int putSLEB(long l, byte[] buffer, int pos) { l = l >> 7; boolean bIsSigned = (b & 0x40) != 0; boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); - if(!done) { + if (!done) { b = (byte) (b | 0x80); } pos = putByte(b, buffer, pos); - if(done) { + if (done) { break; } } @@ -589,7 +472,7 @@ public int putAsciiStringBytes(String s, byte[] buffer, int pos) { public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); - if(c > 127) { + if (c > 127) { throw new RuntimeException("oops : expected ASCII string! " + s); } buffer[pos++] = (byte) c; @@ -630,7 +513,7 @@ public int writeFlag(byte flag, byte[] buffer, int pos) { } } - public int writeAttr_addr(long address, byte[] buffer, int pos) { + public int writeAttrAddress(long address, byte[] buffer, int pos) { if (buffer == null) { return pos + 8; } else { @@ -638,7 +521,7 @@ public int writeAttr_addr(long address, byte[] buffer, int pos) { } } - public int writeAttr_data8(long value, byte[] buffer, int pos) { + public int writeAttrData8(long value, byte[] buffer, int pos) { if (buffer == null) { return pos + putLong(value, scratch, 0); } else { @@ -646,7 +529,7 @@ public int writeAttr_data8(long value, byte[] buffer, int pos) { } } - public int writeAttr_data4(int value, byte[] buffer, int pos) { + public int writeAttrData4(int value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(value, scratch, 0); } else { @@ -654,7 +537,7 @@ public int writeAttr_data4(int value, byte[] buffer, int pos) { } } - public int writeAttr_data1(byte value, byte[] buffer, int pos) { + public int writeAttrData1(byte value, byte[] buffer, int pos) { if (buffer == null) { return pos + putByte(value, scratch, 0); } else { @@ -662,7 +545,7 @@ public int writeAttr_data1(byte value, byte[] buffer, int pos) { } } - public int writeAttr_null(byte[] buffer, int pos) { + public int writeAttrNull(byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(0, scratch, 0); } else { @@ -693,11 +576,10 @@ public byte[] getOrDecideContent(Map alreadyDecided, } @Override - public Set getDependencies(Map decisions) - { + public Set getDependencies(Map decisions) { Set deps = super.getDependencies(decisions); String targetName = targetSectionName(); - ELFSection targetSection = (ELFSection)getElement().getOwner().elementForName(targetName); + ELFSection targetSection = (ELFSection) getElement().getOwner().elementForName(targetName); LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); LayoutDecision.Kind[] targetKinds = targetSectionKinds(); @@ -727,7 +609,7 @@ public String getSectionName() { public void createContent() { int pos = 0; for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()){ + if (stringEntry.isAddToStrSection()) { stringEntry.setOffset(pos); String string = stringEntry.getString(); pos += string.length() + 1; @@ -746,7 +628,7 @@ public void writeContent() { checkDebug(pos); for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()){ + if (stringEntry.isAddToStrSection()) { assert stringEntry.getOffset() == pos; String string = stringEntry.getString(); pos = putAsciiStringBytes(string, buffer, pos); @@ -760,18 +642,18 @@ protected void debug(String format, Object... args) { } // .debug_str section content depends on text section content and offset - public final static String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -787,8 +669,7 @@ public String getSectionName() { } @Override - public void createContent() - { + public void createContent() { int pos = 0; // an abbrev table contains abbrev entries for one or // more CUs. the table includes a sequence of abbrev @@ -838,8 +719,7 @@ public void createContent() } @Override - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -912,18 +792,18 @@ protected void debug(String format, Object... args) { } // .debug_abbrev section content depends on .debug_frame section content and offset - public final static String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -939,8 +819,7 @@ public String getSectionName() { } @Override - public void createContent() - { + public void createContent() { int pos = 0; // the frame section contains one CIE at offset 0 @@ -953,8 +832,7 @@ public void createContent() } @Override - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -991,7 +869,7 @@ public int writeCIE(byte[] buffer, int pos) { pos += putAsciiStringBytes("", scratch, 0); pos += putULEB(1, scratch, 0); pos += putULEB(-8, scratch, 0); - pos += putByte((byte)getPCIdx(), scratch, 0); + pos += putByte((byte) getPCIdx(), scratch, 0); // write insns to set up empty frame pos = writeInitialInstructions(buffer, pos); // pad to word alignment @@ -1006,7 +884,7 @@ public int writeCIE(byte[] buffer, int pos) { pos = putAsciiStringBytes("", buffer, pos); pos = putULEB(1, buffer, pos); pos = putSLEB(-8, buffer, pos); - pos = putByte((byte)getPCIdx(), buffer, pos); + pos = putByte((byte) getPCIdx(), buffer, pos); // write insns to set up empty frame pos = writeInitialInstructions(buffer, pos); // pad to word alignment @@ -1024,7 +902,7 @@ public int writeMethodFrames(byte[] buffer, int pos) { int frameSize = primaryEntry.getFrameSize(); int currentOffset = 0; int lengthPos = pos; - pos = writeFDEHeader((int)lo, (int)hi, buffer, pos); + pos = writeFDEHeader((int) lo, (int) hi, buffer, pos); for (DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { int advance = debugFrameSizeInfo.getOffset() - currentOffset; currentOffset += advance; @@ -1103,9 +981,9 @@ public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { if (offset <= 0x3f) { return writeAdvanceLoc0((byte) offset, buffer, pos); - } else if(offset <= 0xff) { + } else if (offset <= 0xff) { return writeAdvanceLoc1((byte) offset, buffer, pos); - } else if(offset <= 0xffff) { + } else if (offset <= 0xffff) { return writeAdvanceLoc2((short) offset, buffer, pos); } else { return writeAdvanceLoc4(offset, buffer, pos); @@ -1179,32 +1057,32 @@ protected void debug(String format, Object... args) { super.debug(format, args); } // .debug_frame section content depends on .debug_line section content and offset - public final static String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } private byte offsetOp(int register) { assert (register >> 6) == 0; - return (byte)((DW_CFA_offset << 6) | register); + return (byte) ((DW_CFA_offset << 6) | register); } private byte advanceLoc0Op(int offset) { assert (offset >= 0 && offset <= 0x3f); - return (byte)((DW_CFA_advance_loc << 6) | offset); + return (byte) ((DW_CFA_advance_loc << 6) | offset); } } - public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl - { - public final static int DW_CFA_RSP_IDX = 7; - public final static int DW_CFA_RIP_IDX = 16; + + public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_RSP_IDX = 7; + public static final int DW_CFA_RIP_IDX = 16; public DwarfFrameSectionImplX86_64() { super(); @@ -1218,8 +1096,7 @@ public int getSPIdx() { return DW_CFA_RSP_IDX; } @Override - public int writeInitialInstructions(byte[] buffer, int pos) - { + public int writeInitialInstructions(byte[] buffer, int pos) { // rsp points at the word containing the saved rip // so the frame base (cfa) is at rsp + 8 (why not - ???) // def_cfa r7 (sp) offset 8 @@ -1230,27 +1107,26 @@ public int writeInitialInstructions(byte[] buffer, int pos) return pos; } } - public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl - { - public final static int DW_CFA_FP_IDX = 29; - public final static int DW_CFA_LR_IDX = 30; - public final static int DW_CFA_SP_IDX = 31; - public final static int DW_CFA_PC_IDX = 32; + + public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_FP_IDX = 29; + public static final int DW_CFA_LR_IDX = 30; + public static final int DW_CFA_SP_IDX = 31; + public static final int DW_CFA_PC_IDX = 32; public DwarfFrameSectionImplAArch64() { super(); } @Override - public int getPCIdx(){ + public int getPCIdx() { return DW_CFA_PC_IDX; } @Override - public int getSPIdx(){ + public int getSPIdx() { return DW_CFA_SP_IDX; } @Override - public int writeInitialInstructions(byte[] buffer, int pos) - { + public int writeInitialInstructions(byte[] buffer, int pos) { // rsp has not been updated // caller pc is in lr // register r32 (rpc), r30 (lr) @@ -1259,25 +1135,21 @@ public int writeInitialInstructions(byte[] buffer, int pos) } } - public class DwarfInfoSectionImpl extends DwarfSectionImpl - { + public class DwarfInfoSectionImpl extends DwarfSectionImpl { // header section always contains fixed number of bytes private static final int DW_DIE_HEADER_SIZE = 11; - public DwarfInfoSectionImpl() - { + public DwarfInfoSectionImpl() { super(); } @Override - public String getSectionName() - { + public String getSectionName() { return DW_INFO_SECTION_NAME; } @Override - public void createContent() - { + public void createContent() { // we need a single level 0 DIE for each compilation unit (CU) // Each CU's Level 0 DIE is preceded by a fixed header: // and terminated by a null DIE @@ -1319,8 +1191,7 @@ public void createContent() } @Override - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -1346,55 +1217,53 @@ public void writeContent() public int writeCUHeader(byte[] buffer, int pos) { if (buffer == null) { - pos += putInt(0, scratch, 0); // CU length - pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version - pos += putInt(0, scratch, 0); // abbrev offset - return pos + putByte((byte)8, scratch, 0); // address size + pos += putInt(0, scratch, 0); // CU length + pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version + pos += putInt(0, scratch, 0); // abbrev offset + return pos + putByte((byte) 8, scratch, 0); // address size } else { - pos = putInt(0, buffer, pos); // CU length - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version - pos = putInt(0, buffer, pos); // abbrev offset - return putByte((byte)8, buffer, pos); // address size + pos = putInt(0, buffer, pos); // CU length + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version + pos = putInt(0, buffer, pos); // abbrev offset + return putByte((byte) 8, buffer, pos); // address size } } - public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { LinkedList primaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); - pos = writeAttr_data1(DW_LANG_Java, buffer, pos); + pos = writeAttrData1(DW_LANG_Java, buffer, pos); debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); - pos = writeAttr_strp(classEntry.getFileName(), buffer, pos); + pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); debug(" [0x%08x] low_pc 0x%08x\n", pos, primaryEntries.getFirst().getPrimary().getLo()); - pos = writeAttr_addr(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + pos = writeAttrAddress(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); debug(" [0x%08x] hi_pc 0x%08x\n", pos, primaryEntries.getLast().getPrimary().getHi()); - pos = writeAttr_addr(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); + pos = writeAttrAddress(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); - pos = writeAttr_data4(classEntry.getLineIndex(), buffer, pos); + pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); for (PrimaryEntry primary : primaryEntries) { pos = writePrimary(primary, buffer, pos); } // write a terminating null attribute for the the level 2 primaries - return writeAttr_null(buffer, pos); + return writeAttrNull(buffer, pos); } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) - { + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getClassAndMethodNameWithParams()), primary.getClassAndMethodNameWithParams()); - pos = writeAttr_strp(primary.getClassAndMethodNameWithParams(), buffer, pos); + pos = writeAttrStrp(primary.getClassAndMethodNameWithParams(), buffer, pos); debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); - pos = writeAttr_addr(primary.getLo(), buffer, pos); + pos = writeAttrAddress(primary.getLo(), buffer, pos); debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); - pos = writeAttr_addr(primary.getHi(), buffer, pos); + pos = writeAttrAddress(primary.getHi(), buffer, pos); // need to pass true only if method is public debug(" [0x%08x] external true\n", pos); return writeFlag(DW_FLAG_true, buffer, pos); } - public int writeAttr_strp(String value, byte[] buffer, int pos) { + public int writeAttrStrp(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(0, scratch, 0); } else { @@ -1402,7 +1271,7 @@ public int writeAttr_strp(String value, byte[] buffer, int pos) { return putInt(idx, buffer, pos); } } - public int writeAttr_string(String value, byte[] buffer, int pos) { + public int writeAttrString(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + value.length() + 1; } else { @@ -1410,7 +1279,7 @@ public int writeAttr_string(String value, byte[] buffer, int pos) { } } protected void debug(String format, Object... args) { - if (((int) args[0] - debug_base) < 0x100000) { + if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); } else if (format.startsWith(" [0x%08x] primary file")) { super.debug(format, args); @@ -1418,18 +1287,18 @@ protected void debug(String format, Object... args) { } // .debug_info section content depends on abbrev section content and offset - public final static String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -1446,8 +1315,7 @@ public String getSectionName() { return DW_ARANGES_SECTION_NAME; } - public void createContent() - { + public void createContent() { int pos = 0; // we need an entry for each compilation unit // @@ -1470,7 +1338,7 @@ public void createContent() // where N is the number of ranges belonging to the compilation unit // and the last range contains two zeroes - for(ClassEntry classEntry : primaryClasses) { + for (ClassEntry classEntry : primaryClasses) { pos += DW_AR_HEADER_SIZE; // align to 2 * address size pos += DW_AR_HEADER_PAD_SIZE; @@ -1482,8 +1350,7 @@ public void createContent() } @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) - { + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { Element textElement = getElement().getOwner().elementForName(".text"); LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); if (decisionMap != null) { @@ -1492,14 +1359,13 @@ public byte[] getOrDecideContent(Map alreadyDecided, // this may not be the final vaddr for the text segment // but it will be close enough to make debug easier // i.e. to within a 4k page or two - debug_text_base = ((Number)valueObj).longValue(); + debugTextBase = ((Number) valueObj).longValue(); } } return super.getOrDecideContent(alreadyDecided, contentHint); } - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -1507,7 +1373,7 @@ public void writeContent() checkDebug(pos); debug(" [0x%08x] DEBUG_ARANGES\n", pos); - for(ClassEntry classEntry : primaryClasses) { + for (ClassEntry classEntry : primaryClasses) { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = classEntry.getCUIndex(); @@ -1517,19 +1383,19 @@ public void writeContent() length += 2 * 8; debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); - pos = putShort(DW_VERSION_2,buffer, pos); // dwarf version is always 2 + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 pos = putInt(cuIndex, buffer, pos); - pos = putByte((byte)8, buffer, pos); // address size is always 8 - pos = putByte((byte)0, buffer, pos); // segment size is always 0 + pos = putByte((byte) 8, buffer, pos); // address size is always 8 + pos = putByte((byte) 0, buffer, pos); // segment size is always 0 assert (pos - lastpos) == DW_AR_HEADER_SIZE; // align to 2 * address size for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { - pos = putByte((byte)0, buffer, pos); + pos = putByte((byte) 0, buffer, pos); } debug(" [0x%08x] Address Length Name\n", pos); for (PrimaryEntry primaryEntry : primaryEntries) { Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debug_text_base + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); + debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); } @@ -1545,18 +1411,18 @@ protected void debug(String format, Object... args) { } // .debug_aranges section content depends on .debug_info section content and offset - public final static String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -1686,12 +1552,11 @@ public int computeFileTableSize(ClassEntry classEntry) { public int computeLineNUmberTableSize(ClassEntry classEntry) { // sigh -- we have to do this by generating the // content even though we cannot write it into a byte[] - return writeLineNumberTable(classEntry,null, 0); + return writeLineNumberTable(classEntry, null, 0); } @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) - { + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { Element textElement = getElement().getOwner().elementForName(".text"); LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); if (decisionMap != null) { @@ -1700,7 +1565,7 @@ public byte[] getOrDecideContent(Map alreadyDecided, // this may not be the final vaddr for the text segment // but it will be close enough to make debug easier // i.e. to within a 4k page or two - debug_text_base = ((Number)valueObj).longValue(); + debugTextBase = ((Number) valueObj).longValue(); } } return super.getOrDecideContent(alreadyDecided, contentHint); @@ -1733,8 +1598,7 @@ public void writeContent() { assert pos == buffer.length; } - public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) { // 4 ubyte length field pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); // 2 ubyte version is always 2 @@ -1769,8 +1633,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) { debug(" [0x%08x] Dir Name\n", pos); // write out the list of dirs referenced form this file entry int dirIdx = 1; @@ -1785,8 +1648,7 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { int fileIdx = 1; debug(" [0x%08x] Entry Dir Name\n", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { @@ -1806,12 +1668,11 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - public int debug_line = 1; - public int debug_copy_count = 0; + public int debugLine = 1; + public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // the primary file entry should always be first in the local files list assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; String primaryClassName = classEntry.getClassName(); @@ -1828,10 +1689,10 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) // at the start of each sequence because we always post an // end_sequence when we finish all the subranges in the method long line = primaryRange.getLine(); - if(line < 0 && primaryEntry.getSubranges().size() > 0) { + if (line < 0 && primaryEntry.getSubranges().size() > 0) { line = primaryEntry.getSubranges().get(0).getLine(); } - if(line < 0) { + if (line < 0) { line = 0; } long address = primaryRange.getLo(); @@ -1842,7 +1703,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) // boolean end_sequence = false; // set state for primary - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + primaryRange.getLo(), debug_text_base + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); // initialize and write a row for the start of the primary method pos = putSetFile(file, fileIdx, buffer, pos); @@ -1851,7 +1712,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) pos = putSetAddress(address, buffer, pos); // state machine value of line is currently 1 // increment to desired line - if(line != 1) { + if (line != 1) { pos = putAdvanceLine(line - 1, buffer, pos); } pos = putCopy(buffer, pos); @@ -1867,8 +1728,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + subAddressLo, debug_text_base + subAddressHi, subrange.getClassAndMethodName(), subLine); - if(subLine < 0) { + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getClassAndMethodName(), subLine); + if (subLine < 0) { // no line info so stay at previous file:line subLine = line; subfile = file; @@ -1886,7 +1747,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) // so the code below is not actually needed. it is left in // to clarify i) that this is a deliberate choice and ii) what // that deliberate choice is avoiding. - if(address < hiAddress && hiAddress < subAddressLo) { + if (address < hiAddress && hiAddress < subAddressLo) { long addressDelta = hiAddress - address; // increment address to hi address, write an // end sequence and update state to new range @@ -1908,7 +1769,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) } */ // if we have to update to a new file then do so - if(subFileIdx != fileIdx) { + if (subFileIdx != fileIdx) { // update the current file pos = putSetFile(subfile, (long) subFileIdx, buffer, pos); file = subfile; @@ -1919,21 +1780,21 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) long lineDelta = subLine - line; long addressDelta = subAddressLo - address; byte opcode = isSpecialOpcode(addressDelta, lineDelta); - if(opcode != DW_LNS_undefined) { + if (opcode != DW_LNS_undefined) { // ignore pointless write when addressDelta == lineDelta == 0 - if(addressDelta != 0 || lineDelta != 0) { + if (addressDelta != 0 || lineDelta != 0) { pos = putSpecialOpcode(opcode, buffer, pos); } } else { // does it help to divide and conquer using // a fixed address increment int remainder = isConstAddPC(addressDelta); - if(remainder > 0) { + if (remainder > 0) { pos = putConstAddPC(buffer, pos); // the remaining address can be handled with a // special opcode but what about the line delta opcode = isSpecialOpcode(remainder, lineDelta); - if(opcode != DW_LNS_undefined) { + if (opcode != DW_LNS_undefined) { // address remainder and line now fit pos = putSpecialOpcode(opcode, buffer, pos); } else { @@ -1946,14 +1807,14 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) } } else { // increment line and pc separately - if(lineDelta != 0) { + if (lineDelta != 0) { pos = putAdvanceLine(lineDelta, buffer, pos); } // n.b. we might just have had an out of range line increment // with a zero address increment - if(addressDelta > 0) { + if (addressDelta > 0) { // see if we can use a ushort for the increment - if(isFixedAdvancePC(addressDelta)) { + if (isFixedAdvancePC(addressDelta)) { pos = putFixedAdvancePC((short) addressDelta, buffer, pos); } else { pos = putAdvancePC(addressDelta, buffer, pos); @@ -1968,7 +1829,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) hiAddress = subAddressHi; } // append a final end sequence just below the next primary range - if(address < primaryRange.getHi()) { + if (address < primaryRange.getHi()) { long addressDelta = primaryRange.getHi() - address; // increment address before we write the end sequence pos = putAdvancePC(addressDelta, buffer, pos); @@ -1980,59 +1841,54 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - protected void debug(String format, Object... args) - { - if (((int) args[0] - debug_base) < 0x100000) { + protected void debug(String format, Object... args) { + if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); } else if (format.startsWith(" [0x%08x] primary file")) { super.debug(format, args); } } - public int putCopy(byte[] buffer, int pos) - { + public int putCopy(byte[] buffer, int pos) { byte opcode = DW_LNS_copy; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { - debug_copy_count++; - debug(" [0x%08x] Copy %d\n", pos, debug_copy_count); + debugCopyCount++; + debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); return putByte(opcode, buffer, pos); } } - public int putAdvancePC(long uleb, byte[] buffer, int pos) - { + public int putAdvancePC(long uleb, byte[] buffer, int pos) { byte opcode = DW_LNS_advance_pc; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { - debug_address += uleb; - debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debug_address); + debugAddress += uleb; + debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); pos = putByte(opcode, buffer, pos); return putULEB(uleb, buffer, pos); } } - public int putAdvanceLine(long sleb, byte[] buffer, int pos) - { + public int putAdvanceLine(long sleb, byte[] buffer, int pos) { byte opcode = DW_LNS_advance_line; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putSLEB(sleb, scratch, 0); } else { - debug_line += sleb; - debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debug_line); + debugLine += sleb; + debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); pos = putByte(opcode, buffer, pos); return putSLEB(sleb, buffer, pos); } } - public int putSetFile(String file, long uleb, byte[] buffer, int pos) - { + public int putSetFile(String file, long uleb, byte[] buffer, int pos) { byte opcode = DW_LNS_set_file; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { @@ -2042,10 +1898,9 @@ public int putSetFile(String file, long uleb, byte[] buffer, int pos) } } - public int putSetColumn(long uleb, byte[] buffer, int pos) - { + public int putSetColumn(long uleb, byte[] buffer, int pos) { byte opcode = DW_LNS_set_column; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { @@ -2054,20 +1909,18 @@ public int putSetColumn(long uleb, byte[] buffer, int pos) } } - public int putNegateStmt(byte[] buffer, int pos) - { + public int putNegateStmt(byte[] buffer, int pos) { byte opcode = DW_LNS_negate_stmt; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { return putByte(opcode, buffer, pos); } } - public int putSetBasicBlock(byte[] buffer, int pos) - { + public int putSetBasicBlock(byte[] buffer, int pos) { byte opcode = DW_LNS_set_basic_block; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { debug(" [0x%08x] Set basic block\n", pos); @@ -2075,46 +1928,43 @@ public int putSetBasicBlock(byte[] buffer, int pos) } } - public int putConstAddPC(byte[] buffer, int pos) - { + public int putConstAddPC(byte[] buffer, int pos) { byte opcode = DW_LNS_const_add_pc; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { int advance = opcodeAddress((byte) 255); - debug_address += advance; - debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debug_address); + debugAddress += advance; + debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); return putByte(opcode, buffer, pos); } } - public int putFixedAdvancePC(short arg, byte[] buffer, int pos) - { + public int putFixedAdvancePC(short arg, byte[] buffer, int pos) { byte opcode = DW_LNS_fixed_advance_pc; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putShort(arg, scratch, 0); } else { - debug_address += arg; - debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debug_address); + debugAddress += arg; + debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); pos = putByte(opcode, buffer, pos); return putShort(arg, buffer, pos); } } - public int putEndSequence(byte[] buffer, int pos) - { + public int putEndSequence(byte[] buffer, int pos) { byte opcode = DW_LNE_end_sequence; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB pos = pos + putULEB(1, scratch, 0); return pos + putByte(opcode, scratch, 0); } else { debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); - debug_address = debug_text_base; - debug_line = 1; - debug_copy_count = 0; + debugAddress = debugTextBase; + debugLine = 1; + debugCopyCount = 0; pos = putByte(DW_LNS_extended_prefix, buffer, pos); // insert extended insn byte count as ULEB pos = putULEB(1, buffer, pos); @@ -2122,18 +1972,17 @@ public int putEndSequence(byte[] buffer, int pos) } } - public int putSetAddress(long arg, byte[] buffer, int pos) - { + public int putSetAddress(long arg, byte[] buffer, int pos) { byte opcode = DW_LNE_set_address; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB pos = pos + putULEB(9, scratch, 0); pos = pos + putByte(opcode, scratch, 0); return pos + putLong(arg, scratch, 0); } else { - debug_address = debug_text_base + (int) arg; - debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debug_address); + debugAddress = debugTextBase + (int) arg; + debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); pos = putByte(DW_LNS_extended_prefix, buffer, pos); // insert extended insn byte count as ULEB pos = putULEB(9, buffer, pos); @@ -2142,8 +1991,7 @@ public int putSetAddress(long arg, byte[] buffer, int pos) } } - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) - { + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) { byte opcode = DW_LNE_define_file; // calculate bytes needed for opcode + args int fileBytes = file.length() + 1; @@ -2152,7 +2000,7 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] insnBytes += putULEB(uleb1, scratch, 0); insnBytes += putULEB(uleb2, scratch, 0); insnBytes += putULEB(uleb3, scratch, 0); - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // write insnBytes as a ULEB pos += putULEB(insnBytes, scratch, 0); @@ -2171,56 +2019,51 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] } } - public int opcodeId(byte opcode) - { + public int opcodeId(byte opcode) { int iopcode = opcode & 0xff; return iopcode - DW_LN_OPCODE_BASE; } - public int opcodeAddress(byte opcode) - { + public int opcodeAddress(byte opcode) { int iopcode = opcode & 0xff; return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; } - public int opcodeLine(byte opcode) - { + public int opcodeLine(byte opcode) { int iopcode = opcode & 0xff; return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) - { - if(buffer == null) { + public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { - if (debug && opcode== 0) { - debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debug_address, debug_line); + if (debug && opcode == 0) { + debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); } - debug_address += opcodeAddress(opcode); - debug_line += opcodeLine(opcode); + debugAddress += opcodeAddress(opcode); + debugLine += opcodeLine(opcode); debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debug_address, opcodeLine(opcode), debug_line); + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, pos); } } - private final static int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; - private final static int MAX_ADDPC_DELTA= MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); + private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - public byte isSpecialOpcode(long addressDelta, long lineDelta) - { - if(addressDelta < 0) { + public byte isSpecialOpcode(long addressDelta, long lineDelta) { + if (addressDelta < 0) { return DW_LNS_undefined; } - if(lineDelta >= DW_LN_LINE_BASE) { + if (lineDelta >= DW_LN_LINE_BASE) { long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; - if(offsetLineDelta < DW_LN_LINE_RANGE) { + if (offsetLineDelta < DW_LN_LINE_RANGE) { // line_delta can be encoded // check if address is ok - if(addressDelta <= MAX_ADDRESS_ONLY_DELTA) { + if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; - if(opcode <= 255) { + if (opcode <= 255) { return (byte) opcode; } } @@ -2231,37 +2074,35 @@ public byte isSpecialOpcode(long addressDelta, long lineDelta) return DW_LNS_undefined; } - public int isConstAddPC(long addressDelta) - { - if(addressDelta < MAX_ADDRESS_ONLY_DELTA) { + public int isConstAddPC(long addressDelta) { + if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { return 0; } - if(addressDelta <= MAX_ADDPC_DELTA) { + if (addressDelta <= MAX_ADDPC_DELTA) { return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); } else { return 0; } } - public boolean isFixedAdvancePC(long addressDiff) - { + public boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } // .debug_line section content depends on .debug_str section content and offset - public final static String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, LayoutDecision.Kind.VADDR, // add this so we can use the base address }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } -} \ No newline at end of file +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index 982305ac9015..5a4ed796d8dc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -1,7 +1,32 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; -public class FileEntry -{ +public class FileEntry { // the name of the associated file including path private String fileName; // the name of the associated file excluding path @@ -9,8 +34,7 @@ public class FileEntry // the directory entry associated with this file entry DirEntry dirEntry; - public FileEntry(String fileName, String baseName, DirEntry dirEntry) - { + public FileEntry(String fileName, String baseName, DirEntry dirEntry) { this.fileName = fileName; this.baseName = baseName; this.dirEntry = dirEntry; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index 963e71714957..cdc84b9c4961 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -5,102 +31,101 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; -public class PrimaryEntry - { - // the primary range detailed by this object - Range primary; - // details of the class owning this range - ClassEntry classEntry; - // a list of subranges associated with the primary range - List subranges; - // a mapping from subranges to their associated file entry - HashMap subrangeIndex; - // details of of compiled method frame size changes - private List frameSizeInfos; - // size of compiled method frame - private int frameSize; - // index of debug_info section compilation unit for this file - private int cuIndex; - // index into debug_line section for associated compilation unit - private int lineIndex; - // size of line number info prologue region for associated compilation unit - private int linePrologueSize; - // total size of line number info region for associated compilation unit - private int totalSize; +public class PrimaryEntry { + // the primary range detailed by this object + Range primary; + // details of the class owning this range + ClassEntry classEntry; + // a list of subranges associated with the primary range + List subranges; + // a mapping from subranges to their associated file entry + HashMap subrangeIndex; + // details of of compiled method frame size changes + private List frameSizeInfos; + // size of compiled method frame + private int frameSize; + // index of debug_info section compilation unit for this file + private int cuIndex; + // index into debug_line section for associated compilation unit + private int lineIndex; + // size of line number info prologue region for associated compilation unit + private int linePrologueSize; + // total size of line number info region for associated compilation unit + private int totalSize; - public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { - this.primary = primary; - this.classEntry = classEntry; - this.subranges = new LinkedList<>(); - this.subrangeIndex = new HashMap<>(); - this.frameSizeInfos = frameSizeInfos; - this.frameSize = frameSize; - // initialize indices into other sections to illegal values - this.cuIndex = -1; - this.lineIndex = -1; - } - public void addSubRange(Range subrange, FileEntry subFileEntry) { - // we should not see a subrange more than once - assert !subranges.contains(subrange); - assert subrangeIndex.get(subrange) == null; - // we need to generate a file table entry - // for all ranges - subranges.add(subrange); - subrangeIndex.put(subrange, subFileEntry); - } - public Range getPrimary() { - return primary; - } - public ClassEntry getClassEntry() { - return classEntry; - } - public FileEntry getFileEntry() { - return classEntry.getFileEntry(); - } - public List getSubranges() { - return subranges; - } - public FileEntry getSubrangeFileEntry(Range subrange) { - return subrangeIndex.get(subrange); - } - List getFrameSizeInfos() { - return frameSizeInfos; - } - int getFrameSize() { - return frameSize; - } - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - int getLineIndex() { - // should have been set before being read - assert lineIndex >= 0; - return lineIndex; - } - void setLineIndex(int lineIndex) { - // should only get set once to a non-negative value - assert lineIndex >= 0; - assert this.lineIndex == -1; - this.lineIndex = lineIndex; - } - public int getLinePrologueSize() { - return linePrologueSize; - } - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - public int getTotalSize() { - return totalSize; - } - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } + public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { + this.primary = primary; + this.classEntry = classEntry; + this.subranges = new LinkedList<>(); + this.subrangeIndex = new HashMap<>(); + this.frameSizeInfos = frameSizeInfos; + this.frameSize = frameSize; + // initialize indices into other sections to illegal values + this.cuIndex = -1; + this.lineIndex = -1; + } + public void addSubRange(Range subrange, FileEntry subFileEntry) { + // we should not see a subrange more than once + assert !subranges.contains(subrange); + assert subrangeIndex.get(subrange) == null; + // we need to generate a file table entry + // for all ranges + subranges.add(subrange); + subrangeIndex.put(subrange, subFileEntry); + } + public Range getPrimary() { + return primary; + } + public ClassEntry getClassEntry() { + return classEntry; + } + public FileEntry getFileEntry() { + return classEntry.getFileEntry(); + } + public List getSubranges() { + return subranges; + } + public FileEntry getSubrangeFileEntry(Range subrange) { + return subrangeIndex.get(subrange); + } + List getFrameSizeInfos() { + return frameSizeInfos; + } + int getFrameSize() { + return frameSize; + } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + // should have been set before being read + assert lineIndex >= 0; + return lineIndex; + } + void setLineIndex(int lineIndex) { + // should only get set once to a non-negative value + assert lineIndex >= 0; + assert this.lineIndex == -1; + this.lineIndex = lineIndex; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 7fc543efd256..e068ded3b845 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; // details of a specific address range in a compiled method diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index ec564851e641..09710793cba7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; // class used to ensure we keep only one copy of a String @@ -35,7 +61,7 @@ public boolean equals(Object object) { if (object == null || !(object instanceof StringEntry)) { return false; } else { - StringEntry other = (StringEntry)object; + StringEntry other = (StringEntry) object; return this == other || string.equals(other.string); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index ba7285bdb1aa..faa2b8ef3b61 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.util.HashMap; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 9a669a3f5ddf..a99b53b47d06 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -980,7 +980,7 @@ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final Iterator> codeCacheIterator; private final Iterator> heapIterator; - public NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { + NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { super(); this.codeCache = codeCache; this.heap = heap; @@ -988,8 +988,7 @@ public NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageH this.heapIterator = heap.objects.entrySet().iterator(); } @Override - public DebugTypeInfoProvider typeInfoProvider() - { + public DebugTypeInfoProvider typeInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { @@ -1016,8 +1015,7 @@ public DebugCodeInfo next() { }; } @Override - public DebugDataInfoProvider dataInfoProvider() - { + public DebugDataInfoProvider dataInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { @@ -1031,11 +1029,10 @@ public DebugDataInfo next() { } } - private class NativeImageDebugCodeInfo implements DebugCodeInfo - { + private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; - public NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { + NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; this.compilation = compilation; } @@ -1065,13 +1062,12 @@ public String fileName() { // name is XXX$YYY so use outer class to derive file name name = name.substring(0, idx); } - name = name.replace('.','/') + ".java"; + name = name.replace('.', '/') + ".java"; } return name; } @Override - public String className() - { + public String className() { return method.format("%H"); } @Override @@ -1105,16 +1101,13 @@ public int line() { @Override public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { if (fileName().length() == 0) { - return () -> new Iterator() - { + return () -> new Iterator() { @Override - public boolean hasNext() - { + public boolean hasNext() { return false; } @Override - public DebugLineInfo next() - { + public DebugLineInfo next() { return null; } }; @@ -1122,13 +1115,11 @@ public DebugLineInfo next() return () -> new Iterator() { final Iterator sourceIterator = compilation.getSourceMappings().iterator(); @Override - public boolean hasNext() - { + public boolean hasNext() { return sourceIterator.hasNext(); } @Override - public DebugLineInfo next() - { + public DebugLineInfo next() { return new NativeImageDebugLineInfo(sourceIterator.next()); } }; @@ -1140,14 +1131,14 @@ public List getFrameSizeChanges() { List frameSizeChanges = new LinkedList<>(); for (Mark mark : compilation.getMarks()) { // we only need to observe stack increment or decrement points - if(mark.id.equals("PROLOGUE_DECD_RSP")) { + if (mark.id.equals("PROLOGUE_DECD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); frameSizeChanges.add(sizeChange); // } else if (mark.id.equals("PROLOGUE_END")) { // can ignore these // } else if (mark.id.equals("EPILOGUE_START")) { // can ignore these - } else if(mark.id.equals("EPILOGUE_INCD_RSP")) { + } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); frameSizeChanges.add(sizeChange); // } else if(mark.id.equals("EPILOGUE_END")) { @@ -1161,7 +1152,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { private final ResolvedJavaMethod method; private final int lo; private final int hi; - public NativeImageDebugLineInfo(SourceMapping sourceMapping) { + NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); int bci = position.getBCI(); this.bci = (bci >= 0 ? bci : 0); @@ -1181,31 +1172,26 @@ public String fileName() { // name is XXX$YYY so use outer class to derive file name name = name.substring(0, idx); } - return name.replace('.','/') + ".java"; + return name.replace('.', '/') + ".java"; } @Override - public String className() - { + public String className() { return method.format("%H"); } @Override - public String methodName() - { + public String methodName() { return method.format("%n"); } @Override - public int addressLo() - { + public int addressLo() { return lo; } @Override - public int addressHi() - { + public int addressHi() { return hi; } @Override - public int line() - { + public int line() { LineNumberTable lineNumberTable = method.getLineNumberTable(); if (lineNumberTable != null) { return lineNumberTable.getLineNumber(bci); @@ -1213,11 +1199,10 @@ public int line() return -1; } } - private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange - { + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; private Type type; - public NativeImageDebugFrameSizeChange(int offset, Type type) { + NativeImageDebugFrameSizeChange(int offset, Type type) { this.offset = offset; this.type = type; } From dd09c0075ceb66e4e4e382d0dee9451952325611 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 14:39:40 +0000 Subject: [PATCH 007/130] fixed eclipseformat style issues --- .../src/com/oracle/objectfile/ObjectFile.java | 2 +- .../debuginfo/DebugInfoProvider.java | 2 +- .../oracle/objectfile/elf/ELFObjectFile.java | 12 ++--- .../objectfile/elf/dwarf/ClassEntry.java | 2 +- .../objectfile/elf/dwarf/DwarfSections.java | 51 +++++++++++-------- .../oracle/objectfile/elf/dwarf/Range.java | 51 +++---------------- .../objectfile/elf/dwarf/StringEntry.java | 3 ++ .../objectfile/elf/dwarf/StringTable.java | 3 +- 8 files changed, 52 insertions(+), 74 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index b6564b8db39e..beabb431a50a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1082,7 +1082,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // support for consuming debug info - public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + public void installDebugInfo( @SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default } 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 3a4cc6eac521..7c4d3757e227 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 @@ -66,7 +66,7 @@ interface DebugLineInfo { } interface DebugFrameSizeChange { - enum Type {EXTEND, CONTRACT}; + enum Type {EXTEND, CONTRACT} int getOffset(); DebugFrameSizeChange.Type getType(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 85c9fbb16d42..aa28733c56ee 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1169,12 +1169,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + @SuppressWarnings("unused") ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + @SuppressWarnings("unused") ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + @SuppressWarnings("unused") ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + @SuppressWarnings("unused") ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + @SuppressWarnings("unused") ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + @SuppressWarnings("unused") ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 90fc7a8d6318..4421181710e7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -117,7 +117,7 @@ public int localDirsIdx(DirEntry dirEntry) { } } - public int localFilesIdx(FileEntry fileEntry) { + public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { return localFilesIndex.get(fileEntry); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index c668f92c0785..19008f6ba50d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -196,7 +196,7 @@ public ELFMachine getElfMachine() { // list detailing all dirs in which files are found to reside // either as part of substrate/compiler or user code - private LinkedList dirs = new LinkedList(); + private LinkedList dirs = new LinkedList<>(); // index of already seen dirs private Map dirsIndex = new HashMap<>(); @@ -207,7 +207,7 @@ public ELFMachine getElfMachine() { // a list recording details of all primary ranges included in // this file sorted by ascending address range - private LinkedList primaryEntries = new LinkedList(); + private LinkedList primaryEntries = new LinkedList<>(); // An alternative traversal option is // 1) by top level class (String id) @@ -227,14 +227,14 @@ public ELFMachine getElfMachine() { // of the file and dir tables. // list of class entries detailing class info for primary ranges - private LinkedList primaryClasses = new LinkedList(); + private LinkedList primaryClasses = new LinkedList<>(); // index of already seen classes private Map primaryClassesIndex = new HashMap<>(); // List of files which contain primary ranges - private LinkedList primaryFiles = new LinkedList(); + private LinkedList primaryFiles = new LinkedList<>(); // List of files which contain primary or secondary ranges - private LinkedList files = new LinkedList(); + private LinkedList files = new LinkedList<>(); // index of already seen files private Map filesIndex = new HashMap<>(); @@ -637,6 +637,7 @@ public void writeContent() { assert pos == size; } + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -787,6 +788,7 @@ public int writeAbbrev2(byte[] buffer, int pos) { return pos; } + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -1053,6 +1055,7 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { public abstract int getSPIdx(); public abstract int writeInitialInstructions(byte[] buffer, int pos); + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -1229,21 +1232,21 @@ public int writeCUHeader(byte[] buffer, int pos) { } } public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { - LinkedList primaryEntries = classEntry.getPrimaryEntries(); + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); pos = writeAttrData1(DW_LANG_Java, buffer, pos); debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, primaryEntries.getFirst().getPrimary().getLo()); - pos = writeAttrAddress(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); - debug(" [0x%08x] hi_pc 0x%08x\n", pos, primaryEntries.getLast().getPrimary().getHi()); - pos = writeAttrAddress(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); + pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); + pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); - for (PrimaryEntry primary : primaryEntries) { - pos = writePrimary(primary, buffer, pos); + for (PrimaryEntry primaryEntry : classPrimaryEntries) { + pos = writePrimary(primaryEntry, buffer, pos); } // write a terminating null attribute for the the level 2 primaries return writeAttrNull(buffer, pos); @@ -1253,8 +1256,8 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getClassAndMethodNameWithParams()), primary.getClassAndMethodNameWithParams()); - pos = writeAttrStrp(primary.getClassAndMethodNameWithParams(), buffer, pos); + debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); + pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); pos = writeAttrAddress(primary.getLo(), buffer, pos); debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); @@ -1278,6 +1281,8 @@ public int writeAttrString(String value, byte[] buffer, int pos) { return putAsciiStringBytes(value, buffer, pos); } } + + @Override protected void debug(String format, Object... args) { if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); @@ -1315,6 +1320,7 @@ public String getSectionName() { return DW_ARANGES_SECTION_NAME; } + @Override public void createContent() { int pos = 0; // we need an entry for each compilation unit @@ -1365,6 +1371,7 @@ public byte[] getOrDecideContent(Map alreadyDecided, return super.getOrDecideContent(alreadyDecided, contentHint); } + @Override public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; @@ -1377,9 +1384,9 @@ public void writeContent() { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = classEntry.getCUIndex(); - LinkedList primaryEntries = classEntry.getPrimaryEntries(); + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); // add room for each entry into length count - length += primaryEntries.size() * 2 * 8; + length += classPrimaryEntries.size() * 2 * 8; length += 2 * 8; debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); @@ -1393,9 +1400,9 @@ public void writeContent() { pos = putByte((byte) 0, buffer, pos); } debug(" [0x%08x] Address Length Name\n", pos); - for (PrimaryEntry primaryEntry : primaryEntries) { - Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); + for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { + Range primary = classPrimaryEntry.getPrimary(); + debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); } @@ -1406,6 +1413,7 @@ public void writeContent() { assert pos == size; } + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -1468,6 +1476,7 @@ public String getSectionName() { return DW_LINE_SECTION_NAME; } + @Override public void createContent() { // we need to create a header, dir table, file table and line // number table encoding for each CU @@ -1571,6 +1580,7 @@ public byte[] getOrDecideContent(Map alreadyDecided, return super.getOrDecideContent(alreadyDecided, contentHint); } + @Override public void writeContent() { byte[] buffer = getContent(); @@ -1728,7 +1738,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getClassAndMethodName(), subLine); + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); if (subLine < 0) { // no line info so stay at previous file:line subLine = line; @@ -1841,6 +1851,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { return pos; } + @Override protected void debug(String format, Object... args) { if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index e068ded3b845..9e72991dcc88 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -58,41 +58,13 @@ public class Range { this.methodName = stringTable.uniqueString(methodName); this.paramNames = stringTable.uniqueString(paramNames); this.returnTypeName = stringTable.uniqueString(returnTypeName); - this.fullMethodName = stringTable.uniqueDebugString(getClassAndMethodNameWithParams()); + this.fullMethodName = stringTable.uniqueDebugString(constructClassAndMethodNameWithParams()); this.lo = lo; this.hi = hi; this.line = line; this.primary = primary; } - - public boolean sameClassName(Range other) { - return className.equals(other.className); - } - - public boolean sameMethodName(Range other) { - return methodName.equals(other.methodName); - } - - public boolean sameParamNames(Range other) { - return paramNames.equals(other.paramNames); - } - - public boolean sameReturnTypeName(Range other) { - return returnTypeName.equals(other.returnTypeName); - } - - public boolean sameFileName(Range other) { - return fileName.equals(other.fileName); - } - - public boolean sameMethod(Range other) { - return sameClassName(other) && - sameMethodName(other) && - sameParamNames(other) && - sameReturnTypeName(other); - } - public boolean contains(Range other) { return (lo <= other.lo && hi >= other.hi); } @@ -114,12 +86,6 @@ public String getClassName() { public String getMethodName() { return methodName; } - public String getParamNames() { - return paramNames; - } - public String getReturnTypeName() { - return returnTypeName; - } public int getHi() { return hi; } @@ -129,17 +95,10 @@ public int getLo() { public int getLine() { return line; } - public String getClassAndMethodName() { - return getExtendedMethodName(false, false); - } - public String getClassAndMethodNameWithParams() { - return getExtendedMethodName(true, false); - } - public String getFullMethodName() { - return getExtendedMethodName(true, true); + return fullMethodName; } - + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); if (includeReturnType && returnTypeName.length() > 0) { @@ -158,4 +117,8 @@ public String getExtendedMethodName(boolean includeParams, boolean includeReturn } return builder.toString(); } + + private String constructClassAndMethodNameWithParams() { + return getExtendedMethodName(true, false); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index 09710793cba7..dd311ed1807a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -57,6 +57,7 @@ public boolean isAddToStrSection() { public void setAddToStrSection() { this.addToStrSection = true; } + @Override public boolean equals(Object object) { if (object == null || !(object instanceof StringEntry)) { return false; @@ -65,9 +66,11 @@ public boolean equals(Object object) { return this == other || string.equals(other.string); } } + @Override public int hashCode() { return string.hashCode() + 37; } + @Override public String toString() { return string; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index faa2b8ef3b61..9ebc74a69bfd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -37,7 +37,7 @@ public class StringTable implements Iterable { private final HashMap table; public StringTable() { - this.table = new HashMap(); + this.table = new HashMap<>(); } public String uniqueString(String string) { @@ -68,6 +68,7 @@ public int debugStringIndex(String string) { } return stringEntry.getOffset(); } + @Override public Iterator iterator() { return table.values().iterator(); } From bfe928fd8e50e2ccd2e3e921b6f8491f3bd6bc8c Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 15:10:17 +0000 Subject: [PATCH 008/130] fixed eclipseformat style issues --- .../src/com/oracle/objectfile/ObjectFile.java | 2 +- .../debuginfo/DebugInfoProvider.java | 27 +- .../oracle/objectfile/elf/ELFObjectFile.java | 18 +- .../objectfile/elf/dwarf/ClassEntry.java | 22 +- .../oracle/objectfile/elf/dwarf/DirEntry.java | 1 - .../objectfile/elf/dwarf/DwarfSections.java | 316 ++++++++++-------- .../objectfile/elf/dwarf/FileEntry.java | 2 + .../objectfile/elf/dwarf/PrimaryEntry.java | 17 + .../oracle/objectfile/elf/dwarf/Range.java | 8 +- .../objectfile/elf/dwarf/StringEntry.java | 9 + .../objectfile/elf/dwarf/StringTable.java | 1 + .../svm/hosted/image/NativeBootImage.java | 45 ++- 12 files changed, 317 insertions(+), 151 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index beabb431a50a..509e7fbfd5ce 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1082,7 +1082,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // support for consuming debug info - public void installDebugInfo( @SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { + public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default } 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 7c4d3757e227..cf6daf5ec247 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 @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.debuginfo; + import java.util.List; // class defining interfaces used to allow a native image @@ -39,15 +40,25 @@ interface DebugTypeInfo { // access details of a specific compiled method interface DebugCodeInfo { String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); + DebugLineInfoProvider lineInfoProvider(); + String paramNames(); + String returnTypeName(); + int getFrameSize(); + List getFrameSizeChanges(); } @@ -58,16 +69,26 @@ interface DebugDataInfo { // access details of a specific outer or inlined method at a given line number interface DebugLineInfo { String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); } interface DebugFrameSizeChange { - enum Type {EXTEND, CONTRACT} + enum Type { + EXTEND, + CONTRACT + } + int getOffset(); + DebugFrameSizeChange.Type getType(); } @@ -80,7 +101,7 @@ interface DebugCodeInfoProvider extends Iterable { } // convenience interface defining iterator type - interface DebugLineInfoProvider extends Iterable{ + interface DebugLineInfoProvider extends Iterable { } // convenience interface defining iterator type @@ -88,6 +109,8 @@ interface DebugDataInfoProvider extends Iterable { } DebugTypeInfoProvider typeInfoProvider(); + DebugCodeInfoProvider codeInfoProvider(); + DebugDataInfoProvider dataInfoProvider(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index aa28733c56ee..936938f5e19f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1169,12 +1169,18 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - @SuppressWarnings("unused") ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - @SuppressWarnings("unused") ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - @SuppressWarnings("unused") ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - @SuppressWarnings("unused") ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - @SuppressWarnings("unused") ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - @SuppressWarnings("unused") ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + @SuppressWarnings("unused") + ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + @SuppressWarnings("unused") + ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + @SuppressWarnings("unused") + ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + @SuppressWarnings("unused") + ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + @SuppressWarnings("unused") + ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + @SuppressWarnings("unused") + ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 4421181710e7..8522cdff9ca6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.elf.dwarf; + import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import java.util.HashMap; @@ -32,12 +33,12 @@ import java.util.List; import java.util.Map; -public class ClassEntry { +public class ClassEntry { // the name of the associated class private String className; // the associated file FileEntry fileEntry; - // a list recording details of all primary ranges included in + // a list recording details of all primary ranges included in // this class sorted by ascending address range private LinkedList primaryEntries; // an index identifying primary ranges which have already been encountered @@ -60,7 +61,7 @@ public class ClassEntry { private int totalSize; public ClassEntry(String className, FileEntry fileEntry) { - this.className = className; + this.className = className; this.fileEntry = fileEntry; this.primaryEntries = new LinkedList<>(); this.primaryIndex = new HashMap<>(); @@ -90,6 +91,7 @@ PrimaryEntry addPrimary(Range primary, List frameSizeInfos } return null; } + void addSubRange(Range subrange, FileEntry subFileEntry) { Range primary = subrange.getPrimary(); // the subrange should belong to a primary range @@ -109,6 +111,7 @@ void addSubRange(Range subrange, FileEntry subFileEntry) { localDirsIndex.put(dirEntry, localDirs.size()); } } + public int localDirsIdx(DirEntry dirEntry) { if (dirEntry != null) { return localDirsIndex.get(dirEntry); @@ -135,44 +138,57 @@ void setCUIndex(int cuIndex) { assert this.cuIndex == -1; this.cuIndex = cuIndex; } + int getCUIndex() { // should have been set before being read assert cuIndex >= 0; return cuIndex; } + int getLineIndex() { return lineIndex; } + void setLineIndex(int lineIndex) { this.lineIndex = lineIndex; } + public void setLinePrologueSize(int linePrologueSize) { this.linePrologueSize = linePrologueSize; } + public int getLinePrologueSize() { return linePrologueSize; } + public int getTotalSize() { return totalSize; } + public void setTotalSize(int totalSize) { this.totalSize = totalSize; } + public FileEntry getFileEntry() { return fileEntry; } + public String getClassName() { return className; } + public LinkedList getPrimaryEntries() { return primaryEntries; } + public Object primaryIndexFor(Range primaryRange) { return primaryIndex.get(primaryRange); } + public LinkedList getLocalDirs() { return localDirs; } + public LinkedList getLocalFiles() { return localFiles; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 1ce68980f93a..89d0b81bb8f0 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -49,4 +49,3 @@ public String getPath() { return path; } } - diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 19008f6ba50d..d01a90b24688 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.elf.dwarf; + import com.oracle.objectfile.BasicProgbitsSectionImpl; import com.oracle.objectfile.BuildDependency; import com.oracle.objectfile.LayoutDecision; @@ -108,9 +109,8 @@ public class DwarfSections { // private static final byte DW_ACCESS_protected = 2; // private static final byte DW_ACCESS_private = 3; - // not yet needed - // private static final int DW_AT_type = 0; // only present for non-void functions + // private static final int DW_AT_type = 0; // only present for non-void functions // private static final int DW_AT_accessibility = 0; // CIE and FDE entries @@ -156,8 +156,8 @@ public DwarfSections(ELFMachine elfMachine) { dwarfARangesSection = new DwarfARangesSectionImpl(); dwarfLineSection = new DwarfLineSectionImpl(); dwarfFameSection = (elfMachine == ELFMachine.AArch64 - ? new DwarfFrameSectionImplAArch64() - : new DwarfFrameSectionImplX86_64()); + ? new DwarfFrameSectionImplAArch64() + : new DwarfFrameSectionImplX86_64()); } public DwarfStrSectionImpl getStrSectionImpl() { @@ -205,7 +205,7 @@ public ELFMachine getElfMachine() { // 2) by inlined method (sub range) within top level method ordered by ascending address // this ensures that all debug records are generated in increasing address order - // a list recording details of all primary ranges included in + // a list recording details of all primary ranges included in // this file sorted by ascending address range private LinkedList primaryEntries = new LinkedList<>(); @@ -271,7 +271,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, returnTypeName, className, methodName, paramNames, fileName); + // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, + // returnTypeName, className, methodName, paramNames, fileName); // create an infoSection entry for the method addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { @@ -280,8 +281,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { String methodNameAtLine = debugLineInfo.methodName(); int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); - int line = debugLineInfo.line(); - // record all subranges even if they have no line or file so we at least get a symbol for them + int line = debugLineInfo.line(); + // record all subranges even if they have no line or file so we at least get a + // symbol for them Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); } @@ -299,7 +301,7 @@ public ClassEntry ensureClassEntry(Range range) { ClassEntry classEntry = primaryClassesIndex.get(className); if (classEntry == null) { // create and index the entry associating it with the right file - FileEntry fileEntry = ensureFileEntry(range); + FileEntry fileEntry = ensureFileEntry(range); classEntry = new ClassEntry(className, fileEntry); primaryClasses.add(classEntry); primaryClassesIndex.put(className, classEntry); @@ -316,8 +318,8 @@ public FileEntry ensureFileEntry(Range range) { DirEntry dirEntry = ensureDirEntry(fileName); String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), - stringTable.uniqueString(baseName), - dirEntry); + stringTable.uniqueString(baseName), + dirEntry); files.add(fileEntry); filesIndex.put(fileName, fileEntry); // if this is a primary entry then add it to the primary list @@ -381,12 +383,14 @@ public DwarfSectionImpl() { } public abstract void createContent(); + public abstract void writeContent(); + public void checkDebug(int pos) { // if the env var relevant to this element // type is set then switch on debugging String name = getSectionName(); - String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); + String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { debug = true; debugBase = pos; @@ -394,7 +398,7 @@ public void checkDebug(int pos) { } } - protected void debug(String format, Object ... args) { + protected void debug(String format, Object... args) { if (debug) { System.out.format(format, args); } @@ -405,11 +409,13 @@ public int putByte(byte b, byte[] buffer, int pos) { buffer[pos++] = b; return pos; } + public int putShort(short s, byte[] buffer, int pos) { buffer[pos++] = (byte) (s & 0xff); buffer[pos++] = (byte) ((s >> 8) & 0xff); return pos; } + public int putInt(int i, byte[] buffer, int pos) { buffer[pos++] = (byte) (i & 0xff); buffer[pos++] = (byte) ((i >> 8) & 0xff); @@ -417,6 +423,7 @@ public int putInt(int i, byte[] buffer, int pos) { buffer[pos++] = (byte) ((i >> 24) & 0xff); return pos; } + public int putLong(long l, byte[] buffer, int pos) { buffer[pos++] = (byte) (l & 0xff); buffer[pos++] = (byte) ((l >> 8) & 0xff); @@ -428,12 +435,14 @@ public int putLong(long l, byte[] buffer, int pos) { buffer[pos++] = (byte) ((l >> 56) & 0xff); return pos; } + public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { // mark address so it is relocated relative to the start of the text segment markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); pos = putLong(0, buffer, pos); return pos; } + public int putULEB(long l, byte[] buffer, int pos) { for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); @@ -449,6 +458,7 @@ public int putULEB(long l, byte[] buffer, int pos) { } return pos; } + public int putSLEB(long l, byte[] buffer, int pos) { boolean negative = l < 0; for (int i = 0; i < 9; i++) { @@ -466,9 +476,11 @@ public int putSLEB(long l, byte[] buffer, int pos) { } return pos; } + public int putAsciiStringBytes(String s, byte[] buffer, int pos) { return putAsciiStringBytes(s, 0, buffer, pos); } + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); @@ -505,6 +517,7 @@ public int writeTag(long code, byte[] buffer, int pos) { return putSLEB(code, buffer, pos); } } + public int writeFlag(byte flag, byte[] buffer, int pos) { if (buffer == null) { return pos + putByte(flag, scratch, 0); @@ -554,16 +567,11 @@ public int writeAttrNull(byte[] buffer, int pos) { } public abstract String targetSectionName(); + public abstract LayoutDecision.Kind[] targetSectionKinds(); public abstract String getSectionName(); - /* - @Override - public int getOrDecideSize(Map alreadyDecided, int sizeHint) { - return super.getOrDecideSize(alreadyDecided, sizeHint); - } - */ @Override public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { // ensure content byte[] has been created before calling super method @@ -580,12 +588,12 @@ public Set getDependencies(Map deci Set deps = super.getDependencies(decisions); String targetName = targetSectionName(); ELFSection targetSection = (ELFSection) getElement().getOwner().elementForName(targetName); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); LayoutDecision.Kind[] targetKinds = targetSectionKinds(); // make our content depend on the size and content of the target for (LayoutDecision.Kind targetKind : targetKinds) { - LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); } // make our size depend on our content @@ -608,7 +616,7 @@ public String getSectionName() { @Override public void createContent() { int pos = 0; - for (StringEntry stringEntry : stringTable) { + for (StringEntry stringEntry : stringTable) { if (stringEntry.isAddToStrSection()) { stringEntry.setOffset(pos); String string = stringEntry.getString(); @@ -627,7 +635,7 @@ public void writeContent() { checkDebug(pos); - for (StringEntry stringEntry : stringTable) { + for (StringEntry stringEntry : stringTable) { if (stringEntry.isAddToStrSection()) { assert stringEntry.getOffset() == pos; String string = stringEntry.getString(); @@ -644,14 +652,17 @@ protected void debug(String format, Object... args) { // .debug_str section content depends on text section content and offset public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; @@ -679,18 +690,18 @@ public void createContent() { // terminated by a null entry // // a null entry has consists of just a 0 abbrev code - // LEB128 abbrev_code; // == 0 + // LEB128 abbrev_code; ...... == 0 // // non-null entries have the following format - // LEB128 abbrev_code; // unique noncode for this layout != 0 - // 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 DIE - // * // zero or more attributes - // // terminator + // LEB128 abbrev_code; ...... unique noncode for this layout != 0 + // 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 DIE + // * ........ zero or more attributes + // .... terminator // // An attribute_spec consists of an attribute name and form - // LEB128 attr_name; // 0 for the null attribute name - // LEB128 attr_form; // 0 for the null attribute form + // LEB128 attr_name; ........ 0 for the null attribute name + // LEB128 attr_form; ........ 0 for the null attribute form // // For the moment we only use one abbrev table for all CUs. // It contains two DIEs, the first to describe the compilation @@ -700,17 +711,17 @@ public void createContent() { // The DIE layouts are as follows: // // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - // DW_AT_language : DW_FORM_data1 - // DW_AT_name : DW_FORM_strp - // DW_AT_low_pc : DW_FORM_address - // DW_AT_hi_pc : DW_FORM_address - // DW_AT_stmt_list : DW_FORM_data4 + // DW_AT_language : ... DW_FORM_data1 + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_address + // DW_AT_hi_pc : ...... DW_FORM_address + // DW_AT_stmt_list : .. DW_FORM_data4 // // abbrev_code == 2, tag == DW_TAG_subprogram, no_children - // DW_AT_name : DW_FORM_strp - // DW_AT_low_pc : DW_FORM_addr - // DW_AT_hi_pc : DW_FORM_addr - // DW_AT_external : DW_FORM_flag + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_addr + // DW_AT_hi_pc : ...... DW_FORM_addr + // DW_AT_external : ... DW_FORM_flag pos = writeAbbrev1(null, pos); pos = writeAbbrev2(null, pos); @@ -727,7 +738,7 @@ public void writeContent() { checkDebug(pos); - pos = writeAbbrev1(buffer, pos); + pos = writeAbbrev1(buffer, pos); pos = writeAbbrev2(buffer, pos); assert pos == size; } @@ -795,14 +806,17 @@ protected void debug(String format, Object... args) { // .debug_abbrev section content depends on .debug_frame section content and offset public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; @@ -856,14 +870,14 @@ public int writeCIE(byte[] buffer, int pos) { // because we have to have at least one // the layout is // - // uint32 : length // length of remaining fields in this CIE - // uint32 : CIE_id // unique id for CIE == 0xffffff - // uint8 : version // == 1 - // uint8[] : augmentation // == "" so always 1 byte - // ULEB : code_alignment_factor // 1 (could use 4 for Aarch64) - // ULEB : data_alignment_factor // -8 - // byte : ret_addr reg id // x86_64 => 16 AArch64 => 32 - // byte[] : initial_instructions // includes pad to 8-byte boundary + // uint32 : length ............... length of remaining fields in this CIE + // uint32 : CIE_id ................ unique id for CIE == 0xffffff + // uint8 : version ................ == 1 + // uint8[] : augmentation ......... == "" so always 1 byte + // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + // ULEB : data_alignment_factor ... == -8 + // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + // byte[] : initial_instructions .. includes pad to 8-byte boundary if (buffer == null) { pos += putInt(0, scratch, 0); // don't care about length pos += putInt(DW_CFA_CIE_id, scratch, 0); @@ -928,22 +942,22 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { // we only need a vanilla FDE header with default fields // the layout is // - // uint32 : length // length of remaining fields in this FDE - // uint32 : CIE_offset // alwasy 0 i.e. identifies our only CIE header - // uint64 : initial_location // i.e. method lo address - // uint64 : address_range // i.e. method hi - lo - // byte[] : instructions // includes pad to 8-byte boundary + // uint32 : length ........... length of remaining fields in this FDE + // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + // uint64 : initial_location .. i.e. method lo address + // uint64 : address_range ..... i.e. method hi - lo + // byte[] : instructions ...... includes pad to 8-byte boundary int lengthPos = pos; if (buffer == null) { pos += putInt(0, scratch, 0); // dummy length pos += putInt(0, scratch, 0); // CIE_offset - pos += putLong(lo, scratch, 0); // initial address + pos += putLong(lo, scratch, 0); // initial address return pos + putLong(hi - lo, scratch, 0); // address range } else { pos = putInt(0, buffer, pos); // dummy length pos = putInt(0, buffer, pos); // CIE_offset - pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address + pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address return putLong(hi - lo, buffer, pos); // address range } } @@ -971,6 +985,7 @@ public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { return putULEB(offset, buffer, pos); } } + public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { if (buffer == null) { pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); @@ -980,6 +995,7 @@ public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { return putULEB(offset, buffer, pos); } } + public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { if (offset <= 0x3f) { return writeAdvanceLoc0((byte) offset, buffer, pos); @@ -991,6 +1007,7 @@ public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { return writeAdvanceLoc4(offset, buffer, pos); } } + public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { byte op = advanceLoc0Op(offset); if (buffer == null) { @@ -999,6 +1016,7 @@ public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { return putByte(op, buffer, pos); } } + public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { byte op = DW_CFA_advance_loc1; if (buffer == null) { @@ -1009,6 +1027,7 @@ public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { return putByte(offset, buffer, pos); } } + public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { byte op = DW_CFA_advance_loc2; if (buffer == null) { @@ -1019,6 +1038,7 @@ public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { return putShort(offset, buffer, pos); } } + public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { byte op = DW_CFA_advance_loc4; if (buffer == null) { @@ -1029,6 +1049,7 @@ public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { return putInt(offset, buffer, pos); } } + public int writeOffset(int register, int offset, byte[] buffer, int pos) { byte op = offsetOp(register); if (buffer == null) { @@ -1039,6 +1060,7 @@ public int writeOffset(int register, int offset, byte[] buffer, int pos) { return putULEB(offset, buffer, pos); } } + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { if (buffer == null) { pos += putByte(DW_CFA_register, scratch, 0); @@ -1052,31 +1074,39 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { } public abstract int getPCIdx(); + public abstract int getSPIdx(); + public abstract int writeInitialInstructions(byte[] buffer, int pos); @Override protected void debug(String format, Object... args) { super.debug(format, args); } + // .debug_frame section content depends on .debug_line section content and offset public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } + private byte offsetOp(int register) { assert (register >> 6) == 0; return (byte) ((DW_CFA_offset << 6) | register); } + private byte advanceLoc0Op(int offset) { assert (offset >= 0 && offset <= 0x3f); return (byte) ((DW_CFA_advance_loc << 6) | offset); @@ -1090,21 +1120,25 @@ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public DwarfFrameSectionImplX86_64() { super(); } + @Override public int getPCIdx() { return DW_CFA_RIP_IDX; } + @Override public int getSPIdx() { return DW_CFA_RSP_IDX; } + @Override public int writeInitialInstructions(byte[] buffer, int pos) { // rsp points at the word containing the saved rip // so the frame base (cfa) is at rsp + 8 (why not - ???) // def_cfa r7 (sp) offset 8 pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); - // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa (why not -1 ???) + // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + // (why not -1 ???) // offset r16 (rip) cfa - 8 pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; @@ -1120,14 +1154,17 @@ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { public DwarfFrameSectionImplAArch64() { super(); } + @Override public int getPCIdx() { return DW_CFA_PC_IDX; } + @Override public int getSPIdx() { return DW_CFA_SP_IDX; } + @Override public int writeInitialInstructions(byte[] buffer, int pos) { // rsp has not been updated @@ -1156,12 +1193,12 @@ public void createContent() { // we need a single level 0 DIE for each compilation unit (CU) // Each CU's Level 0 DIE is preceded by a fixed header: // and terminated by a null DIE - // uint32 length // excluding this length field - // uint16 dwarf_version // always 2 ?? - // uint32 abbrev offset // always 0 ?? - // uint8 address_size // always 8 - // * // sequence of top-level and nested child entries - // // == 0 + // uint32 length ......... excluding this length field + // uint16 dwarf_version .. always 2 ?? + // uint32 abbrev offset .. always 0 ?? + // uint8 address_size .... always 8 + // * ................ sequence of top-level and nested child entries + // ............ == 0 // // a DIE is a recursively defined structure // it starts with a code for the associated @@ -1170,13 +1207,13 @@ public void createContent() { // a null value and followed by zero or more child // DIEs (zero iff has_children == no_children) // - // LEB128 abbrev_code != 0 // non-zero value indexes tag + attr layout of DIE - // * // value sequence as determined by abbrev entry - // * // sequence of child DIEs (if appropriate) - // // == 0 + // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + // * ....... value sequence as determined by abbrev entry + // * ................... sequence of child DIEs (if appropriate) + // ............. == 0 // // note that a null_DIE looks like - // LEB128 abbrev_code == 0 + // LEB128 abbrev_code ....... == 0 // i.e. it also looks like a null_value byte[] buffer = null; @@ -1231,6 +1268,7 @@ public int writeCUHeader(byte[] buffer, int pos) { return putByte((byte) 8, buffer, pos); // address size } } + public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); @@ -1252,7 +1290,8 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { return writeAttrNull(buffer, pos); } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { + + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); @@ -1266,6 +1305,7 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) debug(" [0x%08x] external true\n", pos); return writeFlag(DW_FLAG_true, buffer, pos); } + public int writeAttrStrp(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(0, scratch, 0); @@ -1274,6 +1314,7 @@ public int writeAttrStrp(String value, byte[] buffer, int pos) { return putInt(idx, buffer, pos); } } + public int writeAttrString(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + value.length() + 1; @@ -1293,14 +1334,17 @@ protected void debug(String format, Object... args) { // .debug_info section content depends on abbrev section content and offset public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; @@ -1325,21 +1369,21 @@ public void createContent() { int pos = 0; // we need an entry for each compilation unit // - // uint32 length // in bytes (not counting these 4 bytes) - // uint16 dwarf_version // always 2 - // uint32 info_offset // offset of compilation unit on debug_info - // uint8 address_size // always 8 - // uint8 segment_desc_size // ??? + // uint32 length ............ in bytes (not counting these 4 bytes) + // uint16 dwarf_version ..... always 2 + // uint32 info_offset ....... offset of compilation unit on debug_info + // uint8 address_size ....... always 8 + // uint8 segment_desc_size .. ??? // // i.e. 12 bytes followed by padding // aligning up to 2 * address size // - // uint8 pad[4] + // uint8 pad[4] // // followed by N + 1 times // - // uint64 lo // lo address of range - // uint64 length // number of bytes in range + // uint64 lo ................ lo address of range + // uint64 length ............ number of bytes in range // // where N is the number of ranges belonging to the compilation unit // and the last range contains two zeroes @@ -1420,19 +1464,22 @@ protected void debug(String format, Object... args) { // .debug_aranges section content depends on .debug_info section content and offset public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } - } + } public class DwarfLineSectionImpl extends DwarfSectionImpl { // header section always contains fixed number of bytes @@ -1447,23 +1494,27 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * standard opcodes defined by Dwarf 2 */ - private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an invalid opcode - private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for extended opcodes - private static final byte DW_LNS_copy = 1; // append current state as matrix row 0 args + private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an + // invalid opcode + private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for + // extended opcodes + private static final byte DW_LNS_copy = 1; // append current state as matrix row + // 0 args private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row - private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode 255 0 args + private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode + // 255 0 args private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg /* * extended opcodes defined by Dwarf 2 */ private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 - private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses + private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 @@ -1489,7 +1540,7 @@ public void createContent() { int headerSize = headerSize(); int dirTableSize = computeDirTableSize(classEntry); int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; + int prologueSize = headerSize + dirTableSize + fileTableSize; classEntry.setLinePrologueSize(prologueSize); int lineNumberTableSize = computeLineNUmberTableSize(classEntry); int totalSize = prologueSize + lineNumberTableSize; @@ -1502,16 +1553,16 @@ public void createContent() { public int headerSize() { // header size is standard 31 bytes - // uint32 total_length - // uint16 version - // uint32 prologue_length - // uint8 min_insn_length - // uint8 default_is_stmt - // int8 line_base - // uint8 line_range - // uint8 opcode_base - // uint8 li_opcode_base - // uint8[opcode_base-1] standard_opcode_lengths + // uint32 total_length + // uint16 version + // uint32 prologue_length + // uint8 min_insn_length + // uint8 default_is_stmt + // int8 line_base + // uint8 line_range + // uint8 opcode_base + // uint8 li_opcode_base + // uint8[opcode_base-1] standard_opcode_lengths return DW_LN_HEADER_SIZE; } @@ -1681,7 +1732,6 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { public int debugLine = 1; public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // the primary file entry should always be first in the local files list assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; @@ -1713,7 +1763,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // boolean end_sequence = false; // set state for primary - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), + primaryRange.getLine()); // initialize and write a row for the start of the primary method pos = putSetFile(file, fileIdx, buffer, pos); @@ -1746,7 +1797,6 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { subFileIdx = fileIdx; debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); } - /* // there is a temptation to append end sequence at here // when the hiAddress lies strictly between the current // address and the start of the next subrange because, @@ -1757,27 +1807,28 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // so the code below is not actually needed. it is left in // to clarify i) that this is a deliberate choice and ii) what // that deliberate choice is avoiding. - if (address < hiAddress && hiAddress < subAddressLo) { - long addressDelta = hiAddress - address; - // increment address to hi address, write an - // end sequence and update state to new range - pos = putAdvancePC(addressDelta, buffer, pos); - pos = putEndSequence(buffer, pos); - file = subfile; - fileIdx = subFileIdx; - pos = putSetFile(file, fileIdx, buffer, pos); - line = subLine; - // state machine value of line is currently 1 - // increment to desired line - if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); + if (false) { + if (address < hiAddress && hiAddress < subAddressLo) { + long addressDelta = hiAddress - address; + // increment address to hi address, write an + // end sequence and update state to new rang + pos = putAdvancePC(addressDelta, buffer, pos); + pos = putEndSequence(buffer, pos); + file = subfile; + fileIdx = subFileIdx; + pos = putSetFile(file, fileIdx, buffer, pos); + line = subLine; + // state machine value of line is currently 1 + // increment to desired line + if (line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putSetBasicBlock(buffer, pos); + // use a reloc to ensure address is relative to text base + address = hiAddress; + pos = putSetAddress(hiAddress, buffer, pos); } - pos = putSetBasicBlock(buffer, pos); - // use a reloc to ensure address is relative to text base - address = hiAddress; - pos = putSetAddress(hiAddress, buffer, pos); } - */ // if we have to update to a new file then do so if (subFileIdx != fileIdx) { // update the current file @@ -2055,7 +2106,7 @@ public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) { debugAddress += opcodeAddress(opcode); debugLine += opcodeLine(opcode); debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, pos); } } @@ -2102,15 +2153,18 @@ public boolean isFixedAdvancePC(long addressDiff) { // .debug_line section content depends on .debug_str section content and offset public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index 5a4ed796d8dc..3a8943cabdf6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -43,9 +43,11 @@ public FileEntry(String fileName, String baseName, DirEntry dirEntry) { public String getFileName() { return fileName; } + public String getBaseName() { return baseName; } + String getDirName() { return (dirEntry != null ? dirEntry.getPath() : ""); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index cdc84b9c4961..a26d060c8859 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; + public class PrimaryEntry { // the primary range detailed by this object Range primary; @@ -64,6 +65,7 @@ public PrimaryEntry(Range primary, List frameSizeInfos, in this.cuIndex = -1; this.lineIndex = -1; } + public void addSubRange(Range subrange, FileEntry subFileEntry) { // we should not see a subrange more than once assert !subranges.contains(subrange); @@ -73,58 +75,73 @@ public void addSubRange(Range subrange, FileEntry subFileEntry) { subranges.add(subrange); subrangeIndex.put(subrange, subFileEntry); } + public Range getPrimary() { return primary; } + public ClassEntry getClassEntry() { return classEntry; } + public FileEntry getFileEntry() { return classEntry.getFileEntry(); } + public List getSubranges() { return subranges; } + public FileEntry getSubrangeFileEntry(Range subrange) { return subrangeIndex.get(subrange); } + List getFrameSizeInfos() { return frameSizeInfos; } + int getFrameSize() { return frameSize; } + void setCUIndex(int cuIndex) { // should only get set once to a non-negative value assert cuIndex >= 0; assert this.cuIndex == -1; this.cuIndex = cuIndex; } + int getCUIndex() { // should have been set before being read assert cuIndex >= 0; return cuIndex; } + int getLineIndex() { // should have been set before being read assert lineIndex >= 0; return lineIndex; } + void setLineIndex(int lineIndex) { // should only get set once to a non-negative value assert lineIndex >= 0; assert this.lineIndex == -1; this.lineIndex = lineIndex; } + public int getLinePrologueSize() { return linePrologueSize; } + public void setLinePrologueSize(int linePrologueSize) { this.linePrologueSize = linePrologueSize; } + public int getTotalSize() { return totalSize; } + public void setTotalSize(int totalSize) { this.totalSize = totalSize; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 9e72991dcc88..6692d23b7df6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -80,25 +80,31 @@ public Range getPrimary() { public String getFileName() { return fileName; } + public String getClassName() { return className; } + public String getMethodName() { return methodName; } + public int getHi() { return hi; } + public int getLo() { return lo; } + public int getLine() { return line; } + public String getFullMethodName() { return fullMethodName; } - + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); if (includeReturnType && returnTypeName.length() > 0) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index dd311ed1807a..a96e5eb19e6a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -38,25 +38,31 @@ public class StringEntry { this.string = string; this.offset = -1; } + public String getString() { return string; } + public int getOffset() { // offset must be set before this can be fetched assert offset >= 0; return offset; } + public void setOffset(int offset) { assert this.offset < 0; assert offset >= 0; this.offset = offset; } + public boolean isAddToStrSection() { return addToStrSection; } + public void setAddToStrSection() { this.addToStrSection = true; } + @Override public boolean equals(Object object) { if (object == null || !(object instanceof StringEntry)) { @@ -66,14 +72,17 @@ public boolean equals(Object object) { return this == other || string.equals(other.string); } } + @Override public int hashCode() { return string.hashCode() + 37; } + @Override public String toString() { return string; } + public boolean isEmpty() { return string.length() == 0; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 9ebc74a69bfd..74506877df94 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -68,6 +68,7 @@ public int debugStringIndex(String string) { } return stringEntry.getOffset(); } + @Override public Iterator iterator() { return table.values().iterator(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index a99b53b47d06..0f31e3da21b5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -987,19 +987,22 @@ private class NativeImageDebugInfoProvider implements DebugInfoProvider { this.codeCacheIterator = codeCache.compilations.entrySet().iterator(); this.heapIterator = heap.objects.entrySet().iterator(); } + @Override - public DebugTypeInfoProvider typeInfoProvider() { + public DebugTypeInfoProvider typeInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { return false; } + @Override public DebugTypeInfo next() { return null; } }; } + @Override public DebugCodeInfoProvider codeInfoProvider() { return () -> new Iterator() { @@ -1007,6 +1010,7 @@ public DebugCodeInfoProvider codeInfoProvider() { public boolean hasNext() { return codeCacheIterator.hasNext(); } + @Override public DebugCodeInfo next() { Map.Entry entry = codeCacheIterator.next(); @@ -1014,13 +1018,15 @@ public DebugCodeInfo next() { } }; } + @Override - public DebugDataInfoProvider dataInfoProvider() { + public DebugDataInfoProvider dataInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { return false; } + @Override public DebugDataInfo next() { return null; @@ -1032,13 +1038,15 @@ public DebugDataInfo next() { private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; + NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; this.compilation = compilation; } + @Override public String fileName() { - HostedType declaringClass = method.getDeclaringClass(); + HostedType declaringClass = method.getDeclaringClass(); String name = declaringClass.getSourceFileName(); if (name != null) { // the file name will not include any path @@ -1066,30 +1074,37 @@ public String fileName() { } return name; } + @Override public String className() { return method.format("%H"); } + @Override public String methodName() { return method.format("%n"); } + @Override public String paramNames() { return method.format("%P"); } + @Override public String returnTypeName() { return method.format("%R"); } + @Override public int addressLo() { return method.getCodeAddressOffset(); } + @Override public int addressHi() { return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); } + @Override public int line() { LineNumberTable lineNumberTable = method.getLineNumberTable(); @@ -1098,6 +1113,7 @@ public int line() { } return -1; } + @Override public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { if (fileName().length() == 0) { @@ -1106,6 +1122,7 @@ public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { public boolean hasNext() { return false; } + @Override public DebugLineInfo next() { return null; @@ -1114,19 +1131,23 @@ public DebugLineInfo next() { } return () -> new Iterator() { final Iterator sourceIterator = compilation.getSourceMappings().iterator(); + @Override public boolean hasNext() { return sourceIterator.hasNext(); } + @Override public DebugLineInfo next() { return new NativeImageDebugLineInfo(sourceIterator.next()); } }; } + public int getFrameSize() { return compilation.getTotalFrameSize(); } + public List getFrameSizeChanges() { List frameSizeChanges = new LinkedList<>(); for (Mark mark : compilation.getMarks()) { @@ -1134,24 +1155,26 @@ public List getFrameSizeChanges() { if (mark.id.equals("PROLOGUE_DECD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); frameSizeChanges.add(sizeChange); - // } else if (mark.id.equals("PROLOGUE_END")) { + // } else if (mark.id.equals("PROLOGUE_END")) { // can ignore these - // } else if (mark.id.equals("EPILOGUE_START")) { + // } else if (mark.id.equals("EPILOGUE_START")) { // can ignore these } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); frameSizeChanges.add(sizeChange); - // } else if(mark.id.equals("EPILOGUE_END")) { + // } else if(mark.id.equals("EPILOGUE_END")) { } } return frameSizeChanges; } } + private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; private final ResolvedJavaMethod method; private final int lo; private final int hi; + NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); int bci = position.getBCI(); @@ -1160,6 +1183,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { this.lo = sourceMapping.getStartOffset(); this.hi = sourceMapping.getEndOffset(); } + @Override public String fileName() { String name = className(); @@ -1174,22 +1198,27 @@ public String fileName() { } return name.replace('.', '/') + ".java"; } + @Override public String className() { return method.format("%H"); } + @Override public String methodName() { return method.format("%n"); } + @Override public int addressLo() { return lo; } + @Override public int addressHi() { return hi; } + @Override public int line() { LineNumberTable lineNumberTable = method.getLineNumberTable(); @@ -1199,17 +1228,21 @@ public int line() { return -1; } } + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; private Type type; + NativeImageDebugFrameSizeChange(int offset, Type type) { this.offset = offset; this.type = type; } + @Override public int getOffset() { return offset; } + @Override public Type getType() { return type; From 0b2bbc402174644bbf8a2a475cb35865eec37f7e Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 15:59:37 +0000 Subject: [PATCH 009/130] more style whackamole --- .../objectfile/elf/dwarf/DwarfSections.java | 183 +++++++++++------- 1 file changed, 114 insertions(+), 69 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index d01a90b24688..5cb930219ea7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -65,7 +65,7 @@ public class DwarfSections { private static final short DW_VERSION_2 = 2; // define all the abbrev section codes we need for our DIEs - private static final int DW_ABBREV_CODE_null = 0; + // private static final int DW_ABBREV_CODE_null = 0; private static final int DW_ABBREV_CODE_compile_unit = 1; private static final int DW_ABBREV_CODE_subprogram = 2; @@ -75,7 +75,7 @@ public class DwarfSections { // define all the Dwarf attributes we need for our DIEs private static final int DW_AT_null = 0x0; private static final int DW_AT_name = 0x3; - private static final int DW_AT_comp_dir = 0x1b; + // private static final int DW_AT_comp_dir = 0x1b; private static final int DW_AT_stmt_list = 0x10; private static final int DW_AT_low_pc = 0x11; private static final int DW_AT_hi_pc = 0x12; @@ -85,13 +85,13 @@ public class DwarfSections { private static final int DW_AT_frame_base = 0x40; // define all the Dwarf attribute forms we need for our DIEs private static final int DW_FORM_null = 0x0; - private static final int DW_FORM_string = 0x8; + // private static final int DW_FORM_string = 0x8; private static final int DW_FORM_strp = 0xe; // not currently used private static final int DW_FORM_addr = 0x1; private static final int DW_FORM_data1 = 0x0b; // use flag instead private static final int DW_FORM_data4 = 0x6; - private static final int DW_FORM_data8 = 0x7; - private static final int DW_FORM_block1 = 0x0a; + // private static final int DW_FORM_data8 = 0x7; + // private static final int DW_FORM_block1 = 0x0a; private static final int DW_FORM_flag = 0xc; // define specific attribute values for given attribute or form types @@ -115,30 +115,30 @@ public class DwarfSections { // CIE and FDE entries - public static final int DW_CFA_CIE_id = -1; - public static final int DW_CFA_FDE_id = 0; + private static final int DW_CFA_CIE_id = -1; + // private static final int DW_CFA_FDE_id = 0; - public static final byte DW_CFA_CIE_version = 1; + private static final byte DW_CFA_CIE_version = 1; // values for high 2 bits - public static final byte DW_CFA_advance_loc = 0x1; - public static final byte DW_CFA_offset = 0x2; - public static final byte DW_CFA_restore = 0x3; + private static final byte DW_CFA_advance_loc = 0x1; + private static final byte DW_CFA_offset = 0x2; + // private static final byte DW_CFA_restore = 0x3; // values for low 6 bits - public static final byte DW_CFA_nop = 0x0; - public static final byte DW_CFA_set_loc1 = 0x1; - public static final byte DW_CFA_advance_loc1 = 0x2; - public static final byte DW_CFA_advance_loc2 = 0x3; - public static final byte DW_CFA_advance_loc4 = 0x4; - public static final byte DW_CFA_offset_extended = 0x5; - public static final byte DW_CFA_restore_extended = 0x6; - public static final byte DW_CFA_undefined = 0x7; - public static final byte DW_CFA_same_value = 0x8; - public static final byte DW_CFA_register = 0x9; - public static final byte DW_CFA_def_cfa = 0xc; - public static final byte DW_CFA_def_cfa_register = 0xd; - public static final byte DW_CFA_def_cfa_offset = 0xe; + private static final byte DW_CFA_nop = 0x0; + // private static final byte DW_CFA_set_loc1 = 0x1; + private static final byte DW_CFA_advance_loc1 = 0x2; + private static final byte DW_CFA_advance_loc2 = 0x3; + private static final byte DW_CFA_advance_loc4 = 0x4; + // private static final byte DW_CFA_offset_extended = 0x5; + // private static final byte DW_CFA_restore_extended = 0x6; + // private static final byte DW_CFA_undefined = 0x7; + // private static final byte DW_CFA_same_value = 0x8; + private static final byte DW_CFA_register = 0x9; + private static final byte DW_CFA_def_cfa = 0xc; + // private static final byte DW_CFA_def_cfa_register = 0xd; + private static final byte DW_CFA_def_cfa_offset = 0xe; private ELFMachine elfMachine; private DwarfStrSectionImpl dwarfStrSection; @@ -405,18 +405,21 @@ protected void debug(String format, Object... args) { } // base level put methods that assume a non-null buffer - public int putByte(byte b, byte[] buffer, int pos) { + public int putByte(byte b, byte[] buffer, int p) { + int pos = p; buffer[pos++] = b; return pos; } - public int putShort(short s, byte[] buffer, int pos) { + public int putShort(short s, byte[] buffer, int p) { + int pos = p; buffer[pos++] = (byte) (s & 0xff); buffer[pos++] = (byte) ((s >> 8) & 0xff); return pos; } - public int putInt(int i, byte[] buffer, int pos) { + public int putInt(int i, byte[] buffer, int p) { + int pos = p; buffer[pos++] = (byte) (i & 0xff); buffer[pos++] = (byte) ((i >> 8) & 0xff); buffer[pos++] = (byte) ((i >> 16) & 0xff); @@ -424,7 +427,8 @@ public int putInt(int i, byte[] buffer, int pos) { return pos; } - public int putLong(long l, byte[] buffer, int pos) { + public int putLong(long l, byte[] buffer, int p) { + int pos = p; buffer[pos++] = (byte) (l & 0xff); buffer[pos++] = (byte) ((l >> 8) & 0xff); buffer[pos++] = (byte) ((l >> 16) & 0xff); @@ -443,7 +447,9 @@ public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { return pos; } - public int putULEB(long l, byte[] buffer, int pos) { + public int putULEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); l = l >>> 7; @@ -459,7 +465,9 @@ public int putULEB(long l, byte[] buffer, int pos) { return pos; } - public int putSLEB(long l, byte[] buffer, int pos) { + public int putSLEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; boolean negative = l < 0; for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); @@ -481,7 +489,8 @@ public int putAsciiStringBytes(String s, byte[] buffer, int pos) { return putAsciiStringBytes(s, 0, buffer, pos); } - public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { + int pos = p; for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); if (c > 127) { @@ -759,7 +768,8 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { } } - public int writeAbbrev1(byte[] buffer, int pos) { + public int writeAbbrev1(byte[] buffer, int p) { + int pos = p; // abbrev 1 compile unit pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); pos = writeTag(DW_TAG_compile_unit, buffer, pos); @@ -780,7 +790,8 @@ public int writeAbbrev1(byte[] buffer, int pos) { return pos; } - public int writeAbbrev2(byte[] buffer, int pos) { + public int writeAbbrev2(byte[] buffer, int p) { + int pos = p; // abbrev 2 compile unit pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); pos = writeTag(DW_TAG_subprogram, buffer, pos); @@ -865,7 +876,7 @@ public void writeContent() { assert pos == size; } - public int writeCIE(byte[] buffer, int pos) { + public int writeCIE(byte[] buffer, int p) { // we only need a vanilla CIE with default fields // because we have to have at least one // the layout is @@ -878,6 +889,7 @@ public int writeCIE(byte[] buffer, int pos) { // ULEB : data_alignment_factor ... == -8 // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 // byte[] : initial_instructions .. includes pad to 8-byte boundary + int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // don't care about length pos += putInt(DW_CFA_CIE_id, scratch, 0); @@ -910,7 +922,8 @@ public int writeCIE(byte[] buffer, int pos) { } } - public int writeMethodFrames(byte[] buffer, int pos) { + public int writeMethodFrames(byte[] buffer, int p) { + int pos = p; for (ClassEntry classEntry : primaryClasses) { for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { long lo = primaryEntry.getPrimary().getLo(); @@ -938,7 +951,7 @@ public int writeMethodFrames(byte[] buffer, int pos) { return pos; } - public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { + public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { // we only need a vanilla FDE header with default fields // the layout is // @@ -948,7 +961,7 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { // uint64 : address_range ..... i.e. method hi - lo // byte[] : instructions ...... includes pad to 8-byte boundary - int lengthPos = pos; + int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // dummy length pos += putInt(0, scratch, 0); // CIE_offset @@ -962,7 +975,8 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { } } - public int writePaddingNops(int alignment, byte[] buffer, int pos) { + public int writePaddingNops(int alignment, byte[] buffer, int p) { + int pos = p; assert (alignment & (alignment - 1)) == 0; while ((pos & (alignment - 1)) != 0) { if (buffer == null) { @@ -974,7 +988,8 @@ public int writePaddingNops(int alignment, byte[] buffer, int pos) { return pos; } - public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { + public int writeDefCFA(int register, int offset, byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putByte(DW_CFA_def_cfa, scratch, 0); pos += putSLEB(register, scratch, 0); @@ -986,7 +1001,8 @@ public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { } } - public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { + public int writeDefCFAOffset(int offset, byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); return pos + putULEB(offset, scratch, 0); @@ -1017,7 +1033,8 @@ public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { + public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { + int pos = p; byte op = DW_CFA_advance_loc1; if (buffer == null) { pos += putByte(op, scratch, 0); @@ -1028,8 +1045,9 @@ public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { + public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { byte op = DW_CFA_advance_loc2; + int pos = p; if (buffer == null) { pos += putByte(op, scratch, 0); return pos + putShort(offset, scratch, 0); @@ -1039,8 +1057,9 @@ public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { + public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { byte op = DW_CFA_advance_loc4; + int pos = p; if (buffer == null) { pos += putByte(op, scratch, 0); return pos + putInt(offset, scratch, 0); @@ -1050,8 +1069,9 @@ public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { } } - public int writeOffset(int register, int offset, byte[] buffer, int pos) { + public int writeOffset(int register, int offset, byte[] buffer, int p) { byte op = offsetOp(register); + int pos = p; if (buffer == null) { pos += putByte(op, scratch, 0); return pos + putULEB(offset, scratch, 0); @@ -1061,7 +1081,8 @@ public int writeOffset(int register, int offset, byte[] buffer, int pos) { } } - public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putByte(DW_CFA_register, scratch, 0); pos += putULEB(savedReg, scratch, 0); @@ -1132,7 +1153,8 @@ public int getSPIdx() { } @Override - public int writeInitialInstructions(byte[] buffer, int pos) { + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; // rsp points at the word containing the saved rip // so the frame base (cfa) is at rsp + 8 (why not - ???) // def_cfa r7 (sp) offset 8 @@ -1166,7 +1188,8 @@ public int getSPIdx() { } @Override - public int writeInitialInstructions(byte[] buffer, int pos) { + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; // rsp has not been updated // caller pc is in lr // register r32 (rpc), r30 (lr) @@ -1255,7 +1278,8 @@ public void writeContent() { assert pos == size; } - public int writeCUHeader(byte[] buffer, int pos) { + public int writeCUHeader(byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // CU length pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version @@ -1269,7 +1293,8 @@ public int writeCUHeader(byte[] buffer, int pos) { } } - public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); @@ -1291,7 +1316,8 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { + int pos = p; Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); @@ -1306,7 +1332,8 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { return writeFlag(DW_FLAG_true, buffer, pos); } - public int writeAttrStrp(String value, byte[] buffer, int pos) { + public int writeAttrStrp(String value, byte[] buffer, int p) { + int pos = p; if (buffer == null) { return pos + putInt(0, scratch, 0); } else { @@ -1315,7 +1342,8 @@ public int writeAttrStrp(String value, byte[] buffer, int pos) { } } - public int writeAttrString(String value, byte[] buffer, int pos) { + public int writeAttrString(String value, byte[] buffer, int p) { + int pos = p; if (buffer == null) { return pos + value.length() + 1; } else { @@ -1659,7 +1687,8 @@ public void writeContent() { assert pos == buffer.length; } - public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; // 4 ubyte length field pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); // 2 ubyte version is always 2 @@ -1694,7 +1723,8 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) { return pos; } - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; debug(" [0x%08x] Dir Name\n", pos); // write out the list of dirs referenced form this file entry int dirIdx = 1; @@ -1709,7 +1739,8 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) { return pos; } - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; int fileIdx = 1; debug(" [0x%08x] Entry Dir Name\n", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { @@ -1732,7 +1763,8 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { public int debugLine = 1; public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; // the primary file entry should always be first in the local files list assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; String primaryClassName = classEntry.getClassName(); @@ -1911,8 +1943,9 @@ protected void debug(String format, Object... args) { } } - public int putCopy(byte[] buffer, int pos) { + public int putCopy(byte[] buffer, int p) { byte opcode = DW_LNS_copy; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -1922,8 +1955,9 @@ public int putCopy(byte[] buffer, int pos) { } } - public int putAdvancePC(long uleb, byte[] buffer, int pos) { + public int putAdvancePC(long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_pc; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); @@ -1935,8 +1969,9 @@ public int putAdvancePC(long uleb, byte[] buffer, int pos) { } } - public int putAdvanceLine(long sleb, byte[] buffer, int pos) { + public int putAdvanceLine(long sleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_line; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putSLEB(sleb, scratch, 0); @@ -1948,8 +1983,9 @@ public int putAdvanceLine(long sleb, byte[] buffer, int pos) { } } - public int putSetFile(String file, long uleb, byte[] buffer, int pos) { + public int putSetFile(String file, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_file; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); @@ -1960,8 +1996,9 @@ public int putSetFile(String file, long uleb, byte[] buffer, int pos) { } } - public int putSetColumn(long uleb, byte[] buffer, int pos) { + public int putSetColumn(long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); @@ -1971,8 +2008,9 @@ public int putSetColumn(long uleb, byte[] buffer, int pos) { } } - public int putNegateStmt(byte[] buffer, int pos) { + public int putNegateStmt(byte[] buffer, int p) { byte opcode = DW_LNS_negate_stmt; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -1980,8 +2018,9 @@ public int putNegateStmt(byte[] buffer, int pos) { } } - public int putSetBasicBlock(byte[] buffer, int pos) { + public int putSetBasicBlock(byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -1990,8 +2029,9 @@ public int putSetBasicBlock(byte[] buffer, int pos) { } } - public int putConstAddPC(byte[] buffer, int pos) { + public int putConstAddPC(byte[] buffer, int p) { byte opcode = DW_LNS_const_add_pc; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -2002,8 +2042,9 @@ public int putConstAddPC(byte[] buffer, int pos) { } } - public int putFixedAdvancePC(short arg, byte[] buffer, int pos) { + public int putFixedAdvancePC(short arg, byte[] buffer, int p) { byte opcode = DW_LNS_fixed_advance_pc; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putShort(arg, scratch, 0); @@ -2015,8 +2056,9 @@ public int putFixedAdvancePC(short arg, byte[] buffer, int pos) { } } - public int putEndSequence(byte[] buffer, int pos) { + public int putEndSequence(byte[] buffer, int p) { byte opcode = DW_LNE_end_sequence; + int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB @@ -2034,8 +2076,9 @@ public int putEndSequence(byte[] buffer, int pos) { } } - public int putSetAddress(long arg, byte[] buffer, int pos) { + public int putSetAddress(long arg, byte[] buffer, int p) { byte opcode = DW_LNE_set_address; + int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB @@ -2053,8 +2096,9 @@ public int putSetAddress(long arg, byte[] buffer, int pos) { } } - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) { + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; + int pos = p; // calculate bytes needed for opcode + args int fileBytes = file.length() + 1; long insnBytes = 1; @@ -2096,7 +2140,8 @@ public int opcodeLine(byte opcode) { return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) { + public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { From 441b64f4df778605ea87ff84a6110d3586a1b527 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 16:46:56 +0000 Subject: [PATCH 010/130] death to style dragons --- .../oracle/objectfile/elf/dwarf/DwarfSections.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 5cb930219ea7..433650f6b657 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -82,7 +82,7 @@ public class DwarfSections { private static final int DW_AT_language = 0x13; private static final int DW_AT_external = 0x3f; // private static final int DW_AT_return_addr = 0x2a; - private static final int DW_AT_frame_base = 0x40; + // private static final int DW_AT_frame_base = 0x40; // define all the Dwarf attribute forms we need for our DIEs private static final int DW_FORM_null = 0x0; // private static final int DW_FORM_string = 0x8; @@ -99,7 +99,7 @@ public class DwarfSections { private static final byte DW_CHILDREN_no = 0; private static final byte DW_CHILDREN_yes = 1; // DW_FORM_flag attribute values - private static final byte DW_FLAG_false = 0; + // private static final byte DW_FLAG_false = 0; private static final byte DW_FLAG_true = 1; // value for DW_AT_language attribute with form DATA1 private static final byte DW_LANG_Java = 0xb; @@ -440,7 +440,8 @@ public int putLong(long l, byte[] buffer, int p) { return pos; } - public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { + public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { + int pos = p; // mark address so it is relocated relative to the start of the text segment markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); pos = putLong(0, buffer, pos); @@ -1541,7 +1542,7 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * extended opcodes defined by Dwarf 2 */ - private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 + // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 @@ -1864,7 +1865,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { // if we have to update to a new file then do so if (subFileIdx != fileIdx) { // update the current file - pos = putSetFile(subfile, (long) subFileIdx, buffer, pos); + pos = putSetFile(subfile, subFileIdx, buffer, pos); file = subfile; fileIdx = subFileIdx; } From 0d5308c2829ba78cd113bbb05a56275b827b12ec Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 17:33:02 +0000 Subject: [PATCH 011/130] sigh ... still more style issues --- .../objectfile/elf/dwarf/DwarfSections.java | 44 ++++--------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 433650f6b657..1c5505780164 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -252,9 +252,9 @@ private int debugStringIndex(String string) { public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); - for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { - // install types - } + // for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { + // install types + // } // ensure we have a null string in the string section uniqueDebugString(""); @@ -289,10 +289,10 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { } } DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - for (DebugDataInfo debugDataInfo : dataInfoProvider) { - // install details of heap elements - String name = debugDataInfo.toString(); - } + // for (DebugDataInfo debugDataInfo : dataInfoProvider) { + // install details of heap elements + // String name = debugDataInfo.toString(); + // } } public ClassEntry ensureClassEntry(Range range) { @@ -390,7 +390,7 @@ public void checkDebug(int pos) { // if the env var relevant to this element // type is set then switch on debugging String name = getSectionName(); - String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); + String envVarName = "DWARF_" + name.substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { debug = true; debugBase = pos; @@ -469,7 +469,6 @@ public int putULEB(long val, byte[] buffer, int p) { public int putSLEB(long val, byte[] buffer, int p) { long l = val; int pos = p; - boolean negative = l < 0; for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); l = l >> 7; @@ -1837,31 +1836,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { // the current subrange and the start of the next one. // however, debug works better if we treat all the insns up // to the next range start as belonging to the current line - // so the code below is not actually needed. it is left in - // to clarify i) that this is a deliberate choice and ii) what - // that deliberate choice is avoiding. - if (false) { - if (address < hiAddress && hiAddress < subAddressLo) { - long addressDelta = hiAddress - address; - // increment address to hi address, write an - // end sequence and update state to new rang - pos = putAdvancePC(addressDelta, buffer, pos); - pos = putEndSequence(buffer, pos); - file = subfile; - fileIdx = subFileIdx; - pos = putSetFile(file, fileIdx, buffer, pos); - line = subLine; - // state machine value of line is currently 1 - // increment to desired line - if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); - } - pos = putSetBasicBlock(buffer, pos); - // use a reloc to ensure address is relative to text base - address = hiAddress; - pos = putSetAddress(hiAddress, buffer, pos); - } - } + // // if we have to update to a new file then do so if (subFileIdx != fileIdx) { // update the current file @@ -1920,7 +1895,6 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { // move line and address range on line += lineDelta; address += addressDelta; - hiAddress = subAddressHi; } // append a final end sequence just below the next primary range if (address < primaryRange.getHi()) { From 7138edc94f05596cf2d70d158f317cad5abb5178 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 09:41:12 +0000 Subject: [PATCH 012/130] another style domino topples --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 1c5505780164..dace87a7a6c0 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -34,11 +34,9 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.elf.ELFMachine; From b4a83df2f73b56d69a96b1fc76261e7743ba77d2 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 11:40:04 +0000 Subject: [PATCH 013/130] converted lots of comments to javadcoc, added new ones and edited content of comments --- .../src/com/oracle/objectfile/ObjectFile.java | 8 +- .../debuginfo/DebugInfoProvider.java | 42 ++-- .../objectfile/elf/dwarf/ClassEntry.java | 61 ++++-- .../oracle/objectfile/elf/dwarf/DirEntry.java | 16 +- .../objectfile/elf/dwarf/DwarfSections.java | 204 +++++++++++++++--- .../objectfile/elf/dwarf/FileEntry.java | 3 + .../objectfile/elf/dwarf/PrimaryEntry.java | 44 +++- .../oracle/objectfile/elf/dwarf/Range.java | 10 +- .../objectfile/elf/dwarf/StringEntry.java | 9 +- .../objectfile/elf/dwarf/StringTable.java | 34 ++- .../svm/hosted/image/NativeBootImage.java | 20 ++ 11 files changed, 365 insertions(+), 86 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 509e7fbfd5ce..aa7b28342399 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1080,8 +1080,12 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // flag compatibility } - // support for consuming debug info - + /** + * API method provided to allow a native image generator to provide details of + * types, code and heap data inserted into a native image + * @param debugInfoProvider an implementation of the provider interface that + * communicates details of the relevant types, code and heap data. + */ public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default } 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 cf6daf5ec247..5caf0caab959 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 @@ -28,16 +28,22 @@ import java.util.List; -// class defining interfaces used to allow a native image -// to communicate details of types, code and data to -// the underlying object file so that the object file -// can insert appropriate debug info +/** + * interfaces used to allow a native image to communicate + * details of types, code and data to the underlying + * object file so that the latter can insert appropriate + * debug info + */ public interface DebugInfoProvider { - // access details of a specific type + /** + * access details of a specific type + */ interface DebugTypeInfo { } - // access details of a specific compiled method + /** + * access details of a specific compiled method + */ interface DebugCodeInfo { String fileName(); @@ -62,11 +68,15 @@ interface DebugCodeInfo { List getFrameSizeChanges(); } - // access details of a specific heap object + /** + * access details of a specific heap object + */ interface DebugDataInfo { } - // access details of a specific outer or inlined method at a given line number + /** + * access details of a specific outer or inlined method at a given line number + */ interface DebugLineInfo { String fileName(); @@ -92,19 +102,27 @@ enum Type { DebugFrameSizeChange.Type getType(); } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugTypeInfoProvider extends Iterable { } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugCodeInfoProvider extends Iterable { } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugLineInfoProvider extends Iterable { } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugDataInfoProvider extends Iterable { } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 8522cdff9ca6..cfdf6c091e11 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -33,31 +33,66 @@ import java.util.List; import java.util.Map; +/** + * track debug info associated with a Java class + */ public class ClassEntry { - // the name of the associated class + /** + * the name of the associated class + */ private String className; - // the associated file + /** + * details of the associated file + */ FileEntry fileEntry; - // a list recording details of all primary ranges included in - // this class sorted by ascending address range + /** + * a list recording details of all primary + * ranges included in this class sorted by + * ascending address range + */ private LinkedList primaryEntries; - // an index identifying primary ranges which have already been encountered + /** + * an index identifying primary ranges which + * have already been encountered + */ private Map primaryIndex; - // an index of all primary and secondary files referenced from this class's CU + /** + * an index of all primary and secondary files + * referenced from this class's compilation unit + */ private Map localFilesIndex; - // a list of the same files + /** + * a list of the same files + */ private LinkedList localFiles; - // an index of all primary and secondary dirs referenced from this class's CU + /** + * an index of all primary and secondary dirs + * referenced from this class's compilation unit + */ private HashMap localDirsIndex; - // a list of the same dirs + /** + * a list of the same dirs + */ private LinkedList localDirs; - // index of debug_info section compilation unit for this class + /** + * index of debug_info section compilation unit + * for this class + */ private int cuIndex; - // index into debug_line section for associated CU + /** + * index into debug_line section for associated + * compilation unit + */ private int lineIndex; - // size of line number info prologue region for associated CU + /** + * size of line number info prologue region for + * associated compilation unit + */ private int linePrologueSize; - // total size of line number info region for associated CU + /** + * total size of line number info region for + * associated compilation unit + */ private int totalSize; public ClassEntry(String className, FileEntry fileEntry) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 89d0b81bb8f0..5f46a82b0665 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -26,21 +26,13 @@ package com.oracle.objectfile.elf.dwarf; -// files may be located in a source directory associated -// with a well known substratevm or compiler root package -// in that case the the file's directory path will be something -// like "foo.bar.baz/src/foo/bar/baz/mumble/grumble/bletch" -// i.e. the root package and "src" will be inserted as a prefix -// before the dirs derived from the actual package -// files whose package does not match a well-known root package -// will be listed using the dirs derived from the package -// i.e. simply "foo/bar/baz/mumble/grumble/bletch" - +/** + * track the directory associated with one or + * more source files + */ public class DirEntry { private String path; - // create an entry for a root package path - // or a user path not under a root package public DirEntry(String path) { this.path = path; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index dace87a7a6c0..425d06220c56 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -48,8 +48,16 @@ import java.util.Map; import java.util.Set; +/** + * an outer class that models the debug info in an + * organization that facilitates generation of the + * required DWARF sections. It groups common data and + * behaviours for use by the various subclasses of + * inner class DwarfSectionImpl that take responsibility + * for generating content for a specific section type. + */ public class DwarfSections { - // names of the different sections we create or reference + // names of the different ELF sections we create or reference // in reverse dependency order public static final String TEXT_SECTION_NAME = ".text"; public static final String DW_STR_SECTION_NAME = ".debug_str"; @@ -59,7 +67,9 @@ public class DwarfSections { public static final String DW_INFO_SECTION_NAME = ".debug_info"; public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; - // dwarf version 2 is all we need for debug info + /** + * currently generated debug info relies on DWARF spec vesion 2 + */ private static final short DW_VERSION_2 = 2; // define all the abbrev section codes we need for our DIEs @@ -186,25 +196,39 @@ public ELFMachine getElfMachine() { return elfMachine; } - // a scratch buffer used during computation of a section's size + /** + * a scratch buffer used during computation of a section's size + */ protected static final byte[] scratch = new byte[10]; - // table listing all known strings + /** + * a table listing all known strings, some of + * which may be marked for insertion into the + * .debug_str section + */ private StringTable stringTable = new StringTable(); - // list detailing all dirs in which files are found to reside - // either as part of substrate/compiler or user code + /** + * list detailing all dirs in which files are found to reside + * either as part of substrate/compiler or user code + */ private LinkedList dirs = new LinkedList<>(); - // index of already seen dirs + /** + * index of already seen dirs + */ private Map dirsIndex = new HashMap<>(); - // The obvious traversal structure for debug records is + // The obvious traversal structure for debug records is: + // // 1) by top level compiled method (primary Range) ordered by ascending address // 2) by inlined method (sub range) within top level method ordered by ascending address + // // this ensures that all debug records are generated in increasing address order - // a list recording details of all primary ranges included in - // this file sorted by ascending address range + /** + * a list recording details of all primary ranges included in + * this file sorted by ascending address range + */ private LinkedList primaryEntries = new LinkedList<>(); // An alternative traversal option is @@ -224,32 +248,67 @@ public ELFMachine getElfMachine() { // time would allow more sharing e.g. enabling all classes in a file to share a single copy // of the file and dir tables. - // list of class entries detailing class info for primary ranges + /** + * list of class entries detailing class info for primary ranges + */ private LinkedList primaryClasses = new LinkedList<>(); - // index of already seen classes + /** + * index of already seen classes + */ private Map primaryClassesIndex = new HashMap<>(); - // List of files which contain primary ranges + /** + * list of files which contain primary ranges + */ private LinkedList primaryFiles = new LinkedList<>(); - // List of files which contain primary or secondary ranges + /** + * List of files which contain primary or secondary ranges + */ private LinkedList files = new LinkedList<>(); - // index of already seen files + /** + * index of already seen files + */ private Map filesIndex = new HashMap<>(); + /** + * indirects this call to the string table + * @param string the string to be inserted + * @return a unique equivalent String + */ public String uniqueString(String string) { return stringTable.uniqueString(string); } + /** + * indirects this call to the string table, ensuring + * the table entry is marked for inclusion in the + * .debug_str section + * @param string the string to be inserted and + * marked for inclusion in the .debug_str section + * @return a unique equivalent String + */ public String uniqueDebugString(String string) { return stringTable.uniqueDebugString(string); } + /** + * indirects this call to the string table + * @param string the string whose index is required + * @return the offset of the string in the .debug_str + * section + */ private int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } + /** + * entry point allowing ELFObjectFile to pass on information + * about types, code and heap data + * @param debugInfoProvider provider instance passed by + * ObjectFile client + */ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); + // DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); // for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { // install types // } @@ -286,7 +345,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { addSubRange(primaryRange, subRange); } } - DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + // DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); // for (DebugDataInfo debugDataInfo : dataInfoProvider) { // install details of heap elements // String name = debugDataInfo.toString(); @@ -370,6 +429,10 @@ private DirEntry ensureDirEntry(String file) { return dirEntry; } + /** + * class from which all DWARF debug section + * inherit providing common behaviours + */ // shared implementation methods to manage content creation public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { public boolean debug = false; @@ -380,8 +443,28 @@ public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { public DwarfSectionImpl() { } + /** + * creates the target byte[] array used to define the section + * contents + * + * the main task of this method is to precompute the + * size of the debug section. given the complexity of the + * data layouts that invariably requires performing a dummy + * write of the contents, inserting bytes into a small, + * scratch buffer only when absolutely necessary. subclasses + * may also cache some information for use when writing the + * contents. + */ public abstract void createContent(); + /** + * populates the byte[] array used to contain the section + * contents + * + * in most cases this task reruns the operations performed + * under createContent but this time actually writing data + * to the target byte[]. + */ public abstract void writeContent(); public void checkDebug(int pos) { @@ -403,6 +486,7 @@ protected void debug(String format, Object... args) { } // base level put methods that assume a non-null buffer + public int putByte(byte b, byte[] buffer, int p) { int pos = p; buffer[pos++] = b; @@ -573,10 +657,25 @@ public int writeAttrNull(byte[] buffer, int pos) { } } + /** + * identify the section after which this debug section + * needs to be ordered when sizing and creating content + * @return the name of the preceding section + */ public abstract String targetSectionName(); + /** + * identify the layout properties of the target section + * which need to have been decided before the contents + * of this section can be created. + * @return an array of the relevant decision kinds + */ public abstract LayoutDecision.Kind[] targetSectionKinds(); + /** + * identify this debug section by name + * @return the name of the debug section + */ public abstract String getSectionName(); @Override @@ -610,6 +709,9 @@ public Set getDependencies(Map deci } } + /** + * generator for .debug_str section + */ public class DwarfStrSectionImpl extends DwarfSectionImpl { public DwarfStrSectionImpl() { super(); @@ -657,7 +759,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_str section content depends on text section content and offset + /** + * .debug_str section content depends on text section content and offset + */ public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @Override @@ -665,6 +769,9 @@ public String targetSectionName() { return TARGET_SECTION_NAME; } + /** + * .debug_str section content depends on text section content and offset + */ public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET @@ -676,6 +783,9 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generator for .debug_abbrev section + */ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { public DwarfAbbrevSectionImpl() { @@ -813,7 +923,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_abbrev section content depends on .debug_frame section content and offset + /** + * .debug_abbrev section content depends on .debug_frame section content and offset + */ public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @Override @@ -832,6 +944,9 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generic generator for .debug_frame section + */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { public DwarfFrameSectionImpl() { @@ -1103,7 +1218,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_frame section content depends on .debug_line section content and offset + /** + * .debug_frame section content depends on .debug_line section content and offset + */ public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @Override @@ -1132,6 +1249,10 @@ private byte advanceLoc0Op(int offset) { } } + /** + * x86_64-specific generator for .debug_frame section + * that knows details of x86_64 registers and frame layout + */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public static final int DW_CFA_RSP_IDX = 7; public static final int DW_CFA_RIP_IDX = 16; @@ -1165,6 +1286,10 @@ public int writeInitialInstructions(byte[] buffer, int p) { } } + /** + * AArch64-specific generator for .debug_frame section + * that knows details of AArch64 registers and frame layout + */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { public static final int DW_CFA_FP_IDX = 29; public static final int DW_CFA_LR_IDX = 30; @@ -1196,8 +1321,13 @@ public int writeInitialInstructions(byte[] buffer, int p) { } } + /** + * generator for .debug_info section + */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { - // header section always contains fixed number of bytes + /** + * an info header section always contains a fixed number of bytes + */ private static final int DW_DIE_HEADER_SIZE = 11; public DwarfInfoSectionImpl() { @@ -1358,7 +1488,9 @@ protected void debug(String format, Object... args) { } } - // .debug_info section content depends on abbrev section content and offset + /** + * .debug_info section content depends on abbrev section content and offset + */ public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @Override @@ -1377,6 +1509,9 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generator for .debug_aranges section + */ public class DwarfARangesSectionImpl extends DwarfSectionImpl { private static final int DW_AR_HEADER_SIZE = 12; private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size @@ -1507,14 +1642,27 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generator for .debug_line section + */ public class DwarfLineSectionImpl extends DwarfSectionImpl { - // header section always contains fixed number of bytes + /** + * line header section always contains fixed number of bytes + */ private static final int DW_LN_HEADER_SIZE = 27; - // line base is -5 + /** + * current generator follows C++ with line base -5 + */ private static final int DW_LN_LINE_BASE = -5; - // opcode line range is 14 giving full range -5 to 8 + /** + * current generator follows C++ with line range 14 + * giving full range -5 to 8 + */ private static final int DW_LN_LINE_RANGE = 14; - // opcode base should equal DW_LNS_define_file + 1 + /** + * current generator uses opcode base of 13 + * which equal DW_LNS_define_file + 1 + */ private static final int DW_LN_OPCODE_BASE = 13; /* @@ -2169,7 +2317,9 @@ public boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } - // .debug_line section content depends on .debug_str section content and offset + /** + * .debug_line section content depends on .debug_str section content and offset + */ public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index 3a8943cabdf6..cd530c68de04 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -26,6 +26,9 @@ package com.oracle.objectfile.elf.dwarf; +/** + * track debug info associated with a Java source file. + */ public class FileEntry { // the name of the associated file including path private String fileName; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index a26d060c8859..2727b03c7e12 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -32,26 +32,50 @@ import java.util.LinkedList; import java.util.List; +/** + * track debug info associated with a primary method + * i.e. a top level compiled method + */ public class PrimaryEntry { - // the primary range detailed by this object + /** + * the primary range detailed by this object + */ Range primary; - // details of the class owning this range + /** + * details of the class owning this range + */ ClassEntry classEntry; - // a list of subranges associated with the primary range + /** + * a list of subranges associated with the primary range + */ List subranges; - // a mapping from subranges to their associated file entry + /** + * a mapping from subranges to their associated file entry + */ HashMap subrangeIndex; - // details of of compiled method frame size changes + /** + * details of of compiled method frame size changes + */ private List frameSizeInfos; - // size of compiled method frame + /** + * size of compiled method frame + */ private int frameSize; - // index of debug_info section compilation unit for this file + /** + * index of debug_info section compilation unit for this file + */ private int cuIndex; - // index into debug_line section for associated compilation unit + /** + * index into debug_line section for associated compilation unit + */ private int lineIndex; - // size of line number info prologue region for associated compilation unit + /** + * size of line number info prologue region for associated compilation unit + */ private int linePrologueSize; - // total size of line number info region for associated compilation unit + /** + * total size of line number info region for associated compilation unit + */ private int totalSize; public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 6692d23b7df6..758825272a7e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -26,10 +26,12 @@ package com.oracle.objectfile.elf.dwarf; -// details of a specific address range in a compiled method -// either a primary range identifying a whole method -// or a sub-range identifying a sequence of -// instructions that belong to an inlined method +/** + * details of a specific address range in a compiled method + * either a primary range identifying a whole method + * or a sub-range identifying a sequence of + * instructions that belong to an inlined method + */ public class Range { private String fileName; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index a96e5eb19e6a..d9a40dc2b3ed 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -26,9 +26,12 @@ package com.oracle.objectfile.elf.dwarf; -// class used to ensure we keep only one copy of a String -// amd track it's locations in the string section should -// it need to be entered +/** + * class used to retain a unique (up to equals) copy of + * a String and also to flag whether the String needs to be + * located in the .debug_string section and track the offset + * where it gets written. + */ public class StringEntry { private String string; private int offset; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 74506877df94..1ec68deb7e70 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -29,9 +29,12 @@ import java.util.HashMap; import java.util.Iterator; -// class which reduces incoming strings to unique -// instances and also marks strings which need -// to be written to the debug_str section +/** + * a class which allows incoming strings to be reduced + * to unique (up to equaals) instances and allows marking + * of strings which need to be written to the debug_str + * section and retrieval of the lcoation offset after writing. + */ public class StringTable implements Iterable { private final HashMap table; @@ -40,10 +43,28 @@ public StringTable() { this.table = new HashMap<>(); } + /** + * ensures a unique instance of a string exists in the + * table, inserting the supplied String if no equivalent + * String is already present. this should only be called + * before the string section has been written. + * @param string the string to be included in the table + * @return the unique instance of the String + */ public String uniqueString(String string) { return ensureString(string, false); } + /** + * ensures a unique instance of a string exists in the + * table and is marked for inclusion in the debug_str + * section, inserting the supplied String if no equivalent + * String is already present. this should only be called + * before the string section has been written. + * @param string the string to be included in the table + * and marked for inclusion in the debug_str section + * @return the unique instance of the String + */ public String uniqueDebugString(String string) { return ensureString(string, true); } @@ -60,6 +81,13 @@ private String ensureString(String string, boolean addToStrSection) { return stringEntry.getString(); } + /** + * retrieves the offset at which a given string was written + * into the debug_str section. this should only be called + * after the string section has been written. + * @param string + * @return + */ public int debugStringIndex(String string) { StringEntry stringEntry = table.get(string); assert stringEntry != null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 0f31e3da21b5..f2b9216b708c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -974,6 +974,11 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final NativeImageCodeCache codeCache; } + /** + * implementation of the DebugInfoProvider API interface + * that allows type, code and heap data info to be passed to + * an ObjectFile when generation of debug info is enabled + */ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; private final NativeImageHeap heap; @@ -1035,6 +1040,11 @@ public DebugDataInfo next() { } } + /** + * implementation of the DebugCodeInfo API interface + * that allows code info to be passed to an ObjectFile + * when generation of debug info is enabled + */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; @@ -1169,6 +1179,11 @@ public List getFrameSizeChanges() { } } + /** + * implementation of the DebugLineInfo API interface + * that allows line number info to be passed to an + * ObjectFile when generation of debug info is enabled + */ private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; private final ResolvedJavaMethod method; @@ -1229,6 +1244,11 @@ public int line() { } } + /** + * implementation of the DebugFrameSizeChange API interface + * that allows stack frame size change info to be passed to + * an ObjectFile when generation of debug info is enabled + */ private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; private Type type; From fc310cff3ba2a24b3d098496377acf4eee98a75f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 13:22:23 +0000 Subject: [PATCH 014/130] fix missing javadoc return and remove unused imports --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 4 ++-- .../src/com/oracle/objectfile/elf/dwarf/StringTable.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 425d06220c56..3004762524f7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -34,10 +34,10 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; +// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; +// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.elf.ELFMachine; import com.oracle.objectfile.elf.ELFObjectFile.ELFSection; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 1ec68deb7e70..87b0af1eb437 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -86,7 +86,9 @@ private String ensureString(String string, boolean addToStrSection) { * into the debug_str section. this should only be called * after the string section has been written. * @param string - * @return + * @return the offset or -1 if the string does not + * define an entry or the entry has nto been written + * to the debug_str section */ public int debugStringIndex(String string) { StringEntry stringEntry = table.get(string); From 65e1aa3f6de44dc02716412d175a5ac26bd72d44 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 14:52:33 +0000 Subject: [PATCH 015/130] fix punctuation issues and remove redudant declaration --- .../src/com/oracle/objectfile/ObjectFile.java | 2 +- .../debuginfo/DebugInfoProvider.java | 18 ++-- .../objectfile/elf/dwarf/ClassEntry.java | 26 +++--- .../oracle/objectfile/elf/dwarf/DirEntry.java | 2 +- .../objectfile/elf/dwarf/DwarfSections.java | 92 +++++++++---------- .../objectfile/elf/dwarf/PrimaryEntry.java | 22 ++--- .../svm/hosted/image/NativeBootImage.java | 8 +- 7 files changed, 82 insertions(+), 88 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index aa7b28342399..59b1edd5e878 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1082,7 +1082,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int /** * API method provided to allow a native image generator to provide details of - * types, code and heap data inserted into a native image + * types, code and heap data inserted into a native image. * @param debugInfoProvider an implementation of the provider interface that * communicates details of the relevant types, code and heap data. */ 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 5caf0caab959..13e8cb73dab3 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 @@ -32,17 +32,17 @@ * interfaces used to allow a native image to communicate * details of types, code and data to the underlying * object file so that the latter can insert appropriate - * debug info + * debug info. */ public interface DebugInfoProvider { /** - * access details of a specific type + * access details of a specific type. */ interface DebugTypeInfo { } /** - * access details of a specific compiled method + * access details of a specific compiled method. */ interface DebugCodeInfo { String fileName(); @@ -69,13 +69,13 @@ interface DebugCodeInfo { } /** - * access details of a specific heap object + * access details of a specific heap object. */ interface DebugDataInfo { } /** - * access details of a specific outer or inlined method at a given line number + * access details of a specific outer or inlined method at a given line number. */ interface DebugLineInfo { String fileName(); @@ -103,25 +103,25 @@ enum Type { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugTypeInfoProvider extends Iterable { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugCodeInfoProvider extends Iterable { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugLineInfoProvider extends Iterable { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugDataInfoProvider extends Iterable { } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index cfdf6c091e11..9e429a565e49 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -34,64 +34,64 @@ import java.util.Map; /** - * track debug info associated with a Java class + * track debug info associated with a Java class. */ public class ClassEntry { /** - * the name of the associated class + * the name of the associated class. */ private String className; /** - * details of the associated file + * details of the associated file. */ FileEntry fileEntry; /** * a list recording details of all primary * ranges included in this class sorted by - * ascending address range + * ascending address range. */ private LinkedList primaryEntries; /** * an index identifying primary ranges which - * have already been encountered + * have already been encountered. */ private Map primaryIndex; /** * an index of all primary and secondary files - * referenced from this class's compilation unit + * referenced from this class's compilation unit. */ private Map localFilesIndex; /** - * a list of the same files + * a list of the same files. */ private LinkedList localFiles; /** * an index of all primary and secondary dirs - * referenced from this class's compilation unit + * referenced from this class's compilation unit. */ private HashMap localDirsIndex; /** - * a list of the same dirs + * a list of the same dirs. */ private LinkedList localDirs; /** * index of debug_info section compilation unit - * for this class + * for this class. */ private int cuIndex; /** * index into debug_line section for associated - * compilation unit + * compilation unit. */ private int lineIndex; /** * size of line number info prologue region for - * associated compilation unit + * associated compilation unit. */ private int linePrologueSize; /** * total size of line number info region for - * associated compilation unit + * associated compilation unit. */ private int totalSize; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 5f46a82b0665..5caac5a20997 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -28,7 +28,7 @@ /** * track the directory associated with one or - * more source files + * more source files. */ public class DirEntry { private String path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 3004762524f7..78217b99bd0c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -68,7 +68,7 @@ public class DwarfSections { public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; /** - * currently generated debug info relies on DWARF spec vesion 2 + * currently generated debug info relies on DWARF spec vesion 2. */ private static final short DW_VERSION_2 = 2; @@ -197,24 +197,24 @@ public ELFMachine getElfMachine() { } /** - * a scratch buffer used during computation of a section's size + * a scratch buffer used during computation of a section's size. */ protected static final byte[] scratch = new byte[10]; /** * a table listing all known strings, some of * which may be marked for insertion into the - * .debug_str section + * debug_str section. */ private StringTable stringTable = new StringTable(); /** * list detailing all dirs in which files are found to reside - * either as part of substrate/compiler or user code + * either as part of substrate/compiler or user code. */ private LinkedList dirs = new LinkedList<>(); /** - * index of already seen dirs + * index of already seen dirs. */ private Map dirsIndex = new HashMap<>(); @@ -227,7 +227,7 @@ public ELFMachine getElfMachine() { /** * a list recording details of all primary ranges included in - * this file sorted by ascending address range + * this file sorted by ascending address range. */ private LinkedList primaryEntries = new LinkedList<>(); @@ -249,29 +249,29 @@ public ELFMachine getElfMachine() { // of the file and dir tables. /** - * list of class entries detailing class info for primary ranges + * list of class entries detailing class info for primary ranges. */ private LinkedList primaryClasses = new LinkedList<>(); /** - * index of already seen classes + * index of already seen classes. */ private Map primaryClassesIndex = new HashMap<>(); /** - * list of files which contain primary ranges + * list of files which contain primary ranges. */ private LinkedList primaryFiles = new LinkedList<>(); /** - * List of files which contain primary or secondary ranges + * List of files which contain primary or secondary ranges. */ private LinkedList files = new LinkedList<>(); /** - * index of already seen files + * index of already seen files. */ private Map filesIndex = new HashMap<>(); /** - * indirects this call to the string table + * indirects this call to the string table. * @param string the string to be inserted * @return a unique equivalent String */ @@ -282,9 +282,9 @@ public String uniqueString(String string) { /** * indirects this call to the string table, ensuring * the table entry is marked for inclusion in the - * .debug_str section + * debug_str section. * @param string the string to be inserted and - * marked for inclusion in the .debug_str section + * marked for inclusion in the debug_str section * @return a unique equivalent String */ public String uniqueDebugString(String string) { @@ -292,7 +292,7 @@ public String uniqueDebugString(String string) { } /** - * indirects this call to the string table + * indirects this call to the string table. * @param string the string whose index is required * @return the offset of the string in the .debug_str * section @@ -303,7 +303,7 @@ private int debugStringIndex(String string) { /** * entry point allowing ELFObjectFile to pass on information - * about types, code and heap data + * about types, code and heap data. * @param debugInfoProvider provider instance passed by * ObjectFile client */ @@ -431,7 +431,7 @@ private DirEntry ensureDirEntry(String file) { /** * class from which all DWARF debug section - * inherit providing common behaviours + * inherit providing common behaviours. */ // shared implementation methods to manage content creation public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { @@ -445,7 +445,7 @@ public DwarfSectionImpl() { /** * creates the target byte[] array used to define the section - * contents + * contents. * * the main task of this method is to precompute the * size of the debug section. given the complexity of the @@ -459,7 +459,7 @@ public DwarfSectionImpl() { /** * populates the byte[] array used to contain the section - * contents + * contents. * * in most cases this task reruns the operations performed * under createContent but this time actually writing data @@ -659,7 +659,7 @@ public int writeAttrNull(byte[] buffer, int pos) { /** * identify the section after which this debug section - * needs to be ordered when sizing and creating content + * needs to be ordered when sizing and creating content. * @return the name of the preceding section */ public abstract String targetSectionName(); @@ -673,7 +673,7 @@ public int writeAttrNull(byte[] buffer, int pos) { public abstract LayoutDecision.Kind[] targetSectionKinds(); /** - * identify this debug section by name + * identify this debug section by name. * @return the name of the debug section */ public abstract String getSectionName(); @@ -710,7 +710,7 @@ public Set getDependencies(Map deci } /** - * generator for .debug_str section + * generator for debug_str section. */ public class DwarfStrSectionImpl extends DwarfSectionImpl { public DwarfStrSectionImpl() { @@ -760,7 +760,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_str section content depends on text section content and offset + * debug_str section content depends on text section content and offset. */ public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @@ -770,7 +770,7 @@ public String targetSectionName() { } /** - * .debug_str section content depends on text section content and offset + * debug_str section content depends on text section content and offset. */ public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, @@ -784,7 +784,7 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generator for .debug_abbrev section + * generator for debug_abbrev section. */ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { @@ -924,7 +924,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_abbrev section content depends on .debug_frame section content and offset + * debug_abbrev section content depends on debug_frame section content and offset. */ public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @@ -945,7 +945,7 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generic generator for .debug_frame section + * generic generator for debug_frame section. */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { @@ -1219,7 +1219,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_frame section content depends on .debug_line section content and offset + * debug_frame section content depends on debug_line section content and offset. */ public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @@ -1250,8 +1250,8 @@ private byte advanceLoc0Op(int offset) { } /** - * x86_64-specific generator for .debug_frame section - * that knows details of x86_64 registers and frame layout + * x86_64-specific generator for debug_frame section + * that knows details of x86_64 registers and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public static final int DW_CFA_RSP_IDX = 7; @@ -1287,8 +1287,8 @@ public int writeInitialInstructions(byte[] buffer, int p) { } /** - * AArch64-specific generator for .debug_frame section - * that knows details of AArch64 registers and frame layout + * AArch64-specific generator for debug_frame section + * that knows details of AArch64 registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { public static final int DW_CFA_FP_IDX = 29; @@ -1322,11 +1322,11 @@ public int writeInitialInstructions(byte[] buffer, int p) { } /** - * generator for .debug_info section + * generator for debug_info section. */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { /** - * an info header section always contains a fixed number of bytes + * an info header section always contains a fixed number of bytes. */ private static final int DW_DIE_HEADER_SIZE = 11; @@ -1489,7 +1489,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_info section content depends on abbrev section content and offset + * debug_info section content depends on abbrev section content and offset. */ public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @@ -1510,7 +1510,7 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generator for .debug_aranges section + * generator for debug_aranges section. */ public class DwarfARangesSectionImpl extends DwarfSectionImpl { private static final int DW_AR_HEADER_SIZE = 12; @@ -1643,25 +1643,25 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generator for .debug_line section + * generator for debug_line section. */ public class DwarfLineSectionImpl extends DwarfSectionImpl { /** - * line header section always contains fixed number of bytes + * line header section always contains fixed number of bytes. */ private static final int DW_LN_HEADER_SIZE = 27; /** - * current generator follows C++ with line base -5 + * current generator follows C++ with line base -5. */ private static final int DW_LN_LINE_BASE = -5; /** * current generator follows C++ with line range 14 - * giving full range -5 to 8 + * giving full range -5 to 8. */ private static final int DW_LN_LINE_RANGE = 14; /** * current generator uses opcode base of 13 - * which equal DW_LNS_define_file + 1 + * which must equal DW_LNS_define_file + 1. */ private static final int DW_LN_OPCODE_BASE = 13; @@ -1934,13 +1934,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { line = 0; } long address = primaryRange.getLo(); - long hiAddress = address; - // int column = 0; - // boolean is_stmt = true; - // boolean is_basic_block = false; - // boolean end_sequence = false; - // set state for primary + // set state for primary debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); @@ -1957,7 +1952,6 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putCopy(buffer, pos); // now write a row for each subrange lo and hi - for (Range subrange : primaryEntry.getSubranges()) { assert subrange.getLo() >= primaryRange.getLo(); assert subrange.getHi() <= primaryRange.getHi(); @@ -2318,7 +2312,7 @@ public boolean isFixedAdvancePC(long addressDiff) { } /** - * .debug_line section content depends on .debug_str section content and offset + * debug_line section content depends on debug_str section content and offset. */ public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index 2727b03c7e12..6720703cf921 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -33,48 +33,48 @@ import java.util.List; /** - * track debug info associated with a primary method + * track debug info associated with a primary method. * i.e. a top level compiled method */ public class PrimaryEntry { /** - * the primary range detailed by this object + * the primary range detailed by this object. */ Range primary; /** - * details of the class owning this range + * details of the class owning this range. */ ClassEntry classEntry; /** - * a list of subranges associated with the primary range + * a list of subranges associated with the primary range. */ List subranges; /** - * a mapping from subranges to their associated file entry + * a mapping from subranges to their associated file entry. */ HashMap subrangeIndex; /** - * details of of compiled method frame size changes + * details of of compiled method frame size changes. */ private List frameSizeInfos; /** - * size of compiled method frame + * size of compiled method frame. */ private int frameSize; /** - * index of debug_info section compilation unit for this file + * index of debug_info section compilation unit for this file. */ private int cuIndex; /** - * index into debug_line section for associated compilation unit + * index into debug_line section for associated compilation unit. */ private int lineIndex; /** - * size of line number info prologue region for associated compilation unit + * size of line number info prologue region for associated compilation unit. */ private int linePrologueSize; /** - * total size of line number info region for associated compilation unit + * total size of line number info region for associated compilation unit. */ private int totalSize; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index f2b9216b708c..562dd1c040e0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -977,7 +977,7 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile /** * implementation of the DebugInfoProvider API interface * that allows type, code and heap data info to be passed to - * an ObjectFile when generation of debug info is enabled + * an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; @@ -1043,7 +1043,7 @@ public DebugDataInfo next() { /** * implementation of the DebugCodeInfo API interface * that allows code info to be passed to an ObjectFile - * when generation of debug info is enabled + * when generation of debug info is enabled. */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; @@ -1182,7 +1182,7 @@ public List getFrameSizeChanges() { /** * implementation of the DebugLineInfo API interface * that allows line number info to be passed to an - * ObjectFile when generation of debug info is enabled + * ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; @@ -1247,7 +1247,7 @@ public int line() { /** * implementation of the DebugFrameSizeChange API interface * that allows stack frame size change info to be passed to - * an ObjectFile when generation of debug info is enabled + * an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; From a39425132f04e3317d6dbae90335baa6539912a5 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 24 Jan 2020 14:51:23 +0000 Subject: [PATCH 016/130] remove debug trace --- substratevm/write_gdbsourcepath | 6 ------ 1 file changed, 6 deletions(-) diff --git a/substratevm/write_gdbsourcepath b/substratevm/write_gdbsourcepath index 2cf9c728e1a4..b211b305a543 100644 --- a/substratevm/write_gdbsourcepath +++ b/substratevm/write_gdbsourcepath @@ -100,7 +100,6 @@ function add_sources() typeset -i ignore ignore=0 verbose "considering $dir" - set -x if [ ! -d ${dir}/src ]; then ignore=1 else @@ -114,24 +113,19 @@ function add_sources() # check for a specific jdk release if [ "${tail#jdk.}" != "$tail" ]; then # jdk. as part of a package name is ok - echo '+++' if ["${tail#jdk.}" != "$tail" ]; then echo allow $dir fi - echo /// ignore=0 elif [ "${tail#*jdk}" != "${JAVA_VERSION}" ]; then # jdk must match JAVA_VERSION - echo '+++' if [ "${dir#jdk.}" != "$dir" ]; then echo disallow $dir fi - echo /// ignore=1 fi fi fi - set +x if [ $ignore -eq 1 ] ; then verbose "ignoring $dir" else From cb8be8e66daf566aa5356e46d3cda15843f93277 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 24 Jan 2020 15:55:39 +0000 Subject: [PATCH 017/130] fix reloc code to ensure content of elf section depends on content of reloc section --- .../oracle/objectfile/elf/ELFRelocationSection.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java index 1209c6662099..7826a6a786ba 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java @@ -236,6 +236,16 @@ public Iterable getDependencies(Map // decisions.get(syms).getDecision(LayoutProperty.Kind.CONTENT); // deps.add(BuildDependency.createOrGet(ourContent, symtabContent)); /* If we're dynamic, it also depends on the vaddr of all referenced sections. */ + + // our content depends on the content of the section being relocated + // (because entries only get registered during generation) + if (relocated != null) { + LayoutDecision relocatedSectionContent = + decisions.get(relocated).getDecision(LayoutDecision.Kind.CONTENT); + deps.add(BuildDependency.createOrGet(ourContent, + relocatedSectionContent)); + } + if (isDynamic()) { Set referenced = new HashSet<>(); for (Entry ent : entries.keySet()) { From df8f5bdf61f91137cfa90aec670482973f780c82 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 24 Jan 2020 15:56:23 +0000 Subject: [PATCH 018/130] add correct VADDR dependency so that debug sections can use vaddr of text section for debug --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 78217b99bd0c..d971e21a1d6a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -774,7 +774,8 @@ public String targetSectionName() { */ public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address }; @Override @@ -2324,7 +2325,6 @@ public String targetSectionName() { public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address }; @Override From b2c884f8fdf3885c5aef077d2af031f4b763b57f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 28 Jan 2020 17:45:49 +0000 Subject: [PATCH 019/130] fix some bugs turned up by enabling asserts --- .../oracle/objectfile/elf/dwarf/DwarfSections.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index d971e21a1d6a..286871c7227b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -467,6 +467,12 @@ public DwarfSectionImpl() { */ public abstract void writeContent(); + @Override + public boolean isLoadable() { + // even though we're a progbits section impl we're not actually loadable + return false; + } + public void checkDebug(int pos) { // if the env var relevant to this element // type is set then switch on debugging @@ -987,6 +993,9 @@ public void writeContent() { pos = writeCIE(buffer, pos); pos = writeMethodFrames(buffer, pos); + if (pos != size) { + System.out.format("pos = 0x%x size = 0x%x", pos, size); + } assert pos == size; } @@ -1010,7 +1019,7 @@ public int writeCIE(byte[] buffer, int p) { pos += putByte(DW_CFA_CIE_version, scratch, 0); pos += putAsciiStringBytes("", scratch, 0); pos += putULEB(1, scratch, 0); - pos += putULEB(-8, scratch, 0); + pos += putSLEB(-8, scratch, 0); pos += putByte((byte) getPCIdx(), scratch, 0); // write insns to set up empty frame pos = writeInitialInstructions(buffer, pos); From 69af9d1e6c1b69eb780e9792b2567b3cafdff88c Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 11:46:45 +0000 Subject: [PATCH 020/130] remove redudant local declarations --- .../oracle/objectfile/elf/ELFObjectFile.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 936938f5e19f..e6d2c4dbecd9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1169,18 +1169,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - @SuppressWarnings("unused") - ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - @SuppressWarnings("unused") - ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - @SuppressWarnings("unused") - ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - @SuppressWarnings("unused") - ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - @SuppressWarnings("unused") - ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - @SuppressWarnings("unused") - ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the From 6b3f95ce72951b1d20a420f79c682d6410036490 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 12:01:52 +0000 Subject: [PATCH 021/130] removed redundant list of primary entries since iteration always happens via primaries within each class entry --- .../objectfile/elf/dwarf/DwarfSections.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 286871c7227b..474e74d20735 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -223,15 +223,10 @@ public ELFMachine getElfMachine() { // 1) by top level compiled method (primary Range) ordered by ascending address // 2) by inlined method (sub range) within top level method ordered by ascending address // - // this ensures that all debug records are generated in increasing address order - - /** - * a list recording details of all primary ranges included in - * this file sorted by ascending address range. - */ - private LinkedList primaryEntries = new LinkedList<>(); - + // these can be used to ensure that all debug records are generated in increasing address order + // // An alternative traversal option is + // // 1) by top level class (String id) // 2) by top level compiled method (primary Range) within a class ordered by ascending address // 3) by inlined method (sub range) within top level method ordered by ascending address @@ -241,6 +236,7 @@ public ELFMachine getElfMachine() { // or data values. this means we can treat each class as a compilation unit, allowing // data common to all methods of the class to be shared. // + // A third option appears to be to traverse via files, then top level class within file etc. // Unfortunately, files cannot be treated as the compilation unit. A file F may contain // multiple classes, say C1 and C2. There is no guarantee that methods for some other // class C' in file F' will not be compiled into the address space interleaved between @@ -395,10 +391,6 @@ public void addRange(Range primaryRange, List frameSizeInf assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); - if (entry != null) { - // track the entry for this range in address order - primaryEntries.add(entry); - } } public void addSubRange(Range primaryRange, Range subrange) { From 24c17a4713308657d1cd87c876219064d25b34d5 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 14:29:32 +0000 Subject: [PATCH 022/130] relocate dwarf section implementations to separate files as outer classes --- .../oracle/objectfile/elf/ELFObjectFile.java | 21 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 171 ++ .../elf/dwarf/DwarfAbbrevSectionImpl.java | 212 ++ .../elf/dwarf/DwarfFrameSectionImpl.java | 350 +++ .../dwarf/DwarfFrameSectionImplAArch64.java | 63 + .../dwarf/DwarfFrameSectionImplX86_64.java | 64 + .../elf/dwarf/DwarfInfoSectionImpl.java | 227 ++ .../elf/dwarf/DwarfLineSectionImpl.java | 726 ++++++ .../elf/dwarf/DwarfSectionImpl.java | 339 +++ .../objectfile/elf/dwarf/DwarfSections.java | 2063 +---------------- .../elf/dwarf/DwarfStrSectionImpl.java | 106 + .../com/oracle/objectfile/elf/dwarf/impl.java | 3 + 12 files changed, 2346 insertions(+), 1999 deletions(-) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index e6d2c4dbecd9..cb3d2a026e47 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -43,7 +43,13 @@ import com.oracle.objectfile.StringTable; import com.oracle.objectfile.SymbolTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.elf.dwarf.DwarfARangesSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfAbbrevSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfFrameSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfInfoSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfLineSectionImpl; import com.oracle.objectfile.elf.dwarf.DwarfSections; +import com.oracle.objectfile.elf.dwarf.DwarfStrSectionImpl; import com.oracle.objectfile.io.AssemblyBuffer; import com.oracle.objectfile.io.OutputAssembler; @@ -1162,19 +1168,20 @@ protected int getMinimumFileSize() { public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections dwarfSections = new DwarfSections(getMachine()); // we need an implementation for each section - DwarfSections.DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); - DwarfSections.DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); - DwarfSections.DwarfFrameSectionImpl frameSectionImpl = dwarfSections.getFrameSectionImpl(); - DwarfSections.DwarfInfoSectionImpl elfInfoSectionImpl = dwarfSections.getInfoSectionImpl(); - DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); - DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); + DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); + DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); + DwarfFrameSectionImpl frameSectionImpl = dwarfSections.getFrameSectionImpl(); + DwarfInfoSectionImpl elfInfoSectionImpl = dwarfSections.getInfoSectionImpl(); + DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); + DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + @SuppressWarnings("unused") + ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java new file mode 100644 index 000000000000..43615669b10f --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; + +import java.util.LinkedList; +import java.util.Map; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ARANGES_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; +/** + * generator for debug_aranges section. + */ +public class DwarfARangesSectionImpl extends DwarfSectionImpl { + private static final int DW_AR_HEADER_SIZE = 12; + private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size + + public DwarfARangesSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_ARANGES_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + // we need an entry for each compilation unit + // + // uint32 length ............ in bytes (not counting these 4 bytes) + // uint16 dwarf_version ..... always 2 + // uint32 info_offset ....... offset of compilation unit on debug_info + // uint8 address_size ....... always 8 + // uint8 segment_desc_size .. ??? + // + // i.e. 12 bytes followed by padding + // aligning up to 2 * address size + // + // uint8 pad[4] + // + // followed by N + 1 times + // + // uint64 lo ................ lo address of range + // uint64 length ............ number of bytes in range + // + // where N is the number of ranges belonging to the compilation unit + // and the last range contains two zeroes + + for (ClassEntry classEntry : getPrimaryClasses()) { + pos += DW_AR_HEADER_SIZE; + // align to 2 * address size + pos += DW_AR_HEADER_PAD_SIZE; + pos += classEntry.getPrimaryEntries().size() * 2 * 8; + pos += 2 * 8; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + ObjectFile.Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debugTextBase = ((Number) valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_ARANGES\n", pos); + for (ClassEntry classEntry : getPrimaryClasses()) { + int lastpos = pos; + int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; + int cuIndex = classEntry.getCUIndex(); + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + // add room for each entry into length count + length += classPrimaryEntries.size() * 2 * 8; + length += 2 * 8; + debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); + pos = putInt(length, buffer, pos); + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 + pos = putInt(cuIndex, buffer, pos); + pos = putByte((byte) 8, buffer, pos); // address size is always 8 + pos = putByte((byte) 0, buffer, pos); // segment size is always 0 + assert (pos - lastpos) == DW_AR_HEADER_SIZE; + // align to 2 * address size + for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { + pos = putByte((byte) 0, buffer, pos); + } + debug(" [0x%08x] Address Length Name\n", pos); + for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { + Range primary = classPrimaryEntry.getPrimary(); + debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); + pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); + pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); + } + pos = putLong(0, buffer, pos); + pos = putLong(0, buffer, pos); + } + + assert pos == size; + } + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_aranges section content depends on .debug_info section content and offset + public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} + 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 new file mode 100644 index 000000000000..2336e27608a4 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_compile_unit; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_subprogram; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_external; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_hi_pc; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_language; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_low_pc; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_name; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_null; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_stmt_list; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CHILDREN_no; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CHILDREN_yes; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_addr; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_data1; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_data4; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_flag; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_null; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_strp; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_TAG_compile_unit; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_TAG_subprogram; + +/** + * generator for debug_abbrev section. + */ +public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { + + public DwarfAbbrevSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_ABBREV_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + // an abbrev table contains abbrev entries for one or + // more CUs. the table includes a sequence of abbrev + // entries each of which defines a specific DIE layout + // employed to describe some DIE in a CU. a table is + // terminated by a null entry + // + // a null entry has consists of just a 0 abbrev code + // LEB128 abbrev_code; ...... == 0 + // + // non-null entries have the following format + // LEB128 abbrev_code; ...... unique noncode for this layout != 0 + // 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 DIE + // * ........ zero or more attributes + // .... terminator + // + // An attribute_spec consists of an attribute name and form + // LEB128 attr_name; ........ 0 for the null attribute name + // LEB128 attr_form; ........ 0 for the null attribute form + // + // For the moment we only use one abbrev table for all CUs. + // It contains two DIEs, the first to describe the compilation + // unit itself and the second to describe each method within + // that compilation unit. + // + // The DIE layouts are as follows: + // + // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + // DW_AT_language : ... DW_FORM_data1 + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_address + // DW_AT_hi_pc : ...... DW_FORM_address + // DW_AT_stmt_list : .. DW_FORM_data4 + // + // abbrev_code == 2, tag == DW_TAG_subprogram, no_children + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_addr + // DW_AT_hi_pc : ...... DW_FORM_addr + // DW_AT_external : ... DW_FORM_flag + + pos = writeAbbrev1(null, pos); + pos = writeAbbrev2(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + pos = writeAbbrev1(buffer, pos); + pos = writeAbbrev2(buffer, pos); + assert pos == size; + } + + public int writeAttrType(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAttrForm(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAbbrev1(byte[] buffer, int p) { + int pos = p; + // abbrev 1 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + pos = writeTag(DW_TAG_compile_unit, buffer, pos); + pos = writeFlag(DW_CHILDREN_yes, buffer, pos); + pos = writeAttrType(DW_AT_language, buffer, pos); + pos = writeAttrForm(DW_FORM_data1, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_stmt_list, buffer, pos); + pos = writeAttrForm(DW_FORM_data4, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + public int writeAbbrev2(byte[] buffer, int p) { + int pos = p; + // abbrev 2 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + pos = writeTag(DW_TAG_subprogram, buffer, pos); + pos = writeFlag(DW_CHILDREN_no, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_external, buffer, pos); + pos = writeAttrForm(DW_FORM_flag, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + /** + * debug_abbrev section content depends on debug_frame section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java new file mode 100644 index 000000000000..93719731dcd8 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_id; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_version; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc1; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc2; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc4; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_def_cfa; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_def_cfa_offset; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_nop; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_offset; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_register; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; +/** + * generic generator for debug_frame section. + */ +public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { + + public DwarfFrameSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_FRAME_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + + // the frame section contains one CIE at offset 0 + // followed by an FIE for each method + pos = writeCIE(null, pos); + pos = writeMethodFrames(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + // there are entries for the prologue region where the + // stack is being built, the method body region(s) where + // the code executes with a fixed size frame and the + // epilogue region(s) where the stack is torn down + pos = writeCIE(buffer, pos); + pos = writeMethodFrames(buffer, pos); + + if (pos != size) { + System.out.format("pos = 0x%x size = 0x%x", pos, size); + } + assert pos == size; + } + + public int writeCIE(byte[] buffer, int p) { + // we only need a vanilla CIE with default fields + // because we have to have at least one + // the layout is + // + // uint32 : length ............... length of remaining fields in this CIE + // uint32 : CIE_id ................ unique id for CIE == 0xffffff + // uint8 : version ................ == 1 + // uint8[] : augmentation ......... == "" so always 1 byte + // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + // ULEB : data_alignment_factor ... == -8 + // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + // byte[] : initial_instructions .. includes pad to 8-byte boundary + int pos = p; + if (buffer == null) { + pos += putInt(0, scratch, 0); // don't care about length + pos += putInt(DW_CFA_CIE_id, scratch, 0); + pos += putByte(DW_CFA_CIE_version, scratch, 0); + pos += putAsciiStringBytes("", scratch, 0); + pos += putULEB(1, scratch, 0); + pos += putSLEB(-8, scratch, 0); + pos += putByte((byte) getPCIdx(), scratch, 0); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + // no need to write length + return pos; + } else { + int lengthPos = pos; + pos = putInt(0, buffer, pos); + pos = putInt(DW_CFA_CIE_id, buffer, pos); + pos = putByte(DW_CFA_CIE_version, buffer, pos); + pos = putAsciiStringBytes("", buffer, pos); + pos = putULEB(1, buffer, pos); + pos = putSLEB(-8, buffer, pos); + pos = putByte((byte) getPCIdx(), buffer, pos); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + return pos; + } + } + + public int writeMethodFrames(byte[] buffer, int p) { + int pos = p; + for (ClassEntry classEntry : getPrimaryClasses()) { + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + long lo = primaryEntry.getPrimary().getLo(); + long hi = primaryEntry.getPrimary().getHi(); + int frameSize = primaryEntry.getFrameSize(); + int currentOffset = 0; + int lengthPos = pos; + pos = writeFDEHeader((int) lo, (int) hi, buffer, pos); + for (DebugInfoProvider.DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { + int advance = debugFrameSizeInfo.getOffset() - currentOffset; + currentOffset += advance; + pos = writeAdvanceLoc(advance, buffer, pos); + if (debugFrameSizeInfo.getType() == DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND) { + // SP has been extended so rebase CFA using full frame + pos = writeDefCFAOffset(frameSize, buffer, pos); + } else { + // SP has been contracted so rebase CFA using empty frame + pos = writeDefCFAOffset(8, buffer, pos); + } + } + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + } + } + return pos; + } + + public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { + // we only need a vanilla FDE header with default fields + // the layout is + // + // uint32 : length ........... length of remaining fields in this FDE + // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + // uint64 : initial_location .. i.e. method lo address + // uint64 : address_range ..... i.e. method hi - lo + // byte[] : instructions ...... includes pad to 8-byte boundary + + int pos = p; + if (buffer == null) { + pos += putInt(0, scratch, 0); // dummy length + pos += putInt(0, scratch, 0); // CIE_offset + pos += putLong(lo, scratch, 0); // initial address + return pos + putLong(hi - lo, scratch, 0); // address range + } else { + pos = putInt(0, buffer, pos); // dummy length + pos = putInt(0, buffer, pos); // CIE_offset + pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address + return putLong(hi - lo, buffer, pos); // address range + } + } + + public int writePaddingNops(int alignment, byte[] buffer, int p) { + int pos = p; + assert (alignment & (alignment - 1)) == 0; + while ((pos & (alignment - 1)) != 0) { + if (buffer == null) { + pos++; + } else { + pos = putByte(DW_CFA_nop, buffer, pos); + } + } + return pos; + } + + public int writeDefCFA(int register, int offset, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa, scratch, 0); + pos += putSLEB(register, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa, buffer, pos); + pos = putULEB(register, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + + public int writeDefCFAOffset(int offset, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa_offset, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + + public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { + if (offset <= 0x3f) { + return writeAdvanceLoc0((byte) offset, buffer, pos); + } else if (offset <= 0xff) { + return writeAdvanceLoc1((byte) offset, buffer, pos); + } else if (offset <= 0xffff) { + return writeAdvanceLoc2((short) offset, buffer, pos); + } else { + return writeAdvanceLoc4(offset, buffer, pos); + } + } + + public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { + byte op = advanceLoc0Op(offset); + if (buffer == null) { + return pos + putByte(op, scratch, 0); + } else { + return putByte(op, buffer, pos); + } + } + + public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { + int pos = p; + byte op = DW_CFA_advance_loc1; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putByte(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putByte(offset, buffer, pos); + } + } + + public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { + byte op = DW_CFA_advance_loc2; + int pos = p; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putShort(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putShort(offset, buffer, pos); + } + } + + public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { + byte op = DW_CFA_advance_loc4; + int pos = p; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putInt(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putInt(offset, buffer, pos); + } + } + + public int writeOffset(int register, int offset, byte[] buffer, int p) { + byte op = offsetOp(register); + int pos = p; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putByte(DW_CFA_register, scratch, 0); + pos += putULEB(savedReg, scratch, 0); + return pos + putULEB(savedToReg, scratch, 0); + } else { + pos = putByte(DW_CFA_register, buffer, pos); + pos = putULEB(savedReg, buffer, pos); + return putULEB(savedToReg, buffer, pos); + } + } + + public abstract int getPCIdx(); + + public abstract int getSPIdx(); + + public abstract int writeInitialInstructions(byte[] buffer, int pos); + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + /** + * debug_frame section content depends on debug_line section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } + + private byte offsetOp(int register) { + assert (register >> 6) == 0; + return (byte) ((DW_CFA_offset << 6) | register); + } + + private byte advanceLoc0Op(int offset) { + assert (offset >= 0 && offset <= 0x3f); + return (byte) ((DW_CFA_advance_loc << 6) | offset); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java new file mode 100644 index 000000000000..58d490853e5b --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; + +/** + * AArch64-specific generator for debug_frame section + * that knows details of AArch64 registers and frame layout. + */ +public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_FP_IDX = 29; + public static final int DW_CFA_LR_IDX = 30; + public static final int DW_CFA_SP_IDX = 31; + public static final int DW_CFA_PC_IDX = 32; + + public DwarfFrameSectionImplAArch64(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public int getPCIdx() { + return DW_CFA_PC_IDX; + } + + @Override + public int getSPIdx() { + return DW_CFA_SP_IDX; + } + + @Override + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; + // rsp has not been updated + // caller pc is in lr + // register r32 (rpc), r30 (lr) + pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); + return pos; + } +} + diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java new file mode 100644 index 000000000000..b4b638305b5f --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; + +/** + * x86_64-specific generator for debug_frame section + * that knows details of x86_64 registers and frame layout. + */ +public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_RSP_IDX = 7; + public static final int DW_CFA_RIP_IDX = 16; + + public DwarfFrameSectionImplX86_64(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public int getPCIdx() { + return DW_CFA_RIP_IDX; + } + + @Override + public int getSPIdx() { + return DW_CFA_RSP_IDX; + } + + @Override + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; + // rsp points at the word containing the saved rip + // so the frame base (cfa) is at rsp + 8 (why not - ???) + // def_cfa r7 (sp) offset 8 + pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); + // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + // (why not -1 ???) + // offset r16 (rip) cfa - 8 + pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); + return pos; + } +} 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 new file mode 100644 index 000000000000..033a09273a68 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; + +import java.util.LinkedList; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_compile_unit; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_subprogram; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FLAG_true; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LANG_Java; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; +/** + * generator for debug_info section. + */ +public class DwarfInfoSectionImpl extends DwarfSectionImpl { + /** + * an info header section always contains a fixed number of bytes. + */ + private static final int DW_DIE_HEADER_SIZE = 11; + + public DwarfInfoSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_INFO_SECTION_NAME; + } + + @Override + public void createContent() { + // we need a single level 0 DIE for each compilation unit (CU) + // Each CU's Level 0 DIE is preceded by a fixed header: + // and terminated by a null DIE + // uint32 length ......... excluding this length field + // uint16 dwarf_version .. always 2 ?? + // uint32 abbrev offset .. always 0 ?? + // uint8 address_size .... always 8 + // * ................ sequence of top-level and nested child entries + // ............ == 0 + // + // a DIE is a recursively defined structure + // it starts with a code for the associated + // abbrev entry followed by a series of attribute + // values as determined by the entry terminated by + // a null value and followed by zero or more child + // DIEs (zero iff has_children == no_children) + // + // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + // * ....... value sequence as determined by abbrev entry + // * ................... sequence of child DIEs (if appropriate) + // ............. == 0 + // + // note that a null_DIE looks like + // LEB128 abbrev_code ....... == 0 + // i.e. it also looks like a null_value + + byte[] buffer = null; + int pos = 0; + + for (ClassEntry classEntry : getPrimaryClasses()) { + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // no need to backpatch length at lengthPos + } + buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_INFO\n", pos); + debug(" [0x%08x] size = 0x%08x\n", pos, size); + for (ClassEntry classEntry : getPrimaryClasses()) { + // save the offset of this file's CU so it can + // be used when writing the aranges section + classEntry.setCUIndex(pos); + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + debug(" [0x%08x] Compilation Unit\n", pos, size); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // backpatch length at lengthPos (excluding length field) + patchLength(lengthPos, buffer, pos); + } + assert pos == size; + } + + public int writeCUHeader(byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putInt(0, scratch, 0); // CU length + pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version + pos += putInt(0, scratch, 0); // abbrev offset + return pos + putByte((byte) 8, scratch, 0); // address size + } else { + pos = putInt(0, buffer, pos); // CU length + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version + pos = putInt(0, buffer, pos); // abbrev offset + return putByte((byte) 8, buffer, pos); // address size + } + } + + public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); + pos = writeAttrData1(DW_LANG_Java, buffer, pos); + debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); + pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); + pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); + pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); + debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); + pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); + for (PrimaryEntry primaryEntry : classPrimaryEntries) { + pos = writePrimary(primaryEntry, buffer, pos); + } + // write a terminating null attribute for the the level 2 primaries + return writeAttrNull(buffer, pos); + + } + + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { + int pos = p; + Range primary = primaryEntry.getPrimary(); + debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); + pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); + pos = writeAttrAddress(primary.getLo(), buffer, pos); + debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); + pos = writeAttrAddress(primary.getHi(), buffer, pos); + // need to pass true only if method is public + debug(" [0x%08x] external true\n", pos); + return writeFlag(DW_FLAG_true, buffer, pos); + } + + public int writeAttrStrp(String value, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + return pos + putInt(0, scratch, 0); + } else { + int idx = debugStringIndex(value); + return putInt(idx, buffer, pos); + } + } + + public int writeAttrString(String value, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + return pos + value.length() + 1; + } else { + return putAsciiStringBytes(value, buffer, pos); + } + } + + @Override + protected void debug(String format, Object... args) { + if (((int) args[0] - debugBase) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + /** + * debug_info section content depends on abbrev section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} + diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java new file mode 100644 index 000000000000..7ae876f3e05f --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; + +import java.util.Map; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; +/** + * generator for debug_line section. + */ +public class DwarfLineSectionImpl extends DwarfSectionImpl { + /** + * line header section always contains fixed number of bytes. + */ + private static final int DW_LN_HEADER_SIZE = 27; + /** + * current generator follows C++ with line base -5. + */ + private static final int DW_LN_LINE_BASE = -5; + /** + * current generator follows C++ with line range 14 + * giving full range -5 to 8. + */ + private static final int DW_LN_LINE_RANGE = 14; + /** + * current generator uses opcode base of 13 + * which must equal DW_LNS_define_file + 1. + */ + private static final int DW_LN_OPCODE_BASE = 13; + + /* + * standard opcodes defined by Dwarf 2 + */ + private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an + // invalid opcode + private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for + // extended opcodes + private static final byte DW_LNS_copy = 1; // append current state as matrix row + // 0 args + private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg + private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg + private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg + private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg + private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args + private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row + private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode + // 255 0 args + private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg + + /* + * extended opcodes defined by Dwarf 2 + */ + // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 + private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses + private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 + private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 + + DwarfLineSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_LINE_SECTION_NAME; + } + + @Override + public void createContent() { + // we need to create a header, dir table, file table and line + // number table encoding for each CU + + // write entries for each file listed in the primary list + int pos = 0; + for (ClassEntry classEntry : getPrimaryClasses()) { + int startPos = pos; + classEntry.setLineIndex(startPos); + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(classEntry); + int fileTableSize = computeFileTableSize(classEntry); + int prologueSize = headerSize + dirTableSize + fileTableSize; + classEntry.setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(classEntry); + int totalSize = prologueSize + lineNumberTableSize; + classEntry.setTotalSize(totalSize); + pos += totalSize; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + public int headerSize() { + // header size is standard 31 bytes + // uint32 total_length + // uint16 version + // uint32 prologue_length + // uint8 min_insn_length + // uint8 default_is_stmt + // int8 line_base + // uint8 line_range + // uint8 opcode_base + // uint8 li_opcode_base + // uint8[opcode_base-1] standard_opcode_lengths + + return DW_LN_HEADER_SIZE; + } + + public int computeDirTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int dirSize = 0; + for (DirEntry dir : classEntry.getLocalDirs()) { + dirSize += dir.getPath().length() + 1; + } + // allow for separator nul + dirSize++; + return dirSize; + } + + public int computeFileTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int fileSize = 0; + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we want the file base name excluding path + String baseName = localEntry.getBaseName(); + int length = baseName.length(); + fileSize += length + 1; + DirEntry dirEntry = localEntry.dirEntry; + int idx = classEntry.localDirsIdx(dirEntry); + fileSize += putULEB(idx, scratch, 0); + // the two zero timestamps require 1 byte each + fileSize += 2; + } + // allow for terminator nul + fileSize++; + return fileSize; + } + + public int computeLineNUmberTableSize(ClassEntry classEntry) { + // sigh -- we have to do this by generating the + // content even though we cannot write it into a byte[] + return writeLineNumberTable(classEntry, null, 0); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + ObjectFile.Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debugTextBase = ((Number) valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + + int pos = 0; + checkDebug(pos); + debug(" [0x%08x] DEBUG_LINE\n", pos); + + for (ClassEntry classEntry : getPrimaryClasses()) { + int startPos = pos; + assert classEntry.getLineIndex() == startPos; + debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + pos = writeHeader(classEntry, buffer, pos); + debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + int dirTablePos = pos; + pos = writeDirTable(classEntry, buffer, pos); + debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(classEntry, buffer, pos); + debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(classEntry, buffer, pos); + debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); + debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + } + assert pos == buffer.length; + } + + public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + // 4 ubyte length field + pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); + // 2 ubyte version is always 2 + pos = putShort(DW_VERSION_2, buffer, pos); + // 4 ubyte prologue length includes rest of header and + // dir + file table section + int prologueSize = classEntry.getLinePrologueSize() - 6; + pos = putInt(prologueSize, buffer, pos); + // 1 ubyte min instruction length is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte default is_stmt is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte line base is always -5 + pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); + // 1 ubyte line range is always 14 giving range -5 to 8 + pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); + // 1 ubyte opcode base is always 13 + pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); + // specify opcode arg sizes for the standard opcodes + putByte((byte) 0, buffer, pos); // DW_LNS_copy + putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc + putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line + putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file + putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column + putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt + putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block + putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc + putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc + putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence + putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address + pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file + return pos; + } + + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + debug(" [0x%08x] Dir Name\n", pos); + // write out the list of dirs referenced form this file entry + int dirIdx = 1; + for (DirEntry dir : classEntry.getLocalDirs()) { + // write nul terminated string text. + debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); + pos = putAsciiStringBytes(dir.getPath(), buffer, pos); + dirIdx++; + } + // separate dirs from files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + int fileIdx = 1; + debug(" [0x%08x] Entry Dir Name\n", pos); + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we need the file name minus path, the associated dir index, and 0 for time stamps + String baseName = localEntry.getBaseName(); + DirEntry dirEntry = localEntry.dirEntry; + int dirIdx = classEntry.localDirsIdx(dirEntry); + debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); + pos = putAsciiStringBytes(baseName, buffer, pos); + pos = putULEB(dirIdx, buffer, pos); + pos = putULEB(0, buffer, pos); + pos = putULEB(0, buffer, pos); + fileIdx++; + } + // terminate files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int debugLine = 1; + public int debugCopyCount = 0; + + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + // the primary file entry should always be first in the local files list + assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; + String primaryClassName = classEntry.getClassName(); + String primaryFileName = classEntry.getFileName(); + String file = primaryFileName; + int fileIdx = 1; + debug(" [0x%08x] primary class %s\n", pos, primaryClassName); + debug(" [0x%08x] primary file %s\n", pos, primaryFileName); + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + Range primaryRange = primaryEntry.getPrimary(); + assert primaryRange.getFileName().equals(primaryFileName); + // each primary represents a method i.e. a contiguous + // sequence of subranges. we assume the default state + // at the start of each sequence because we always post an + // end_sequence when we finish all the subranges in the method + long line = primaryRange.getLine(); + if (line < 0 && primaryEntry.getSubranges().size() > 0) { + line = primaryEntry.getSubranges().get(0).getLine(); + } + if (line < 0) { + line = 0; + } + long address = primaryRange.getLo(); + + // set state for primary + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), + primaryRange.getLine()); + + // initialize and write a row for the start of the primary method + pos = putSetFile(file, fileIdx, buffer, pos); + pos = putSetBasicBlock(buffer, pos); + // address is currently 0 + pos = putSetAddress(address, buffer, pos); + // state machine value of line is currently 1 + // increment to desired line + if (line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putCopy(buffer, pos); + + // now write a row for each subrange lo and hi + for (Range subrange : primaryEntry.getSubranges()) { + assert subrange.getLo() >= primaryRange.getLo(); + assert subrange.getHi() <= primaryRange.getHi(); + FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); + String subfile = subFileEntry.getFileName(); + int subFileIdx = classEntry.localFilesIdx(subFileEntry); + long subLine = subrange.getLine(); + long subAddressLo = subrange.getLo(); + long subAddressHi = subrange.getHi(); + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); + if (subLine < 0) { + // no line info so stay at previous file:line + subLine = line; + subfile = file; + subFileIdx = fileIdx; + debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); + } + // there is a temptation to append end sequence at here + // when the hiAddress lies strictly between the current + // address and the start of the next subrange because, + // ostensibly, we have void space between the end of + // the current subrange and the start of the next one. + // however, debug works better if we treat all the insns up + // to the next range start as belonging to the current line + // + // if we have to update to a new file then do so + if (subFileIdx != fileIdx) { + // update the current file + pos = putSetFile(subfile, subFileIdx, buffer, pos); + file = subfile; + fileIdx = subFileIdx; + } + // check if we can advance line and/or address in + // one byte with a special opcode + long lineDelta = subLine - line; + long addressDelta = subAddressLo - address; + byte opcode = isSpecialOpcode(addressDelta, lineDelta); + if (opcode != DW_LNS_undefined) { + // ignore pointless write when addressDelta == lineDelta == 0 + if (addressDelta != 0 || lineDelta != 0) { + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // does it help to divide and conquer using + // a fixed address increment + int remainder = isConstAddPC(addressDelta); + if (remainder > 0) { + pos = putConstAddPC(buffer, pos); + // the remaining address can be handled with a + // special opcode but what about the line delta + opcode = isSpecialOpcode(remainder, lineDelta); + if (opcode != DW_LNS_undefined) { + // address remainder and line now fit + pos = putSpecialOpcode(opcode, buffer, pos); + } else { + // ok, bump the line separately then use a + // special opcode for the address remainder + opcode = isSpecialOpcode(remainder, 0); + assert opcode != DW_LNS_undefined; + pos = putAdvanceLine(lineDelta, buffer, pos); + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // increment line and pc separately + if (lineDelta != 0) { + pos = putAdvanceLine(lineDelta, buffer, pos); + } + // n.b. we might just have had an out of range line increment + // with a zero address increment + if (addressDelta > 0) { + // see if we can use a ushort for the increment + if (isFixedAdvancePC(addressDelta)) { + pos = putFixedAdvancePC((short) addressDelta, buffer, pos); + } else { + pos = putAdvancePC(addressDelta, buffer, pos); + } + } + pos = putCopy(buffer, pos); + } + } + // move line and address range on + line += lineDelta; + address += addressDelta; + } + // append a final end sequence just below the next primary range + if (address < primaryRange.getHi()) { + long addressDelta = primaryRange.getHi() - address; + // increment address before we write the end sequence + pos = putAdvancePC(addressDelta, buffer, pos); + } + pos = putEndSequence(buffer, pos); + } + debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); + + return pos; + } + + @Override + protected void debug(String format, Object... args) { + if (((int) args[0] - debugBase) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + public int putCopy(byte[] buffer, int p) { + byte opcode = DW_LNS_copy; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debugCopyCount++; + debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); + return putByte(opcode, buffer, pos); + } + } + + public int putAdvancePC(long uleb, byte[] buffer, int p) { + byte opcode = DW_LNS_advance_pc; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debugAddress += uleb; + debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putAdvanceLine(long sleb, byte[] buffer, int p) { + byte opcode = DW_LNS_advance_line; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putSLEB(sleb, scratch, 0); + } else { + debugLine += sleb; + debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); + pos = putByte(opcode, buffer, pos); + return putSLEB(sleb, buffer, pos); + } + } + + public int putSetFile(String file, long uleb, byte[] buffer, int p) { + byte opcode = DW_LNS_set_file; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putSetColumn(long uleb, byte[] buffer, int p) { + byte opcode = DW_LNS_set_column; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putNegateStmt(byte[] buffer, int p) { + byte opcode = DW_LNS_negate_stmt; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + return putByte(opcode, buffer, pos); + } + } + + public int putSetBasicBlock(byte[] buffer, int p) { + byte opcode = DW_LNS_set_basic_block; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Set basic block\n", pos); + return putByte(opcode, buffer, pos); + } + } + + public int putConstAddPC(byte[] buffer, int p) { + byte opcode = DW_LNS_const_add_pc; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + int advance = opcodeAddress((byte) 255); + debugAddress += advance; + debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); + return putByte(opcode, buffer, pos); + } + } + + public int putFixedAdvancePC(short arg, byte[] buffer, int p) { + byte opcode = DW_LNS_fixed_advance_pc; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putShort(arg, scratch, 0); + } else { + debugAddress += arg; + debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); + pos = putByte(opcode, buffer, pos); + return putShort(arg, buffer, pos); + } + } + + public int putEndSequence(byte[] buffer, int p) { + byte opcode = DW_LNE_end_sequence; + int pos = p; + if (buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(1, scratch, 0); + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); + debugAddress = debugTextBase; + debugLine = 1; + debugCopyCount = 0; + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(1, buffer, pos); + return putByte(opcode, buffer, pos); + } + } + + public int putSetAddress(long arg, byte[] buffer, int p) { + byte opcode = DW_LNE_set_address; + int pos = p; + if (buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(9, scratch, 0); + pos = pos + putByte(opcode, scratch, 0); + return pos + putLong(arg, scratch, 0); + } else { + debugAddress = debugTextBase + (int) arg; + debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(9, buffer, pos); + pos = putByte(opcode, buffer, pos); + return putRelocatableCodeOffset(arg, buffer, pos); + } + } + + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { + byte opcode = DW_LNE_define_file; + int pos = p; + // calculate bytes needed for opcode + args + int fileBytes = file.length() + 1; + long insnBytes = 1; + insnBytes += fileBytes; + insnBytes += putULEB(uleb1, scratch, 0); + insnBytes += putULEB(uleb2, scratch, 0); + insnBytes += putULEB(uleb3, scratch, 0); + if (buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // write insnBytes as a ULEB + pos += putULEB(insnBytes, scratch, 0); + return pos + (int) insnBytes; + } else { + debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert insn length as uleb + pos = putULEB(insnBytes, buffer, pos); + // insert opcode and args + pos = putByte(opcode, buffer, pos); + pos = putAsciiStringBytes(file, buffer, pos); + pos = putULEB(uleb1, buffer, pos); + pos = putULEB(uleb2, buffer, pos); + return putULEB(uleb3, buffer, pos); + } + } + + public int opcodeId(byte opcode) { + int iopcode = opcode & 0xff; + return iopcode - DW_LN_OPCODE_BASE; + } + + public int opcodeAddress(byte opcode) { + int iopcode = opcode & 0xff; + return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + } + + public int opcodeLine(byte opcode) { + int iopcode = opcode & 0xff; + return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; + } + + public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + if (debug && opcode == 0) { + debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); + } + debugAddress += opcodeAddress(opcode); + debugLine += opcodeLine(opcode); + debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + return putByte(opcode, buffer, pos); + } + } + + private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); + + public byte isSpecialOpcode(long addressDelta, long lineDelta) { + if (addressDelta < 0) { + return DW_LNS_undefined; + } + if (lineDelta >= DW_LN_LINE_BASE) { + long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; + if (offsetLineDelta < DW_LN_LINE_RANGE) { + // line_delta can be encoded + // check if address is ok + if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { + long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; + if (opcode <= 255) { + return (byte) opcode; + } + } + } + } + + // return invalid opcode + return DW_LNS_undefined; + } + + public int isConstAddPC(long addressDelta) { + if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { + return 0; + } + if (addressDelta <= MAX_ADDPC_DELTA) { + return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); + } else { + return 0; + } + } + + public boolean isFixedAdvancePC(long addressDiff) { + return addressDiff >= 0 && addressDiff < 0xffff; + } + + /** + * debug_line section content depends on debug_str section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} 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 new file mode 100644 index 000000000000..b3a270fe5682 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.elf.ELFObjectFile; + +import java.util.Map; +import java.util.Set; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; + +/** + * class from which all DWARF debug sections + * inherit providing common behaviours. + */ +public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { + protected DwarfSections dwarfSections; + public boolean debug = false; + public long debugTextBase = 0; + public long debugAddress = 0; + public int debugBase = 0; + + public DwarfSectionImpl(DwarfSections dwarfSections) { + this.dwarfSections = dwarfSections; + } + + /** + * creates the target byte[] array used to define the section + * contents. + * + * the main task of this method is to precompute the + * size of the debug section. given the complexity of the + * data layouts that invariably requires performing a dummy + * write of the contents, inserting bytes into a small, + * scratch buffer only when absolutely necessary. subclasses + * may also cache some information for use when writing the + * contents. + */ + public abstract void createContent(); + + /** + * populates the byte[] array used to contain the section + * contents. + * + * in most cases this task reruns the operations performed + * under createContent but this time actually writing data + * to the target byte[]. + */ + public abstract void writeContent(); + + @Override + public boolean isLoadable() { + // even though we're a progbits section impl we're not actually loadable + return false; + } + + public void checkDebug(int pos) { + // if the env var relevant to this element + // type is set then switch on debugging + String name = getSectionName(); + String envVarName = "DWARF_" + name.substring(1).toUpperCase(); + if (System.getenv(envVarName) != null) { + debug = true; + debugBase = pos; + debugAddress = debugTextBase; + } + } + + protected void debug(String format, Object... args) { + if (debug) { + System.out.format(format, args); + } + } + + // base level put methods that assume a non-null buffer + + public int putByte(byte b, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = b; + return pos; + } + + public int putShort(short s, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + return pos; + } + + public int putInt(int i, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + return pos; + } + + public int putLong(long l, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + return pos; + } + + public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { + int pos = p; + // mark address so it is relocated relative to the start of the text segment + markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); + pos = putLong(0, buffer, pos); + return pos; + } + + public int putULEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >>> 7; + boolean done = (l == 0); + if (!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if (done) { + break; + } + } + return pos; + } + + public int putSLEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >> 7; + boolean bIsSigned = (b & 0x40) != 0; + boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); + if (!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if (done) { + break; + } + } + return pos; + } + + public int putAsciiStringBytes(String s, byte[] buffer, int pos) { + return putAsciiStringBytes(s, 0, buffer, pos); + } + + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { + int pos = p; + for (int l = startChar; l < s.length(); l++) { + char c = s.charAt(l); + if (c > 127) { + throw new RuntimeException("oops : expected ASCII string! " + s); + } + buffer[pos++] = (byte) c; + } + buffer[pos++] = '\0'; + return pos; + } + + // common write methods that check for a null buffer + + public void patchLength(int lengthPos, byte[] buffer, int pos) { + if (buffer != null) { + int length = pos - (lengthPos + 4); + putInt(length, buffer, lengthPos); + } + } + + public int writeAbbrevCode(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeTag(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeFlag(byte flag, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(flag, scratch, 0); + } else { + return putByte(flag, buffer, pos); + } + } + + public int writeAttrAddress(long address, byte[] buffer, int pos) { + if (buffer == null) { + return pos + 8; + } else { + return putRelocatableCodeOffset(address, buffer, pos); + } + } + + public int writeAttrData8(long value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putLong(value, scratch, 0); + } else { + return putLong(value, buffer, pos); + } + } + + public int writeAttrData4(int value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putInt(value, scratch, 0); + } else { + return putInt(value, buffer, pos); + } + } + + public int writeAttrData1(byte value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(value, scratch, 0); + } else { + return putByte(value, buffer, pos); + } + } + + public int writeAttrNull(byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(0, scratch, 0); + } else { + return putSLEB(0, buffer, pos); + } + } + + /** + * identify the section after which this debug section + * needs to be ordered when sizing and creating content. + * @return the name of the preceding section + */ + public abstract String targetSectionName(); + + /** + * identify the layout properties of the target section + * which need to have been decided before the contents + * of this section can be created. + * @return an array of the relevant decision kinds + */ + public abstract LayoutDecision.Kind[] targetSectionKinds(); + + /** + * identify this debug section by name. + * @return the name of the debug section + */ + public abstract String getSectionName(); + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + // ensure content byte[] has been created before calling super method + createContent(); + + // ensure content byte[] has been written before calling super method + writeContent(); + + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public Set getDependencies(Map decisions) { + Set deps = super.getDependencies(decisions); + String targetName = targetSectionName(); + ELFObjectFile.ELFSection targetSection = (ELFObjectFile.ELFSection) getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + // make our content depend on the size and content of the target + for (LayoutDecision.Kind targetKind : targetKinds) { + LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + } + // make our size depend on our content + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + + return deps; + } + + /** + * a scratch buffer used during computation of a section's size. + */ + protected static final byte[] scratch = new byte[10]; + + protected Iterable getPrimaryClasses() { + return dwarfSections.getPrimaryClasses(); + } + + protected int debugStringIndex(String str) { + return dwarfSections.debugStringIndex(str); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 474e74d20735..817ad2f868a7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -26,11 +26,7 @@ package com.oracle.objectfile.elf.dwarf; -import com.oracle.objectfile.BasicProgbitsSectionImpl; -import com.oracle.objectfile.BuildDependency; import com.oracle.objectfile.LayoutDecision; -import com.oracle.objectfile.LayoutDecisionMap; -import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; @@ -38,22 +34,19 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; // import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; -import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.elf.ELFMachine; -import com.oracle.objectfile.elf.ELFObjectFile.ELFSection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; /** - * an outer class that models the debug info in an + * A class that models the debug info in an * organization that facilitates generation of the * required DWARF sections. It groups common data and * behaviours for use by the various subclasses of - * inner class DwarfSectionImpl that take responsibility + * class DwarfSectionImpl that take responsibility * for generating content for a specific section type. */ public class DwarfSections { @@ -70,83 +63,83 @@ public class DwarfSections { /** * currently generated debug info relies on DWARF spec vesion 2. */ - private static final short DW_VERSION_2 = 2; + public static final short DW_VERSION_2 = 2; // define all the abbrev section codes we need for our DIEs - // private static final int DW_ABBREV_CODE_null = 0; - private static final int DW_ABBREV_CODE_compile_unit = 1; - private static final int DW_ABBREV_CODE_subprogram = 2; + // public static final int DW_ABBREV_CODE_null = 0; + public static final int DW_ABBREV_CODE_compile_unit = 1; + public static final int DW_ABBREV_CODE_subprogram = 2; // define all the Dwarf tags we need for our DIEs - private static final int DW_TAG_compile_unit = 0x11; - private static final int DW_TAG_subprogram = 0x2e; + public static final int DW_TAG_compile_unit = 0x11; + public static final int DW_TAG_subprogram = 0x2e; // define all the Dwarf attributes we need for our DIEs - private static final int DW_AT_null = 0x0; - private static final int DW_AT_name = 0x3; - // private static final int DW_AT_comp_dir = 0x1b; - private static final int DW_AT_stmt_list = 0x10; - private static final int DW_AT_low_pc = 0x11; - private static final int DW_AT_hi_pc = 0x12; - private static final int DW_AT_language = 0x13; - private static final int DW_AT_external = 0x3f; - // private static final int DW_AT_return_addr = 0x2a; - // private static final int DW_AT_frame_base = 0x40; + public static final int DW_AT_null = 0x0; + public static final int DW_AT_name = 0x3; + // public static final int DW_AT_comp_dir = 0x1b; + public static final int DW_AT_stmt_list = 0x10; + public static final int DW_AT_low_pc = 0x11; + public static final int DW_AT_hi_pc = 0x12; + public static final int DW_AT_language = 0x13; + public static final int DW_AT_external = 0x3f; + // public static final int DW_AT_return_addr = 0x2a; + // public static final int DW_AT_frame_base = 0x40; // define all the Dwarf attribute forms we need for our DIEs - private static final int DW_FORM_null = 0x0; + public static final int DW_FORM_null = 0x0; // private static final int DW_FORM_string = 0x8; - private static final int DW_FORM_strp = 0xe; // not currently used - private static final int DW_FORM_addr = 0x1; - private static final int DW_FORM_data1 = 0x0b; // use flag instead - private static final int DW_FORM_data4 = 0x6; - // private static final int DW_FORM_data8 = 0x7; - // private static final int DW_FORM_block1 = 0x0a; - private static final int DW_FORM_flag = 0xc; + public static final int DW_FORM_strp = 0xe; // not currently used + public static final int DW_FORM_addr = 0x1; + public static final int DW_FORM_data1 = 0x0b; // use flag instead + public static final int DW_FORM_data4 = 0x6; + // public static final int DW_FORM_data8 = 0x7; + // public static final int DW_FORM_block1 = 0x0a; + public static final int DW_FORM_flag = 0xc; // define specific attribute values for given attribute or form types // DIE header has_children attribute values - private static final byte DW_CHILDREN_no = 0; - private static final byte DW_CHILDREN_yes = 1; + public static final byte DW_CHILDREN_no = 0; + public static final byte DW_CHILDREN_yes = 1; // DW_FORM_flag attribute values - // private static final byte DW_FLAG_false = 0; - private static final byte DW_FLAG_true = 1; + // public static final byte DW_FLAG_false = 0; + public static final byte DW_FLAG_true = 1; // value for DW_AT_language attribute with form DATA1 - private static final byte DW_LANG_Java = 0xb; + public static final byte DW_LANG_Java = 0xb; // access not needed until we make functions members // DW_AT_Accessibility attribute values - // private static final byte DW_ACCESS_public = 1; - // private static final byte DW_ACCESS_protected = 2; - // private static final byte DW_ACCESS_private = 3; + // public static final byte DW_ACCESS_public = 1; + // public static final byte DW_ACCESS_protected = 2; + // public static final byte DW_ACCESS_private = 3; // not yet needed - // private static final int DW_AT_type = 0; // only present for non-void functions - // private static final int DW_AT_accessibility = 0; + // public static final int DW_AT_type = 0; // only present for non-void functions + // public static final int DW_AT_accessibility = 0; // CIE and FDE entries - private static final int DW_CFA_CIE_id = -1; - // private static final int DW_CFA_FDE_id = 0; + public static final int DW_CFA_CIE_id = -1; + // public static final int DW_CFA_FDE_id = 0; - private static final byte DW_CFA_CIE_version = 1; + public static final byte DW_CFA_CIE_version = 1; // values for high 2 bits - private static final byte DW_CFA_advance_loc = 0x1; - private static final byte DW_CFA_offset = 0x2; - // private static final byte DW_CFA_restore = 0x3; + public static final byte DW_CFA_advance_loc = 0x1; + public static final byte DW_CFA_offset = 0x2; + // public static final byte DW_CFA_restore = 0x3; // values for low 6 bits - private static final byte DW_CFA_nop = 0x0; - // private static final byte DW_CFA_set_loc1 = 0x1; - private static final byte DW_CFA_advance_loc1 = 0x2; - private static final byte DW_CFA_advance_loc2 = 0x3; - private static final byte DW_CFA_advance_loc4 = 0x4; - // private static final byte DW_CFA_offset_extended = 0x5; - // private static final byte DW_CFA_restore_extended = 0x6; - // private static final byte DW_CFA_undefined = 0x7; - // private static final byte DW_CFA_same_value = 0x8; - private static final byte DW_CFA_register = 0x9; - private static final byte DW_CFA_def_cfa = 0xc; - // private static final byte DW_CFA_def_cfa_register = 0xd; - private static final byte DW_CFA_def_cfa_offset = 0xe; + public static final byte DW_CFA_nop = 0x0; + // public static final byte DW_CFA_set_loc1 = 0x1; + public static final byte DW_CFA_advance_loc1 = 0x2; + public static final byte DW_CFA_advance_loc2 = 0x3; + public static final byte DW_CFA_advance_loc4 = 0x4; + // public static final byte DW_CFA_offset_extended = 0x5; + // public static final byte DW_CFA_restore_extended = 0x6; + // public static final byte DW_CFA_undefined = 0x7; + // public static final byte DW_CFA_same_value = 0x8; + public static final byte DW_CFA_register = 0x9; + public static final byte DW_CFA_def_cfa = 0xc; + // public static final byte DW_CFA_def_cfa_register = 0xd; + public static final byte DW_CFA_def_cfa_offset = 0xe; private ELFMachine elfMachine; private DwarfStrSectionImpl dwarfStrSection; @@ -158,14 +151,16 @@ public class DwarfSections { public DwarfSections(ELFMachine elfMachine) { this.elfMachine = elfMachine; - dwarfStrSection = new DwarfStrSectionImpl(); - dwarfAbbrevSection = new DwarfAbbrevSectionImpl(); - dwarfInfoSection = new DwarfInfoSectionImpl(); - dwarfARangesSection = new DwarfARangesSectionImpl(); - dwarfLineSection = new DwarfLineSectionImpl(); - dwarfFameSection = (elfMachine == ELFMachine.AArch64 - ? new DwarfFrameSectionImplAArch64() - : new DwarfFrameSectionImplX86_64()); + dwarfStrSection = new DwarfStrSectionImpl(this); + dwarfAbbrevSection = new DwarfAbbrevSectionImpl(this); + dwarfInfoSection = new DwarfInfoSectionImpl(this); + dwarfARangesSection = new DwarfARangesSectionImpl(this); + dwarfLineSection = new DwarfLineSectionImpl(this); + if (elfMachine == ELFMachine.AArch64) { + dwarfFameSection = new DwarfFrameSectionImplAArch64(this); + } else { + dwarfFameSection = new DwarfFrameSectionImplX86_64(this); + } } public DwarfStrSectionImpl getStrSectionImpl() { @@ -192,15 +187,6 @@ public DwarfLineSectionImpl getLineSectionImpl() { return dwarfLineSection; } - public ELFMachine getElfMachine() { - return elfMachine; - } - - /** - * a scratch buffer used during computation of a section's size. - */ - protected static final byte[] scratch = new byte[10]; - /** * a table listing all known strings, some of * which may be marked for insertion into the @@ -293,7 +279,7 @@ public String uniqueDebugString(String string) { * @return the offset of the string in the .debug_str * section */ - private int debugStringIndex(String string) { + public int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } @@ -405,7 +391,7 @@ public void addSubRange(Range primaryRange, Range subrange) { classEntry.addSubRange(subrange, subrangeEntry); } - private DirEntry ensureDirEntry(String file) { + public DirEntry ensureDirEntry(String file) { int pathLength = file.lastIndexOf('/'); if (pathLength < 0) { // no path/package means use dir entry 0 @@ -420,1917 +406,10 @@ private DirEntry ensureDirEntry(String file) { } return dirEntry; } - - /** - * class from which all DWARF debug section - * inherit providing common behaviours. - */ - // shared implementation methods to manage content creation - public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { - public boolean debug = false; - public long debugTextBase = 0; - public long debugAddress = 0; - public int debugBase = 0; - - public DwarfSectionImpl() { - } - - /** - * creates the target byte[] array used to define the section - * contents. - * - * the main task of this method is to precompute the - * size of the debug section. given the complexity of the - * data layouts that invariably requires performing a dummy - * write of the contents, inserting bytes into a small, - * scratch buffer only when absolutely necessary. subclasses - * may also cache some information for use when writing the - * contents. - */ - public abstract void createContent(); - - /** - * populates the byte[] array used to contain the section - * contents. - * - * in most cases this task reruns the operations performed - * under createContent but this time actually writing data - * to the target byte[]. - */ - public abstract void writeContent(); - - @Override - public boolean isLoadable() { - // even though we're a progbits section impl we're not actually loadable - return false; - } - - public void checkDebug(int pos) { - // if the env var relevant to this element - // type is set then switch on debugging - String name = getSectionName(); - String envVarName = "DWARF_" + name.substring(1).toUpperCase(); - if (System.getenv(envVarName) != null) { - debug = true; - debugBase = pos; - debugAddress = debugTextBase; - } - } - - protected void debug(String format, Object... args) { - if (debug) { - System.out.format(format, args); - } - } - - // base level put methods that assume a non-null buffer - - public int putByte(byte b, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = b; - return pos; - } - - public int putShort(short s, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = (byte) (s & 0xff); - buffer[pos++] = (byte) ((s >> 8) & 0xff); - return pos; - } - - public int putInt(int i, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = (byte) (i & 0xff); - buffer[pos++] = (byte) ((i >> 8) & 0xff); - buffer[pos++] = (byte) ((i >> 16) & 0xff); - buffer[pos++] = (byte) ((i >> 24) & 0xff); - return pos; - } - - public int putLong(long l, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = (byte) (l & 0xff); - buffer[pos++] = (byte) ((l >> 8) & 0xff); - buffer[pos++] = (byte) ((l >> 16) & 0xff); - buffer[pos++] = (byte) ((l >> 24) & 0xff); - buffer[pos++] = (byte) ((l >> 32) & 0xff); - buffer[pos++] = (byte) ((l >> 40) & 0xff); - buffer[pos++] = (byte) ((l >> 48) & 0xff); - buffer[pos++] = (byte) ((l >> 56) & 0xff); - return pos; - } - - public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { - int pos = p; - // mark address so it is relocated relative to the start of the text segment - markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); - pos = putLong(0, buffer, pos); - return pos; - } - - public int putULEB(long val, byte[] buffer, int p) { - long l = val; - int pos = p; - for (int i = 0; i < 9; i++) { - byte b = (byte) (l & 0x7f); - l = l >>> 7; - boolean done = (l == 0); - if (!done) { - b = (byte) (b | 0x80); - } - pos = putByte(b, buffer, pos); - if (done) { - break; - } - } - return pos; - } - - public int putSLEB(long val, byte[] buffer, int p) { - long l = val; - int pos = p; - for (int i = 0; i < 9; i++) { - byte b = (byte) (l & 0x7f); - l = l >> 7; - boolean bIsSigned = (b & 0x40) != 0; - boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); - if (!done) { - b = (byte) (b | 0x80); - } - pos = putByte(b, buffer, pos); - if (done) { - break; - } - } - return pos; - } - - public int putAsciiStringBytes(String s, byte[] buffer, int pos) { - return putAsciiStringBytes(s, 0, buffer, pos); - } - - public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { - int pos = p; - for (int l = startChar; l < s.length(); l++) { - char c = s.charAt(l); - if (c > 127) { - throw new RuntimeException("oops : expected ASCII string! " + s); - } - buffer[pos++] = (byte) c; - } - buffer[pos++] = '\0'; - return pos; - } - - // common write methods that check for a null buffer - - public void patchLength(int lengthPos, byte[] buffer, int pos) { - if (buffer != null) { - int length = pos - (lengthPos + 4); - putInt(length, buffer, lengthPos); - } - } - - public int writeAbbrevCode(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeTag(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeFlag(byte flag, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putByte(flag, scratch, 0); - } else { - return putByte(flag, buffer, pos); - } - } - - public int writeAttrAddress(long address, byte[] buffer, int pos) { - if (buffer == null) { - return pos + 8; - } else { - return putRelocatableCodeOffset(address, buffer, pos); - } - } - - public int writeAttrData8(long value, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putLong(value, scratch, 0); - } else { - return putLong(value, buffer, pos); - } - } - - public int writeAttrData4(int value, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putInt(value, scratch, 0); - } else { - return putInt(value, buffer, pos); - } - } - - public int writeAttrData1(byte value, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putByte(value, scratch, 0); - } else { - return putByte(value, buffer, pos); - } - } - - public int writeAttrNull(byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(0, scratch, 0); - } else { - return putSLEB(0, buffer, pos); - } - } - - /** - * identify the section after which this debug section - * needs to be ordered when sizing and creating content. - * @return the name of the preceding section - */ - public abstract String targetSectionName(); - - /** - * identify the layout properties of the target section - * which need to have been decided before the contents - * of this section can be created. - * @return an array of the relevant decision kinds - */ - public abstract LayoutDecision.Kind[] targetSectionKinds(); - - /** - * identify this debug section by name. - * @return the name of the debug section - */ - public abstract String getSectionName(); - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - // ensure content byte[] has been created before calling super method - createContent(); - - // ensure content byte[] has been written before calling super method - writeContent(); - - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public Set getDependencies(Map decisions) { - Set deps = super.getDependencies(decisions); - String targetName = targetSectionName(); - ELFSection targetSection = (ELFSection) getElement().getOwner().elementForName(targetName); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); - LayoutDecision.Kind[] targetKinds = targetSectionKinds(); - // make our content depend on the size and content of the target - for (LayoutDecision.Kind targetKind : targetKinds) { - LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); - deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); - } - // make our size depend on our content - deps.add(BuildDependency.createOrGet(ourSize, ourContent)); - - return deps; - } - } - - /** - * generator for debug_str section. - */ - public class DwarfStrSectionImpl extends DwarfSectionImpl { - public DwarfStrSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_STR_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()) { - stringEntry.setOffset(pos); - String string = stringEntry.getString(); - pos += string.length() + 1; - } - } - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()) { - assert stringEntry.getOffset() == pos; - String string = stringEntry.getString(); - pos = putAsciiStringBytes(string, buffer, pos); - } - } - assert pos == size; - } - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - /** - * debug_str section content depends on text section content and offset. - */ - public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - /** - * debug_str section content depends on text section content and offset. - */ - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } + public StringTable getStringTable() { + return stringTable; } - - /** - * generator for debug_abbrev section. - */ - public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { - - public DwarfAbbrevSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_ABBREV_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - // an abbrev table contains abbrev entries for one or - // more CUs. the table includes a sequence of abbrev - // entries each of which defines a specific DIE layout - // employed to describe some DIE in a CU. a table is - // terminated by a null entry - // - // a null entry has consists of just a 0 abbrev code - // LEB128 abbrev_code; ...... == 0 - // - // non-null entries have the following format - // LEB128 abbrev_code; ...... unique noncode for this layout != 0 - // 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 DIE - // * ........ zero or more attributes - // .... terminator - // - // An attribute_spec consists of an attribute name and form - // LEB128 attr_name; ........ 0 for the null attribute name - // LEB128 attr_form; ........ 0 for the null attribute form - // - // For the moment we only use one abbrev table for all CUs. - // It contains two DIEs, the first to describe the compilation - // unit itself and the second to describe each method within - // that compilation unit. - // - // The DIE layouts are as follows: - // - // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - // DW_AT_language : ... DW_FORM_data1 - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_address - // DW_AT_hi_pc : ...... DW_FORM_address - // DW_AT_stmt_list : .. DW_FORM_data4 - // - // abbrev_code == 2, tag == DW_TAG_subprogram, no_children - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_addr - // DW_AT_hi_pc : ...... DW_FORM_addr - // DW_AT_external : ... DW_FORM_flag - - pos = writeAbbrev1(null, pos); - pos = writeAbbrev2(null, pos); - - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - pos = writeAbbrev1(buffer, pos); - pos = writeAbbrev2(buffer, pos); - assert pos == size; - } - - public int writeAttrType(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeAttrForm(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeAbbrev1(byte[] buffer, int p) { - int pos = p; - // abbrev 1 compile unit - pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); - pos = writeTag(DW_TAG_compile_unit, buffer, pos); - pos = writeFlag(DW_CHILDREN_yes, buffer, pos); - pos = writeAttrType(DW_AT_language, buffer, pos); - pos = writeAttrForm(DW_FORM_data1, buffer, pos); - pos = writeAttrType(DW_AT_name, buffer, pos); - pos = writeAttrForm(DW_FORM_strp, buffer, pos); - pos = writeAttrType(DW_AT_low_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_hi_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_stmt_list, buffer, pos); - pos = writeAttrForm(DW_FORM_data4, buffer, pos); - // now terminate - pos = writeAttrType(DW_AT_null, buffer, pos); - pos = writeAttrForm(DW_FORM_null, buffer, pos); - return pos; - } - - public int writeAbbrev2(byte[] buffer, int p) { - int pos = p; - // abbrev 2 compile unit - pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - pos = writeTag(DW_TAG_subprogram, buffer, pos); - pos = writeFlag(DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DW_AT_name, buffer, pos); - pos = writeAttrForm(DW_FORM_strp, buffer, pos); - pos = writeAttrType(DW_AT_low_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_hi_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_external, buffer, pos); - pos = writeAttrForm(DW_FORM_flag, buffer, pos); - // now terminate - pos = writeAttrType(DW_AT_null, buffer, pos); - pos = writeAttrForm(DW_FORM_null, buffer, pos); - return pos; - } - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - /** - * debug_abbrev section content depends on debug_frame section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - } - - /** - * generic generator for debug_frame section. - */ - public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { - - public DwarfFrameSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_FRAME_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - - // the frame section contains one CIE at offset 0 - // followed by an FIE for each method - pos = writeCIE(null, pos); - pos = writeMethodFrames(null, pos); - - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - // there are entries for the prologue region where the - // stack is being built, the method body region(s) where - // the code executes with a fixed size frame and the - // epilogue region(s) where the stack is torn down - pos = writeCIE(buffer, pos); - pos = writeMethodFrames(buffer, pos); - - if (pos != size) { - System.out.format("pos = 0x%x size = 0x%x", pos, size); - } - assert pos == size; - } - - public int writeCIE(byte[] buffer, int p) { - // we only need a vanilla CIE with default fields - // because we have to have at least one - // the layout is - // - // uint32 : length ............... length of remaining fields in this CIE - // uint32 : CIE_id ................ unique id for CIE == 0xffffff - // uint8 : version ................ == 1 - // uint8[] : augmentation ......... == "" so always 1 byte - // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) - // ULEB : data_alignment_factor ... == -8 - // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 - // byte[] : initial_instructions .. includes pad to 8-byte boundary - int pos = p; - if (buffer == null) { - pos += putInt(0, scratch, 0); // don't care about length - pos += putInt(DW_CFA_CIE_id, scratch, 0); - pos += putByte(DW_CFA_CIE_version, scratch, 0); - pos += putAsciiStringBytes("", scratch, 0); - pos += putULEB(1, scratch, 0); - pos += putSLEB(-8, scratch, 0); - pos += putByte((byte) getPCIdx(), scratch, 0); - // write insns to set up empty frame - pos = writeInitialInstructions(buffer, pos); - // pad to word alignment - pos = writePaddingNops(8, buffer, pos); - // no need to write length - return pos; - } else { - int lengthPos = pos; - pos = putInt(0, buffer, pos); - pos = putInt(DW_CFA_CIE_id, buffer, pos); - pos = putByte(DW_CFA_CIE_version, buffer, pos); - pos = putAsciiStringBytes("", buffer, pos); - pos = putULEB(1, buffer, pos); - pos = putSLEB(-8, buffer, pos); - pos = putByte((byte) getPCIdx(), buffer, pos); - // write insns to set up empty frame - pos = writeInitialInstructions(buffer, pos); - // pad to word alignment - pos = writePaddingNops(8, buffer, pos); - patchLength(lengthPos, buffer, pos); - return pos; - } - } - - public int writeMethodFrames(byte[] buffer, int p) { - int pos = p; - for (ClassEntry classEntry : primaryClasses) { - for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { - long lo = primaryEntry.getPrimary().getLo(); - long hi = primaryEntry.getPrimary().getHi(); - int frameSize = primaryEntry.getFrameSize(); - int currentOffset = 0; - int lengthPos = pos; - pos = writeFDEHeader((int) lo, (int) hi, buffer, pos); - for (DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { - int advance = debugFrameSizeInfo.getOffset() - currentOffset; - currentOffset += advance; - pos = writeAdvanceLoc(advance, buffer, pos); - if (debugFrameSizeInfo.getType() == DebugFrameSizeChange.Type.EXTEND) { - // SP has been extended so rebase CFA using full frame - pos = writeDefCFAOffset(frameSize, buffer, pos); - } else { - // SP has been contracted so rebase CFA using empty frame - pos = writeDefCFAOffset(8, buffer, pos); - } - } - pos = writePaddingNops(8, buffer, pos); - patchLength(lengthPos, buffer, pos); - } - } - return pos; - } - - public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { - // we only need a vanilla FDE header with default fields - // the layout is - // - // uint32 : length ........... length of remaining fields in this FDE - // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header - // uint64 : initial_location .. i.e. method lo address - // uint64 : address_range ..... i.e. method hi - lo - // byte[] : instructions ...... includes pad to 8-byte boundary - - int pos = p; - if (buffer == null) { - pos += putInt(0, scratch, 0); // dummy length - pos += putInt(0, scratch, 0); // CIE_offset - pos += putLong(lo, scratch, 0); // initial address - return pos + putLong(hi - lo, scratch, 0); // address range - } else { - pos = putInt(0, buffer, pos); // dummy length - pos = putInt(0, buffer, pos); // CIE_offset - pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address - return putLong(hi - lo, buffer, pos); // address range - } - } - - public int writePaddingNops(int alignment, byte[] buffer, int p) { - int pos = p; - assert (alignment & (alignment - 1)) == 0; - while ((pos & (alignment - 1)) != 0) { - if (buffer == null) { - pos++; - } else { - pos = putByte(DW_CFA_nop, buffer, pos); - } - } - return pos; - } - - public int writeDefCFA(int register, int offset, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putByte(DW_CFA_def_cfa, scratch, 0); - pos += putSLEB(register, scratch, 0); - return pos + putULEB(offset, scratch, 0); - } else { - pos = putByte(DW_CFA_def_cfa, buffer, pos); - pos = putULEB(register, buffer, pos); - return putULEB(offset, buffer, pos); - } - } - - public int writeDefCFAOffset(int offset, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); - return pos + putULEB(offset, scratch, 0); - } else { - pos = putByte(DW_CFA_def_cfa_offset, buffer, pos); - return putULEB(offset, buffer, pos); - } - } - - public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { - if (offset <= 0x3f) { - return writeAdvanceLoc0((byte) offset, buffer, pos); - } else if (offset <= 0xff) { - return writeAdvanceLoc1((byte) offset, buffer, pos); - } else if (offset <= 0xffff) { - return writeAdvanceLoc2((short) offset, buffer, pos); - } else { - return writeAdvanceLoc4(offset, buffer, pos); - } - } - - public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { - byte op = advanceLoc0Op(offset); - if (buffer == null) { - return pos + putByte(op, scratch, 0); - } else { - return putByte(op, buffer, pos); - } - } - - public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { - int pos = p; - byte op = DW_CFA_advance_loc1; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putByte(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putByte(offset, buffer, pos); - } - } - - public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { - byte op = DW_CFA_advance_loc2; - int pos = p; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putShort(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putShort(offset, buffer, pos); - } - } - - public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { - byte op = DW_CFA_advance_loc4; - int pos = p; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putInt(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putInt(offset, buffer, pos); - } - } - - public int writeOffset(int register, int offset, byte[] buffer, int p) { - byte op = offsetOp(register); - int pos = p; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putULEB(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putULEB(offset, buffer, pos); - } - } - - public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putByte(DW_CFA_register, scratch, 0); - pos += putULEB(savedReg, scratch, 0); - return pos + putULEB(savedToReg, scratch, 0); - } else { - pos = putByte(DW_CFA_register, buffer, pos); - pos = putULEB(savedReg, buffer, pos); - return putULEB(savedToReg, buffer, pos); - } - } - - public abstract int getPCIdx(); - - public abstract int getSPIdx(); - - public abstract int writeInitialInstructions(byte[] buffer, int pos); - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - /** - * debug_frame section content depends on debug_line section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - - private byte offsetOp(int register) { - assert (register >> 6) == 0; - return (byte) ((DW_CFA_offset << 6) | register); - } - - private byte advanceLoc0Op(int offset) { - assert (offset >= 0 && offset <= 0x3f); - return (byte) ((DW_CFA_advance_loc << 6) | offset); - } - } - - /** - * x86_64-specific generator for debug_frame section - * that knows details of x86_64 registers and frame layout. - */ - public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_RSP_IDX = 7; - public static final int DW_CFA_RIP_IDX = 16; - - public DwarfFrameSectionImplX86_64() { - super(); - } - - @Override - public int getPCIdx() { - return DW_CFA_RIP_IDX; - } - - @Override - public int getSPIdx() { - return DW_CFA_RSP_IDX; - } - - @Override - public int writeInitialInstructions(byte[] buffer, int p) { - int pos = p; - // rsp points at the word containing the saved rip - // so the frame base (cfa) is at rsp + 8 (why not - ???) - // def_cfa r7 (sp) offset 8 - pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); - // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa - // (why not -1 ???) - // offset r16 (rip) cfa - 8 - pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); - return pos; - } - } - - /** - * AArch64-specific generator for debug_frame section - * that knows details of AArch64 registers and frame layout. - */ - public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_FP_IDX = 29; - public static final int DW_CFA_LR_IDX = 30; - public static final int DW_CFA_SP_IDX = 31; - public static final int DW_CFA_PC_IDX = 32; - - public DwarfFrameSectionImplAArch64() { - super(); - } - - @Override - public int getPCIdx() { - return DW_CFA_PC_IDX; - } - - @Override - public int getSPIdx() { - return DW_CFA_SP_IDX; - } - - @Override - public int writeInitialInstructions(byte[] buffer, int p) { - int pos = p; - // rsp has not been updated - // caller pc is in lr - // register r32 (rpc), r30 (lr) - pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); - return pos; - } - } - - /** - * generator for debug_info section. - */ - public class DwarfInfoSectionImpl extends DwarfSectionImpl { - /** - * an info header section always contains a fixed number of bytes. - */ - private static final int DW_DIE_HEADER_SIZE = 11; - - public DwarfInfoSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_INFO_SECTION_NAME; - } - - @Override - public void createContent() { - // we need a single level 0 DIE for each compilation unit (CU) - // Each CU's Level 0 DIE is preceded by a fixed header: - // and terminated by a null DIE - // uint32 length ......... excluding this length field - // uint16 dwarf_version .. always 2 ?? - // uint32 abbrev offset .. always 0 ?? - // uint8 address_size .... always 8 - // * ................ sequence of top-level and nested child entries - // ............ == 0 - // - // a DIE is a recursively defined structure - // it starts with a code for the associated - // abbrev entry followed by a series of attribute - // values as determined by the entry terminated by - // a null value and followed by zero or more child - // DIEs (zero iff has_children == no_children) - // - // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE - // * ....... value sequence as determined by abbrev entry - // * ................... sequence of child DIEs (if appropriate) - // ............. == 0 - // - // note that a null_DIE looks like - // LEB128 abbrev_code ....... == 0 - // i.e. it also looks like a null_value - - byte[] buffer = null; - int pos = 0; - - for (ClassEntry classEntry : primaryClasses) { - int lengthPos = pos; - pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); - // no need to backpatch length at lengthPos - } - buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - debug(" [0x%08x] DEBUG_INFO\n", pos); - debug(" [0x%08x] size = 0x%08x\n", pos, size); - for (ClassEntry classEntry : primaryClasses) { - // save the offset of this file's CU so it can - // be used when writing the aranges section - classEntry.setCUIndex(pos); - int lengthPos = pos; - pos = writeCUHeader(buffer, pos); - debug(" [0x%08x] Compilation Unit\n", pos, size); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); - // backpatch length at lengthPos (excluding length field) - patchLength(lengthPos, buffer, pos); - } - assert pos == size; - } - - public int writeCUHeader(byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putInt(0, scratch, 0); // CU length - pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version - pos += putInt(0, scratch, 0); // abbrev offset - return pos + putByte((byte) 8, scratch, 0); // address size - } else { - pos = putInt(0, buffer, pos); // CU length - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version - pos = putInt(0, buffer, pos); // abbrev offset - return putByte((byte) 8, buffer, pos); // address size - } - } - - public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); - pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); - debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); - pos = writeAttrData1(DW_LANG_Java, buffer, pos); - debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); - pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); - pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); - debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); - pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); - debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); - pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); - for (PrimaryEntry primaryEntry : classPrimaryEntries) { - pos = writePrimary(primaryEntry, buffer, pos); - } - // write a terminating null attribute for the the level 2 primaries - return writeAttrNull(buffer, pos); - - } - - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { - int pos = p; - Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); - pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); - pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); - pos = writeAttrAddress(primary.getLo(), buffer, pos); - debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); - pos = writeAttrAddress(primary.getHi(), buffer, pos); - // need to pass true only if method is public - debug(" [0x%08x] external true\n", pos); - return writeFlag(DW_FLAG_true, buffer, pos); - } - - public int writeAttrStrp(String value, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - return pos + putInt(0, scratch, 0); - } else { - int idx = debugStringIndex(value); - return putInt(idx, buffer, pos); - } - } - - public int writeAttrString(String value, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - return pos + value.length() + 1; - } else { - return putAsciiStringBytes(value, buffer, pos); - } - } - - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - - /** - * debug_info section content depends on abbrev section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - } - - /** - * generator for debug_aranges section. - */ - public class DwarfARangesSectionImpl extends DwarfSectionImpl { - private static final int DW_AR_HEADER_SIZE = 12; - private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size - - public DwarfARangesSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_ARANGES_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - // we need an entry for each compilation unit - // - // uint32 length ............ in bytes (not counting these 4 bytes) - // uint16 dwarf_version ..... always 2 - // uint32 info_offset ....... offset of compilation unit on debug_info - // uint8 address_size ....... always 8 - // uint8 segment_desc_size .. ??? - // - // i.e. 12 bytes followed by padding - // aligning up to 2 * address size - // - // uint8 pad[4] - // - // followed by N + 1 times - // - // uint64 lo ................ lo address of range - // uint64 length ............ number of bytes in range - // - // where N is the number of ranges belonging to the compilation unit - // and the last range contains two zeroes - - for (ClassEntry classEntry : primaryClasses) { - pos += DW_AR_HEADER_SIZE; - // align to 2 * address size - pos += DW_AR_HEADER_PAD_SIZE; - pos += classEntry.getPrimaryEntries().size() * 2 * 8; - pos += 2 * 8; - } - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - Element textElement = getElement().getOwner().elementForName(".text"); - LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); - if (decisionMap != null) { - Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); - if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two - debugTextBase = ((Number) valueObj).longValue(); - } - } - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - debug(" [0x%08x] DEBUG_ARANGES\n", pos); - for (ClassEntry classEntry : primaryClasses) { - int lastpos = pos; - int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; - int cuIndex = classEntry.getCUIndex(); - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - // add room for each entry into length count - length += classPrimaryEntries.size() * 2 * 8; - length += 2 * 8; - debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); - pos = putInt(length, buffer, pos); - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 - pos = putInt(cuIndex, buffer, pos); - pos = putByte((byte) 8, buffer, pos); // address size is always 8 - pos = putByte((byte) 0, buffer, pos); // segment size is always 0 - assert (pos - lastpos) == DW_AR_HEADER_SIZE; - // align to 2 * address size - for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { - pos = putByte((byte) 0, buffer, pos); - } - debug(" [0x%08x] Address Length Name\n", pos); - for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { - Range primary = classPrimaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); - pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); - pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); - } - pos = putLong(0, buffer, pos); - pos = putLong(0, buffer, pos); - } - - assert pos == size; - } - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - // .debug_aranges section content depends on .debug_info section content and offset - public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - } - - /** - * generator for debug_line section. - */ - public class DwarfLineSectionImpl extends DwarfSectionImpl { - /** - * line header section always contains fixed number of bytes. - */ - private static final int DW_LN_HEADER_SIZE = 27; - /** - * current generator follows C++ with line base -5. - */ - private static final int DW_LN_LINE_BASE = -5; - /** - * current generator follows C++ with line range 14 - * giving full range -5 to 8. - */ - private static final int DW_LN_LINE_RANGE = 14; - /** - * current generator uses opcode base of 13 - * which must equal DW_LNS_define_file + 1. - */ - private static final int DW_LN_OPCODE_BASE = 13; - - /* - * standard opcodes defined by Dwarf 2 - */ - private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an - // invalid opcode - private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for - // extended opcodes - private static final byte DW_LNS_copy = 1; // append current state as matrix row - // 0 args - private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg - private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg - private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg - private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg - private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args - private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row - private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode - // 255 0 args - private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg - - /* - * extended opcodes defined by Dwarf 2 - */ - // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 - private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses - private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 - private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 - - DwarfLineSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_LINE_SECTION_NAME; - } - - @Override - public void createContent() { - // we need to create a header, dir table, file table and line - // number table encoding for each CU - - // write entries for each file listed in the primary list - int pos = 0; - for (ClassEntry classEntry : primaryClasses) { - int startPos = pos; - classEntry.setLineIndex(startPos); - int headerSize = headerSize(); - int dirTableSize = computeDirTableSize(classEntry); - int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; - classEntry.setLinePrologueSize(prologueSize); - int lineNumberTableSize = computeLineNUmberTableSize(classEntry); - int totalSize = prologueSize + lineNumberTableSize; - classEntry.setTotalSize(totalSize); - pos += totalSize; - } - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - public int headerSize() { - // header size is standard 31 bytes - // uint32 total_length - // uint16 version - // uint32 prologue_length - // uint8 min_insn_length - // uint8 default_is_stmt - // int8 line_base - // uint8 line_range - // uint8 opcode_base - // uint8 li_opcode_base - // uint8[opcode_base-1] standard_opcode_lengths - - return DW_LN_HEADER_SIZE; - } - - public int computeDirTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings - int dirSize = 0; - for (DirEntry dir : classEntry.getLocalDirs()) { - dirSize += dir.getPath().length() + 1; - } - // allow for separator nul - dirSize++; - return dirSize; - } - - public int computeFileTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings - int fileSize = 0; - for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we want the file base name excluding path - String baseName = localEntry.getBaseName(); - int length = baseName.length(); - fileSize += length + 1; - DirEntry dirEntry = localEntry.dirEntry; - int idx = classEntry.localDirsIdx(dirEntry); - fileSize += putULEB(idx, scratch, 0); - // the two zero timestamps require 1 byte each - fileSize += 2; - } - // allow for terminator nul - fileSize++; - return fileSize; - } - - public int computeLineNUmberTableSize(ClassEntry classEntry) { - // sigh -- we have to do this by generating the - // content even though we cannot write it into a byte[] - return writeLineNumberTable(classEntry, null, 0); - } - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - Element textElement = getElement().getOwner().elementForName(".text"); - LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); - if (decisionMap != null) { - Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); - if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two - debugTextBase = ((Number) valueObj).longValue(); - } - } - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - - int pos = 0; - checkDebug(pos); - debug(" [0x%08x] DEBUG_LINE\n", pos); - - for (ClassEntry classEntry : primaryClasses) { - int startPos = pos; - assert classEntry.getLineIndex() == startPos; - debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); - pos = writeHeader(classEntry, buffer, pos); - debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); - int dirTablePos = pos; - pos = writeDirTable(classEntry, buffer, pos); - debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); - int fileTablePos = pos; - pos = writeFileTable(classEntry, buffer, pos); - debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); - int lineNumberTablePos = pos; - pos = writeLineNumberTable(classEntry, buffer, pos); - debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); - debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); - } - assert pos == buffer.length; - } - - public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - // 4 ubyte length field - pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); - // 2 ubyte version is always 2 - pos = putShort(DW_VERSION_2, buffer, pos); - // 4 ubyte prologue length includes rest of header and - // dir + file table section - int prologueSize = classEntry.getLinePrologueSize() - 6; - pos = putInt(prologueSize, buffer, pos); - // 1 ubyte min instruction length is always 1 - pos = putByte((byte) 1, buffer, pos); - // 1 byte default is_stmt is always 1 - pos = putByte((byte) 1, buffer, pos); - // 1 byte line base is always -5 - pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); - // 1 ubyte line range is always 14 giving range -5 to 8 - pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); - // 1 ubyte opcode base is always 13 - pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); - // specify opcode arg sizes for the standard opcodes - putByte((byte) 0, buffer, pos); // DW_LNS_copy - putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc - putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line - putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file - putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column - putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt - putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block - putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc - putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc - putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence - putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address - pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file - return pos; - } - - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - debug(" [0x%08x] Dir Name\n", pos); - // write out the list of dirs referenced form this file entry - int dirIdx = 1; - for (DirEntry dir : classEntry.getLocalDirs()) { - // write nul terminated string text. - debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); - pos = putAsciiStringBytes(dir.getPath(), buffer, pos); - dirIdx++; - } - // separate dirs from files with a nul - pos = putByte((byte) 0, buffer, pos); - return pos; - } - - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - int fileIdx = 1; - debug(" [0x%08x] Entry Dir Name\n", pos); - for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we need the file name minus path, the associated dir index, and 0 for time stamps - String baseName = localEntry.getBaseName(); - DirEntry dirEntry = localEntry.dirEntry; - int dirIdx = classEntry.localDirsIdx(dirEntry); - debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); - pos = putAsciiStringBytes(baseName, buffer, pos); - pos = putULEB(dirIdx, buffer, pos); - pos = putULEB(0, buffer, pos); - pos = putULEB(0, buffer, pos); - fileIdx++; - } - // terminate files with a nul - pos = putByte((byte) 0, buffer, pos); - return pos; - } - - public int debugLine = 1; - public int debugCopyCount = 0; - - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - // the primary file entry should always be first in the local files list - assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; - String primaryClassName = classEntry.getClassName(); - String primaryFileName = classEntry.getFileName(); - String file = primaryFileName; - int fileIdx = 1; - debug(" [0x%08x] primary class %s\n", pos, primaryClassName); - debug(" [0x%08x] primary file %s\n", pos, primaryFileName); - for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { - Range primaryRange = primaryEntry.getPrimary(); - assert primaryRange.getFileName().equals(primaryFileName); - // each primary represents a method i.e. a contiguous - // sequence of subranges. we assume the default state - // at the start of each sequence because we always post an - // end_sequence when we finish all the subranges in the method - long line = primaryRange.getLine(); - if (line < 0 && primaryEntry.getSubranges().size() > 0) { - line = primaryEntry.getSubranges().get(0).getLine(); - } - if (line < 0) { - line = 0; - } - long address = primaryRange.getLo(); - - // set state for primary - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), - primaryRange.getLine()); - - // initialize and write a row for the start of the primary method - pos = putSetFile(file, fileIdx, buffer, pos); - pos = putSetBasicBlock(buffer, pos); - // address is currently 0 - pos = putSetAddress(address, buffer, pos); - // state machine value of line is currently 1 - // increment to desired line - if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); - } - pos = putCopy(buffer, pos); - - // now write a row for each subrange lo and hi - for (Range subrange : primaryEntry.getSubranges()) { - assert subrange.getLo() >= primaryRange.getLo(); - assert subrange.getHi() <= primaryRange.getHi(); - FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); - String subfile = subFileEntry.getFileName(); - int subFileIdx = classEntry.localFilesIdx(subFileEntry); - long subLine = subrange.getLine(); - long subAddressLo = subrange.getLo(); - long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); - if (subLine < 0) { - // no line info so stay at previous file:line - subLine = line; - subfile = file; - subFileIdx = fileIdx; - debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); - } - // there is a temptation to append end sequence at here - // when the hiAddress lies strictly between the current - // address and the start of the next subrange because, - // ostensibly, we have void space between the end of - // the current subrange and the start of the next one. - // however, debug works better if we treat all the insns up - // to the next range start as belonging to the current line - // - // if we have to update to a new file then do so - if (subFileIdx != fileIdx) { - // update the current file - pos = putSetFile(subfile, subFileIdx, buffer, pos); - file = subfile; - fileIdx = subFileIdx; - } - // check if we can advance line and/or address in - // one byte with a special opcode - long lineDelta = subLine - line; - long addressDelta = subAddressLo - address; - byte opcode = isSpecialOpcode(addressDelta, lineDelta); - if (opcode != DW_LNS_undefined) { - // ignore pointless write when addressDelta == lineDelta == 0 - if (addressDelta != 0 || lineDelta != 0) { - pos = putSpecialOpcode(opcode, buffer, pos); - } - } else { - // does it help to divide and conquer using - // a fixed address increment - int remainder = isConstAddPC(addressDelta); - if (remainder > 0) { - pos = putConstAddPC(buffer, pos); - // the remaining address can be handled with a - // special opcode but what about the line delta - opcode = isSpecialOpcode(remainder, lineDelta); - if (opcode != DW_LNS_undefined) { - // address remainder and line now fit - pos = putSpecialOpcode(opcode, buffer, pos); - } else { - // ok, bump the line separately then use a - // special opcode for the address remainder - opcode = isSpecialOpcode(remainder, 0); - assert opcode != DW_LNS_undefined; - pos = putAdvanceLine(lineDelta, buffer, pos); - pos = putSpecialOpcode(opcode, buffer, pos); - } - } else { - // increment line and pc separately - if (lineDelta != 0) { - pos = putAdvanceLine(lineDelta, buffer, pos); - } - // n.b. we might just have had an out of range line increment - // with a zero address increment - if (addressDelta > 0) { - // see if we can use a ushort for the increment - if (isFixedAdvancePC(addressDelta)) { - pos = putFixedAdvancePC((short) addressDelta, buffer, pos); - } else { - pos = putAdvancePC(addressDelta, buffer, pos); - } - } - pos = putCopy(buffer, pos); - } - } - // move line and address range on - line += lineDelta; - address += addressDelta; - } - // append a final end sequence just below the next primary range - if (address < primaryRange.getHi()) { - long addressDelta = primaryRange.getHi() - address; - // increment address before we write the end sequence - pos = putAdvancePC(addressDelta, buffer, pos); - } - pos = putEndSequence(buffer, pos); - } - debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); - - return pos; - } - - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - - public int putCopy(byte[] buffer, int p) { - byte opcode = DW_LNS_copy; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - debugCopyCount++; - debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); - return putByte(opcode, buffer, pos); - } - } - - public int putAdvancePC(long uleb, byte[] buffer, int p) { - byte opcode = DW_LNS_advance_pc; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putULEB(uleb, scratch, 0); - } else { - debugAddress += uleb; - debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); - pos = putByte(opcode, buffer, pos); - return putULEB(uleb, buffer, pos); - } - } - - public int putAdvanceLine(long sleb, byte[] buffer, int p) { - byte opcode = DW_LNS_advance_line; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putSLEB(sleb, scratch, 0); - } else { - debugLine += sleb; - debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); - pos = putByte(opcode, buffer, pos); - return putSLEB(sleb, buffer, pos); - } - } - - public int putSetFile(String file, long uleb, byte[] buffer, int p) { - byte opcode = DW_LNS_set_file; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putULEB(uleb, scratch, 0); - } else { - debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); - pos = putByte(opcode, buffer, pos); - return putULEB(uleb, buffer, pos); - } - } - - public int putSetColumn(long uleb, byte[] buffer, int p) { - byte opcode = DW_LNS_set_column; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putULEB(uleb, scratch, 0); - } else { - pos = putByte(opcode, buffer, pos); - return putULEB(uleb, buffer, pos); - } - } - - public int putNegateStmt(byte[] buffer, int p) { - byte opcode = DW_LNS_negate_stmt; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - return putByte(opcode, buffer, pos); - } - } - - public int putSetBasicBlock(byte[] buffer, int p) { - byte opcode = DW_LNS_set_basic_block; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - debug(" [0x%08x] Set basic block\n", pos); - return putByte(opcode, buffer, pos); - } - } - - public int putConstAddPC(byte[] buffer, int p) { - byte opcode = DW_LNS_const_add_pc; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - int advance = opcodeAddress((byte) 255); - debugAddress += advance; - debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); - return putByte(opcode, buffer, pos); - } - } - - public int putFixedAdvancePC(short arg, byte[] buffer, int p) { - byte opcode = DW_LNS_fixed_advance_pc; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putShort(arg, scratch, 0); - } else { - debugAddress += arg; - debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); - pos = putByte(opcode, buffer, pos); - return putShort(arg, buffer, pos); - } - } - - public int putEndSequence(byte[] buffer, int p) { - byte opcode = DW_LNE_end_sequence; - int pos = p; - if (buffer == null) { - pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB - pos = pos + putULEB(1, scratch, 0); - return pos + putByte(opcode, scratch, 0); - } else { - debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); - debugAddress = debugTextBase; - debugLine = 1; - debugCopyCount = 0; - pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB - pos = putULEB(1, buffer, pos); - return putByte(opcode, buffer, pos); - } - } - - public int putSetAddress(long arg, byte[] buffer, int p) { - byte opcode = DW_LNE_set_address; - int pos = p; - if (buffer == null) { - pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB - pos = pos + putULEB(9, scratch, 0); - pos = pos + putByte(opcode, scratch, 0); - return pos + putLong(arg, scratch, 0); - } else { - debugAddress = debugTextBase + (int) arg; - debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); - pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB - pos = putULEB(9, buffer, pos); - pos = putByte(opcode, buffer, pos); - return putRelocatableCodeOffset(arg, buffer, pos); - } - } - - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { - byte opcode = DW_LNE_define_file; - int pos = p; - // calculate bytes needed for opcode + args - int fileBytes = file.length() + 1; - long insnBytes = 1; - insnBytes += fileBytes; - insnBytes += putULEB(uleb1, scratch, 0); - insnBytes += putULEB(uleb2, scratch, 0); - insnBytes += putULEB(uleb3, scratch, 0); - if (buffer == null) { - pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // write insnBytes as a ULEB - pos += putULEB(insnBytes, scratch, 0); - return pos + (int) insnBytes; - } else { - debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); - pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert insn length as uleb - pos = putULEB(insnBytes, buffer, pos); - // insert opcode and args - pos = putByte(opcode, buffer, pos); - pos = putAsciiStringBytes(file, buffer, pos); - pos = putULEB(uleb1, buffer, pos); - pos = putULEB(uleb2, buffer, pos); - return putULEB(uleb3, buffer, pos); - } - } - - public int opcodeId(byte opcode) { - int iopcode = opcode & 0xff; - return iopcode - DW_LN_OPCODE_BASE; - } - - public int opcodeAddress(byte opcode) { - int iopcode = opcode & 0xff; - return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; - } - - public int opcodeLine(byte opcode) { - int iopcode = opcode & 0xff; - return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; - } - - public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - if (debug && opcode == 0) { - debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); - } - debugAddress += opcodeAddress(opcode); - debugLine += opcodeLine(opcode); - debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); - return putByte(opcode, buffer, pos); - } - } - - private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; - private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - - public byte isSpecialOpcode(long addressDelta, long lineDelta) { - if (addressDelta < 0) { - return DW_LNS_undefined; - } - if (lineDelta >= DW_LN_LINE_BASE) { - long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; - if (offsetLineDelta < DW_LN_LINE_RANGE) { - // line_delta can be encoded - // check if address is ok - if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { - long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; - if (opcode <= 255) { - return (byte) opcode; - } - } - } - } - - // return invalid opcode - return DW_LNS_undefined; - } - - public int isConstAddPC(long addressDelta) { - if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { - return 0; - } - if (addressDelta <= MAX_ADDPC_DELTA) { - return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); - } else { - return 0; - } - } - - public boolean isFixedAdvancePC(long addressDiff) { - return addressDiff >= 0 && addressDiff < 0xffff; - } - - /** - * debug_line section content depends on debug_str section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } + public LinkedList getPrimaryClasses() { + return primaryClasses; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java new file mode 100644 index 000000000000..855bca3c749d --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; +/** + * generator for debug_str section. + */ +public class DwarfStrSectionImpl extends DwarfSectionImpl { + public DwarfStrSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_STR_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + for (StringEntry stringEntry : dwarfSections.getStringTable()) { + if (stringEntry.isAddToStrSection()) { + stringEntry.setOffset(pos); + String string = stringEntry.getString(); + pos += string.length() + 1; + } + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + for (StringEntry stringEntry : dwarfSections.getStringTable()) { + if (stringEntry.isAddToStrSection()) { + assert stringEntry.getOffset() == pos; + String string = stringEntry.getString(); + pos = putAsciiStringBytes(string, buffer, pos); + } + } + assert pos == size; + } + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + /** + * debug_str section content depends on text section content and offset. + */ + public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + /** + * debug_str section content depends on text section content and offset. + */ + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java new file mode 100644 index 000000000000..51c785b0a98d --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java @@ -0,0 +1,3 @@ +package com.oracle.objectfile.elf.dwarf; +public class impl { +} From 80d4c19bd1e92acfce6e40ef9344e63d5930101c Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 17:53:01 +0000 Subject: [PATCH 023/130] added option GenertaeDebugInfo= and made it force TrackNodeSourcePosition=true --- .../oracle/objectfile/elf/dwarf/DwarfSections.java | 1 + .../src/com/oracle/svm/core/SubstrateOptions.java | 13 +++++++++++++ .../oracle/svm/hosted/image/NativeBootImage.java | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 817ad2f868a7..2d7fd87a2586 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -50,6 +50,7 @@ * for generating content for a specific section type. */ public class DwarfSections { + // names of the different ELF sections we create or reference // in reverse dependency order public static final String TEXT_SECTION_NAME = ".text"; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 57d2e39f9763..75d4144a0fac 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -48,6 +48,8 @@ import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.XOptions; +import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; + public class SubstrateOptions { @Option(help = "Class containing the default entry point method. Optional if --shared is used.", type = OptionType.User)// @@ -409,4 +411,15 @@ public static Predicate makeFilter(String[] definedFilters) { public static int codeAlignment() { return GraalOptions.LoopHeaderAlignment.getValue(HostedOptionValues.singleton()); } + @Option(help = "Insert debug info into the generated native image or library")// + public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey(0) { + @Override + protected void onValueUpdate(EconomicMap, Object> values, Integer oldValue, Integer newValue) { + // force update of TrackNodeSourcePosition + if (newValue > 0 && !Boolean.TRUE.equals(values.get(TrackNodeSourcePosition))) { + TrackNodeSourcePosition.update(values, true); + } + } + }; + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 562dd1c040e0..7589c7d3ff33 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -475,7 +475,7 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { // if we have constructed any debug info then // give the object file a chance to install it - if (GraalOptions.TrackNodeSourcePosition.getValue(HostedOptionValues.singleton())) { + if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); objectFile.installDebugInfo(provider); } From 7d74c91ebd4aa49ed38a3b2f8f1d6a088a1fa59c Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 17:54:06 +0000 Subject: [PATCH 024/130] deleted another remaining redundant local var --- .../src/com/oracle/objectfile/elf/ELFObjectFile.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index cb3d2a026e47..be498456e553 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1180,8 +1180,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - @SuppressWarnings("unused") - ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the From da14ccd60814ad1edbe5026cfd57c01c56fc0e55 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 7 Feb 2020 16:53:06 +0000 Subject: [PATCH 025/130] fixed style issues and made code aware of target byte order --- .../oracle/objectfile/elf/ELFObjectFile.java | 2 +- .../objectfile/elf/dwarf/ClassEntry.java | 8 +- .../oracle/objectfile/elf/dwarf/DirEntry.java | 9 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 78 +-- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 98 ++-- .../elf/dwarf/DwarfFrameSectionImpl.java | 118 +++-- .../dwarf/DwarfFrameSectionImplAArch64.java | 10 +- .../dwarf/DwarfFrameSectionImplX86_64.java | 18 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 100 ++-- .../elf/dwarf/DwarfLineSectionImpl.java | 455 ++++++++++++------ .../elf/dwarf/DwarfSectionImpl.java | 94 +++- .../objectfile/elf/dwarf/DwarfSections.java | 200 +++++--- .../elf/dwarf/DwarfStrSectionImpl.java | 3 +- .../objectfile/elf/dwarf/FileEntry.java | 14 +- .../objectfile/elf/dwarf/PrimaryEntry.java | 86 +--- .../oracle/objectfile/elf/dwarf/Range.java | 22 +- .../objectfile/elf/dwarf/StringEntry.java | 12 +- .../objectfile/elf/dwarf/StringTable.java | 20 +- .../com/oracle/objectfile/elf/dwarf/impl.java | 3 - 19 files changed, 835 insertions(+), 515 deletions(-) delete mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index be498456e553..ac9472d06b78 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1166,7 +1166,7 @@ protected int getMinimumFileSize() { @Override public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - DwarfSections dwarfSections = new DwarfSections(getMachine()); + DwarfSections dwarfSections = new DwarfSections(getMachine(), getByteOrder()); // we need an implementation for each section DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 9e429a565e49..0ff7290cb43f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -129,10 +129,14 @@ PrimaryEntry addPrimary(Range primary, List frameSizeInfos void addSubRange(Range subrange, FileEntry subFileEntry) { Range primary = subrange.getPrimary(); - // the subrange should belong to a primary range + /* + * the subrange should belong to a primary range + */ assert primary != null; PrimaryEntry primaryEntry = primaryIndex.get(primary); - // we should already have seen the primary range + /* + * we should already have seen the primary range + */ assert primaryEntry != null; assert primaryEntry.getClassEntry() == this; primaryEntry.addSubRange(subrange, subFileEntry); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 5caac5a20997..dde46b4b8828 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -27,8 +27,15 @@ package com.oracle.objectfile.elf.dwarf; /** - * track the directory associated with one or + * Tracks the directory associated with one or * more source files. + * + * This is identified separately from each FileEntry + * idenityfing files that reside in the directory. + * That is necessary because the line info generator + * needs to collect and write out directory names + * into directory tables once only rather than once + * per file. */ public class DirEntry { private String path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 43615669b10f..8ae11c436937 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -37,7 +37,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; /** - * generator for debug_aranges section. + * Section generator for debug_aranges section. */ public class DwarfARangesSectionImpl extends DwarfSectionImpl { private static final int DW_AR_HEADER_SIZE = 12; @@ -55,30 +55,34 @@ public String getSectionName() { @Override public void createContent() { int pos = 0; - // we need an entry for each compilation unit - // - // uint32 length ............ in bytes (not counting these 4 bytes) - // uint16 dwarf_version ..... always 2 - // uint32 info_offset ....... offset of compilation unit on debug_info - // uint8 address_size ....... always 8 - // uint8 segment_desc_size .. ??? - // - // i.e. 12 bytes followed by padding - // aligning up to 2 * address size - // - // uint8 pad[4] - // - // followed by N + 1 times - // - // uint64 lo ................ lo address of range - // uint64 length ............ number of bytes in range - // - // where N is the number of ranges belonging to the compilation unit - // and the last range contains two zeroes + /* + * we need an entry for each compilation unit + * + * uint32 length ............ in bytes (not counting these 4 bytes) + * uint16 dwarf_version ..... always 2 + * uint32 info_offset ....... offset of compilation unit on debug_info + * uint8 address_size ....... always 8 + * uint8 segment_desc_size .. ??? + * + * i.e. 12 bytes followed by padding + * aligning up to 2 * address size + * + * uint8 pad[4] + * + * followed by N + 1 times + * + * uint64 lo ................ lo address of range + * uint64 length ............ number of bytes in range + * + * where N is the number of ranges belonging to the compilation unit + * and the last range contains two zeroes + */ for (ClassEntry classEntry : getPrimaryClasses()) { pos += DW_AR_HEADER_SIZE; - // align to 2 * address size + /* + * align to 2 * address size + */ pos += DW_AR_HEADER_PAD_SIZE; pos += classEntry.getPrimaryEntries().size() * 2 * 8; pos += 2 * 8; @@ -94,9 +98,11 @@ public byte[] getOrDecideContent(Map alre if (decisionMap != null) { Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two + /* + * this may not be the final vaddr for the text segment + * but it will be close enough to make debug easier + * i.e. to within a 4k page or two + */ debugTextBase = ((Number) valueObj).longValue(); } } @@ -117,17 +123,24 @@ public void writeContent() { int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = classEntry.getCUIndex(); LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - // add room for each entry into length count + /* + * add room for each entry into length count + */ length += classPrimaryEntries.size() * 2 * 8; length += 2 * 8; debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 + /* dwarf version is always 2 */ + pos = putShort(DW_VERSION_2, buffer, pos); pos = putInt(cuIndex, buffer, pos); - pos = putByte((byte) 8, buffer, pos); // address size is always 8 - pos = putByte((byte) 0, buffer, pos); // segment size is always 0 + /* address size is always 8 */ + pos = putByte((byte) 8, buffer, pos); + /* segment size is always 0 */ + pos = putByte((byte) 0, buffer, pos); assert (pos - lastpos) == DW_AR_HEADER_SIZE; - // align to 2 * address size + /* + * align to 2 * address size + */ for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { pos = putByte((byte) 0, buffer, pos); } @@ -150,7 +163,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_aranges section content depends on .debug_info section content and offset + /* + * debug_aranges section content depends on debug_info section content and offset + */ public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; @Override @@ -168,4 +183,3 @@ public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } } - 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 2336e27608a4..c8f97729dd95 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 @@ -51,7 +51,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_TAG_subprogram; /** - * generator for debug_abbrev section. + * Section generator for debug_abbrev section. */ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { @@ -67,45 +67,47 @@ public String getSectionName() { @Override public void createContent() { int pos = 0; - // an abbrev table contains abbrev entries for one or - // more CUs. the table includes a sequence of abbrev - // entries each of which defines a specific DIE layout - // employed to describe some DIE in a CU. a table is - // terminated by a null entry - // - // a null entry has consists of just a 0 abbrev code - // LEB128 abbrev_code; ...... == 0 - // - // non-null entries have the following format - // LEB128 abbrev_code; ...... unique noncode for this layout != 0 - // 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 DIE - // * ........ zero or more attributes - // .... terminator - // - // An attribute_spec consists of an attribute name and form - // LEB128 attr_name; ........ 0 for the null attribute name - // LEB128 attr_form; ........ 0 for the null attribute form - // - // For the moment we only use one abbrev table for all CUs. - // It contains two DIEs, the first to describe the compilation - // unit itself and the second to describe each method within - // that compilation unit. - // - // The DIE layouts are as follows: - // - // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - // DW_AT_language : ... DW_FORM_data1 - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_address - // DW_AT_hi_pc : ...... DW_FORM_address - // DW_AT_stmt_list : .. DW_FORM_data4 - // - // abbrev_code == 2, tag == DW_TAG_subprogram, no_children - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_addr - // DW_AT_hi_pc : ...... DW_FORM_addr - // DW_AT_external : ... DW_FORM_flag + /* + * an abbrev table contains abbrev entries for one or + * more CUs. the table includes a sequence of abbrev + * entries each of which defines a specific DIE layout + * employed to describe some DIE in a CU. a table is + * terminated by a null entry + * + * a null entry has consists of just a 0 abbrev code + * LEB128 abbrev_code; ...... == 0 + * + * non-null entries have the following format + * LEB128 abbrev_code; ...... unique noncode for this layout != 0 + * 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 DIE + * * ........ zero or more attributes + * .... terminator + * + * An attribute_spec consists of an attribute name and form + * LEB128 attr_name; ........ 0 for the null attribute name + * LEB128 attr_form; ........ 0 for the null attribute form + * + * For the moment we only use one abbrev table for all CUs. + * It contains two DIEs, the first to describe the compilation + * unit itself and the second to describe each method within + * that compilation unit. + * + * The DIE layouts are as follows: + * + * abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + * DW_AT_language : ... DW_FORM_data1 + * DW_AT_name : ....... DW_FORM_strp + * DW_AT_low_pc : ..... DW_FORM_address + * DW_AT_hi_pc : ...... DW_FORM_address + * DW_AT_stmt_list : .. DW_FORM_data4 + * + * abbrev_code == 2, tag == DW_TAG_subprogram, no_children + * DW_AT_name : ....... DW_FORM_strp + * DW_AT_low_pc : ..... DW_FORM_addr + * DW_AT_hi_pc : ...... DW_FORM_addr + * DW_AT_external : ... DW_FORM_flag + */ pos = writeAbbrev1(null, pos); pos = writeAbbrev2(null, pos); @@ -145,7 +147,9 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { public int writeAbbrev1(byte[] buffer, int p) { int pos = p; - // abbrev 1 compile unit + /* + * abbrev 1 compile unit + */ pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); pos = writeTag(DW_TAG_compile_unit, buffer, pos); pos = writeFlag(DW_CHILDREN_yes, buffer, pos); @@ -159,7 +163,9 @@ public int writeAbbrev1(byte[] buffer, int p) { pos = writeAttrForm(DW_FORM_addr, buffer, pos); pos = writeAttrType(DW_AT_stmt_list, buffer, pos); pos = writeAttrForm(DW_FORM_data4, buffer, pos); - // now terminate + /* + * now terminate + */ pos = writeAttrType(DW_AT_null, buffer, pos); pos = writeAttrForm(DW_FORM_null, buffer, pos); return pos; @@ -167,7 +173,9 @@ public int writeAbbrev1(byte[] buffer, int p) { public int writeAbbrev2(byte[] buffer, int p) { int pos = p; - // abbrev 2 compile unit + /* + * abbrev 2 compile unit + */ pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); pos = writeTag(DW_TAG_subprogram, buffer, pos); pos = writeFlag(DW_CHILDREN_no, buffer, pos); @@ -179,7 +187,9 @@ public int writeAbbrev2(byte[] buffer, int p) { pos = writeAttrForm(DW_FORM_addr, buffer, pos); pos = writeAttrType(DW_AT_external, buffer, pos); pos = writeAttrForm(DW_FORM_flag, buffer, pos); - // now terminate + /* + * now terminate + */ pos = writeAttrType(DW_AT_null, buffer, pos); pos = writeAttrForm(DW_FORM_null, buffer, pos); return pos; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 93719731dcd8..3923045bacd4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -42,7 +42,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; /** - * generic generator for debug_frame section. + * Section generic generator for debug_frame section. */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { @@ -59,8 +59,10 @@ public String getSectionName() { public void createContent() { int pos = 0; - // the frame section contains one CIE at offset 0 - // followed by an FIE for each method + /* + * the frame section contains one CIE at offset 0 + * followed by an FIE for each method + */ pos = writeCIE(null, pos); pos = writeMethodFrames(null, pos); @@ -76,10 +78,12 @@ public void writeContent() { checkDebug(pos); - // there are entries for the prologue region where the - // stack is being built, the method body region(s) where - // the code executes with a fixed size frame and the - // epilogue region(s) where the stack is torn down + /* + * there are entries for the prologue region where the + * stack is being built, the method body region(s) where + * the code executes with a fixed size frame and the + * epilogue region(s) where the stack is torn down + */ pos = writeCIE(buffer, pos); pos = writeMethodFrames(buffer, pos); @@ -90,18 +94,20 @@ public void writeContent() { } public int writeCIE(byte[] buffer, int p) { - // we only need a vanilla CIE with default fields - // because we have to have at least one - // the layout is - // - // uint32 : length ............... length of remaining fields in this CIE - // uint32 : CIE_id ................ unique id for CIE == 0xffffff - // uint8 : version ................ == 1 - // uint8[] : augmentation ......... == "" so always 1 byte - // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) - // ULEB : data_alignment_factor ... == -8 - // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 - // byte[] : initial_instructions .. includes pad to 8-byte boundary + /* + * we only need a vanilla CIE with default fields + * because we have to have at least one + * the layout is + * + * uint32 : length ............... length of remaining fields in this CIE + * uint32 : CIE_id ................ unique id for CIE == 0xffffff + * uint8 : version ................ == 1 + * uint8[] : augmentation ......... == "" so always 1 byte + * ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + * ULEB : data_alignment_factor ... == -8 + * byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + * byte[] : initial_instructions .. includes pad to 8-byte boundary + */ int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // don't care about length @@ -111,11 +117,17 @@ public int writeCIE(byte[] buffer, int p) { pos += putULEB(1, scratch, 0); pos += putSLEB(-8, scratch, 0); pos += putByte((byte) getPCIdx(), scratch, 0); - // write insns to set up empty frame + /* + * write insns to set up empty frame + */ pos = writeInitialInstructions(buffer, pos); - // pad to word alignment + /* + * pad to word alignment + */ pos = writePaddingNops(8, buffer, pos); - // no need to write length + /* + * no need to write length + */ return pos; } else { int lengthPos = pos; @@ -126,9 +138,13 @@ public int writeCIE(byte[] buffer, int p) { pos = putULEB(1, buffer, pos); pos = putSLEB(-8, buffer, pos); pos = putByte((byte) getPCIdx(), buffer, pos); - // write insns to set up empty frame + /* + * write insns to set up empty frame + */ pos = writeInitialInstructions(buffer, pos); - // pad to word alignment + /* + * pad to word alignment + */ pos = writePaddingNops(8, buffer, pos); patchLength(lengthPos, buffer, pos); return pos; @@ -150,10 +166,14 @@ public int writeMethodFrames(byte[] buffer, int p) { currentOffset += advance; pos = writeAdvanceLoc(advance, buffer, pos); if (debugFrameSizeInfo.getType() == DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND) { - // SP has been extended so rebase CFA using full frame + /* + * SP has been extended so rebase CFA using full frame + */ pos = writeDefCFAOffset(frameSize, buffer, pos); } else { - // SP has been contracted so rebase CFA using empty frame + /* + * SP has been contracted so rebase CFA using empty frame + */ pos = writeDefCFAOffset(8, buffer, pos); } } @@ -165,26 +185,36 @@ public int writeMethodFrames(byte[] buffer, int p) { } public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { - // we only need a vanilla FDE header with default fields - // the layout is - // - // uint32 : length ........... length of remaining fields in this FDE - // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header - // uint64 : initial_location .. i.e. method lo address - // uint64 : address_range ..... i.e. method hi - lo - // byte[] : instructions ...... includes pad to 8-byte boundary + /* + * we only need a vanilla FDE header with default fields + * the layout is + * + * uint32 : length ........... length of remaining fields in this FDE + * uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + * uint64 : initial_location .. i.e. method lo address + * uint64 : address_range ..... i.e. method hi - lo + * byte[] : instructions ...... includes pad to 8-byte boundary + */ int pos = p; if (buffer == null) { - pos += putInt(0, scratch, 0); // dummy length - pos += putInt(0, scratch, 0); // CIE_offset - pos += putLong(lo, scratch, 0); // initial address - return pos + putLong(hi - lo, scratch, 0); // address range + /* dummy length */ + pos += putInt(0, scratch, 0); + /* CIE_offset */ + pos += putInt(0, scratch, 0); + /* initial address */ + pos += putLong(lo, scratch, 0); + /* address range */ + return pos + putLong(hi - lo, scratch, 0); } else { - pos = putInt(0, buffer, pos); // dummy length - pos = putInt(0, buffer, pos); // CIE_offset - pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address - return putLong(hi - lo, buffer, pos); // address range + /* dummy length */ + pos = putInt(0, buffer, pos); + /* CIE_offset */ + pos = putInt(0, buffer, pos); + /* initial address */ + pos = putRelocatableCodeOffset(lo, buffer, pos); + /* address range */ + return putLong(hi - lo, buffer, pos); } } @@ -338,12 +368,12 @@ public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } - private byte offsetOp(int register) { + private static byte offsetOp(int register) { assert (register >> 6) == 0; return (byte) ((DW_CFA_offset << 6) | register); } - private byte advanceLoc0Op(int offset) { + private static byte advanceLoc0Op(int offset) { assert (offset >= 0 && offset <= 0x3f); return (byte) ((DW_CFA_advance_loc << 6) | offset); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index 58d490853e5b..8f4ab1818ec4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -27,7 +27,7 @@ package com.oracle.objectfile.elf.dwarf; /** - * AArch64-specific generator for debug_frame section + * AArch64-specific section generator for debug_frame section * that knows details of AArch64 registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { @@ -53,9 +53,11 @@ public int getSPIdx() { @Override public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; - // rsp has not been updated - // caller pc is in lr - // register r32 (rpc), r30 (lr) + /* + * rsp has not been updated + * caller pc is in lr + * register r32 (rpc), r30 (lr) + */ pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); return pos; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java index b4b638305b5f..7fabf34ad449 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -27,7 +27,7 @@ package com.oracle.objectfile.elf.dwarf; /** - * x86_64-specific generator for debug_frame section + * x86_64-specific section generator for debug_frame section * that knows details of x86_64 registers and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { @@ -51,13 +51,17 @@ public int getSPIdx() { @Override public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; - // rsp points at the word containing the saved rip - // so the frame base (cfa) is at rsp + 8 (why not - ???) - // def_cfa r7 (sp) offset 8 + /* + * rsp points at the word containing the saved rip + * so the frame base (cfa) is at rsp + 8 (why not - ???) + * def_cfa r7 (sp) offset 8 + */ pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); - // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa - // (why not -1 ???) - // offset r16 (rip) cfa - 8 + /* + * and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + * (why not -1 ???) + * offset r16 (rip) cfa - 8 + */ pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; } 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 033a09273a68..6a07284cb46a 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 @@ -38,7 +38,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LANG_Java; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; /** - * generator for debug_info section. + * Section generator for debug_info section. */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { /** @@ -57,31 +57,33 @@ public String getSectionName() { @Override public void createContent() { - // we need a single level 0 DIE for each compilation unit (CU) - // Each CU's Level 0 DIE is preceded by a fixed header: - // and terminated by a null DIE - // uint32 length ......... excluding this length field - // uint16 dwarf_version .. always 2 ?? - // uint32 abbrev offset .. always 0 ?? - // uint8 address_size .... always 8 - // * ................ sequence of top-level and nested child entries - // ............ == 0 - // - // a DIE is a recursively defined structure - // it starts with a code for the associated - // abbrev entry followed by a series of attribute - // values as determined by the entry terminated by - // a null value and followed by zero or more child - // DIEs (zero iff has_children == no_children) - // - // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE - // * ....... value sequence as determined by abbrev entry - // * ................... sequence of child DIEs (if appropriate) - // ............. == 0 - // - // note that a null_DIE looks like - // LEB128 abbrev_code ....... == 0 - // i.e. it also looks like a null_value + /* + * we need a single level 0 DIE for each compilation unit (CU) + * Each CU's Level 0 DIE is preceded by a fixed header: + * and terminated by a null DIE + * uint32 length ......... excluding this length field + * uint16 dwarf_version .. always 2 ?? + * uint32 abbrev offset .. always 0 ?? + * uint8 address_size .... always 8 + * * ................ sequence of top-level and nested child entries + * ............ == 0 + * + * a DIE is a recursively defined structure + * it starts with a code for the associated + * abbrev entry followed by a series of attribute + * values as determined by the entry terminated by + * a null value and followed by zero or more child + * DIEs (zero iff has_children == no_children) + * + * LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + * * ....... value sequence as determined by abbrev entry + * * ................... sequence of child DIEs (if appropriate) + * ............. == 0 + * + * note that a null_DIE looks like + * LEB128 abbrev_code ....... == 0 + * i.e. it also looks like a null_value + */ byte[] buffer = null; int pos = 0; @@ -91,7 +93,9 @@ public void createContent() { pos = writeCUHeader(buffer, pos); assert pos == lengthPos + DW_DIE_HEADER_SIZE; pos = writeCU(classEntry, buffer, pos); - // no need to backpatch length at lengthPos + /* + * no need to backpatch length at lengthPos + */ } buffer = new byte[pos]; super.setContent(buffer); @@ -108,15 +112,19 @@ public void writeContent() { debug(" [0x%08x] DEBUG_INFO\n", pos); debug(" [0x%08x] size = 0x%08x\n", pos, size); for (ClassEntry classEntry : getPrimaryClasses()) { - // save the offset of this file's CU so it can - // be used when writing the aranges section + /* + * save the offset of this file's CU so it can + * be used when writing the aranges section + */ classEntry.setCUIndex(pos); int lengthPos = pos; pos = writeCUHeader(buffer, pos); debug(" [0x%08x] Compilation Unit\n", pos, size); assert pos == lengthPos + DW_DIE_HEADER_SIZE; pos = writeCU(classEntry, buffer, pos); - // backpatch length at lengthPos (excluding length field) + /* + * backpatch length at lengthPos (excluding length field) + */ patchLength(lengthPos, buffer, pos); } assert pos == size; @@ -125,15 +133,23 @@ public void writeContent() { public int writeCUHeader(byte[] buffer, int p) { int pos = p; if (buffer == null) { - pos += putInt(0, scratch, 0); // CU length - pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version - pos += putInt(0, scratch, 0); // abbrev offset - return pos + putByte((byte) 8, scratch, 0); // address size + /* CU length */ + pos += putInt(0, scratch, 0); + /* dwarf version */ + pos += putShort(DW_VERSION_2, scratch, 0); + /* abbrev offset */ + pos += putInt(0, scratch, 0); + /* address size */ + return pos + putByte((byte) 8, scratch, 0); } else { - pos = putInt(0, buffer, pos); // CU length - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version - pos = putInt(0, buffer, pos); // abbrev offset - return putByte((byte) 8, buffer, pos); // address size + /* CU length */ + pos = putInt(0, buffer, pos); + /* dwarf version */ + pos = putShort(DW_VERSION_2, buffer, pos); + /* abbrev offset */ + pos = putInt(0, buffer, pos); + /* address size */ + return putByte((byte) 8, buffer, pos); } } @@ -155,7 +171,9 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { for (PrimaryEntry primaryEntry : classPrimaryEntries) { pos = writePrimary(primaryEntry, buffer, pos); } - // write a terminating null attribute for the the level 2 primaries + /* + * write a terminating null attribute for the the level 2 primaries + */ return writeAttrNull(buffer, pos); } @@ -171,7 +189,9 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { pos = writeAttrAddress(primary.getLo(), buffer, pos); debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); pos = writeAttrAddress(primary.getHi(), buffer, pos); - // need to pass true only if method is public + /* + * need to pass true only if method is public + */ debug(" [0x%08x] external true\n", pos); return writeFlag(DW_FLAG_true, buffer, pos); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 7ae876f3e05f..d19ce896362d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -36,7 +36,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; /** - * generator for debug_line section. + * Section generator for debug_line section. */ public class DwarfLineSectionImpl extends DwarfSectionImpl { /** @@ -59,31 +59,72 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { private static final int DW_LN_OPCODE_BASE = 13; /* - * standard opcodes defined by Dwarf 2 - */ - private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an - // invalid opcode - private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for - // extended opcodes - private static final byte DW_LNS_copy = 1; // append current state as matrix row - // 0 args - private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg - private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg - private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg - private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg - private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args - private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row - private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode - // 255 0 args - private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg + * standard opcodes defined by Dwarf 2 + */ + /* + * 0 can be returned to indicate an invalid opcode + */ + private static final byte DW_LNS_undefined = 0; + /* + * 0 can be inserted as a prefix for extended opcodes + */ + private static final byte DW_LNS_extended_prefix = 0; + /* + * append current state as matrix row 0 args + */ + private static final byte DW_LNS_copy = 1; + /* + * increment address 1 uleb arg + */ + private static final byte DW_LNS_advance_pc = 2; + /* + * increment line 1 sleb arg + */ + private static final byte DW_LNS_advance_line = 3; + /* + * set file 1 uleb arg + */ + private static final byte DW_LNS_set_file = 4; + /* + * set column 1 uleb arg + */ + private static final byte DW_LNS_set_column = 5; + /* + * flip is_stmt 0 args + */ + private static final byte DW_LNS_negate_stmt = 6; + /* + * set end sequence and copy row 0 args + */ + private static final byte DW_LNS_set_basic_block = 7; + /* + * increment address as per opcode 255 0 args + */ + private static final byte DW_LNS_const_add_pc = 8; + /* + * increment address 1 ushort arg + */ + private static final byte DW_LNS_fixed_advance_pc = 9; /* - * extended opcodes defined by Dwarf 2 - */ - // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 - private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses - private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 - private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 + * extended opcodes defined by Dwarf 2 + */ + /* + * there is no extended opcode 0 + */ + // private static final byte DW_LNE_undefined = 0; + /* + * end sequence of addresses + */ + private static final byte DW_LNE_end_sequence = 1; + /* + * set address as explicit long argument + */ + private static final byte DW_LNE_set_address = 2; + /* + * set file as explicit string argument + */ + private static final byte DW_LNE_define_file = 3; DwarfLineSectionImpl(DwarfSections dwarfSections) { super(dwarfSections); @@ -96,10 +137,14 @@ public String getSectionName() { @Override public void createContent() { - // we need to create a header, dir table, file table and line - // number table encoding for each CU + /* + * we need to create a header, dir table, file table and line + * number table encoding for each CU + */ - // write entries for each file listed in the primary list + /* + * write entries for each file listed in the primary list + */ int pos = 0; for (ClassEntry classEntry : getPrimaryClasses()) { int startPos = pos; @@ -119,66 +164,82 @@ public void createContent() { } public int headerSize() { - // header size is standard 31 bytes - // uint32 total_length - // uint16 version - // uint32 prologue_length - // uint8 min_insn_length - // uint8 default_is_stmt - // int8 line_base - // uint8 line_range - // uint8 opcode_base - // uint8 li_opcode_base - // uint8[opcode_base-1] standard_opcode_lengths + /* + * header size is standard 31 bytes + * uint32 total_length + * uint16 version + * uint32 prologue_length + * uint8 min_insn_length + * uint8 default_is_stmt + * int8 line_base + * uint8 line_range + * uint8 opcode_base + * uint8 li_opcode_base + * uint8[opcode_base-1] standard_opcode_lengths + */ return DW_LN_HEADER_SIZE; } public int computeDirTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings + /* + * table contains a sequence of 'nul'-terminated + * dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated + * file name bytes followed by an extra 'nul' + * + * for now we assume dir and file names are ASCII + * byte strings + */ int dirSize = 0; for (DirEntry dir : classEntry.getLocalDirs()) { dirSize += dir.getPath().length() + 1; } - // allow for separator nul + /* + * allow for separator nul + */ dirSize++; return dirSize; } public int computeFileTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings + /* + * table contains a sequence of 'nul'-terminated + * dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated + * file name bytes followed by an extra 'nul' + + * for now we assume dir and file names are ASCII + * byte strings + */ int fileSize = 0; for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we want the file base name excluding path + /* + * we want the file base name excluding path + */ String baseName = localEntry.getBaseName(); int length = baseName.length(); fileSize += length + 1; DirEntry dirEntry = localEntry.dirEntry; int idx = classEntry.localDirsIdx(dirEntry); fileSize += putULEB(idx, scratch, 0); - // the two zero timestamps require 1 byte each + /* + * the two zero timestamps require 1 byte each + */ fileSize += 2; } - // allow for terminator nul + /* + * allow for terminator nul + */ fileSize++; return fileSize; } public int computeLineNUmberTableSize(ClassEntry classEntry) { - // sigh -- we have to do this by generating the - // content even though we cannot write it into a byte[] + /* + * sigh -- we have to do this by generating the + * content even though we cannot write it into a byte[] + */ return writeLineNumberTable(classEntry, null, 0); } @@ -189,9 +250,11 @@ public byte[] getOrDecideContent(Map alre if (decisionMap != null) { Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two + /* + * this may not be the final vaddr for the text segment + * but it will be close enough to make debug easier + * i.e. to within a 4k page or two + */ debugTextBase = ((Number) valueObj).longValue(); } } @@ -228,52 +291,88 @@ public void writeContent() { public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - // 4 ubyte length field + /* + * 4 ubyte length field + */ pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); - // 2 ubyte version is always 2 + /* + * 2 ubyte version is always 2 + */ pos = putShort(DW_VERSION_2, buffer, pos); - // 4 ubyte prologue length includes rest of header and - // dir + file table section + /* + * 4 ubyte prologue length includes rest of header and + * dir + file table section + */ int prologueSize = classEntry.getLinePrologueSize() - 6; pos = putInt(prologueSize, buffer, pos); - // 1 ubyte min instruction length is always 1 + /* + * 1 ubyte min instruction length is always 1 + */ pos = putByte((byte) 1, buffer, pos); - // 1 byte default is_stmt is always 1 + /* + * 1 byte default is_stmt is always 1 + */ pos = putByte((byte) 1, buffer, pos); - // 1 byte line base is always -5 + /* + * 1 byte line base is always -5 + */ pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); - // 1 ubyte line range is always 14 giving range -5 to 8 + /* + * 1 ubyte line range is always 14 giving range -5 to 8 + */ pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); - // 1 ubyte opcode base is always 13 + /* + * 1 ubyte opcode base is always 13 + */ pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); - // specify opcode arg sizes for the standard opcodes - putByte((byte) 0, buffer, pos); // DW_LNS_copy - putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc - putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line - putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file - putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column - putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt - putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block - putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc - putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc - putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence - putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address - pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file + /* + * specify opcode arg sizes for the standard opcodes + */ + /* DW_LNS_copy */ + putByte((byte) 0, buffer, pos); + /* DW_LNS_advance_pc */ + putByte((byte) 1, buffer, pos + 1); + /* DW_LNS_advance_line */ + putByte((byte) 1, buffer, pos + 2); + /* DW_LNS_set_file */ + putByte((byte) 1, buffer, pos + 3); + /* DW_LNS_set_column */ + putByte((byte) 1, buffer, pos + 4); + /* DW_LNS_negate_stmt */ + putByte((byte) 0, buffer, pos + 5); + /* DW_LNS_set_basic_block */ + putByte((byte) 0, buffer, pos + 6); + /* DW_LNS_const_add_pc */ + putByte((byte) 0, buffer, pos + 7); + /* DW_LNS_fixed_advance_pc */ + putByte((byte) 1, buffer, pos + 8); + /* DW_LNS_end_sequence */ + putByte((byte) 0, buffer, pos + 9); + /* DW_LNS_set_address */ + putByte((byte) 0, buffer, pos + 10); + /* DW_LNS_define_file */ + pos = putByte((byte) 1, buffer, pos + 11); return pos; } public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; debug(" [0x%08x] Dir Name\n", pos); - // write out the list of dirs referenced form this file entry + /* + * write out the list of dirs referenced form this file entry + */ int dirIdx = 1; for (DirEntry dir : classEntry.getLocalDirs()) { - // write nul terminated string text. + /* + * write nul terminated string text. + */ debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); pos = putAsciiStringBytes(dir.getPath(), buffer, pos); dirIdx++; } - // separate dirs from files with a nul + /* + * separate dirs from files with a nul + */ pos = putByte((byte) 0, buffer, pos); return pos; } @@ -283,7 +382,9 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { int fileIdx = 1; debug(" [0x%08x] Entry Dir Name\n", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we need the file name minus path, the associated dir index, and 0 for time stamps + /* + * we need the file name minus path, the associated dir index, and 0 for time stamps + */ String baseName = localEntry.getBaseName(); DirEntry dirEntry = localEntry.dirEntry; int dirIdx = classEntry.localDirsIdx(dirEntry); @@ -294,7 +395,9 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putULEB(0, buffer, pos); fileIdx++; } - // terminate files with a nul + /* + * terminate files with a nul + */ pos = putByte((byte) 0, buffer, pos); return pos; } @@ -304,7 +407,9 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - // the primary file entry should always be first in the local files list + /* + * the primary file entry should always be first in the local files list + */ assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; String primaryClassName = classEntry.getClassName(); String primaryFileName = classEntry.getFileName(); @@ -315,10 +420,12 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { Range primaryRange = primaryEntry.getPrimary(); assert primaryRange.getFileName().equals(primaryFileName); - // each primary represents a method i.e. a contiguous - // sequence of subranges. we assume the default state - // at the start of each sequence because we always post an - // end_sequence when we finish all the subranges in the method + /* + * each primary represents a method i.e. a contiguous + * sequence of subranges. we assume the default state + * at the start of each sequence because we always post an + * end_sequence when we finish all the subranges in the method + */ long line = primaryRange.getLine(); if (line < 0 && primaryEntry.getSubranges().size() > 0) { line = primaryEntry.getSubranges().get(0).getLine(); @@ -328,23 +435,33 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { } long address = primaryRange.getLo(); - // set state for primary + /* + * set state for primary + */ debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); - // initialize and write a row for the start of the primary method + /* + * initialize and write a row for the start of the primary method + */ pos = putSetFile(file, fileIdx, buffer, pos); pos = putSetBasicBlock(buffer, pos); - // address is currently 0 + /* + * address is currently 0 + */ pos = putSetAddress(address, buffer, pos); - // state machine value of line is currently 1 - // increment to desired line + /* + * state machine value of line is currently 1 + * increment to desired line + */ if (line != 1) { pos = putAdvanceLine(line - 1, buffer, pos); } pos = putCopy(buffer, pos); - // now write a row for each subrange lo and hi + /* + * now write a row for each subrange lo and hi + */ for (Range subrange : primaryEntry.getSubranges()) { assert subrange.getLo() >= primaryRange.getLo(); assert subrange.getHi() <= primaryRange.getHi(); @@ -356,66 +473,90 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { long subAddressHi = subrange.getHi(); debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); if (subLine < 0) { - // no line info so stay at previous file:line + /* + * no line info so stay at previous file:line + */ subLine = line; subfile = file; subFileIdx = fileIdx; debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); } - // there is a temptation to append end sequence at here - // when the hiAddress lies strictly between the current - // address and the start of the next subrange because, - // ostensibly, we have void space between the end of - // the current subrange and the start of the next one. - // however, debug works better if we treat all the insns up - // to the next range start as belonging to the current line - // - // if we have to update to a new file then do so + /* + * there is a temptation to append end sequence at here + * when the hiAddress lies strictly between the current + * address and the start of the next subrange because, + * ostensibly, we have void space between the end of + * the current subrange and the start of the next one. + * however, debug works better if we treat all the insns up + * to the next range start as belonging to the current line + * + * if we have to update to a new file then do so + */ if (subFileIdx != fileIdx) { - // update the current file + /* + * update the current file + */ pos = putSetFile(subfile, subFileIdx, buffer, pos); file = subfile; fileIdx = subFileIdx; } - // check if we can advance line and/or address in - // one byte with a special opcode + /* + * check if we can advance line and/or address in + * one byte with a special opcode + */ long lineDelta = subLine - line; long addressDelta = subAddressLo - address; byte opcode = isSpecialOpcode(addressDelta, lineDelta); if (opcode != DW_LNS_undefined) { - // ignore pointless write when addressDelta == lineDelta == 0 + /* + * ignore pointless write when addressDelta == lineDelta == 0 + */ if (addressDelta != 0 || lineDelta != 0) { pos = putSpecialOpcode(opcode, buffer, pos); } } else { - // does it help to divide and conquer using - // a fixed address increment + /* + * does it help to divide and conquer using + * a fixed address increment + */ int remainder = isConstAddPC(addressDelta); if (remainder > 0) { pos = putConstAddPC(buffer, pos); - // the remaining address can be handled with a - // special opcode but what about the line delta + /* + * the remaining address can be handled with a + * special opcode but what about the line delta + */ opcode = isSpecialOpcode(remainder, lineDelta); if (opcode != DW_LNS_undefined) { - // address remainder and line now fit + /* + * address remainder and line now fit + */ pos = putSpecialOpcode(opcode, buffer, pos); } else { - // ok, bump the line separately then use a - // special opcode for the address remainder + /* + * ok, bump the line separately then use a + * special opcode for the address remainder + */ opcode = isSpecialOpcode(remainder, 0); assert opcode != DW_LNS_undefined; pos = putAdvanceLine(lineDelta, buffer, pos); pos = putSpecialOpcode(opcode, buffer, pos); } } else { - // increment line and pc separately + /* + * increment line and pc separately + */ if (lineDelta != 0) { pos = putAdvanceLine(lineDelta, buffer, pos); } - // n.b. we might just have had an out of range line increment - // with a zero address increment + /* + * n.b. we might just have had an out of range line increment + * with a zero address increment + */ if (addressDelta > 0) { - // see if we can use a ushort for the increment + /* + * see if we can use a ushort for the increment + */ if (isFixedAdvancePC(addressDelta)) { pos = putFixedAdvancePC((short) addressDelta, buffer, pos); } else { @@ -425,14 +566,20 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putCopy(buffer, pos); } } - // move line and address range on + /* + * move line and address range on + */ line += lineDelta; address += addressDelta; } - // append a final end sequence just below the next primary range + /* + * append a final end sequence just below the next primary range + */ if (address < primaryRange.getHi()) { long addressDelta = primaryRange.getHi() - address; - // increment address before we write the end sequence + /* + * increment address before we write the end sequence + */ pos = putAdvancePC(addressDelta, buffer, pos); } pos = putEndSequence(buffer, pos); @@ -569,7 +716,9 @@ public int putEndSequence(byte[] buffer, int p) { int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = pos + putULEB(1, scratch, 0); return pos + putByte(opcode, scratch, 0); } else { @@ -578,7 +727,9 @@ public int putEndSequence(byte[] buffer, int p) { debugLine = 1; debugCopyCount = 0; pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = putULEB(1, buffer, pos); return putByte(opcode, buffer, pos); } @@ -589,7 +740,9 @@ public int putSetAddress(long arg, byte[] buffer, int p) { int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = pos + putULEB(9, scratch, 0); pos = pos + putByte(opcode, scratch, 0); return pos + putLong(arg, scratch, 0); @@ -597,7 +750,9 @@ public int putSetAddress(long arg, byte[] buffer, int p) { debugAddress = debugTextBase + (int) arg; debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = putULEB(9, buffer, pos); pos = putByte(opcode, buffer, pos); return putRelocatableCodeOffset(arg, buffer, pos); @@ -607,7 +762,9 @@ public int putSetAddress(long arg, byte[] buffer, int p) { public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; int pos = p; - // calculate bytes needed for opcode + args + /* + * calculate bytes needed for opcode + args + */ int fileBytes = file.length() + 1; long insnBytes = 1; insnBytes += fileBytes; @@ -616,15 +773,21 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] insnBytes += putULEB(uleb3, scratch, 0); if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // write insnBytes as a ULEB + /* + * write insnBytes as a ULEB + */ pos += putULEB(insnBytes, scratch, 0); return pos + (int) insnBytes; } else { debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert insn length as uleb + /* + * insert insn length as uleb + */ pos = putULEB(insnBytes, buffer, pos); - // insert opcode and args + /* + * insert opcode and args + */ pos = putByte(opcode, buffer, pos); pos = putAsciiStringBytes(file, buffer, pos); pos = putULEB(uleb1, buffer, pos); @@ -633,17 +796,17 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] } } - public int opcodeId(byte opcode) { + public static int opcodeId(byte opcode) { int iopcode = opcode & 0xff; return iopcode - DW_LN_OPCODE_BASE; } - public int opcodeAddress(byte opcode) { + public static int opcodeAddress(byte opcode) { int iopcode = opcode & 0xff; return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; } - public int opcodeLine(byte opcode) { + public static int opcodeLine(byte opcode) { int iopcode = opcode & 0xff; return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } @@ -667,15 +830,17 @@ public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - public byte isSpecialOpcode(long addressDelta, long lineDelta) { + public static byte isSpecialOpcode(long addressDelta, long lineDelta) { if (addressDelta < 0) { return DW_LNS_undefined; } if (lineDelta >= DW_LN_LINE_BASE) { long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; if (offsetLineDelta < DW_LN_LINE_RANGE) { - // line_delta can be encoded - // check if address is ok + /* + * line_delta can be encoded + * check if address is ok + */ if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; if (opcode <= 255) { @@ -685,11 +850,13 @@ public byte isSpecialOpcode(long addressDelta, long lineDelta) { } } - // return invalid opcode + /* + * answer no by returning an invalid opcode + */ return DW_LNS_undefined; } - public int isConstAddPC(long addressDelta) { + public static int isConstAddPC(long addressDelta) { if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { return 0; } @@ -700,7 +867,7 @@ public int isConstAddPC(long addressDelta) { } } - public boolean isFixedAdvancePC(long addressDiff) { + public static boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } 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 b3a270fe5682..b508ef12f6a9 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 @@ -33,6 +33,7 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.elf.ELFObjectFile; +import java.nio.ByteOrder; import java.util.Map; import java.util.Set; @@ -79,13 +80,17 @@ public DwarfSectionImpl(DwarfSections dwarfSections) { @Override public boolean isLoadable() { - // even though we're a progbits section impl we're not actually loadable + /* + * even though we're a progbits section impl we're not actually loadable + */ return false; } public void checkDebug(int pos) { - // if the env var relevant to this element - // type is set then switch on debugging + /* + * if the env var relevant to this element + * type is set then switch on debugging + */ String name = getSectionName(); String envVarName = "DWARF_" + name.substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { @@ -101,7 +106,13 @@ protected void debug(String format, Object... args) { } } - // base level put methods that assume a non-null buffer + protected boolean littleEndian() { + return dwarfSections.getByteOrder() == ByteOrder.LITTLE_ENDIAN; + } + + /* + * base level put methods that assume a non-null buffer + */ public int putByte(byte b, byte[] buffer, int p) { int pos = p; @@ -111,36 +122,61 @@ public int putByte(byte b, byte[] buffer, int p) { public int putShort(short s, byte[] buffer, int p) { int pos = p; - buffer[pos++] = (byte) (s & 0xff); - buffer[pos++] = (byte) ((s >> 8) & 0xff); + if (littleEndian()) { + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + } else { + buffer[pos++] = (byte) ((s >> 8) & 0xff); + buffer[pos++] = (byte) (s & 0xff); + } return pos; } public int putInt(int i, byte[] buffer, int p) { int pos = p; - buffer[pos++] = (byte) (i & 0xff); - buffer[pos++] = (byte) ((i >> 8) & 0xff); - buffer[pos++] = (byte) ((i >> 16) & 0xff); - buffer[pos++] = (byte) ((i >> 24) & 0xff); + if (littleEndian()) { + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + } else { + buffer[pos++] = (byte) ((i >> 24) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) (i & 0xff); + } return pos; } public int putLong(long l, byte[] buffer, int p) { int pos = p; - buffer[pos++] = (byte) (l & 0xff); - buffer[pos++] = (byte) ((l >> 8) & 0xff); - buffer[pos++] = (byte) ((l >> 16) & 0xff); - buffer[pos++] = (byte) ((l >> 24) & 0xff); - buffer[pos++] = (byte) ((l >> 32) & 0xff); - buffer[pos++] = (byte) ((l >> 40) & 0xff); - buffer[pos++] = (byte) ((l >> 48) & 0xff); - buffer[pos++] = (byte) ((l >> 56) & 0xff); + if (littleEndian()) { + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + } else { + buffer[pos++] = (byte) ((l >> 56) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) (l & 0xff); + } return pos; } public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { int pos = p; - // mark address so it is relocated relative to the start of the text segment + /* + * mark address so it is relocated relative to the start of the text segment + */ markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); pos = putLong(0, buffer, pos); return pos; @@ -200,7 +236,9 @@ public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { return pos; } - // common write methods that check for a null buffer + /* + * common write methods that check for a null buffer + */ public void patchLength(int lengthPos, byte[] buffer, int pos) { if (buffer != null) { @@ -296,10 +334,14 @@ public int writeAttrNull(byte[] buffer, int pos) { @Override public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - // ensure content byte[] has been created before calling super method + /* + * ensure content byte[] has been created before calling super method + */ createContent(); - // ensure content byte[] has been written before calling super method + /* + * ensure content byte[] has been written before calling super method + */ writeContent(); return super.getOrDecideContent(alreadyDecided, contentHint); @@ -313,12 +355,16 @@ public Set getDependencies(Map dirsIndex = new HashMap<>(); - // The obvious traversal structure for debug records is: - // - // 1) by top level compiled method (primary Range) ordered by ascending address - // 2) by inlined method (sub range) within top level method ordered by ascending address - // - // these can be used to ensure that all debug records are generated in increasing address order - // - // An alternative traversal option is - // - // 1) by top level class (String id) - // 2) by top level compiled method (primary Range) within a class ordered by ascending address - // 3) by inlined method (sub range) within top level method ordered by ascending address - // - // this relies on the (current) fact that methods of a given class always appear - // in a single continuous address range with no intervening code from other methods - // or data values. this means we can treat each class as a compilation unit, allowing - // data common to all methods of the class to be shared. - // - // A third option appears to be to traverse via files, then top level class within file etc. - // Unfortunately, files cannot be treated as the compilation unit. A file F may contain - // multiple classes, say C1 and C2. There is no guarantee that methods for some other - // class C' in file F' will not be compiled into the address space interleaved between - // methods of C1 and C2. That is a shame because generating debug info records one file at a - // time would allow more sharing e.g. enabling all classes in a file to share a single copy - // of the file and dir tables. + /* + * The obvious traversal structure for debug records is: + * + * 1) by top level compiled method (primary Range) ordered by ascending address + * 2) by inlined method (sub range) within top level method ordered by ascending address + * + * these can be used to ensure that all debug records are generated in increasing address order + * + * An alternative traversal option is + * + * 1) by top level class (String id) + * 2) by top level compiled method (primary Range) within a class ordered by ascending address + * 3) by inlined method (sub range) within top level method ordered by ascending address + * + * this relies on the (current) fact that methods of a given class always appear + * in a single continuous address range with no intervening code from other methods + * or data values. this means we can treat each class as a compilation unit, allowing + * data common to all methods of the class to be shared. + * + * A third option appears to be to traverse via files, then top level class within file etc. + * Unfortunately, files cannot be treated as the compilation unit. A file F may contain + * multiple classes, say C1 and C2. There is no guarantee that methods for some other + * class C' in file F' will not be compiled into the address space interleaved between + * methods of C1 and C2. That is a shame because generating debug info records one file at a + * time would allow more sharing e.g. enabling all classes in a file to share a single copy + * of the file and dir tables. + */ /** * list of class entries detailing class info for primary ranges. @@ -291,17 +324,23 @@ public int debugStringIndex(String string) { * ObjectFile client */ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - // DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); - // for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { - // install types - // } - - // ensure we have a null string in the string section + /* + * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); + * for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { + * install types + * } + */ + + /* + * ensure we have a null string in the string section + */ uniqueDebugString(""); DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { - // primary file name and full method name need to be written to the debug_str section + /* + * primary file name and full method name need to be written to the debug_str section + */ String fileName = debugCodeInfo.fileName(); String className = debugCodeInfo.className(); String methodName = debugCodeInfo.methodName(); @@ -311,9 +350,11 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, - // returnTypeName, className, methodName, paramNames, fileName); - // create an infoSection entry for the method + /* + * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, + * returnTypeName, className, methodName, paramNames, fileName); + * create an infoSection entry for the method + */ addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { String fileNameAtLine = debugLineInfo.fileName(); @@ -322,25 +363,33 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); int line = debugLineInfo.line(); - // record all subranges even if they have no line or file so we at least get a - // symbol for them + /* + * record all subranges even if they have no line or file so we at least get a + * symbol for them + */ Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); } } - // DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - // for (DebugDataInfo debugDataInfo : dataInfoProvider) { - // install details of heap elements - // String name = debugDataInfo.toString(); - // } + /* + * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + * for (DebugDataInfo debugDataInfo : dataInfoProvider) { + * install details of heap elements + * String name = debugDataInfo.toString(); + * } + */ } public ClassEntry ensureClassEntry(Range range) { String className = range.getClassName(); - // see if we already have an entry + /* + * see if we already have an entry + */ ClassEntry classEntry = primaryClassesIndex.get(className); if (classEntry == null) { - // create and index the entry associating it with the right file + /* + * create and index the entry associating it with the right file + */ FileEntry fileEntry = ensureFileEntry(range); classEntry = new ClassEntry(className, fileEntry); primaryClasses.add(classEntry); @@ -352,7 +401,9 @@ public ClassEntry ensureClassEntry(Range range) { public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); - // ensure we have an entry + /* + * ensure we have an entry + */ FileEntry fileEntry = filesIndex.get(fileName); if (fileEntry == null) { DirEntry dirEntry = ensureDirEntry(fileName); @@ -362,7 +413,9 @@ public FileEntry ensureFileEntry(Range range) { dirEntry); files.add(fileEntry); filesIndex.put(fileName, fileEntry); - // if this is a primary entry then add it to the primary list + /* + * if this is a primary entry then add it to the primary list + */ if (range.isPrimary()) { primaryFiles.add(fileEntry); } else { @@ -386,8 +439,10 @@ public void addSubRange(Range primaryRange, Range subrange) { String className = primaryRange.getClassName(); ClassEntry classEntry = primaryClassesIndex.get(className); FileEntry subrangeEntry = ensureFileEntry(subrange); - // the primary range should already have been seen - // and associated with a primary class entry + /* + * the primary range should already have been seen + * and associated with a primary class entry + */ assert classEntry.primaryIndexFor(primaryRange) != null; classEntry.addSubRange(subrange, subrangeEntry); } @@ -395,7 +450,9 @@ public void addSubRange(Range primaryRange, Range subrange) { public DirEntry ensureDirEntry(String file) { int pathLength = file.lastIndexOf('/'); if (pathLength < 0) { - // no path/package means use dir entry 0 + /* + * no path/package means use dir entry 0 + */ return null; } String filePath = file.substring(0, pathLength); @@ -413,4 +470,7 @@ public StringTable getStringTable() { public LinkedList getPrimaryClasses() { return primaryClasses; } + public ByteOrder getByteOrder() { + return byteOrder; + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 855bca3c749d..0bcdbccb5992 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -96,7 +96,8 @@ public String targetSectionName() { public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address + /* add this so we can use the text section base address for debug */ + LayoutDecision.Kind.VADDR, }; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index cd530c68de04..a597a4df17bc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -27,14 +27,20 @@ package com.oracle.objectfile.elf.dwarf; /** - * track debug info associated with a Java source file. + * Tracks debug info associated with a Java source file. */ public class FileEntry { - // the name of the associated file including path + /** + * The name of the associated file including path + */ private String fileName; - // the name of the associated file excluding path + /** + * The name of the associated file excluding path + */ private String baseName; - // the directory entry associated with this file entry + /** + * The directory entry associated with this file entry + */ DirEntry dirEntry; public FileEntry(String fileName, String baseName, DirEntry dirEntry) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index 6720703cf921..cd356dd00535 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -33,51 +33,34 @@ import java.util.List; /** - * track debug info associated with a primary method. + * Tracks debug info associated with a primary method. * i.e. a top level compiled method */ public class PrimaryEntry { /** - * the primary range detailed by this object. + * The primary range detailed by this object. */ Range primary; /** - * details of the class owning this range. + * Details of the class owning this range. */ ClassEntry classEntry; /** - * a list of subranges associated with the primary range. + * A list of subranges associated with the primary range. */ List subranges; /** - * a mapping from subranges to their associated file entry. + * A mapping from subranges to their associated file entry. */ HashMap subrangeIndex; /** - * details of of compiled method frame size changes. + * Details of of compiled method frame size changes. */ private List frameSizeInfos; /** - * size of compiled method frame. + * Size of compiled method frame. */ private int frameSize; - /** - * index of debug_info section compilation unit for this file. - */ - private int cuIndex; - /** - * index into debug_line section for associated compilation unit. - */ - private int lineIndex; - /** - * size of line number info prologue region for associated compilation unit. - */ - private int linePrologueSize; - /** - * total size of line number info region for associated compilation unit. - */ - private int totalSize; - public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { this.primary = primary; this.classEntry = classEntry; @@ -85,17 +68,18 @@ public PrimaryEntry(Range primary, List frameSizeInfos, in this.subrangeIndex = new HashMap<>(); this.frameSizeInfos = frameSizeInfos; this.frameSize = frameSize; - // initialize indices into other sections to illegal values - this.cuIndex = -1; - this.lineIndex = -1; } public void addSubRange(Range subrange, FileEntry subFileEntry) { - // we should not see a subrange more than once + /* + * we should not see a subrange more than once + */ assert !subranges.contains(subrange); assert subrangeIndex.get(subrange) == null; - // we need to generate a file table entry - // for all ranges + /* + * we need to generate a file table entry + * for all ranges + */ subranges.add(subrange); subrangeIndex.put(subrange, subFileEntry); } @@ -127,46 +111,4 @@ List getFrameSizeInfos() { int getFrameSize() { return frameSize; } - - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - - int getLineIndex() { - // should have been set before being read - assert lineIndex >= 0; - return lineIndex; - } - - void setLineIndex(int lineIndex) { - // should only get set once to a non-negative value - assert lineIndex >= 0; - assert this.lineIndex == -1; - this.lineIndex = lineIndex; - } - - public int getLinePrologueSize() { - return linePrologueSize; - } - - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - - public int getTotalSize() { - return totalSize; - } - - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 758825272a7e..41c78a176b2d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -27,10 +27,10 @@ package com.oracle.objectfile.elf.dwarf; /** - * details of a specific address range in a compiled method + * Details of a specific address range in a compiled method * either a primary range identifying a whole method * or a sub-range identifying a sequence of - * instructions that belong to an inlined method + * instructions that belong to an inlined method. */ public class Range { @@ -43,18 +43,26 @@ public class Range { private int lo; private int hi; private int line; - // this is null for a primary range + /* + * this is null for a primary range + */ private Range primary; - // create a primary range + /* + * create a primary range + */ Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { this(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); } - // create a primary or secondary range + /* + * create a primary or secondary range + */ Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { - // currently file name and full method name need to go into the debug_str section - // other strings just need to be deduplicated to save space + /* + * currently file name and full method name need to go into the debug_str section + * other strings just need to be deduplicated to save space + */ this.fileName = stringTable.uniqueDebugString(fileName); this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index d9a40dc2b3ed..b7963faf9661 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -27,10 +27,10 @@ package com.oracle.objectfile.elf.dwarf; /** - * class used to retain a unique (up to equals) copy of - * a String and also to flag whether the String needs to be - * located in the .debug_string section and track the offset - * where it gets written. + * Used to retain a unique (up to equals) copy of a + * String. Also flag swhether the String needs to be + * located in the debug_string section and, if so, + * tracks the offset at which it gets written. */ public class StringEntry { private String string; @@ -47,7 +47,9 @@ public String getString() { } public int getOffset() { - // offset must be set before this can be fetched + /* + * offset must be set before this can be fetched + */ assert offset >= 0; return offset; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 87b0af1eb437..1ba2def55f73 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -30,10 +30,10 @@ import java.util.Iterator; /** - * a class which allows incoming strings to be reduced - * to unique (up to equaals) instances and allows marking - * of strings which need to be written to the debug_str - * section and retrieval of the lcoation offset after writing. + * Allows incoming strings to be reduced to unique (up + * to equals) instances and supports marking of strings + * which need to be written to the debug_str section + * and retrieval of the location offset after writing. */ public class StringTable implements Iterable { @@ -44,9 +44,9 @@ public StringTable() { } /** - * ensures a unique instance of a string exists in the + * Wnsures a unique instance of a string exists in the * table, inserting the supplied String if no equivalent - * String is already present. this should only be called + * String is already present. This should only be called * before the string section has been written. * @param string the string to be included in the table * @return the unique instance of the String @@ -56,10 +56,10 @@ public String uniqueString(String string) { } /** - * ensures a unique instance of a string exists in the + * Ensures a unique instance of a string exists in the * table and is marked for inclusion in the debug_str * section, inserting the supplied String if no equivalent - * String is already present. this should only be called + * String is already present. This should only be called * before the string section has been written. * @param string the string to be included in the table * and marked for inclusion in the debug_str section @@ -82,8 +82,8 @@ private String ensureString(String string, boolean addToStrSection) { } /** - * retrieves the offset at which a given string was written - * into the debug_str section. this should only be called + * Retrieves the offset at which a given string was written + * into the debug_str section. This should only be called * after the string section has been written. * @param string * @return the offset or -1 if the string does not diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java deleted file mode 100644 index 51c785b0a98d..000000000000 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.oracle.objectfile.elf.dwarf; -public class impl { -} From 8366f51a1246d314030a696c687d8dd391f3f2ca Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 11 Feb 2020 16:59:32 +0000 Subject: [PATCH 026/130] start using Path expressions for directories and file names --- .../debuginfo/DebugInfoProvider.java | 96 +++++++++++++++---- .../objectfile/elf/dwarf/ClassEntry.java | 10 +- .../oracle/objectfile/elf/dwarf/DirEntry.java | 12 ++- .../elf/dwarf/DwarfLineSectionImpl.java | 68 ++++++------- .../objectfile/elf/dwarf/DwarfSections.java | 43 ++++----- .../objectfile/elf/dwarf/FileEntry.java | 32 +++---- .../oracle/objectfile/elf/dwarf/Range.java | 22 ++++- .../svm/hosted/image/NativeBootImage.java | 82 ++++++++++------ 8 files changed, 242 insertions(+), 123 deletions(-) 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 13e8cb73dab3..5aff1370bb33 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 @@ -26,6 +26,7 @@ package com.oracle.objectfile.debuginfo; +import java.nio.file.Path; import java.util.List; /** @@ -45,26 +46,63 @@ interface DebugTypeInfo { * access details of a specific compiled method. */ interface DebugCodeInfo { + /** + * @return the name of the file containing a compiled + * method excluding any path + */ String fileName(); - + /** + * @return a relative path to the file containing a compiled + * method derived from its package name or null if the method + * is in the empty package + */ + Path filePath(); + /** + * @return the fully qualified name of the class owning the + * compiled method + */ String className(); - + /** + * @return the name of the compiled method including + * signature + */ String methodName(); - + /** + * @return the lowest address containing code generated for + * the method represented as an offset into the code segment + */ int addressLo(); - + /** + * @return the first address above the code generated for + * the method represented as an offset into the code segment + */ int addressHi(); - + /** + * @return the starting line number for the method + */ int line(); - + /** + * @return a provider detailing line numbers + * addresses within the compiled method + */ DebugLineInfoProvider lineInfoProvider(); - + /** + * @return a string identifying the method parameters + */ String paramNames(); - + /** + * @return a string identifying the method return type + */ String returnTypeName(); - + /** + * @return the size of the method frame between prologue + * and epilogue + */ int getFrameSize(); - + /** + * @return a list of positions at which the stack is extended + * to a full frame or torn down to an empty frame + */ List getFrameSizeChanges(); } @@ -75,19 +113,45 @@ interface DebugDataInfo { } /** - * access details of a specific outer or inlined method at a given line number. + * access details of code generated for a specific outer + * or inlined method at a given line number. */ interface DebugLineInfo { + /** + * @return the name of the file containing the outer + * or inlined method excluding any path + */ String fileName(); - + /** + * @return a relative path to the file containing the outer + * or inlined method derived from its package name or null + * if the method is in the empty package + */ + Path filePath(); + /** + * @return the fully qualified name of the class owning the + * outer or inlined method + */ String className(); - + /** + * @return the name of the outer or inlined method including signature + */ String methodName(); - + /** + * @return the lowest address containing code generated for + * an outer or inlined code segment reported at this line + * represented as an offset into the code segment + */ int addressLo(); - + /** + * @return the first address above the code generated for + * an outer or inlined code segment reported at this line + * represented as an offset into the code segment + */ int addressHi(); - + /** + * @return the line number for the outer or inlined segment + */ int line(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 0ff7290cb43f..6d8714c5ae38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -106,7 +106,7 @@ public ClassEntry(String className, FileEntry fileEntry) { this.localDirsIndex = new HashMap<>(); localFiles.add(fileEntry); localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.dirEntry; + DirEntry dirEntry = fileEntry.getDirEntry(); if (dirEntry != null) { localDirs.add(dirEntry); localDirsIndex.put(dirEntry, localDirs.size()); @@ -144,7 +144,7 @@ void addSubRange(Range subrange, FileEntry subFileEntry) { localFiles.add(subFileEntry); localFilesIndex.put(subFileEntry, localFiles.size()); } - DirEntry dirEntry = subFileEntry.dirEntry; + DirEntry dirEntry = subFileEntry.getDirEntry(); if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { localDirs.add(dirEntry); localDirsIndex.put(dirEntry, localDirs.size()); @@ -167,8 +167,12 @@ String getFileName() { return fileEntry.getFileName(); } + String getFullFileName() { + return fileEntry.getFullName(); + } + String getDirName() { - return fileEntry.getDirName(); + return fileEntry.getPathName(); } void setCUIndex(int cuIndex) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index dde46b4b8828..c033986b8be6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.elf.dwarf; +import java.nio.file.Path; + /** * Tracks the directory associated with one or * more source files. @@ -38,13 +40,17 @@ * per file. */ public class DirEntry { - private String path; + private Path path; - public DirEntry(String path) { + public DirEntry(Path path) { this.path = path; } - public String getPath() { + public Path getPath() { return path; } + + public String getPathString() { + return path.toString(); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index d19ce896362d..10305904c0ea 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -147,17 +147,19 @@ public void createContent() { */ int pos = 0; for (ClassEntry classEntry : getPrimaryClasses()) { - int startPos = pos; - classEntry.setLineIndex(startPos); - int headerSize = headerSize(); - int dirTableSize = computeDirTableSize(classEntry); - int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; - classEntry.setLinePrologueSize(prologueSize); - int lineNumberTableSize = computeLineNUmberTableSize(classEntry); - int totalSize = prologueSize + lineNumberTableSize; - classEntry.setTotalSize(totalSize); - pos += totalSize; + if (classEntry.getFileName().length() != 0) { + int startPos = pos; + classEntry.setLineIndex(startPos); + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(classEntry); + int fileTableSize = computeFileTableSize(classEntry); + int prologueSize = headerSize + dirTableSize + fileTableSize; + classEntry.setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(classEntry); + int totalSize = prologueSize + lineNumberTableSize; + classEntry.setTotalSize(totalSize); + pos += totalSize; + } } byte[] buffer = new byte[pos]; super.setContent(buffer); @@ -193,7 +195,7 @@ public int computeDirTableSize(ClassEntry classEntry) { */ int dirSize = 0; for (DirEntry dir : classEntry.getLocalDirs()) { - dirSize += dir.getPath().length() + 1; + dirSize += dir.getPathString().length() + 1; } /* * allow for separator nul @@ -217,10 +219,10 @@ public int computeFileTableSize(ClassEntry classEntry) { /* * we want the file base name excluding path */ - String baseName = localEntry.getBaseName(); + String baseName = localEntry.getFileName(); int length = baseName.length(); fileSize += length + 1; - DirEntry dirEntry = localEntry.dirEntry; + DirEntry dirEntry = localEntry.getDirEntry(); int idx = classEntry.localDirsIdx(dirEntry); fileSize += putULEB(idx, scratch, 0); /* @@ -270,21 +272,23 @@ public void writeContent() { debug(" [0x%08x] DEBUG_LINE\n", pos); for (ClassEntry classEntry : getPrimaryClasses()) { - int startPos = pos; - assert classEntry.getLineIndex() == startPos; - debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); - pos = writeHeader(classEntry, buffer, pos); - debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); - int dirTablePos = pos; - pos = writeDirTable(classEntry, buffer, pos); - debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); - int fileTablePos = pos; - pos = writeFileTable(classEntry, buffer, pos); - debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); - int lineNumberTablePos = pos; - pos = writeLineNumberTable(classEntry, buffer, pos); - debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); - debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + if (classEntry.getFileName().length() != 0) { + int startPos = pos; + assert classEntry.getLineIndex() == startPos; + debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + pos = writeHeader(classEntry, buffer, pos); + debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + int dirTablePos = pos; + pos = writeDirTable(classEntry, buffer, pos); + debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(classEntry, buffer, pos); + debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(classEntry, buffer, pos); + debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); + debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + } } assert pos == buffer.length; } @@ -367,7 +371,7 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { * write nul terminated string text. */ debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); - pos = putAsciiStringBytes(dir.getPath(), buffer, pos); + pos = putAsciiStringBytes(dir.getPathString(), buffer, pos); dirIdx++; } /* @@ -385,8 +389,8 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { /* * we need the file name minus path, the associated dir index, and 0 for time stamps */ - String baseName = localEntry.getBaseName(); - DirEntry dirEntry = localEntry.dirEntry; + String baseName = localEntry.getFileName(); + DirEntry dirEntry = localEntry.getDirEntry(); int dirIdx = classEntry.localDirsIdx(dirEntry); debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); pos = putAsciiStringBytes(baseName, buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index afd996cda14d..42df6ae317cb 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -36,6 +36,7 @@ import com.oracle.objectfile.elf.ELFMachine; import java.nio.ByteOrder; +import java.nio.file.Path; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -234,7 +235,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { /** * index of already seen dirs. */ - private Map dirsIndex = new HashMap<>(); + private Map dirsIndex = new HashMap<>(); /* * The obvious traversal structure for debug records is: @@ -284,7 +285,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { /** * index of already seen files. */ - private Map filesIndex = new HashMap<>(); + private Map filesIndex = new HashMap<>(); /** * indirects this call to the string table. @@ -342,14 +343,16 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * primary file name and full method name need to be written to the debug_str section */ String fileName = debugCodeInfo.fileName(); - String className = debugCodeInfo.className(); + Path filePath = debugCodeInfo.filePath(); + // switch '$' in class names for '.' + String className = debugCodeInfo.className().replaceAll("\\$", "."); String methodName = debugCodeInfo.methodName(); String paramNames = debugCodeInfo.paramNames(); String returnTypeName = debugCodeInfo.returnTypeName(); int lo = debugCodeInfo.addressLo(); int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); - Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); + Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); /* * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, * returnTypeName, className, methodName, paramNames, fileName); @@ -358,7 +361,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { String fileNameAtLine = debugLineInfo.fileName(); - String classNameAtLine = debugLineInfo.className(); + Path filePathAtLine = debugLineInfo.filePath(); + // switch '$' in class names for '.' + String classNameAtLine = debugLineInfo.className().replaceAll("\\$", "."); String methodNameAtLine = debugLineInfo.methodName(); int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); @@ -367,7 +372,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * record all subranges even if they have no line or file so we at least get a * symbol for them */ - Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); + Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); } } @@ -401,18 +406,17 @@ public ClassEntry ensureClassEntry(Range range) { public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); + Path filePath = range.getFilePath(); + Path fileAsPath = range.getFileAsPath(); /* * ensure we have an entry */ - FileEntry fileEntry = filesIndex.get(fileName); + FileEntry fileEntry = filesIndex.get(fileAsPath); if (fileEntry == null) { - DirEntry dirEntry = ensureDirEntry(fileName); - String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); - fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), - stringTable.uniqueString(baseName), - dirEntry); + DirEntry dirEntry = ensureDirEntry(filePath); + fileEntry = new FileEntry(fileName, dirEntry); files.add(fileEntry); - filesIndex.put(fileName, fileEntry); + filesIndex.put(fileAsPath, fileEntry); /* * if this is a primary entry then add it to the primary list */ @@ -420,7 +424,7 @@ public FileEntry ensureFileEntry(Range range) { primaryFiles.add(fileEntry); } else { Range primaryRange = range.getPrimary(); - FileEntry primaryEntry = filesIndex.get(primaryRange.getFileName()); + FileEntry primaryEntry = filesIndex.get(primaryRange.getFileAsPath()); assert primaryEntry != null; } } @@ -447,18 +451,13 @@ public void addSubRange(Range primaryRange, Range subrange) { classEntry.addSubRange(subrange, subrangeEntry); } - public DirEntry ensureDirEntry(String file) { - int pathLength = file.lastIndexOf('/'); - if (pathLength < 0) { - /* - * no path/package means use dir entry 0 - */ + public DirEntry ensureDirEntry(Path filePath) { + if (filePath == null) { return null; } - String filePath = file.substring(0, pathLength); DirEntry dirEntry = dirsIndex.get(filePath); if (dirEntry == null) { - dirEntry = new DirEntry(stringTable.uniqueString(filePath)); + dirEntry = new DirEntry(filePath); dirsIndex.put(filePath, dirEntry); dirs.add(dirEntry); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index a597a4df17bc..bc53ec654e64 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -30,34 +30,32 @@ * Tracks debug info associated with a Java source file. */ public class FileEntry { - /** - * The name of the associated file including path - */ private String fileName; - /** - * The name of the associated file excluding path - */ - private String baseName; - /** - * The directory entry associated with this file entry - */ - DirEntry dirEntry; + private DirEntry dirEntry; - public FileEntry(String fileName, String baseName, DirEntry dirEntry) { + public FileEntry(String fileName, DirEntry dirEntry) { this.fileName = fileName; - this.baseName = baseName; this.dirEntry = dirEntry; } + /** + * The name of the associated file excluding path elements. + */ public String getFileName() { return fileName; } - public String getBaseName() { - return baseName; + public String getPathName() { + return getDirEntry().getPathString(); } - String getDirName() { - return (dirEntry != null ? dirEntry.getPath() : ""); + public String getFullName() { + return getDirEntry().getPath().resolve(getFileName()).toString(); + } + /** + * The directory entry associated with this file entry. + */ + public DirEntry getDirEntry() { + return dirEntry; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 41c78a176b2d..2608be71322b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.elf.dwarf; +import java.nio.file.Path; +import java.nio.file.Paths; /** * Details of a specific address range in a compiled method * either a primary range identifying a whole method @@ -35,6 +37,7 @@ public class Range { private String fileName; + private Path filePath; private String className; private String methodName; private String paramNames; @@ -51,19 +54,20 @@ public class Range { /* * create a primary range */ - Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { - this(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); + Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { + this(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); } /* * create a primary or secondary range */ - Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { + Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { /* * currently file name and full method name need to go into the debug_str section * other strings just need to be deduplicated to save space */ this.fileName = stringTable.uniqueDebugString(fileName); + this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); this.paramNames = stringTable.uniqueString(paramNames); @@ -91,6 +95,18 @@ public String getFileName() { return fileName; } + public Path getFilePath() { + return filePath; + } + + public Path getFileAsPath() { + if (filePath != null) { + return filePath.resolve(fileName); + } else { + return Paths.get(fileName); + } + } + public String getClassName() { return className; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 7589c7d3ff33..d1efc98c3901 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -39,6 +39,7 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Collection; @@ -62,7 +63,6 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; @@ -1057,32 +1057,41 @@ private class NativeImageDebugCodeInfo implements DebugCodeInfo { @Override public String fileName() { HostedType declaringClass = method.getDeclaringClass(); - String name = declaringClass.getSourceFileName(); - if (name != null) { - // the file name will not include any path - // use the package to create a path prefix - Package pkg = declaringClass.getJavaClass().getPackage(); - if (pkg != null) { - String prefix = pkg.getName(); - prefix = prefix.replace('.', '/'); - name = prefix + "/" + name; + String sourceFileName = declaringClass.getSourceFileName(); + + if (sourceFileName == null) { + String className = declaringClass.getJavaClass().getName(); + int idx = className.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + className = className.substring(idx + 1); } - } else { - // build file name from the class name which includes the package - name = className(); - // try to map inner classes back to their parent class's file - int idx = name.indexOf('$'); + idx = className.indexOf('$'); if (idx == 0) { // name is $XXX so cannot associate with a file - return ""; - } - if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - name = name.substring(0, idx); + // create a path with an empty name + sourceFileName = ""; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + className = className.substring(0, idx); + } + sourceFileName = className + ".java"; } - name = name.replace('.', '/') + ".java"; } - return name; + + return sourceFileName; + } + @Override + public Path filePath() { + HostedType declaringClass = method.getDeclaringClass(); + Package pkg = declaringClass.getJavaClass().getPackage(); + if (pkg != null) { + // use the package name as a path to the file + return Paths.get("", pkg.getName().split("\\.")); + } else { + return null; + } } @Override @@ -1126,7 +1135,7 @@ public int line() { @Override public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { - if (fileName().length() == 0) { + if (fileName().toString().length() == 0) { return () -> new Iterator() { @Override public boolean hasNext() { @@ -1202,16 +1211,35 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { String name = className(); - int idx = name.indexOf('$'); + int idx = name.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + name = name.substring(idx + 1); + } + idx = name.indexOf('$'); if (idx == 0) { // name is $XXX so cannot associate with a file - return ""; + name = ""; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + name = name.substring(0, idx); + } + name = name + ".java"; } + + return name; + } + + public Path filePath() { + String name = className(); + int idx = name.lastIndexOf('.'); if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name name = name.substring(0, idx); + return Paths.get("", name.split("\\.")); + } else { + return null; } - return name.replace('.', '/') + ".java"; } @Override From a0bae1e675140cd8835d04ac195357a159cd6851 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Feb 2020 10:30:23 +0000 Subject: [PATCH 027/130] ensure dir path for module classes include module name at start --- .../svm/hosted/image/NativeBootImage.java | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index d1efc98c3901..8c495c4dfc27 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -55,8 +55,10 @@ import java.util.Set; import java.util.stream.Collectors; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; @@ -1085,10 +1087,18 @@ public String fileName() { @Override public Path filePath() { HostedType declaringClass = method.getDeclaringClass(); - Package pkg = declaringClass.getJavaClass().getPackage(); + Class javaClass = declaringClass.getJavaClass(); + Package pkg = javaClass.getPackage(); + String module = ModuleSupport.getModuleName(javaClass); if (pkg != null) { - // use the package name as a path to the file - return Paths.get("", pkg.getName().split("\\.")); + /* + * use the package name as a path to the file + * for jdk11 classes we assume that the path includes + * the module name then the package name components + * for jdk8 classes this will just collapse to + * the sequence of package name elements + */ + return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); } else { return null; } @@ -1210,35 +1220,63 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { - String name = className(); - int idx = name.lastIndexOf('.'); - if (idx > 0) { - // strip off package prefix - name = name.substring(idx + 1); - } - idx = name.indexOf('$'); - if (idx == 0) { - // name is $XXX so cannot associate with a file - name = ""; - } else { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + String sourceFileName = declaringClass.getSourceFileName(); + + if (sourceFileName == null) { + String className = declaringClass.getName(); + int idx = className.lastIndexOf('.'); if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - name = name.substring(0, idx); + // strip off package prefix + className = className.substring(idx + 1); + } + idx = className.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + // create a path with an empty name + sourceFileName = ""; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + className = className.substring(0, idx); + } + sourceFileName = className + ".java"; } - name = name + ".java"; } - return name; + return sourceFileName; } public Path filePath() { - String name = className(); - int idx = name.lastIndexOf('.'); - if (idx > 0) { - name = name.substring(0, idx); - return Paths.get("", name.split("\\.")); + ResolvedJavaType declaringClass = (method.getDeclaringClass()); + if (declaringClass instanceof OriginalClassProvider) { + Class javaClass = ((OriginalClassProvider) declaringClass).getJavaClass(); + Package pkg = javaClass.getPackage(); + String module = ModuleSupport.getModuleName(javaClass); + if (pkg != null) { + /* + * use the package name as a path to the file + * + * for jdk11 classes we assume that the path includes + * the module name then the package name components + * + * for jdk8 classes this will just collapse to + * the sequence of package name components + */ + return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); + } else { + return null; + } } else { - return null; + // use the class name to generate a path + String name = className(); + int idx = name.lastIndexOf('.'); + if (idx > 0) { + name = name.substring(0, idx); + return Paths.get("", name.split("\\.")); + } else { + return null; + } } } From 392b580d2ad17643e0e65f37deddd65d4cde4228 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Feb 2020 12:47:53 +0000 Subject: [PATCH 028/130] fix problem with non-null return for empty package on jdk11 --- .../src/com/oracle/svm/hosted/image/NativeBootImage.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 8c495c4dfc27..130ef701904d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -1089,8 +1089,9 @@ public Path filePath() { HostedType declaringClass = method.getDeclaringClass(); Class javaClass = declaringClass.getJavaClass(); Package pkg = javaClass.getPackage(); + String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); - if (pkg != null) { + if (packageName.length() != 0) { /* * use the package name as a path to the file * for jdk11 classes we assume that the path includes @@ -1252,8 +1253,9 @@ public Path filePath() { if (declaringClass instanceof OriginalClassProvider) { Class javaClass = ((OriginalClassProvider) declaringClass).getJavaClass(); Package pkg = javaClass.getPackage(); + String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); - if (pkg != null) { + if (packageName.length() != 0) { /* * use the package name as a path to the file * From 94512bf8983f70f77b0caf6bc4b03f885978b75d Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Feb 2020 17:17:54 +0000 Subject: [PATCH 029/130] avoid addition ofmodule prefix to file paths for Graal classes --- .../svm/hosted/image/NativeBootImage.java | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 130ef701904d..97b423f5045d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -1042,6 +1042,43 @@ public DebugDataInfo next() { } } + private static final String[] GRAAL_SRC_PACKAGE_PREFIXES = { + "org.graalvm", + "com.oracle.graal", + "com.oracle.objectfile", + "com.oracle.svm", + "com.oracle.truffle", + }; + + + /** + * compute a prefix to be added to the front of the file path for + * a class in order to locate it under a GRaal or JDK-specific + * search root + * @param packageName the name of the package the class belongs to + * or possibly an empty string if it is in the default package. + * @param moduleName the name of the module the class belongs to + * or possibly null or an empty string if it is not located + * in a module + * @return any required prefix or the empty string if no prefix is required + */ + private String getPathPrefix(String packageName, String moduleName) { + /* + * if we have a module name it is used as a prefix except + * when the class belongs to Graal itself. + */ + if (moduleName == null || moduleName.length() == 0) { + return ""; + } else { + for (String prefix : GRAAL_SRC_PACKAGE_PREFIXES) { + if (packageName.startsWith(prefix)) { + return ""; + } + } + return moduleName; + } + } + /** * implementation of the DebugCodeInfo API interface * that allows code info to be passed to an ObjectFile @@ -1092,6 +1129,7 @@ public Path filePath() { String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); if (packageName.length() != 0) { + String prefix = getPathPrefix(packageName, module); /* * use the package name as a path to the file * for jdk11 classes we assume that the path includes @@ -1099,7 +1137,7 @@ public Path filePath() { * for jdk8 classes this will just collapse to * the sequence of package name elements */ - return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); + return Paths.get(prefix, pkg.getName().split("\\.")); } else { return null; } @@ -1256,6 +1294,7 @@ public Path filePath() { String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); if (packageName.length() != 0) { + String prefix = getPathPrefix(packageName, module); /* * use the package name as a path to the file * @@ -1265,7 +1304,7 @@ public Path filePath() { * for jdk8 classes this will just collapse to * the sequence of package name components */ - return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); + return Paths.get(prefix, pkg.getName().split("\\.")); } else { return null; } From 396b5520df81ba963c67e08de23d253a9d988009 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 24 Feb 2020 17:55:22 +0000 Subject: [PATCH 030/130] lookup source files via classpath or local dir and cache copies in local sources dir --- .../svm/hosted/image/NativeBootImage.java | 160 ++------- .../image/sources/ApplicationSourceCache.java | 93 ++++++ .../image/sources/GraalVMSourceCache.java | 153 +++++++++ .../hosted/image/sources/JDKSourceCache.java | 71 ++++ .../svm/hosted/image/sources/SourceCache.java | 306 ++++++++++++++++++ .../hosted/image/sources/SourceCacheType.java | 33 ++ .../hosted/image/sources/SourceManager.java | 267 +++++++++++++++ substratevm/write_gdbsourcepath | 193 ----------- 8 files changed, 956 insertions(+), 320 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java delete mode 100644 substratevm/write_gdbsourcepath diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 97b423f5045d..2a56809069a3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -39,7 +39,6 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Collection; @@ -55,10 +54,9 @@ import java.util.Set; import java.util.stream.Collectors; -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.hosted.image.sources.SourceManager; import com.oracle.svm.hosted.meta.HostedType; -import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; @@ -478,6 +476,7 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { // if we have constructed any debug info then // give the object file a chance to install it if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { + ImageSingletons.add(SourceManager.class, new SourceManager()); DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); objectFile.installDebugInfo(provider); } @@ -1051,34 +1050,6 @@ public DebugDataInfo next() { }; - /** - * compute a prefix to be added to the front of the file path for - * a class in order to locate it under a GRaal or JDK-specific - * search root - * @param packageName the name of the package the class belongs to - * or possibly an empty string if it is in the default package. - * @param moduleName the name of the module the class belongs to - * or possibly null or an empty string if it is not located - * in a module - * @return any required prefix or the empty string if no prefix is required - */ - private String getPathPrefix(String packageName, String moduleName) { - /* - * if we have a module name it is used as a prefix except - * when the class belongs to Graal itself. - */ - if (moduleName == null || moduleName.length() == 0) { - return ""; - } else { - for (String prefix : GRAAL_SRC_PACKAGE_PREFIXES) { - if (packageName.startsWith(prefix)) { - return ""; - } - } - return moduleName; - } - } - /** * implementation of the DebugCodeInfo API interface * that allows code info to be passed to an ObjectFile @@ -1087,60 +1058,35 @@ private String getPathPrefix(String packageName, String moduleName) { private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; + private Path fullFilePath; NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; this.compilation = compilation; + this.fullFilePath = null; } @Override public String fileName() { - HostedType declaringClass = method.getDeclaringClass(); - String sourceFileName = declaringClass.getSourceFileName(); - - if (sourceFileName == null) { - String className = declaringClass.getJavaClass().getName(); - int idx = className.lastIndexOf('.'); - if (idx > 0) { - // strip off package prefix - className = className.substring(idx + 1); - } - idx = className.indexOf('$'); - if (idx == 0) { - // name is $XXX so cannot associate with a file - // create a path with an empty name - sourceFileName = ""; - } else { - if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - className = className.substring(0, idx); - } - sourceFileName = className + ".java"; - } + if (fullFilePath == null) { + HostedType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); } - - return sourceFileName; + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; } @Override public Path filePath() { - HostedType declaringClass = method.getDeclaringClass(); - Class javaClass = declaringClass.getJavaClass(); - Package pkg = javaClass.getPackage(); - String packageName = (pkg != null ? pkg.getName() : ""); - String module = ModuleSupport.getModuleName(javaClass); - if (packageName.length() != 0) { - String prefix = getPathPrefix(packageName, module); - /* - * use the package name as a path to the file - * for jdk11 classes we assume that the path includes - * the module name then the package name components - * for jdk8 classes this will just collapse to - * the sequence of package name elements - */ - return Paths.get(prefix, pkg.getName().split("\\.")); - } else { - return null; + if (fullFilePath == null) { + HostedType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getParent(); } + return null; } @Override @@ -1247,6 +1193,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { private final ResolvedJavaMethod method; private final int lo; private final int hi; + private Path fullFilePath = null; NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); @@ -1259,66 +1206,25 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - String sourceFileName = declaringClass.getSourceFileName(); - - if (sourceFileName == null) { - String className = declaringClass.getName(); - int idx = className.lastIndexOf('.'); - if (idx > 0) { - // strip off package prefix - className = className.substring(idx + 1); - } - idx = className.indexOf('$'); - if (idx == 0) { - // name is $XXX so cannot associate with a file - // create a path with an empty name - sourceFileName = ""; - } else { - if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - className = className.substring(0, idx); - } - sourceFileName = className + ".java"; - } + if (fullFilePath == null) { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); } - - return sourceFileName; + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; } public Path filePath() { - ResolvedJavaType declaringClass = (method.getDeclaringClass()); - if (declaringClass instanceof OriginalClassProvider) { - Class javaClass = ((OriginalClassProvider) declaringClass).getJavaClass(); - Package pkg = javaClass.getPackage(); - String packageName = (pkg != null ? pkg.getName() : ""); - String module = ModuleSupport.getModuleName(javaClass); - if (packageName.length() != 0) { - String prefix = getPathPrefix(packageName, module); - /* - * use the package name as a path to the file - * - * for jdk11 classes we assume that the path includes - * the module name then the package name components - * - * for jdk8 classes this will just collapse to - * the sequence of package name components - */ - return Paths.get(prefix, pkg.getName().split("\\.")); - } else { - return null; - } - } else { - // use the class name to generate a path - String name = className(); - int idx = name.lastIndexOf('.'); - if (idx > 0) { - name = name.substring(0, idx); - return Paths.get("", name.split("\\.")); - } else { - return null; - } + if (fullFilePath == null) { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getParent(); } + return null; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java new file mode 100644 index 000000000000..1a9ebc2304fa --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ApplicationSourceCache extends SourceCache { + /** + * create an application source cache + */ + protected ApplicationSourceCache() { + super(SourceCache.APPLICATION_CACHE_KEY); + initSrcRoots(); + } + + private void initSrcRoots() { + String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); + assert javaClassPath != null; + String[] classPathEntries = javaClassPath.split(File.pathSeparator); + /* add dirs or jars found in the classpath */ + for (String classPathEntry : classPathEntries) { + Path entryPath = Paths.get(classPathEntry); + String fileNameString = entryPath.getFileName().toString(); + if (fileNameString.endsWith(".jar")) { + // application jar /path/to/xxx.jar should have + // sources /path/to/xxx-sources.jar + int length = fileNameString.length(); + String srcFileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; + Path srcPath = entryPath.getParent().resolve(srcFileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(root); + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } else { + /* + * for dir entries ending in classes or target/classes + * look for a parallel src tree + */ + if (entryPath.endsWith("classes")) { + Path parent = entryPath.getParent(); + if (parent.endsWith("target")) { + parent = parent.getParent(); + } + Path srcPath = (parent.resolve("src")); + File file = srcPath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(srcPath); + } + } + } + } + /* add the current working directory as a path of last resort */ + srcRoots.add(Paths.get(".")); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java new file mode 100644 index 000000000000..181076bb364a --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedList; +import java.util.List; + +import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; +public class GraalVMSourceCache extends SourceCache { + /** + * create a GraalVM source cache + */ + protected GraalVMSourceCache() { + super(SourceCache.GRAALVM_CACHE_KEY); + initSrcRoots(); + } + + private static final String JAVA_CLASSPATH_PROP = "java.class.path"; + + private void initSrcRoots() { + String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); + assert javaClassPath != null; + String[] classPathEntries = javaClassPath.split(File.pathSeparator); + for (String classPathEntry : classPathEntries) { + Path entryPath = Paths.get(classPathEntry); + String fileNameString = entryPath.getFileName().toString(); + if (fileNameString.endsWith(".jar")) { + // GraalVM jar /path/to/xxx.jar should have + // sources /path/to/xxx.src.zip.jar + int length = fileNameString.length(); + String srcFileNameString = fileNameString.substring(0, length - 3) + "src.zip"; + Path srcPath = entryPath.getParent().resolve(srcFileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + if (filterSrcRoot(root)) { + srcRoots.add(root); + } + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } else { + /* graal classpath dir entries should have a src and/or src_gen subdirectory */ + Path srcPath = entryPath.resolve("src"); + if (filterSrcRoot(srcPath)) { + srcRoots.add(srcPath); + } + srcPath = entryPath.resolve("src_gen"); + if (filterSrcRoot(srcPath)) { + srcRoots.add(srcPath); + } + } + } + } + /** + * Ensure that the supplied root dir contains + * at least one subdirectory that matches one + * of the expected Graal package dir hierarchies. + * + * @param root A root path under which to locate + * the desired subdirectory + * @return true if a + */ + private boolean filterSrcRoot(Path root) { + // we are only interested in source roots + // that potentially contain GraalVM code + String separator = root.getFileSystem().getSeparator(); + + LinkedList toTest = new LinkedList<>(); + LinkedList toBeMatched = new LinkedList<>(); + /* build a list of GraalVM Paths to look for */ + for (String prefix : GRAALVM_SRC_PACKAGE_PREFIXES) { + String subDir = prefix.replaceAll("\\.", separator); + toBeMatched.add(root.resolve(subDir)); + } + /* start by checking immediate subdirs of root */ + try { + addSubDirs(root, toTest); + } catch (IOException e) { + // hmm, ignore this root then + return false; + } + + return searchDirectories(toTest, toBeMatched); + + } + private void addSubDirs(Path parent, LinkedList toSearch) throws IOException { + DirectoryStream directoryStream = Files.newDirectoryStream(parent); + for (Path dir : directoryStream) { + toSearch.addLast(dir); + } + } + private boolean searchDirectories(LinkedList toTest, LinkedList toBeMatched) { + try { + while (!toTest.isEmpty()) { + Path next = toTest.pop(); + for (Path p : toBeMatched) { + if (p.equals(next)) { + /* yes, the full monty! */ + return true; + } else if (p.startsWith(next)) { + /* this may lead where we want to go -- check subdirs */ + addSubDirs(next, toTest); + /* other matches are disjoint so we can break */ + break; + } + } + } + } catch (IOException e) { + /* ignore the exception and also skip the jar */ + } + /* nope, no useful dirs under this root */ + return false; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java new file mode 100644 index 000000000000..e10d5ce44226 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class JDKSourceCache extends SourceCache { + /** + * create a JDK runtime class source cache. + */ + protected JDKSourceCache() { + super(SourceCache.JDK_CACHE_KEY); + initSrcRoots(); + } + + private void initSrcRoots() { + String javaHome = System.getProperty(JAVA_HOME_PROP); + assert javaHome != null; + Path javaHomePath = Paths.get("", javaHome); + Path srcZipPath = null; + String javaSpecversion = System.getProperty(JAVA_SPEC_VERSION_PROP); + if (javaSpecversion.equals("1.8")) { + srcZipPath = javaHomePath.resolve("src.zip"); + } else { + assert javaSpecversion.matches("[1-9][0-9]"); + srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); + } + if (srcZipPath.toFile().exists()) { + try { + FileSystem srcFileSystem = FileSystems.newFileSystem(srcZipPath, null); + for (Path root : srcFileSystem.getRootDirectories()) { + srcRoots.add(root); + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } +} + diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java new file mode 100644 index 000000000000..64577d729ba2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2020, 2020, 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.List; +/** + * An abstract cache manager for some subspace of the + * JDK, GraalVM or application source file space. This class + * implements core behaviours that manage a cache of source + * files in a specific subdirectory of the local sources + * directory. It allows source files to be located + * when present in the local cache or cached when not + * already present. Subclasses are responsible for providing + * behaviours that identify an original source for addition + * to the cache and for verifying that a cached file is not + * out of date with respect to its original. + */ + +public abstract class SourceCache { + + /* + * properties needed to locate relevant JDK and app source roots + */ + protected static final String JAVA_CLASSPATH_PROP = "java.class.path"; + protected static final String JAVA_HOME_PROP = "java.home"; + protected static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + /** + * A list of root directories which may contain source files + * from which this cache can be populated + */ + protected List srcRoots; + + /** + * Create a source cache with a specific base type. + * @param key a String identifying the subdir under + * which sources should be cached which should also + * match the type of content being cached + */ + protected SourceCache(String key) { + basePath = Paths.get(SOURCE_CACHE_ROOT_DIR, key); + srcRoots = new ArrayList<>(); + + } + + /** + * A local directory serving as the root for all + * source trees maintained by the different + * available source caches. + */ + private static final String SOURCE_CACHE_ROOT_DIR = "sources"; + /** + * The top level path relative to the root directory + * under which files belonging to this specific cache + * are located. + */ + private Path basePath; + /** + * JDK runtime code sources are cached using this key as a + * leading path prefix with a module name as a sub-path + * prefix when we have a modular JDK. + * + * For example, the full file path to a file under the cache + * root directory might be jdk/java/lang/Throwable.java on jdk8 or + * jdk/java.base/java/lang/Throwable.java on jdk11 + */ + protected static final String JDK_CACHE_KEY = "jdk"; + /** + * GraalVM code sources are cached using this key as a + * leading path prefix with an enclosing package name + * and the name src or src_gen forming a sub-path prefix. + * + * For example, the full file path to a file under the cache + * root directory might be + * graal/com/oracle/svm/core/Isolates.java + * or + * graal/org/graalvm/compiler/core/phases/LowTier_OptionDescriptors.java + */ + protected static final String GRAALVM_CACHE_KEY = "graal"; + /** + * Application code sources are cached using this key as + * a leading path prefix with a name or sequence of + * names derived from a classpath jar or dir entry + * employed as a sub-path prefix. + * + * For example, the full file path to a file under the cache + * root directory might be + * src/Hello.java + * or + * src/hello/impl/HelloImpl.java + * or + * src/hibernate-core-5.4.4.Final/org/hibernate/annotations/Entity.java + */ + protected static final String APPLICATION_CACHE_KEY = "src"; + /** + * Cache the source file identified by the supplied prototype + * path if a legitimate candidate for inclusion in this cache + * can be identified and is not yet included in the cache or + * alternatively identify and validate any existing candidate + * cache entry to ensure it is not out of date refreshing it + * if need be. + * + * @param filePath a prototype path for a file to be included + * in the cache derived from the name of some associated class. + * @return a path identifying the cached file or null + * if the candidate cannot be found. + */ + public Path resolve(Path filePath) { + File cachedFile = findCandidate(filePath); + if (cachedFile == null) { + return tryCacheFile(filePath); + } else { + return checkCacheFile(filePath); + } + } + + /** + * Given a prototype path for a file to be resolved + * return a File identifying a cached candidate for + * for that Path or null if no cached candidate exists. + * @param filePath a prototype path for a file to be included + * in the cache derived from the name of some associated class. + * @return a File identifying a cached candidate or null. + */ + public File findCandidate(Path filePath) { + /* + * JDK source candidates are stored in the src.zip file + * using the path we are being asked for. A cached version + * should exist under this cache's root using that same + * path. + */ + File file = cachedFile(filePath); + if (file.exists()) { + return file; + } + return null; + } + public Path tryCacheFile(Path filePath) { + for (Path root : srcRoots) { + Path targetPath = cachedPath(filePath); + Path sourcePath = extendPath(root, filePath); + try { + if (checkSourcePath(sourcePath)) { + ensureTargetDirs(targetPath.getParent()); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + // return the original filePath + // we don't want the sources/jdk prefix to go into the debuginfo + return filePath; + } + } catch (IOException e) { + } + } + return null; + } + public Path checkCacheFile(Path filePath) { + for (Path root : srcRoots) { + Path targetPath = cachedPath(filePath); + Path sourcePath = extendPath(root, filePath); + try { + if (checkSourcePath(sourcePath)) { + FileTime sourceTime = Files.getLastModifiedTime(sourcePath); + FileTime destTime = Files.getLastModifiedTime(targetPath); + if (destTime.compareTo(sourceTime) < 0) { + try { + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + } catch (IOException e) { + return null; + } + } + return filePath; + } else { + /* delete the target file as it is out of date */ + targetPath.toFile().delete(); + } + } catch (IOException e) { + // hmm last modified time blew up? + return tryCacheFile(filePath); + } + } + return null; + } + /** + * Create and intialize the source cache used to locate and cache + * sources of a given type as determined by the supplied key. + * @param type an enum identifying both the type of Java sources + * cached by the returned cache and the subdir of the cached + * source subdirectory in which those sources are located. + * @return the desired source cache. + */ + public static SourceCache createSourceCache(SourceCacheType type) { + SourceCache sourceCache = null; + switch (type) { + case JDK: + sourceCache = new JDKSourceCache(); + break; + case GRAALVM: + sourceCache = new GraalVMSourceCache(); + break; + case APPLICATION: + sourceCache = new ApplicationSourceCache(); + break; + default: + assert false; + } + return sourceCache; + } + /** + * Extend a root path form one file system using a path potentially derived + * from another file system by converting he latter to a text string and + * replacing the file separator if necessary. + * @param root the path to be extended + * @param filePath the subpath to extend it with + * @return the extended path + */ + protected Path extendPath(Path root, Path filePath) { + String filePathString = filePath.toString(); + String fileSeparator = filePath.getFileSystem().getSeparator(); + String newSeparator = root.getFileSystem().getSeparator(); + if (!fileSeparator.equals(newSeparator)) { + filePathString = filePathString.replaceAll(fileSeparator, newSeparator); + } + return root.resolve(filePathString); + } + + /** + * convert a potential resolved candidate path to + * the corresponding local Path in this cache. + * @param candidate a resolved candidate path for + * some given resolution request + * @return the corresponding local Path + */ + protected Path cachedPath(Path candidate) { + return basePath.resolve(candidate); + } + /** + * convert a potential resolved candidate path to + * the corresponding local File in this cache. + * @param candidate a resolved candidate path for + * some given resolution request + * @return the corresponding local File + */ + protected File cachedFile(Path candidate) { + return cachedPath(candidate).toFile(); + } + /** + * indicate whether a source path identifies a fie in the associated file system + * @param sourcePath + * @return true if the path identifies a file or false if no such file can be found + * @throws IOException if there is some error in resolving the path + */ + private boolean checkSourcePath(Path sourcePath) throws IOException { + DirectoryStream stream = Files.newDirectoryStream(sourcePath.getParent()); + for (Path path : stream) { + if (path.equals(sourcePath)) { + return true; + } + } + return false; + } + /** + * ensure the directory hierarchy for a path exists + * creating any missing directories if needed + * @param targetDir a path to the desired directory + * @throws IOException if it is not possible to create + * one or more directories in the path + */ + private void ensureTargetDirs(Path targetDir) throws IOException { + if (targetDir != null) { + File targetFile = targetDir.toFile(); + if (!targetFile.exists()) { + targetDir.toFile().mkdirs(); + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java new file mode 100644 index 000000000000..10863a5e572c --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +public enum SourceCacheType { + JDK, + GRAALVM, + APPLICATION +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java new file mode 100644 index 000000000000..459acebe6a08 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.svm.util.ModuleSupport; +import jdk.vm.ci.meta.ResolvedJavaType; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; + +/** + * A singleton class responsible for locating source files + * for classes included in a native image and copying them + * into the local sources. + */ +public class SourceManager { + /** + * Find and cache a source file for a give Java class and + * return a Path to the file relative to the source. + * @param resolvedType the Java type whose source file + * should be located and cached + * @return a path identifying the location of a successfully + * cached file for inclusion in the generated debug info or + * null if a source file cannot be found or cached. + */ + public Path findAndCacheSource(ResolvedJavaType resolvedType) { + Path path = null; + String fileName = computeBaseName(resolvedType); + /* + * null for the name means this class + * will not have a source so we skip on that + */ + if (fileName != null) { + /* + * we can only provide sources + * for known classes and interfaces + */ + if (resolvedType.isInstanceClass() || resolvedType.isInterface()) { + /* + * if we have an OriginalClassProvider we + * can use the underlying Java class + * to provide the details we need to locate + * a source + */ + if (resolvedType instanceof OriginalClassProvider) { + Class javaClass = ((OriginalClassProvider) resolvedType).getJavaClass(); + String packageName = computePackageName(javaClass); + SourceCacheType type = sourceCacheType(packageName, javaClass); + path = locateSource(fileName, packageName, type, javaClass); + } + /* + * if we could not locate a source via the cache + * then the fallback is to generate a path to the + * file based on the class name and let the + * user configure a path to the sources + */ + if (path == null) { + String name = resolvedType.toJavaName(); + int idx = name.lastIndexOf('.'); + if (idx >= 0 && idx < name.length() - 1) { + name = name.substring(0, idx); + path = Paths.get("", name.split("\\.")); + path = path.resolve(fileName); + } + } + } + } + return path; + } + + /** + * Construct the base file name for a resolved + * Java class excluding path elements using either + * the source name embedded in the class file or + * the class name itself. + * @param resolvedType the resolved java type whose + * source file name is required + * @return the file name or null if it the class cannot + * be associated with a source file + */ + private String computeBaseName(ResolvedJavaType resolvedType) { + String fileName = resolvedType.getSourceFileName(); + if (fileName == null) { + /* ok, try to construct it from the class name */ + fileName = resolvedType.toJavaName(); + int idx = fileName.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + fileName = fileName.substring(idx + 1); + } + idx = fileName.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + // + fileName = null; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + fileName = fileName.substring(0, idx); + } + fileName = fileName + ".java"; + } + } + return fileName; + } + /** + * Construct the package name for a Java class or + * the empty String if it has no package. + * @param javaClass the java class whose package + * name is required + * @return the package name or the empty String + * if it has no package + */ + private String computePackageName(Class javaClass) { + Package pkg = javaClass.getPackage(); + return (pkg == null ? "" : pkg.getName()); + } + /** + * Construct the prototype name for a Java source file + * which can be used to resolve and cache an actual source + * file. + * @param fileName the base file name for the source file + * @param packageName the name of the package for the associated Java class + * @param type the type of cache in which to lookup or cache this class's source file + * @param javaClass the java class whose prototype name is required + * @return a protoype name for the source file + */ + private Path computePrototypeName(String fileName, String packageName, SourceCacheType type, Class javaClass) { + String prefix = ""; + if (type == SourceCacheType.JDK) { + /* JDK paths may require the module name as prefix */ + String moduleName = ModuleSupport.getModuleName(javaClass); + if (moduleName != null) { + prefix = moduleName; + } + } + if (packageName.length() == 0) { + return Paths.get("", fileName); + } else { + return Paths.get(prefix, packageName.split("\\.")).resolve(fileName); + } + } + /** + * A whitelist of packages prefixes used to + * pre-filter JDK runtime class lookups. + */ + public static final String[] JDK_SRC_PACKAGE_PREFIXES = { + "java.", + "jdk.", + "javax.", + "sun.", + "com.sun.", + "org.ietf.", + "org.jcp.", + "org.omg.", + "org.w3c.", + "org.xml", + }; + /** + * A whitelist of packages prefixes used to + * pre-filter GraalVM class lookups. + */ + public static final String[] GRAALVM_SRC_PACKAGE_PREFIXES = { + "com.oracle.graal.", + "com.oracle.objectfile.", + "com.oracle.svm.", + "com.oracle.truffle.", + "org.graalvm.", + }; + + /** + * A whitelist of packages prefixes used to + * pre-filter app class lookups which + * includes just the empty string because + * any package will do. + */ + private static final String[] APP_SRC_PACKAGE_PREFIXES = { + "", + }; + + /** + * Check a package name against a whitelist of acceptable packages. + * @param packageName the package name of the class to be checked + * @param whitelist a list of prefixes one of which may form + * the initial prefix of the package name being checked + * @return true if the package name matches an entry in the + * whitelist otherwise false + */ + private boolean whiteListPackage(String packageName, String[] whitelist) { + for (String prefix : whitelist) { + if (packageName.startsWith(prefix)) { + return true; + } + } + return false; + } + + /** + * Identify which type of source cache should be used + * to locate a given class's source code. + */ + private SourceCacheType sourceCacheType(String packageName, Class javaClass) { + if (whiteListPackage(packageName, JDK_SRC_PACKAGE_PREFIXES)) { + return SourceCacheType.JDK; + } + if (whiteListPackage(packageName, GRAALVM_SRC_PACKAGE_PREFIXES)) { + return SourceCacheType.GRAALVM; + } + return SourceCacheType.APPLICATION; + } + /** + * A map from each of the top level root keys to a + * cache that knows how to handle lookup and caching + * of the associated type of source file. + */ + private static HashMap caches = new HashMap<>(); + + /** + * Retrieve the source cache used to locate and cache sources + * of a given type as determined by the supplied key, creating + * and initializing it if it does not already exist. + * @param type an enum identifying the type of Java sources + * cached by the returned cache. + * @return the desired source cache. + */ + private SourceCache getOrCreateCache(SourceCacheType type) { + SourceCache sourceCache = caches.get(type); + if (sourceCache == null) { + sourceCache = SourceCache.createSourceCache(type); + caches.put(type, sourceCache); + } + return sourceCache; + } + + private Path locateSource(String fileName, String packagename, SourceCacheType type, Class javaClass) { + SourceCache cache = getOrCreateCache(type); + Path prototypeName = computePrototypeName(fileName, packagename, type, javaClass); + return cache.resolve(prototypeName); + } +} + diff --git a/substratevm/write_gdbsourcepath b/substratevm/write_gdbsourcepath deleted file mode 100644 index b211b305a543..000000000000 --- a/substratevm/write_gdbsourcepath +++ /dev/null @@ -1,193 +0,0 @@ -#!/bin/bash - - -function usage() -{ - echo "write_gdbsourcepath [-h | -v]" - echo "writes command to set source path to .gdbsourcepath" - echo "set GRAAL_SRC_ROOT to graal git repo root" - echo " defaults to .. when . = sdk, compile, substratevm, truffle" - echo "set GRAAL_JDK_SRC_ROOT to unzipped src.zip root" - echo " defaults to JAVA_HOME/src" - exit $1 -} - -function check_args() -{ - while [ $# -ge 1 ]; do - if [ "$1" == "-v" ]; then - VERBOSE=1 - shift - elif [ "$1" == "-h" ]; then - usage 0 - else - usage 1 - fi - done -} - -typeset -i VERBOSE -VERBOSE=0 - -# debug -function verbose() -{ - if [ $VERBOSE -eq 1 ]; then - echo $* - fi -} - -# check which java we are using and set up JAVA_VERSION -function check_java_version() -{ - JAVA_VERSION_STRING=$(java -version |& grep version | cut -d' ' -f3) - if [ "${JAVA_VERSION_STRING#\"1.8.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=8 - elif [ "${JAVA_VERSION_STRING#\"9.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=9 - elif [ "${JAVA_VERSION_STRING#\"11.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=11 - elif [ "${JAVA_VERSION_STRING#\"14.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=14 - else - echo "Unrecognized java version : $JAVA_VERSION_STRING" - exit 1 - fi -} - -# check for the required source trees and -# set up GRAAL_SRC_ROOT and GRAAL_JDK_SRC_ROOT -function check_source_dirs() -{ - if [ -z "$GRAAL_SRC_ROOT" ]; then - # see if we are in one of the Graal trees - if [ "${PWD#*/sdk}" != "$PWD" -o \ - "${PWD#*/compiler}" != "$PWD" -o \ - "${PWD#*/substratevm}" != "$PWD" -o \ - "${PWD#*/truffle}" != "$PWD" ]; then - GRAAL_SRC_ROOT=$(cd ..; pwd) - echo "defaulting GRAAL_SRC_ROOT to .. : $GRAAL_SRC_ROOT" - else - echo "Please set GRAAL_SRC_ROOT to git repo checkout dir" - exit 1 - fi - fi - - if [ -z "$GRAAL_JDK_SRC_ROOT" ]; then - if [ ! -z "$JAVA_HOME" ]; then - GRAAL_JDK_SRC_ROOT=$JAVA_HOME/src - echo "defaulting GRAAL_JDK_SRC_ROOT to JAVA_HOME : $GRAAL_JDK_SRC_ROOT" - else - JAVA_EXE=`which java` - GRAAL_JDK_SRC_ROOT=${JAVA_EXE%/bin/java}/src - fi - fi -} - -# add sources from a supplied graal source dir -function add_sources() -{ - # sanity check - if [ ! -d $1 ]; then - echo "hmm, was expecting a graal component directory, not this : $1" - fi - if [ ! -d $1/src ]; then - echo "hmm, was expecting to find a graal component source tree, not this : $1/src" - fi - root=$1 - for dir in $1/src/* - do - typeset -i ignore - ignore=0 - verbose "considering $dir" - if [ ! -d ${dir}/src ]; then - ignore=1 - else - # look for test or jdk in the trailing path - tail=${dir#$root} - if [ "${tail%*test}" != "$tail" -o \ - "${tail#*test}" != "$tail" ] ; then - # ignore test dirs - ignore=1 - elif [ "${tail#*jdk}" != "$tail" ]; then - # check for a specific jdk release - if [ "${tail#jdk.}" != "$tail" ]; then - # jdk. as part of a package name is ok - if ["${tail#jdk.}" != "$tail" ]; then - echo allow $dir - fi - ignore=0 - elif [ "${tail#*jdk}" != "${JAVA_VERSION}" ]; then - # jdk must match JAVA_VERSION - if [ "${dir#jdk.}" != "$dir" ]; then - echo disallow $dir - fi - ignore=1 - fi - fi - fi - if [ $ignore -eq 1 ] ; then - verbose "ignoring $dir" - else - verbose "including $dir" - SOURCEPATH=${SOURCEPATH}:$dir/src - fi - done -} - -# add sources from a supplied java source dir -function add_java_sources() -{ - # sanity check - if [ ! -d $1 ]; then - echo "hmm, was expecting to find a JDK source dir, not this : $1" - fi - SOURCEPATH=${SOURCEPATH}:$1 -} - -check_args $* - -check_java_version - -check_source_dirs - -GRAAL_SDK_SRC_ROOT=${GRAAL_SRC_ROOT}/sdk -GRAAL_COMPILER_SRC_ROOT=${GRAAL_SRC_ROOT}/compiler -GRAAL_SUBSTRATEVM_SRC_ROOT=${GRAAL_SRC_ROOT}/substratevm -GRAAL_TRUFFLE_SRC_ROOT=${GRAAL_SRC_ROOT}/truffle - -SOURCEPATH= - -if [ -d ${GRAAL_SDK_SRC_ROOT} ]; then - add_sources ${GRAAL_SDK_SRC_ROOT} -else - echo "Unable to find sdk sources in ${GRAAL_SDK_SRC_ROOT}" -fi -if [ -d ${GRAAL_COMPILER_SRC_ROOT} ]; then - add_sources ${GRAAL_COMPILER_SRC_ROOT} -else - echo "Unable to find compiler sources in ${GRAAL_COMPILER_SRC_ROOT}" -fi -if [ -d ${GRAAL_SUBSTRATEVM_SRC_ROOT} ]; then - add_sources ${GRAAL_SUBSTRATEVM_SRC_ROOT} -else - echo "Unable to find substratevm sources in ${GRAAL_SUBSTRATEVM_SRC_ROOT}" -fi -if [ -d ${GRAAL_TRUFFLE_SRC_ROOT} ]; then - add_sources ${GRAAL_TRUFFLE_SRC_ROOT} -else - echo "Unable to find truffle sources in ${GRAAL_TRUFFLE_SRC_ROOT}" -fi - -if [ -d ${GRAAL_JDK_SRC_ROOT} ]; then - add_java_sources ${GRAAL_JDK_SRC_ROOT} -else - echo "Unable to find JDK sources in ${GRAAL_JDK_SRC_ROOT}/src" - echo "unzip src.zip into \${GRAAL_JDK_SRC_ROOT}/src" -fi - -SOURCEPATH=${SOURCEPATH#:*} -echo "set directories $SOURCEPATH" > .gdbsourcepath -if [ $VERBOSE -gt 0 ]; then - cat .gdbsourcepath -fi From 0700ec608d76a6f1d1cca45787fa3012ddbd3b92 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 25 Feb 2020 10:43:54 +0000 Subject: [PATCH 031/130] correct use File and Path APIs --- .../image/sources/GraalVMSourceCache.java | 46 ++----------------- .../hosted/image/sources/JDKSourceCache.java | 8 ++-- .../svm/hosted/image/sources/SourceCache.java | 8 +--- 3 files changed, 9 insertions(+), 53 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 181076bb364a..2db78649e819 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -100,54 +100,16 @@ private void initSrcRoots() { * @return true if a */ private boolean filterSrcRoot(Path root) { - // we are only interested in source roots - // that potentially contain GraalVM code String separator = root.getFileSystem().getSeparator(); - LinkedList toTest = new LinkedList<>(); - LinkedList toBeMatched = new LinkedList<>(); - /* build a list of GraalVM Paths to look for */ + /* if any of the graal paths exist accept this root */ for (String prefix : GRAALVM_SRC_PACKAGE_PREFIXES) { String subDir = prefix.replaceAll("\\.", separator); - toBeMatched.add(root.resolve(subDir)); - } - /* start by checking immediate subdirs of root */ - try { - addSubDirs(root, toTest); - } catch (IOException e) { - // hmm, ignore this root then - return false; - } - - return searchDirectories(toTest, toBeMatched); - - } - private void addSubDirs(Path parent, LinkedList toSearch) throws IOException { - DirectoryStream directoryStream = Files.newDirectoryStream(parent); - for (Path dir : directoryStream) { - toSearch.addLast(dir); - } - } - private boolean searchDirectories(LinkedList toTest, LinkedList toBeMatched) { - try { - while (!toTest.isEmpty()) { - Path next = toTest.pop(); - for (Path p : toBeMatched) { - if (p.equals(next)) { - /* yes, the full monty! */ - return true; - } else if (p.startsWith(next)) { - /* this may lead where we want to go -- check subdirs */ - addSubDirs(next, toTest); - /* other matches are disjoint so we can break */ - break; - } - } + if (Files.isDirectory(root.resolve(subDir))) { + return true; } - } catch (IOException e) { - /* ignore the exception and also skip the jar */ } - /* nope, no useful dirs under this root */ + return false; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index e10d5ce44226..e53d75f75c9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -46,12 +46,12 @@ private void initSrcRoots() { String javaHome = System.getProperty(JAVA_HOME_PROP); assert javaHome != null; Path javaHomePath = Paths.get("", javaHome); - Path srcZipPath = null; - String javaSpecversion = System.getProperty(JAVA_SPEC_VERSION_PROP); - if (javaSpecversion.equals("1.8")) { + Path srcZipPath; + String javaSpecVersion = System.getProperty(JAVA_SPEC_VERSION_PROP); + if (javaSpecVersion.equals("1.8")) { srcZipPath = javaHomePath.resolve("src.zip"); } else { - assert javaSpecversion.matches("[1-9][0-9]"); + assert javaSpecVersion.matches("[1-9][0-9]"); srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); } if (srcZipPath.toFile().exists()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 64577d729ba2..dcf6b4f0961f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -280,13 +280,7 @@ protected File cachedFile(Path candidate) { * @throws IOException if there is some error in resolving the path */ private boolean checkSourcePath(Path sourcePath) throws IOException { - DirectoryStream stream = Files.newDirectoryStream(sourcePath.getParent()); - for (Path path : stream) { - if (path.equals(sourcePath)) { - return true; - } - } - return false; + return Files.isRegularFile(sourcePath); } /** * ensure the directory hierarchy for a path exists From 61eeb39534d0cadde523992540afeef107183399 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 25 Feb 2020 11:28:29 +0000 Subject: [PATCH 032/130] remove redundant imports --- .../oracle/svm/hosted/image/sources/GraalVMSourceCache.java | 3 --- .../src/com/oracle/svm/hosted/image/sources/SourceCache.java | 1 - 2 files changed, 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 2db78649e819..da8bfd6cde07 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -28,15 +28,12 @@ import java.io.File; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.LinkedList; -import java.util.List; import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; public class GraalVMSourceCache extends SourceCache { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index dcf6b4f0961f..91384cfcb553 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -27,7 +27,6 @@ import java.io.File; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; From 99fb818c46d8893b656005514d6a8682fb320ac2 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 25 Feb 2020 15:56:24 +0000 Subject: [PATCH 033/130] modified debug info API to use streams instead of iterators --- .../debuginfo/DebugInfoProvider.java | 13 ++-- .../objectfile/elf/dwarf/DwarfSections.java | 14 +--- .../svm/hosted/image/NativeBootImage.java | 77 +++---------------- 3 files changed, 21 insertions(+), 83 deletions(-) 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 5aff1370bb33..937e40c108f3 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 @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.util.List; +import java.util.stream.Stream; /** * interfaces used to allow a native image to communicate @@ -82,10 +83,10 @@ interface DebugCodeInfo { */ int line(); /** - * @return a provider detailing line numbers - * addresses within the compiled method + * @return a stream of records detailing line numbers + * and addresses within the compiled method */ - DebugLineInfoProvider lineInfoProvider(); + Stream lineInfoProvider(); /** * @return a string identifying the method parameters */ @@ -190,9 +191,9 @@ interface DebugLineInfoProvider extends Iterable { interface DebugDataInfoProvider extends Iterable { } - DebugTypeInfoProvider typeInfoProvider(); + Stream typeInfoProvider(); - DebugCodeInfoProvider codeInfoProvider(); + Stream codeInfoProvider(); - DebugDataInfoProvider dataInfoProvider(); + Stream dataInfoProvider(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 42df6ae317cb..0ba4bd7543ea 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -27,12 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; -// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; -// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; import com.oracle.objectfile.elf.ELFMachine; import java.nio.ByteOrder; @@ -337,8 +332,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ uniqueDebugString(""); - DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); - for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { + debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> { /* * primary file name and full method name need to be written to the debug_str section */ @@ -359,7 +353,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * create an infoSection entry for the method */ addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); - for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { + debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); Path filePathAtLine = debugLineInfo.filePath(); // switch '$' in class names for '.' @@ -374,8 +368,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); - } - } + }); + }); /* * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); * for (DebugDataInfo debugDataInfo : dataInfoProvider) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 2a56809069a3..c54cc8dde4c4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -46,13 +46,13 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.hosted.image.sources.SourceManager; @@ -983,61 +983,26 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; private final NativeImageHeap heap; - private final Iterator> codeCacheIterator; - private final Iterator> heapIterator; NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { super(); this.codeCache = codeCache; this.heap = heap; - this.codeCacheIterator = codeCache.compilations.entrySet().iterator(); - this.heapIterator = heap.objects.entrySet().iterator(); } @Override - public DebugTypeInfoProvider typeInfoProvider() { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public DebugTypeInfo next() { - return null; - } - }; + public Stream typeInfoProvider() { + return Stream.empty(); } @Override - public DebugCodeInfoProvider codeInfoProvider() { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return codeCacheIterator.hasNext(); - } - - @Override - public DebugCodeInfo next() { - Map.Entry entry = codeCacheIterator.next(); - return new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue()); - } - }; + public Stream codeInfoProvider() { + return codeCache.compilations.entrySet().stream().map(entry -> new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue())); } @Override - public DebugDataInfoProvider dataInfoProvider() { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public DebugDataInfo next() { - return null; - } - }; + public Stream dataInfoProvider() { + return Stream.empty(); } } @@ -1129,33 +1094,11 @@ public int line() { } @Override - public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { + public Stream lineInfoProvider() { if (fileName().toString().length() == 0) { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public DebugLineInfo next() { - return null; - } - }; + return Stream.empty(); } - return () -> new Iterator() { - final Iterator sourceIterator = compilation.getSourceMappings().iterator(); - - @Override - public boolean hasNext() { - return sourceIterator.hasNext(); - } - - @Override - public DebugLineInfo next() { - return new NativeImageDebugLineInfo(sourceIterator.next()); - } - }; + return compilation.getSourceMappings().stream().map(sourceMapping -> new NativeImageDebugLineInfo(sourceMapping)); } public int getFrameSize() { From 93dbfe57b94099877ef6a333795780f1897e3de8 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 26 Feb 2020 11:13:45 +0000 Subject: [PATCH 034/130] updated DEBUGINFO readme to match latest version --- substratevm/DEBUGINFO.md | 152 +++++++++++++++++++++++++++++---------- 1 file changed, 116 insertions(+), 36 deletions(-) diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 5b859cd3cd7a..0536be0bf2a3 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -2,11 +2,22 @@ Using the ptototype debug info feature -------------------------------------- To add debug info to a generated native image add flag --H:+TrackNodeSourcePosition to the native image command line. +-H:+GenerateDebugInfo to the native image command line. - mx native-image -H:+TrackNodeSourcePosition Hello.java + $ javac Hello.java + $ mx native-image -H:+GenerateDebugInfo Hello + +The resulting image should contain code (method) debug records in a +format gdb understands (VS support is still under development). + +The flag also enables caching of sources for JDK runtime classes, +GraalVM classes and application classes which can be located during +native image generation. The cache is created under local subdirectory +sources and can be used to configure source file search path roots for +the debugger. Files in the cache are located in a directory hierarchy +that matches the file path information included in the native image +debug records -The resulting image should contain code (method) debug symbols. What is currently implemented ----------------------------- @@ -25,50 +36,119 @@ compiled method. Identifying the location of source code --------------------------------------- -In order for gdb to be able to locate the source files for your app -methods, Graal methods and JDK runtime methods you need to provide gdb -with a list of source root dirs a 'set directories' command: +One goal of the implementation is to make it simple to configure your +debugger so that it can identify the relevant source file when it +stops during program execution. The native image generator tries to +achieve this by accumulating the relevant sources in a suitably +structured file cache. + +The native image generator uses different strategies to locate source +files for JDK runtime classes, GraalVM classses and application source +classes for inclusion in the local sources cache. It identifies which +strategy to use based on the package name of the class. So, for +example, packages starting with java.* or jdk.* are JDK classes; +packages starting with org.graal.* or com.oracle.svm.* are GraalVM +classes; any other packages are regarded as application classes. + +Sources for JDK runtime classes are retrieved from the src.zip found +in the JDK release used to run the native image generation process. +Retrieved files are cached under subdirectory sources/jdk, using the +module name (for JDK11) and package name of the associated class to +define the directory hierarchy in which the source is located. + +So, for example, on Linux the source for class java.util.HashMap will +be cached in file sources/jdk/java.base/java/util/HashMap.java. Debug +info records for this class and its methods will identify this source +file using the relative directory path java.base/java/util and file +name HashMap.java. On Windows things will be the same modulo use of +'\' rather than '/' as the file separator. + +Sources for GraalVM classes are retrieved from zip files or source +directories derived from entries in the classpath. Retrieved files are +cached under subdirectory sources/graal, using the package name of the +associated class to define the directory hierarchy in which the source +is located (e.g. class com.oracle.svm.core.VM has its source file +cached at sources/graal/com/oracle/svm/core/VM.java). + +The lookup scheme for cached GraalVM sources varies depending upon +what is found in each classpath entry. Given a jar file entry like +/path/to/foo.jar, the corresponding file /path/to/foo.src.zip is +considered as a candidate zip file system from which source files may +be extracted. When the entry specifies a dir like /path/to/bar then +directories /path/to/bar/src and /path/to/bar/src_gen are considered +as candidates. Candidates are skipped when i) the zip file or source +directory does not exist or ii) it does not contain at least one +subdirectory hierarchy that matches one of the the expected GraalVM +package hierarchies. + +Sources for application classes are retrieved from source jar files or +source directories derived from entries in the classpath. Retrieved +files are cached under subdirectory sources/src, using the package +name of the associated class to define the directory hierarchy in +which the source is located (e.g. class org.my.foo.Foo has its +source file cached as sources/src/org/my/foo/Foo.java). + +The lookup scheme for cached pplication sources varies depending upon +what is found in each classpath entry. Given a jar file entry like +/path/to/foo.jar, the corresponding jar /path/to/foo-sources.jar is +considered as a candidate zip file system from which source files may +be extracted. When the entry specifies a dir like /path/to/bar/classes +or /path/to/bar/target/classes then directory /path/to/bar/src is +considered as a candidate. Finally, the current directory in whcih the +native image program is being run is also considered as a candidate. + +These lookup strategies are only provisional and may need extending in +future. Note however that it is possible to make missing sources +available by other means. One option is to unzip extra app source jars +or copying extra app source trees into the cache. Another is to +configure extra source search paths (see below). + +Configuring source paths in gdb +------------------------------- - (gdb) set directories /home/adinn/hello/src:/home/adinn/graal/sdk/src/org/graalvm.word/src:/home/adinn/graal/sdk/src/org.graalvm.options/src:... - -The argument is a comma separated list of source roots. It needs to -identify: +In order for gdb to be able to locate the source files for your app +classes, Graal classes and JDK runtime classes you need to provide gdb +with a list of source root dirs using the 'set directories' command: - - sources for your app - - sources under the Graal sdk, compiler, substratevm and truffle trees - - sources in the JDK src.zip file + (gdb) set directories /path/to/sources/jdk:/path/to/sources/graal:/path/to/sources/src -Needless to say the list for Graal is long and complex. Also, the JDK -sources are in a zip file and gdb does not understand zip sources. So -you need to extract the JDK sources as a preparatory step, +Directory .../sources/jdk should contain source files for all JDK runtime +classes referenced from debug records. -You can use shell script write_gdbsourcepath (added to Graal dir -substratevm) to auto-generate settings for the GRaal and JDK sources. +Directory .../sources/graal should contain source files for all GraalVM +classes referenced from debug records. Note that the current +implementation does not yet find some sources for the GraalVM JIT +compiler in the org.graalvm.compiler* package subspace. - $ bash write_gdbsourcepath +Directory .../sources/src should contain source files for all +application classes referenced from debug records, assuming they can +be located using the lookup strategy described above. -It creates a local file .gdbsourcepath which sets the relevant -directories. Before running it you can set two env vars to tell it -where to locate the source trees it needs to include: +You can supplement the files cached in sources/src by unzipping +application source jars or copying application source trees into the +cache. You need to ensure that any new subdirectory you add to +sources/src corresponds to the top level package for the classes whose +sources are being included. - - GRAAL_JAVA_SRC_ROOT should point to the dir into which you have - unzipped the src.zip from your Graal JDK release - - GRAAL_SRC_ROOT should point to the dir in which your Graal git - tree checkout is located +You can also add extra directories to the search path. Note that gdb +does not understand zip fomrat file systems so any extra entries you +add must identify a directory tree containing the relevant +sources. Once again. top leel entries in the directory added to the +search path must correspond to the top level package for the classes +whose sources are being included. -Note that the script ignores test source dirs and jdk dirs that do not -match the release level of the JDK (i.e. if you use jdk8 it will ony -include jdk8 src dirs). The script runs the java command available via -JAVA_HOME to idenitfy which JDK is in use). +Configuring source paths in VS +------------------------------ -If you run the script from the substratevm dir of your Graal git repo -checkout the script will default GRAAL_SRC_ROOT to the parent dir. +TO BE ADDED -If JAVA_HOME is set the script will default GRAAL_JAVA_SRC_ROOT to -$JAVA_HOME/src +Checking debug info on Linux +---------------------------- -Checking debug info -------------------- +n.b. this is only of interest to those who want to understand how the +debug info implemetation works or want to trouble shoot problems +encountered during debugging that might relate to the debug info +encoding. The objdump command can be used to display the dbeug info embedded into a native image. The following commands (which all assume the From db7ec660ca23a13d2fba4816d8a9f39277c3e3fd Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 26 Feb 2020 15:14:31 +0000 Subject: [PATCH 035/130] fixed typos and small format/wording errors and rmeoved smeredudant code removed some redundant code --- substratevm/DEBUGINFO.md | 8 +++---- .../debuginfo/DebugInfoProvider.java | 24 ------------------- .../objectfile/elf/dwarf/StringEntry.java | 2 +- .../objectfile/elf/dwarf/StringTable.java | 2 +- 4 files changed, 6 insertions(+), 30 deletions(-) diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 0536be0bf2a3..58e8bd48b63e 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -5,7 +5,7 @@ To add debug info to a generated native image add flag -H:+GenerateDebugInfo to the native image command line. $ javac Hello.java - $ mx native-image -H:+GenerateDebugInfo Hello + $ mx native-image -H:GenerateDebugInfo=1 Hello The resulting image should contain code (method) debug records in a format gdb understands (VS support is still under development). @@ -88,13 +88,13 @@ name of the associated class to define the directory hierarchy in which the source is located (e.g. class org.my.foo.Foo has its source file cached as sources/src/org/my/foo/Foo.java). -The lookup scheme for cached pplication sources varies depending upon +The lookup scheme for cached Application sources varies depending upon what is found in each classpath entry. Given a jar file entry like /path/to/foo.jar, the corresponding jar /path/to/foo-sources.jar is considered as a candidate zip file system from which source files may be extracted. When the entry specifies a dir like /path/to/bar/classes or /path/to/bar/target/classes then directory /path/to/bar/src is -considered as a candidate. Finally, the current directory in whcih the +considered as a candidate. Finally, the current directory in which the native image program is being run is also considered as a candidate. These lookup strategies are only provisional and may need extending in @@ -131,7 +131,7 @@ sources/src corresponds to the top level package for the classes whose sources are being included. You can also add extra directories to the search path. Note that gdb -does not understand zip fomrat file systems so any extra entries you +does not understand zip format file systems so any extra entries you add must identify a directory tree containing the relevant sources. Once again. top leel entries in the directory added to the search path must correspond to the top level package for the classes 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 937e40c108f3..444be49613ac 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 @@ -167,30 +167,6 @@ enum Type { DebugFrameSizeChange.Type getType(); } - /** - * convenience interface defining iterator type. - */ - interface DebugTypeInfoProvider extends Iterable { - } - - /** - * convenience interface defining iterator type. - */ - interface DebugCodeInfoProvider extends Iterable { - } - - /** - * convenience interface defining iterator type. - */ - interface DebugLineInfoProvider extends Iterable { - } - - /** - * convenience interface defining iterator type. - */ - interface DebugDataInfoProvider extends Iterable { - } - Stream typeInfoProvider(); Stream codeInfoProvider(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index b7963faf9661..f08fa4da79c7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -48,7 +48,7 @@ public String getString() { public int getOffset() { /* - * offset must be set before this can be fetched + * Offset must be set before this can be fetched */ assert offset >= 0; return offset; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 1ba2def55f73..b2e0479e5e31 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -44,7 +44,7 @@ public StringTable() { } /** - * Wnsures a unique instance of a string exists in the + * Ensures a unique instance of a string exists in the * table, inserting the supplied String if no equivalent * String is already present. This should only be called * before the string section has been written. From 2d0a7e7e7a5a23b57c92bc1ab9ec53930f98a3ae Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Wed, 26 Feb 2020 15:38:43 -0500 Subject: [PATCH 036/130] Add Windows SECTION and SECREL relocations types --- .../src/com/oracle/objectfile/ObjectFile.java | 10 +++ .../com/oracle/objectfile/pecoff/PECoff.java | 4 +- .../objectfile/pecoff/PECoffMachine.java | 64 +++++++++++++++++++ .../objectfile/pecoff/PECoffObjectFile.java | 1 + 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index cbf13d644688..49d6dfaab877 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -249,6 +249,16 @@ public enum RelocationKind { * The relocation's symbol provides high fixup bytes. */ DIRECT_HI, + /** + * The index of the object file section containing the relocation's symbol supplies the fixup bytes + * (used in CodeView debug information) + */ + SECTION, + /** + * The address of the object file section containing the relocation's symbol (+addend( supplies the fixup bytes. + * (used in CodeView debug information) + */ + SECREL, /** * The relocation's symbol provides low fixup bytes. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoff.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoff.java index 6925ab456f69..f057384794d8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoff.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoff.java @@ -124,6 +124,7 @@ enum IMAGE_SECTION_HEADER { static final int IMAGE_SCN_LNK_NRELOC_OVFL = 0x01000000; + static final int IMAGE_SCN_MEM_DISCARDABLE = 0x02000000; static final int IMAGE_SCN_MEM_SHARED = 0x10000000; static final int IMAGE_SCN_MEM_EXECUTE = 0x20000000; static final int IMAGE_SCN_MEM_READ = 0x40000000; @@ -202,7 +203,8 @@ enum IMAGE_RELOCATION { static final int IMAGE_REL_AMD64_REL32_3 = 0x7; static final int IMAGE_REL_AMD64_REL32_4 = 0x8; static final int IMAGE_REL_AMD64_REL32_5 = 0x9; - + static final int IMAGE_REL_AMD64_SECTION = 0xa; + static final int IMAGE_REL_AMD64_SECREL = 0xb; } //@formatter:on // Checkstyle: resume diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java index 7ec064e04c54..239e0637a020 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffMachine.java @@ -56,6 +56,8 @@ public static PECoffRelocationMethod getRelocation(PECoffMachine m, RelocationKi switch (k) { case DIRECT: switch (sizeInBytes) { + case 4: + return PECoffX86_64Relocation.ADDR32; case 8: return PECoffX86_64Relocation.ADDR64; default: @@ -68,6 +70,20 @@ public static PECoffRelocationMethod getRelocation(PECoffMachine m, RelocationKi default: throw new IllegalArgumentException("unsupported relocation type: " + k + " size: " + sizeInBytes); } + case SECTION: + switch (sizeInBytes) { + case 2: + return PECoffX86_64Relocation.SECTION; + default: + throw new IllegalArgumentException("unsupported relocation type: " + k + " size: " + sizeInBytes); + } + case SECREL: + switch (sizeInBytes) { + case 4: + return PECoffX86_64Relocation.SECREL; + default: + throw new IllegalArgumentException("unsupported relocation type: " + k + " size: " + sizeInBytes); + } default: case UNKNOWN: throw new IllegalArgumentException("cannot map unknown relocation kind to an PECoff x86-64 relocation type"); @@ -176,6 +192,54 @@ public long toLong() { return IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR64; } }, + ADDR32 { + @Override + public RelocationKind getKind() { + return RelocationKind.DIRECT; + } + + @Override + public int getRelocatedByteSize() { + return 4; + } + + @Override + public long toLong() { + return IMAGE_RELOCATION.IMAGE_REL_AMD64_ADDR32; + } + }, + SECREL { + @Override + public RelocationKind getKind() { + return RelocationKind.DIRECT; + } + + @Override + public int getRelocatedByteSize() { + return 4; + } + + @Override + public long toLong() { + return IMAGE_RELOCATION.IMAGE_REL_AMD64_SECREL; + } + }, + SECTION { + @Override + public RelocationKind getKind() { + return RelocationKind.DIRECT; + } + + @Override + public int getRelocatedByteSize() { + return 2; + } + + @Override + public long toLong() { + return IMAGE_RELOCATION.IMAGE_REL_AMD64_SECTION; + } + }, REL32 { @Override public RelocationKind getKind() { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 83ce337ae3d6..473537169808 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -379,6 +379,7 @@ public enum PECoffSectionFlag implements ValueEnum { READ(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_READ), WRITE(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_WRITE), EXECUTE(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_EXECUTE), + DISCARDABLE(IMAGE_SECTION_HEADER.IMAGE_SCN_MEM_DISCARDABLE), LINKER(IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_INFO | IMAGE_SECTION_HEADER.IMAGE_SCN_LNK_REMOVE); private final int value; From 63ee7cddf9e0eebbc8d6fcb68f02e5b17de8c2a6 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Wed, 26 Feb 2020 17:05:15 -0500 Subject: [PATCH 037/130] initial PECoff CodeView support --- .../src/com/oracle/objectfile/ObjectFile.java | 13 +- .../com/oracle/objectfile/SectionName.java | 5 +- .../debuginfo/DebugInfoProvider.java | 175 ++++ .../objectfile/pecoff/PECoffObjectFile.java | 42 + .../objectfile/pecoff/cv/CVConstants.java | 54 ++ .../pecoff/cv/CVDebugConstants.java | 102 +++ .../objectfile/pecoff/cv/CVLineRecord.java | 188 +++++ .../pecoff/cv/CVLineRecordBuilder.java | 175 ++++ .../objectfile/pecoff/cv/CVRootPackages.java | 178 ++++ .../objectfile/pecoff/cv/CVSections.java | 144 ++++ .../objectfile/pecoff/cv/CVSymbolRecord.java | 236 ++++++ .../pecoff/cv/CVSymbolRecordBuilder.java | 124 +++ .../pecoff/cv/CVSymbolSectionImpl.java | 181 ++++ .../pecoff/cv/CVSymbolSubrecord.java | 621 ++++++++++++++ .../pecoff/cv/CVSymbolSubsection.java | 70 ++ .../objectfile/pecoff/cv/CVTypeConstants.java | 98 +++ .../objectfile/pecoff/cv/CVTypeRecord.java | 671 +++++++++++++++ .../pecoff/cv/CVTypeRecordBuilder.java | 60 ++ .../pecoff/cv/CVTypeSectionImpl.java | 130 +++ .../oracle/objectfile/pecoff/cv/CVUtil.java | 166 ++++ .../objectfile/pecoff/cv/DebugInfoBase.java | 786 ++++++++++++++++++ .../com/oracle/svm/core/SubstrateOptions.java | 13 + .../svm/hosted/image/NativeBootImage.java | 274 ++++++ .../image/sources/ApplicationSourceCache.java | 93 +++ .../image/sources/GraalVMSourceCache.java | 112 +++ .../hosted/image/sources/JDKSourceCache.java | 71 ++ .../svm/hosted/image/sources/SourceCache.java | 299 +++++++ .../hosted/image/sources/SourceCacheType.java | 33 + .../hosted/image/sources/SourceManager.java | 267 ++++++ 29 files changed, 5379 insertions(+), 2 deletions(-) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 49d6dfaab877..ede349881240 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -45,6 +45,7 @@ import java.util.TreeSet; import java.util.stream.StreamSupport; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.elf.ELFObjectFile; import com.oracle.objectfile.macho.MachOObjectFile; import com.oracle.objectfile.pecoff.PECoffObjectFile; @@ -250,7 +251,7 @@ public enum RelocationKind { */ DIRECT_HI, /** - * The index of the object file section containing the relocation's symbol supplies the fixup bytes + * The index of the object file section containing the relocation's symbol supplies the fixup bytes. * (used in CodeView debug information) */ SECTION, @@ -1096,6 +1097,16 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // flag compatibility } + /** + * API method provided to allow a native image generator to provide details of + * types, code and heap data inserted into a native image. + * @param debugInfoProvider an implementation of the provider interface that + * communicates details of the relevant types, code and heap data. + */ + public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { + // do nothing by default + } + protected static Iterable allDecisions(final Map decisions) { return () -> StreamSupport.stream(decisions.values().spliterator(), false) .flatMap(layoutDecisionMap -> StreamSupport.stream(layoutDecisionMap.spliterator(), false)).iterator(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/SectionName.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/SectionName.java index ea04271c3deb..e821bb0235ab 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/SectionName.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/SectionName.java @@ -94,11 +94,14 @@ public String getFormatDependentName(Format f) { public static final SectionName APPLE_NAMESPACE = new ProgbitsSectionName("apple_namespac"); public static final SectionName APPLE_OBJC = new ProgbitsSectionName("apple_objc"); public static final SectionName LLVM_STACKMAPS = new ProgbitsSectionName("llvm_stackmaps"); + // Windows PECOFF CodeView 4 debug sections + public static final SectionName CV4_DEBUG_SYMBOLS = new ProgbitsSectionName("debug$S"); + public static final SectionName CV4_DEBUG_TYPES = new ProgbitsSectionName("debug$T"); private static final SectionName[] myValues; static { - myValues = new SectionName[]{DATA, RODATA, TEXT, BSS, APPLE_NAMES, APPLE_TYPES, APPLE_NAMESPACE, APPLE_OBJC, LLVM_STACKMAPS}; + myValues = new SectionName[]{DATA, RODATA, TEXT, BSS, APPLE_NAMES, APPLE_TYPES, APPLE_NAMESPACE, APPLE_OBJC, LLVM_STACKMAPS, CV4_DEBUG_SYMBOLS, CV4_DEBUG_TYPES}; } private static String getFormatPrefix(ObjectFile.Format f) { 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 new file mode 100644 index 000000000000..444be49613ac --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.debuginfo; + +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +/** + * interfaces used to allow a native image to communicate + * details of types, code and data to the underlying + * object file so that the latter can insert appropriate + * debug info. + */ +public interface DebugInfoProvider { + /** + * access details of a specific type. + */ + interface DebugTypeInfo { + } + + /** + * access details of a specific compiled method. + */ + interface DebugCodeInfo { + /** + * @return the name of the file containing a compiled + * method excluding any path + */ + String fileName(); + /** + * @return a relative path to the file containing a compiled + * method derived from its package name or null if the method + * is in the empty package + */ + Path filePath(); + /** + * @return the fully qualified name of the class owning the + * compiled method + */ + String className(); + /** + * @return the name of the compiled method including + * signature + */ + String methodName(); + /** + * @return the lowest address containing code generated for + * the method represented as an offset into the code segment + */ + int addressLo(); + /** + * @return the first address above the code generated for + * the method represented as an offset into the code segment + */ + int addressHi(); + /** + * @return the starting line number for the method + */ + int line(); + /** + * @return a stream of records detailing line numbers + * and addresses within the compiled method + */ + Stream lineInfoProvider(); + /** + * @return a string identifying the method parameters + */ + String paramNames(); + /** + * @return a string identifying the method return type + */ + String returnTypeName(); + /** + * @return the size of the method frame between prologue + * and epilogue + */ + int getFrameSize(); + /** + * @return a list of positions at which the stack is extended + * to a full frame or torn down to an empty frame + */ + List getFrameSizeChanges(); + } + + /** + * access details of a specific heap object. + */ + interface DebugDataInfo { + } + + /** + * access details of code generated for a specific outer + * or inlined method at a given line number. + */ + interface DebugLineInfo { + /** + * @return the name of the file containing the outer + * or inlined method excluding any path + */ + String fileName(); + /** + * @return a relative path to the file containing the outer + * or inlined method derived from its package name or null + * if the method is in the empty package + */ + Path filePath(); + /** + * @return the fully qualified name of the class owning the + * outer or inlined method + */ + String className(); + /** + * @return the name of the outer or inlined method including signature + */ + String methodName(); + /** + * @return the lowest address containing code generated for + * an outer or inlined code segment reported at this line + * represented as an offset into the code segment + */ + int addressLo(); + /** + * @return the first address above the code generated for + * an outer or inlined code segment reported at this line + * represented as an offset into the code segment + */ + int addressHi(); + /** + * @return the line number for the outer or inlined segment + */ + int line(); + } + + interface DebugFrameSizeChange { + enum Type { + EXTEND, + CONTRACT + } + + int getOffset(); + + DebugFrameSizeChange.Type getType(); + } + + Stream typeInfoProvider(); + + Stream codeInfoProvider(); + + Stream dataInfoProvider(); +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 473537169808..3c33a33367a3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -39,10 +39,14 @@ import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.SymbolTable; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.io.AssemblyBuffer; import com.oracle.objectfile.io.OutputAssembler; import com.oracle.objectfile.pecoff.PECoff.IMAGE_FILE_HEADER; import com.oracle.objectfile.pecoff.PECoff.IMAGE_SECTION_HEADER; +import com.oracle.objectfile.pecoff.cv.CVSections; +import com.oracle.objectfile.pecoff.cv.CVSymbolSectionImpl; +import com.oracle.objectfile.pecoff.cv.CVTypeSectionImpl; /** * Represents a PECoff object file. @@ -684,4 +688,42 @@ public PECoffRelocationTable getRelocationTable() { protected int getMinimumFileSize() { return 0; } + + @Override + public Section newDebugSection(String name, ElementImpl impl) { + PECoffSection coffSection = (PECoffSection) super.newDebugSection(name, impl); + coffSection.getFlags().add(PECoffSectionFlag.DISCARDABLE); + coffSection.getFlags().add(PECoffSectionFlag.READ); + coffSection.getFlags().add(PECoffSectionFlag.INITIALIZED_DATA); + impl.setElement(coffSection); + return coffSection; + } + + @Override + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + CVSections cvSections = new CVSections(getMachine()); + + // we need an implementation for each section + CVSymbolSectionImpl cvSymbolSectionImpl = cvSections.getCVSymbolSection(); + CVTypeSectionImpl cvTypeSectionImpl = cvSections.getCVTypeSection(); + + // now we can create the section elements with empty content + PECoffSection symbolSection = (PECoffSection) newDebugSection(cvSymbolSectionImpl.getSectionName(), cvSymbolSectionImpl); + PECoffSection typeSection = (PECoffSection) newDebugSection(cvTypeSectionImpl.getSectionName(), cvTypeSectionImpl); + + // the byte[] for each implementation's content are created and + // written under getOrDecideContent. doing that ensures that all + // dependent sections are filled in and then sized according to the + // declared dependencies. however, if we leave it at that then + // associated reloc sections only get created when the first reloc + // is inserted during content write that's too late for them to have + // layout constraints included in the layout decision set and causes + // an NPE during reloc section write. so we need to create the relevant + // reloc sections here in advance + cvSymbolSectionImpl.getOrCreateRelocationElement(false); + cvTypeSectionImpl.getOrCreateRelocationElement(false); + + // ok now we can populate the implementations + cvSections.installDebugInfo(debugInfoProvider); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java new file mode 100644 index 000000000000..efdc8913dd12 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +public interface CVConstants { + + /* names of relevant codeview sections */ + String CV_SYMBOL_SECTION_NAME = ".debug$S"; + String CV_TYPE_SECTION_NAME = ".debug$T"; + //String CV_RDATA_SECTION_NAME = ".rdata"; + //String CV_PDATA_SECTION_NAME = ".pdata"; + //String CV_XDATA_SECTION_NAME = ".xdata"; + //String TEXT_SECTION_NAME = ".text"; + //String DATA_SECTION_NAME = ".data"; + + /* Codeview section header signature */ + int CV_SIGNATURE_C13 = 4; + + /* Knobs */ + String JDK_SOURCE_BASE = ""; //"C:\\tmp\\graal-8\\jdk8_jvmci\\src\\"; + String GRAAL_SOURCE_BASE = ""; //"C:\\tmp\\graal-8\\graal8\\"; + + boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ + boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ + boolean mergeAdjacentLineRecords = false; /* if a line record is the same line in the same file as the previous record, meerge them */ + String replaceMainFunctionName = null; //"javamain"; /* first main() becomes this name (with no arg list at all) */ + + /* setting functionNamesHashArgs causes link errors as the illegal characters in arg lists confuse link.exe */ + boolean functionNamesHashArgs = true; /* if true, arg lists become obscure integers */ +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java new file mode 100644 index 000000000000..9c6856563853 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +public interface CVDebugConstants { + + //int DEBUG_S_IGNORE = 0x00; + int DEBUG_S_SYMBOLS = 0xf1; + int DEBUG_S_LINES = 0xf2; + int DEBUG_S_STRINGTABLE = 0xf3; + int DEBUG_S_FILECHKSMS = 0xf4; + + /* subcommands in DEBUG_S_SYMBOLS section */ + //short S_COMPILE = 0x0001; + short S_SSEARCH = 0x0005; + short S_END = 0x0006; + short S_OBJNAME = 0x1101; + short S_LDATA32_ST = 0x1007; + short S_FRAMEPROC = 0x1012; + short S_CONSTANT = 0x1107; + short S_UDT = 0x1108; + short S_LDATA32 = 0x110c; + short S_GDATA32 = 0x110d; + short S_GPROC32 = 0x1110; + short S_REGREL32 = 0x1111; + short S_COMPILE3 = 0x113c; + short S_ENVBLOCK = 0x113d; + short S_GPROC32_ID = 0x1147; + short S_PROC_ID_END = 0x114f; + //short S_BUILDINFO = 0x114c; + + /* enums are more typesafe but the IDE no longer knows which enum constant is unused + enum CV_RECORD { + CV_SIGNATURE_C13(4), + S_COMPILE(0x0001), + S_SSEARCH(0x0005), + S_END(0x0006), + S_OBJNAME(0x1101), + S_LDATA32_ST(0x1007), + S_FRAMEPROC(0x1012), + S_CONSTANT(0x1107), + S_UDT(0x1108), + S_LDATA32(0x110c), + S_GDATA32(0x110d), + S_GPROC32(0x1110), + S_REGREL32(0x1111), + S_COMPILE3(0x113c), + S_ENVBLOCK(0x113d); + + final int cmd; + + CV_RECORD(int cmd) { + this.cmd = cmd; + } + + public int command() { + return cmd; + } + } + + enum DEBUG_S { + DEBUG_S_IGNORE(0x00), + DEBUG_S_SYMBOLS(0xf1), + DEBUG_S_LINES(0xf2), + DEBUG_S_STRINGTABLE(0xf3), + DEBUG_S_FILECHKSMS(0xf4); + + final short cmd; + + DEBUG_S(int cmd) { + this.cmd = (short)cmd; + } + + public short command() { + return cmd; + } + } */ +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java new file mode 100644 index 000000000000..8ef5cefbfd36 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.FileEntry; +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.PrimaryEntry; +import com.oracle.objectfile.ObjectFile; + +import java.util.ArrayList; + +/* + * a line record (DEBUG_S_LINES) consists of a list of (file block record + subrecords) + * Graal will generate one CVLineRecord per function. + */ +final class CVLineRecord extends CVSymbolRecord { + + private static final boolean HAS_COLUMNS = false; + + private static final int DEFAULT_LINE_BLOCK_COUNT = 100; + private static final int DEFAULT_LINE_ENTRY_COUNT = 100; + + private static final short CB_HAS_COLUMNS_FLAG = 0x01; + private static final short CB_HAS_NO_COLUMNS_FLAG = 0x00; + + private String symbolName; + private PrimaryEntry primaryEntry; + private ArrayList fileBlocks = new ArrayList<>(DEFAULT_LINE_BLOCK_COUNT); + + /* + * FileBlock is a section of contiguous code in a compilation unit, associated with a single source file. + * if a function includes inlined code, that code needs its own FileBlock, surroneded by FileBlocks descibing the inclosing source file + * A fileBlock consists of a list of LineEntries + */ + private static class FileBlock { + + ArrayList lineEntries = new ArrayList<>(DEFAULT_LINE_ENTRY_COUNT); + int highAddr = 0; + FileEntry file; + + FileBlock(FileEntry file) { + this.file = file; + } + + void addEntry(LineEntry le) { + highAddr = Math.max(highAddr, le.addr); + lineEntries.add(le); + } + + int computeContents(byte[] buffer, int initialPos) { + int pos = initialPos; + pos = CVUtil.putInt(file.getFileId(), buffer, pos); + pos = CVUtil.putInt(lineEntries.size(), buffer, pos); + /* if HAS_COLUMNS is true, this formula is incorrect */ + assert !HAS_COLUMNS; + pos = CVUtil.putInt(Integer.BYTES * 3 + lineEntries.size() * LineEntry.LINE_ENTRY_SIZE, buffer, pos); + for (LineEntry lineEntry : lineEntries) { + pos = lineEntry.computeContents(buffer, pos); + } + return pos; + } + + int computeSize(int initialPos) { + /* if HAS_COLUMNS is true, this formula is incorrect */ + assert !HAS_COLUMNS; + return initialPos + Integer.BYTES * 3 + LineEntry.LINE_ENTRY_SIZE * lineEntries.size(); + } + + int getHighAddr() { + return highAddr; + } + } + + /* + * LineEntry associates some object code (at 'addr', relative to the start of this DEBUG_S_LINES record) + * with a source line in the current FileBlock file + */ + static class LineEntry { + + static final int LINE_ENTRY_SIZE = 2 * Integer.BYTES; + + int addr; + int lineAndFLags; +/* + LineEntry(int addr, int line, int deltaEnd, boolean isStatement) { + this.addr = addr; + assert line <= 0xffffff; + assert line >= 0; + assert deltaEnd <= 0x7f; + assert deltaEnd >= 0; + lineAndFLags = line | (deltaEnd << 24) | (isStatement ? 0x80000000 : 0); + } +*/ + LineEntry(int addr, int line) { + this.addr = addr; + this.lineAndFLags = line; + } + + int computeContents(byte[] buffer, int initialPos) { + int pos = initialPos; + pos = CVUtil.putInt(addr, buffer, pos); + pos = CVUtil.putInt(lineAndFLags, buffer, pos); + return pos; + } + } + + CVLineRecord(CVSections cvSections, String symbolName, PrimaryEntry primaryEntry) { + super(cvSections, DEBUG_S_LINES); + this.primaryEntry = primaryEntry; + this.symbolName = symbolName; + } + + void addNewFile(FileEntry file) { + fileBlocks.add(new FileBlock(file)); + } + + void addNewLine(int addr, int line) { + fileBlocks.get(fileBlocks.size() - 1).addEntry(new LineEntry(addr, line)); + } + + @Override + protected int computeSize(int startPos) { + /* header */ + int pos = startPos + Integer.BYTES + Short.BYTES * 2 + Integer.BYTES; + /* all blocks */ + for (FileBlock fileBlock : fileBlocks) { + pos = fileBlock.computeSize(pos); + } + return pos; + } + + @Override + protected int computeContents(byte[] buffer, int initialPos) { + int pos = initialPos; + + assert symbolName != null; + /* can't handle columns yet */ + assert !HAS_COLUMNS; + + if (buffer != null) { + cvSections.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, symbolName, false, 1L); + } + pos = CVUtil.putInt(0, buffer, pos); + if (buffer != null) { + cvSections.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, symbolName, false, 1L); + } + pos = CVUtil.putShort((short) 0, buffer, pos); + final short flags = HAS_COLUMNS ? CB_HAS_COLUMNS_FLAG : CB_HAS_NO_COLUMNS_FLAG; + pos = CVUtil.putShort(flags, buffer, pos); /* flags */ + final int cbConPos = pos; /* save position of length int32 */ + pos = CVUtil.putInt(0, buffer, pos); /* highAddr = length of this chunk in object file (fill in correctly later) */ + int highAddr = 0; + for (FileBlock fileBlock : fileBlocks) { + highAddr = Math.max(highAddr, fileBlock.getHighAddr()); + pos = fileBlock.computeContents(buffer, pos); + } + CVUtil.putInt(highAddr, buffer, cbConPos); + return pos; + } + + @Override + public String toString() { + return String.format("CVLineRecord(type=0x%04x pos=0x%05x size=0x%d)", type, pos, fileBlocks.size()); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java new file mode 100644 index 000000000000..b0bc8cf4e7fe --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.FileEntry; +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.PrimaryEntry; +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.Range; + +import static com.oracle.objectfile.pecoff.cv.CVConstants.skipGraalInternals; +import static com.oracle.objectfile.pecoff.cv.CVConstants.skipGraalIntrinsics; +import static com.oracle.objectfile.pecoff.cv.CVRootPackages.isJavaPackage; + +public class CVLineRecordBuilder { + + private static final boolean debug = true; + private static final boolean HAS_COLUMNS = false; + + private CVSections cvSections; + private CVLineRecord lineRecord; + private Range previousRange = null; + private PrimaryEntry primaryEntry; + + CVLineRecordBuilder(CVSections cvSections) { + this.cvSections = cvSections; + } + + /* + * In CV4, the line table consists of a series of file headers followed by line number entries + * to handle this, first we decide if we want to merge this with the previous range (only if same file and start of this range is end of previous range) + * if we are emitting a new range to the same file, write the range, save it as the previous range and go on + * If this is a different file, then update the length of the previous file header, write the new file header and write the new range + * At the very end, make sure we update the last file header + * + * In addition, optionally ignore Ranges that point into Graal innards, just adding them to the current enclosing ramge + */ + + /** + * Feed Range structures to processRange. + * @param primaryEntry input containing sub ranges + * @return CVLineRecord containing any entries generated, or null if o entries + */ + CVLineRecord build(String methodName, PrimaryEntry primaryEntry) { + long lowAddr = Long.MAX_VALUE; + long highAddr = 0; + this.primaryEntry = primaryEntry; + previousRange = null; + + assert (!HAS_COLUMNS); /* can't handle columns yet */ + + Range primaryRange = primaryEntry.getPrimary(); + if (skipGraalInternals && isGraalIntrinsic(primaryRange.getClassName())) { + CVUtil.debug(" skipping Graal internal class %s\n", primaryRange); + return null; + } + CVUtil.debug(" DEBUG_S_LINES linerecord for 0x%05x file: %s:%d\n", primaryRange.getLo(), primaryEntry.getFileEntry().getFileName(), primaryRange.getLine()); + this.lineRecord = new CVLineRecord(cvSections, methodName, primaryEntry); + CVUtil.debug(" CVLineRecord.computeContents: processing primary range %s\n", primaryRange); + processRange(primaryRange); + lowAddr = Math.min(lowAddr, primaryRange.getLo()); + highAddr = Math.max(highAddr, primaryRange.getHi()); + + for (Range subRange : primaryEntry.getSubranges()) { + CVUtil.debug(" CVLineRecord.computeContents: processing range %s\n", subRange); + processRange(subRange); + lowAddr = Math.min(lowAddr, subRange.getLo()); + highAddr = Math.max(highAddr, subRange.getHi()); + } + return lineRecord; + } + + /** + * Merge input Range structures into line number table. + * The Range structures are assumed to be ordered by ascending address + * merge with previous line entry if: + * - if a Range has a negative linenumber + * - if a range is part of Graal or the JDK, and skipGraalOption is true + * - if a range has the same line number, source file and function + * @param range to be merged or added to line number record + */ + private void processRange(Range range) { + + /* should we merge this range with the previous entry? */ + if (shouldMerge(previousRange, range)) { + Range newRange = new Range(previousRange); + newRange.setLo(range.getLo()); + newRange.setHi(range.getHi()); + range = newRange; + } else if (range.getLine() == -1) { + return; + } + + boolean wantNewFile = previousRange == null || !previousRange.sameFileName(range); + if (wantNewFile) { + FileEntry file = cvSections.ensureFileEntry(range); + previousRange = null; + CVUtil.debug(" adding linerecord for file: %s\n", file.getFileName()); + lineRecord.addNewFile(file); + } + + if (wantNewRange(previousRange, range)) { + previousRange = range; + int lineLo = range.getLo() - primaryEntry.getPrimary().getLo(); + CVUtil.debug(" line: 0x%05x %s\n", lineLo, range.getLine()); + lineRecord.addNewLine(lineLo, range.getLine()); + } + } + + private boolean isGraalIntrinsic(String className) { + return className.startsWith("com.oracle.svm") || className.startsWith("org.graalvm") || isJavaPackage(className); + } + + private boolean shouldMerge(Range previousRange, Range range) { + if (previousRange == null) { + return false; + } + if (skipGraalIntrinsics && isGraalIntrinsic(range.getClassName())) { + return true; + } + return previousRange.sameFileName(range) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); + } + + private boolean wantNewRange(Range previous, Range range) { + return true; + /*if (debug) { + if (previous == null) { + CVUtil.debug("wantNewRange() prevnull:true"); + } else { + CVUtil.debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previous.getLine() != range.getLine()) + + " fndiffer:" + (!previous.sameFileName(range)) + " contig:" + (previous.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); + } + }*/ + /* + if (previous == null) + return true; + if (previous.getLine() != range.getLine()) + return true; + if (!previous.sameFileName(range)) + return true; + if (previous.getHi() < range.getLo()) + return true; + long delta = range.getHi() - previousRange.getLo(); + return delta >= 127; + */ + } + + + @Override + public String toString() { + return "CVLineRecordBuilder()"; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java new file mode 100644 index 000000000000..27da4409d1e6 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import java.util.Collections; +import java.util.HashSet; + +abstract class CVRootPackages { + private static String[] rootPackageNames = { + /* substrate root packages */ + "com.oracle.graal.pointsto", + "com.oracle.objectfile", + "com.oracle.svm.agent", + "com.oracle.svm.configure", + "com.oracle.svm.core", + "com.oracle.svm.core.genscavenge", + "com.oracle.svm.core.graal", + "com.oracle.svm.core.graal.aarch64", + "com.oracle.svm.core.graal.amd64", + "com.oracle.svm.core.graal.llvm", + "com.oracle.svm.core.jdk11", + "com.oracle.svm.core.jdk8", + "com.oracle.svm.core.posix", + "com.oracle.svm.core.posix.jdk11", + "com.oracle.svm.core.windows", + "com.oracle.svm.driver", + "com.oracle.svm.graal", + "com.oracle.svm.graal.hotspot.libgraal", + "com.oracle.svm.hosted", + "com.oracle.svm.jline", + "com.oracle.svm.jni", + "com.oracle.svm.junit", + "com.oracle.svm.libffi", + "com.oracle.svm.native.jvm.posix", + "com.oracle.svm.native.jvm.windows", + "com.oracle.svm.native.libchelper", + "com.oracle.svm.native.strictmath", + "com.oracle.svm.polyglot", + "com.oracle.svm.reflect", + "com.oracle.svm.test", + "com.oracle.svm.test.jdk11", + "com.oracle.svm.thirdparty", + "com.oracle.svm.truffle", + "com.oracle.svm.truffle.nfi", + "com.oracle.svm.truffle.nfi.posix", + "com.oracle.svm.truffle.nfi.windows", + "com.oracle.svm.tutorial", + "com.oracle.svm.util", + "com.oracle.svm.util.jdk11", + "org.graalvm.polyglot.nativeapi", + /* compiler root packages */ + "jdk.tools.jaotc", + "jdk.tools.jaotc.binformat", + "jdk.tools.jaotc", + "org.graalvm.compiler.api.directives", + "org.graalvm.compiler.api.replacements", + "org.graalvm.compiler.api.runtime", + "org.graalvm.compiler.asm", + "org.graalvm.compiler.asm.aarch64", + "org.graalvm.compiler.asm.amd64", + "org.graalvm.compiler.asm.sparc", + "org.graalvm.compiler.bytecode", + "org.graalvm.compiler.code", + "org.graalvm.compiler.core", + "org.graalvm.compiler.core.aarch64", + "org.graalvm.compiler.core.amd64", + "org.graalvm.compiler.core.common", + "org.graalvm.compiler.core.llvm", + "org.graalvm.compiler.core.match.processor", + "org.graalvm.compiler.core.sparc", + "org.graalvm.compiler.debug", + "org.graalvm.compiler.graph", + "org.graalvm.compiler.hotspot", + "org.graalvm.compiler.hotspot.aarch64", + "org.graalvm.compiler.hotspot.amd64", + "org.graalvm.compiler.hotspot.jdk8", + "org.graalvm.compiler.hotspot.management", + "org.graalvm.compiler.hotspot.sparc", + "org.graalvm.compiler.java", + "org.graalvm.compiler.jtt", + "org.graalvm.compiler.lir", + "org.graalvm.compiler.lir.aarch64", + "org.graalvm.compiler.lir.amd64", + "org.graalvm.compiler.lir.jtt", + "org.graalvm.compiler.lir.sparc", + "org.graalvm.compiler.loop", + "org.graalvm.compiler.loop.phases", + "org.graalvm.compiler.microbenchmarks", + "org.graalvm.compiler.nodeinfo", + "org.graalvm.compiler.nodeinfo.processor", + "org.graalvm.compiler.nodes", + "org.graalvm.compiler.options", + "org.graalvm.compiler.options.processor", + "org.graalvm.compiler.phases", + "org.graalvm.compiler.phases.common", + "org.graalvm.compiler.printer", + "org.graalvm.compiler.processor", + "org.graalvm.compiler.replacements", + "org.graalvm.compiler.replacements.aarch64", + "org.graalvm.compiler.replacements.amd64", + "org.graalvm.compiler.replacements.processor", + "org.graalvm.compiler.replacements.sparc", + "org.graalvm.compiler.runtime", + "org.graalvm.compiler.serviceprovider", + "org.graalvm.compiler.serviceprovider.jdk8", + "org.graalvm.compiler.serviceprovider.processor", + "org.graalvm.compiler.truffle.common", + "org.graalvm.compiler.truffle.common.hotspot", + "org.graalvm.compiler.truffle.common.hotspot.libgraal", + "org.graalvm.compiler.truffle.common.processor", + "org.graalvm.compiler.truffle.compiler", + "org.graalvm.compiler.truffle.compiler.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot", + "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", + "org.graalvm.compiler.truffle.compiler.hotspot.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", + "org.graalvm.compiler.truffle.compiler.hotspot.sparc", + "org.graalvm.compiler.truffle.runtime", + "org.graalvm.compiler.truffle.runtime.hotspot", + "org.graalvm.compiler.truffle.runtime.hotspot.java", + "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", + "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", + "org.graalvm.compiler.truffle.runtime.serviceprovider", + "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", + "org.graalvm.compiler.virtual", + "org.graalvm.compiler.virtual.bench", + "org.graalvm.compiler.word", + "org.graalvm.graphio", + "org.graalvm.libgraal", + "org.graalvm.libgraal.jdk8", + "org.graalvm.micro.benchmarks", + "org.graalvm.util", + }; + + private static final HashSet rootPackageSet; + + static { + rootPackageSet = new HashSet<>(rootPackageNames.length); + Collections.addAll(rootPackageSet, rootPackageNames); + } + + static boolean isRootPackage(String pn) { + return rootPackageSet.contains(pn); + } + + static boolean isJavaPackage(String pn) { + return pn.startsWith("java.") || pn.startsWith("javax.") || pn.startsWith("sun."); + } + + static boolean isJavaFile(String pn) { + return pn.startsWith("java/") || pn.startsWith("javax/") || pn.startsWith("sun/"); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java new file mode 100644 index 000000000000..c628558fe559 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.pecoff.PECoffMachine; +import com.oracle.objectfile.pecoff.PECoffObjectFile; + +import java.util.Map; +import java.util.Set; + +/** + * CVSections is a container class for all the CodeView sections to be emitted in the object file. + * Currently, that will be .debug$S (CVSymbolSectionImpl) (and .debug$T (CVTypeSectionImpl) when implemented) + * Common data (useful to more than one CodeView section) goes here, mostly that gathered by calls to installDebugInfo->addRange() and installDebugInfo->addSubRange() + */ +public final class CVSections extends DebugInfoBase { + + private PECoffMachine machine; + private CVSymbolSectionImpl cvSymbolSection; + private CVTypeSectionImpl cvTypeSection; + + public CVSections(PECoffMachine machine) { + this.machine = machine; + cvSymbolSection = new CVSymbolSectionImpl(this); + cvTypeSection = new CVTypeSectionImpl(); + } + + public CVSymbolSectionImpl getCVSymbolSection() { + return cvSymbolSection; + } + + public CVTypeSectionImpl getCVTypeSection() { + return cvTypeSection; + } + + abstract static class CVSectionImplBase extends BasicProgbitsSectionImpl { + + int debugLevel = 1; + long debugTextBase = 0; + long debugAddress = 0; + int debugBase = 0; + + CVSectionImplBase() { + checkDebug(0); + } + + @Override + public void setElement(ObjectFile.Element e) { + super.setElement(e); + /* define the section as a COFF symbol */ + getOwner().createDefinedSymbol(getSectionName(), getElement(), 0, 0, false, false); + } + + void checkDebug(int pos) { + /* if the env var relevant to this element type is set then switch on debugging */ + String envVarName = "DEBUG_" + getSectionName().substring(1).toUpperCase(); + if (System.getenv(envVarName) != null) { + debugLevel = 1; + debugBase = pos; + debugAddress = debugTextBase; + } + } + + @Override + public int getAlignment() { + return 1; + } + + public void debug(String format, Object ... args) { + if (debugLevel > 1) { + CVUtil.debug(format + "\n", args); + } + } + + public void info(String format, Object ... args) { + if (debugLevel > 0) { + CVUtil.debug(format + "\n", args); + } + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + /* ensure content byte[] has been created before calling super method */ + createContent(); + + /* ensure content byte[] has been written before calling super method */ + writeContent(); + + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public Set getDependencies(Map decisions) { + Set deps = super.getDependencies(decisions); + String targetName = getSectionName(); + PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + //LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + /* make our content depend on the size and content of the target */ + //for (LayoutDecision.Kind targetKind : targetKinds) { + // LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + // deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + //} + /* make our size depend on our content */ + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + + return deps; + } + //public abstract LayoutDecision.Kind[] targetSectionKinds(); + public abstract void createContent(); + public abstract void writeContent(); + public abstract String getSectionName(); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java new file mode 100644 index 000000000000..1b4e5353e7bd --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.FileEntry; + +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.NoSuchFileException; +import java.security.MessageDigest; + +import static com.oracle.objectfile.pecoff.cv.CVConstants.GRAAL_SOURCE_BASE; +import static com.oracle.objectfile.pecoff.cv.CVConstants.JDK_SOURCE_BASE; + +/* + * A Symbol record is a top-level record in the CodeView .debug$S section + */ +abstract class CVSymbolRecord implements CVDebugConstants { + + CVSections cvSections; + protected int pos; + protected final int type; + + CVSymbolRecord(CVSections cvSections, int type) { + this.cvSections = cvSections; + this.type = type; + } + + int computeFullSize(int pos) { + this.pos = pos; + pos += Integer.BYTES * 2; + return computeSize(pos); + } + + int computeFullContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(type, buffer, pos); + int lenPos = pos; + pos = computeContents(buffer, pos + Integer.BYTES); + /* length does not include debug record header (4 bytes record id + 4 bytes length) */ + CVUtil.putInt(pos - lenPos - Integer.BYTES, buffer, lenPos); + return pos; + } + + protected abstract int computeSize(int pos); + protected abstract int computeContents(byte[] buffer, int pos); + + @Override + public String toString() { + return "CVSymbolRecord(type=" + type + ",pos=" + pos + ")"; + } + + public void dump(PrintStream out) { + out.format("%s\n", this); + } + + static final class CVStringTableRecord extends CVSymbolRecord { + + private final CVSymbolSectionImpl.CVStringTable stringTable; + + CVStringTableRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable stringTable) { + super(cvSections, DEBUG_S_STRINGTABLE); + this.stringTable = stringTable; + } + + int add(String string) { + return stringTable.add(string); + } + + @Override + public int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + public int computeContents(byte[] buffer, int pos) { + for (CVSymbolSectionImpl.CVStringTable.StringTableEntry entry : stringTable.values()) { + pos = CVUtil.putUTF8StringBytes(entry.text, buffer, pos); + } + return pos; + } + + @Override + public String toString() { + return String.format("CVStringTableRecord(type=0x%04x pos=0x%06x size=%d)", type, pos, stringTable.size()); + } + + @Override + public void dump(PrintStream out) { + int idx = 0; + out.format("%s:\n", this); + for (CVSymbolSectionImpl.CVStringTable.StringTableEntry entry : stringTable.values()) { + out.format("%4d 0x%08x %s\n", idx, entry.offset, entry.text); + idx += 1; + } + } + } + + static final class CVFileRecord extends CVSymbolRecord { + + static final boolean debug = false; + + static final byte CHECKSUM_NONE = 0x00; + static final byte CHECKSUM_MD5 = 0x01; + static final byte CB_VALUE = 0x10; + + static final int FILE_RECORD_LENGTH = 24; + + static final int CHECKSUM_LENGTH = 16; + static final byte[] EMPTY_CHECKSUM = new byte[CHECKSUM_LENGTH]; + + final CVSections cvSections; + final CVSymbolSectionImpl.CVStringTable strings; + + CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { + super(cvSections, DEBUG_S_FILECHKSMS); + this.cvSections = cvSections; + this.strings = strings; + } + + private String fixPath(String fn) { + String substrateDir = GRAAL_SOURCE_BASE + "substratevm\\src\\"; + String compilerDir = GRAAL_SOURCE_BASE + "compiler\\src\\"; + String newFn; + if (fn.startsWith("com/oracle/svm/core/snippets")) { + newFn = substrateDir + "com.oracle.svm.core.snippets\\src\\" + fn.replace("/", "\\"); + } else if (fn.startsWith("org/graalvm/compiler/replacements")) { + newFn = compilerDir + "org.graalvm.compiler.replacements\\src\\" + fn.replace("/", "\\"); + } else if (fn.startsWith("com/oracle/svm/core/genscavenge")) { + newFn = substrateDir + "com.oracle.svm.core.genscavenge\\src\\" + fn.replace("/", "\\"); + } else if (fn.startsWith("com/oracle/svm/core")) { + newFn = substrateDir + "com.oracle.svm.core\\src\\" + fn.replace("/", "\\"); + } else if (CVRootPackages.isJavaFile(fn)) { + newFn = JDK_SOURCE_BASE + fn.replace("/", "\\"); + } else { + newFn = fn; + } + return newFn; + } + + @Override + public int computeSize(int initialPos) { + if (cvSections.getFiles().isEmpty()) { + return initialPos; + } + /* first, insert fileIds into file table for use by line number table */ + int fileId = 0; + for (FileEntry entry : cvSections.getFiles()) { + entry.setFileId(fileId); + strings.add(fixPath(entry.getFileName())); // create required stringtable entries + fileId += FILE_RECORD_LENGTH; + } + return initialPos + (cvSections.getFiles().size() * FILE_RECORD_LENGTH); + } + + private int put(FileEntry entry, byte[] buffer, int initialPos) { + String fn = fixPath(entry.getFileName()); + int stringId = strings.add(fn); + int pos = CVUtil.putInt(stringId, buffer, initialPos); /* stringtable index */ + pos = CVUtil.putByte(CB_VALUE, buffer, pos); /* Cb (unknown what this is) */ + byte[] checksum = calculateMD5Sum(fn); + if (checksum != null) { + pos = CVUtil.putByte(CHECKSUM_MD5, buffer, pos); /* checksum type (0x01 == MD5) */ + pos = CVUtil.putBytes(checksum, buffer, pos); + } else { + pos = CVUtil.putByte(CHECKSUM_NONE, buffer, pos); + pos = CVUtil.putBytes(EMPTY_CHECKSUM, buffer, pos); + } + pos = CVUtil.align4(pos); + return pos; + } + + private byte[] calculateMD5Sum(String fn) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(Files.readAllBytes(Paths.get(fn))); + return md.digest(); + } catch (NoSuchFileException e) { + return null; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Override + public int computeContents(byte[] buffer, int pos) { + CVUtil.debug("XXXX file computeContents(%d) nf=%d\n", pos, cvSections.getFiles().size()); + for (FileEntry entry : cvSections.getFiles()) { + pos = put(entry, buffer, pos); + } + return pos; + } + + @Override + public String toString() { + return "CVFileRecord(type=" + type + ",pos=" + pos + ", size=" + 999 + ")"; + } + + @Override + public void dump(PrintStream out) { + int idx = 0; + int offset = 0; + out.format("%s:\n", this); + for (FileEntry entry : cvSections.getFiles()) { + out.format("%4d 0x%08x %2d %2d %s\n", idx, offset, 0x10, 1, entry.getFileName()); + idx += 1; + offset += 24; + } + } + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java new file mode 100644 index 000000000000..fe6b84087e61 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.ClassEntry; +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.PrimaryEntry; +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.Range; + +import static com.oracle.objectfile.pecoff.cv.CVConstants.functionNamesHashArgs; +import static com.oracle.objectfile.pecoff.cv.CVConstants.replaceMainFunctionName; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.T_NOTYPE; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.T_VOID; + +final class CVSymbolRecordBuilder { + + private final CVSections cvSections; + private final CVTypeSectionImpl typeSection; + private final CVSymbolSubsection symbolRecord; + + CVSymbolRecordBuilder(CVSections cvSections) { + this.symbolRecord = new CVSymbolSubsection(cvSections); + this.cvSections = cvSections; + this.typeSection = cvSections.getCVTypeSection(); + } + + private boolean noMainFound = true; + + private String fixMethodName(Range range) { + final String methodName; + if (replaceMainFunctionName != null && noMainFound && range.getMethodName().equals("main")) { + noMainFound = false; + methodName = replaceMainFunctionName; + } else if (functionNamesHashArgs) { + long hash = ((long) range.getParamNames().hashCode()) & 0xffffffffL; + methodName = range.getClassAndMethodName() + "." + hash; + } else { + methodName = range.getClassAndMethodNameWithParams(); + } + CVUtil.debug("replacing %s with %s\n", range.getClassAndMethodNameWithParams(), methodName); + return methodName; + } + + void build() { + /* A module has a set of (function def, block def, linenumbers) for each function */ + String previousMethodName = ""; + for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { + for (PrimaryEntry primary : classEntry.getPrimaryEntries()) { + Range range = primary.getPrimary(); + // for each function + String newMethodName = fixMethodName(range); + if (!newMethodName.equals(previousMethodName)) { + previousMethodName = newMethodName; + processFunction(newMethodName, range); + addLineNumberRecords(newMethodName, primary); + } + } + } + cvSections.getCVSymbolSection().addRecord(symbolRecord); + } + + private void processFunction(String methodName, Range range) { + + CVUtil.debug("XXXX addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); + int functionTypeIndex = addTypeRecords(); + byte funcFlags = 0; + CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvSections, methodName, 0, 0, 0, range.getHi() - range.getLo(), 0, 0, functionTypeIndex, range.getLo(), (short) 0, funcFlags); + addToSymbolRecord(proc32); + int frameFlags = 0; /* LLVM uses 0x14000; */ + addToSymbolRecord(new CVSymbolSubrecord.CVSymbolFrameProcRecord(cvSections, range.getHi() - range.getLo(), frameFlags)); + /* TODO: add local variavles, and their types */ + addToSymbolRecord(new CVSymbolSubrecord.CVSymbolEndRecord(cvSections)); + } + + private void addLineNumberRecords(String methodName, PrimaryEntry primary) { + CVLineRecord record = new CVLineRecordBuilder(cvSections).build(methodName, primary); + /* + * if the builder decides this entry is uninteresting, we don't build a record. + * for example, Graal intrinsics may be uninteresting. + */ + if (record != null) { + cvSections.getCVSymbolSection().addRecord(record); + } + } + + private void addToSymbolRecord(CVSymbolSubrecord record) { + CVUtil.debug("adding symbol subrecord: %s\n", record); + symbolRecord.addRecord(record); + } + + private int addTypeRecords() { + /* add type records for function (later add arglist, and arrlist and local types) */ + CVTypeRecord.CVTypeArglistRecord argListType = addTypeRecord(new CVTypeRecord.CVTypeArglistRecord().add(T_NOTYPE)); + CVTypeRecord funcType = addTypeRecord(new CVTypeRecord.CVTypeProcedureRecord().returnType(T_VOID).argList(argListType)); + return funcType.getSequenceNumber(); + } + + private T addTypeRecord(T record) { + return cvSections.getCVTypeSection().addRecord(record); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java new file mode 100644 index 000000000000..dbde248830dc --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.pecoff.cv.CVSections.CVSectionImplBase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SIGNATURE_C13; +import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SYMBOL_SECTION_NAME; + +public final class CVSymbolSectionImpl extends CVSectionImplBase { + + private static final int CV_VECTOR_DEFAULT_SIZE = 200; + private static final int CV_STRINGTABLE_DEFAULT_SIZE = 200; + + private CVSections cvSections; + private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); + private CVStringTable stringTable = new CVStringTable(CV_STRINGTABLE_DEFAULT_SIZE); + + CVSymbolSectionImpl(CVSections cvSections) { + this.cvSections = cvSections; + } + + @Override + public String getSectionName() { + return CV_SYMBOL_SECTION_NAME; + } + + /* + * the CodeView symbol section ("debug$S") is actually a list of records containing sub-records + */ + @Override + public void createContent() { + info("CVSymbolSectionImpl.createContent() adding records"); + addRecords(); + info("CVSymbolSectionImpl.createContent() start"); + int pos = 0; + /* add header size */ + pos += Integer.BYTES; + /* add sum of all record sizes */ + for (CVSymbolRecord record : cvRecords) { + pos = CVUtil.align4(pos); + pos = record.computeFullSize(pos); + } + /* create a buffer that holds it all */ + byte[] buffer = new byte[pos]; + super.setContent(buffer); + info("CVSymbolSectionImpl.createContent() end"); + } + + @Override + public void writeContent() { + info("CVSymbolSectionImpl.writeContent() start"); + byte[] buffer = getContent(); + int pos = 0; + /* write section header */ + pos = CVUtil.putInt(CV_SIGNATURE_C13, buffer, pos); + /* write all records */ + for (CVSymbolRecord record : cvRecords) { + pos = CVUtil.align4(pos); + pos = record.computeFullContents(buffer, pos); + } + info("CVSymbolSectionImpl.writeContent() end"); + } + + private void addRecords() { + addPrologueRecords(); + addFunctionRecords(); + addTypeRecords(); + addFileRecords(); + addStringTableRecord(); + } + + private void addPrologueRecords() { + CVSymbolRecord prologue = new CVSymbolSubsection(cvSections) { + @Override + void addSubrecords() { + CVSymbolSubrecord.CVObjectNameRecord objectNameRecord = new CVSymbolSubrecord.CVObjectNameRecord(cvSections); + if (objectNameRecord.isValid()) { + addRecord(objectNameRecord); + } + addRecord(new CVSymbolSubrecord.CVCompile3Record(cvSections)); + addRecord(new CVSymbolSubrecord.CVEnvBlockRecord(cvSections)); + } + }; + addRecord(prologue); + } + + private void addFunctionRecords() { + new CVSymbolRecordBuilder(cvSections).build(); + } + + private void addTypeRecords() { + /* not yet implemented. S_UDT, etc */ + //CVSymbolRecord externs = new CVSymbolSubsection.CVExternalSymbolRecord(cvSections); + //addRecord(externs); + } + + private void addFileRecords() { + CVSymbolRecord fileChecksums = new CVSymbolRecord.CVFileRecord(cvSections, stringTable); + addRecord(fileChecksums); + } + + private void addStringTableRecord() { + CVSymbolRecord stringTableRecord = new CVSymbolRecord.CVStringTableRecord(cvSections, stringTable); + addRecord(stringTableRecord); + } + + static final class CVStringTable { + static final class StringTableEntry { + public int offset; + public String text; + StringTableEntry(int offset, String text) { + this.offset = offset; + this.text = text; + } + } + + /* using LinkedHashMap so order is maintained when writing string table */ + private final HashMap strings; + private int currentOffset = 0; + + CVStringTable(int startSize) { + strings = new LinkedHashMap<>(startSize); + /* ensure that the empty string has index 0 */ + add(""); + } + + int add(String s) { + StringTableEntry newEntry = new StringTableEntry(currentOffset, s); + StringTableEntry entry = strings.putIfAbsent(s, newEntry); + if (entry == null) { + int utf8Length = s.getBytes(UTF_8).length; /* TODO: getting the enecoded size should be made more efficient */ + currentOffset += utf8Length + 1; + } + return entry == null ? newEntry.offset : entry.offset; + } + + Collection values() { + return strings.values(); + } + + int size() { + return strings.size(); + } + } + + void addRecord(CVSymbolRecord record) { + cvRecords.add(record); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java new file mode 100644 index 000000000000..f0d3476e323c --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.pecoff.cv.DebugInfoBase.ClassEntry; + +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.SectionName; + +import java.util.HashMap; +import java.util.Map; + +import static java.nio.charset.StandardCharsets.UTF_8; + +/* + * a CVSymbolSubrecord is a record in a DEBUG_S_SYMBOL record within a debug$S section + */ +abstract class CVSymbolSubrecord { + + private int initialPos; + private final short cmd; + CVSections cvSections; + + CVSymbolSubrecord(CVSections cvSections, short cmd) { + this.cvSections = cvSections; + this.cmd = cmd; + } + + int computeFullSize(int initialPos) { + this.initialPos = initialPos; + int prologueLength = Short.BYTES * 2; /* room for length and subcommand */ + return computeSize(initialPos + prologueLength); + } + + int computeFullContents(byte[] buffer, int initialPos) { + int pos = initialPos; + pos += Short.BYTES; /* save room for length (no including length bytes) */ + pos = CVUtil.putShort(cmd, buffer, pos); + pos = computeContents(buffer, pos); + short length = (short) (pos - initialPos - Short.BYTES); + CVUtil.putShort(length, buffer, initialPos); + return pos; + } + + @Override + public String toString() { + return String.format("CVSymbolSubrecord(cmd=0x%04x pos=0x%06x)", cmd, initialPos); + } + + protected abstract int computeSize(int pos); + protected abstract int computeContents(byte[] buffer, int pos); + + public static final class CVObjectNameRecord extends CVSymbolSubrecord { + + String objName; /* TODO: how to find this? full path to object file we will produce */ + + CVObjectNameRecord(CVSections cvSections, String objName) { + super(cvSections, CVDebugConstants.S_OBJNAME); + this.objName = objName; + } + + CVObjectNameRecord(CVSections cvSections) { + this(cvSections, findObjectName(cvSections)); + } + + private static String findObjectName(CVSections cvSections) { + /* Get file from first class object */ + String fn = null; + for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { + if (classEntry.getFileName() != null) { + fn = classEntry.getFileEntry().getFileName(); + if (fn.endsWith(".java")) { + fn = fn.substring(0, fn.lastIndexOf(".java")) + ".obj"; + } + break; + } + } + return fn; + } + + boolean isValid() { + return objName != null; + } + + @Override + protected int computeSize(int pos) { + pos += Integer.BYTES; /* signature = 0; */ + pos += objName.getBytes(UTF_8).length + 1; /* inline null terminated */ + return pos; + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(0, buffer, pos); /* signature = 0 */ + pos = CVUtil.putUTF8StringBytes(objName, buffer, pos); /* inline null terminated */ + return pos; + } + } + + public static final class CVCompile3Record extends CVSymbolSubrecord { + + private static final byte HAS_DEBUG_FLAG = 0; + //private static final byte HAS_NO_DEBUG_FLAG = (byte)0x80; + + private byte language; + private byte cf1; + private byte cf2; + private byte padding; + private short machine; + private short feMajor; + private short feMinor; + private short feBuild; + private short feQFE; + private short beMajor; + private short beMinor; + private short beBuild; + private short beQFE; + private String compiler; + + CVCompile3Record(CVSections cvSections) { + super(cvSections, CVDebugConstants.S_COMPILE3); + language = 0; + cf1 = HAS_DEBUG_FLAG; + cf2 = (byte) 0; + padding = (byte) 0; + machine = (short) 208; + feMajor = (short) 2; + feMinor = (short) 3; + feBuild = (short) 4; + feQFE = (short) 5; + beMajor = (short) 6; + beMinor = (short) 7; + beBuild = (short) 8; + beQFE = (short) 9; + compiler = "graal"; + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putByte(language, buffer, pos); + pos = CVUtil.putByte(cf1, buffer, pos); + pos = CVUtil.putByte(cf2, buffer, pos); + pos = CVUtil.putByte(padding, buffer, pos); + pos = CVUtil.putShort(machine, buffer, pos); + pos = CVUtil.putShort(feMajor, buffer, pos); + pos = CVUtil.putShort(feMinor, buffer, pos); + pos = CVUtil.putShort(feBuild, buffer, pos); + pos = CVUtil.putShort(feQFE, buffer, pos); + pos = CVUtil.putShort(beMajor, buffer, pos); + pos = CVUtil.putShort(beMinor, buffer, pos); + pos = CVUtil.putShort(beBuild, buffer, pos); + pos = CVUtil.putShort(beQFE, buffer, pos); + pos = CVUtil.putUTF8StringBytes(compiler, buffer, pos); // inline null terminated + return pos; + } + } + + public static final class CVEnvBlockRecord extends CVSymbolSubrecord { + + private static final int ENVMAP_INITIAL_CAPACITY = 10; + + private Map map = new HashMap<>(ENVMAP_INITIAL_CAPACITY); + + /* + * Example: + * cwd = C:\tmp\graal-8 + * cl = C:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\Bin\x86_amd64\cl.exe + * cmd = -Zi -MT -IC:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\INCLUDE -IC:\tmp\graal-8\ojdkbuild\tools\toolchain\sdk71\INCLUDE -IC:\tmp\graal-8\ojdkbuild\tools\toolchain\sdk71\INCLUDE\gl -TC -X + * src = helloworld.c + * pdb = C:\tmp\graal-8\vc100.pdb + */ + + CVEnvBlockRecord(CVSections cvSections) { + super(cvSections, CVDebugConstants.S_ENVBLOCK); + + /* current directory */ + map.put("cwd", System.getProperty("user.dir")); + + /* compiler executable */ + //map.put("cl", "cl.exe"); + + /* argument list */ + //map.put("cmd", "-Zi -MT -wishfulthinking"); + + /* find first source file */ + String fn = findFirstFile(cvSections); + if (fn != null) { + map.put("src", fn); + } + + /* Graal doesn't yet create PDB files; all type info is stored in object file */ + //map.put("pdb", System.getProperty("user.dir") + File.separator + "vc100.pdb"); + } + + private static String findFirstFile(CVSections cvSections) { + String fn = null; + for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { + if (classEntry.getFileName() != null) { + fn = classEntry.getFileEntry().getFileName(); + break; + } + } + return fn; + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + /* flags */ + pos = CVUtil.putByte((byte) 0, buffer, pos); + + /* key/value pairs */ + for (Map.Entry entry : map.entrySet()) { + pos = CVUtil.putUTF8StringBytes(entry.getKey(), buffer, pos); + pos = CVUtil.putUTF8StringBytes(entry.getValue(), buffer, pos); + } + + /* end marker */ + pos = CVUtil.putUTF8StringBytes("", buffer, pos); + return pos; + } + } + + /* + * creating a proc32 record has side effects. + * - a global symbol is added to the COFF symbol section + * - two relocation entries are added to the section relocation table, they refer to the global symbol + */ + public static class CVSymbolGProc32Record extends CVSymbolSubrecord { + + private static ObjectFile.Element textSection; + + int pparent; + int pend; + int pnext; + int proclen; + int debugStart; + int debugEnd; + int typeIndex; + int offset; + short segment; + byte flags; + String name; + + CVSymbolGProc32Record(CVSections cvSections, short cmd, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + super(cvSections, cmd); + this.name = name; + this.pparent = pparent; + this.pend = pend; + this.pnext = pnext; + this.proclen = proclen; + this.debugStart = debugStart; + this.debugEnd = debugEnd; + this.typeIndex = typeIndex; + this.offset = offset; + this.segment = segment; + this.flags = flags; + } + + CVSymbolGProc32Record(CVSections cvSections, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + this(cvSections, CVDebugConstants.S_GPROC32, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(pparent, buffer, pos); + pos = CVUtil.putInt(pend, buffer, pos); + pos = CVUtil.putInt(pnext, buffer, pos); + pos = CVUtil.putInt(proclen, buffer, pos); + pos = CVUtil.putInt(debugStart, buffer, pos); + pos = CVUtil.putInt(debugEnd, buffer, pos); + pos = CVUtil.putInt(typeIndex, buffer, pos); + if (buffer == null) { + ObjectFile.Element textSection = getTextSection(); + cvSections.getCVSymbolSection().getOwner().createDefinedSymbol(name, textSection, offset, proclen, true, true); + } + if (buffer != null) { + //CVUtil.debug("XXXX CVSymbolGProc32Record() adding SECREL reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); + cvSections.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, name, false, 1L); + } + pos = CVUtil.putInt(0, buffer, pos); + if (buffer != null) { + //CVUtil.debug("XXXX CVSymbolGProc32Record() adding SECTION reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); + cvSections.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, name, false, 1L); + } + pos = CVUtil.putShort((short) 0, buffer, pos); + pos = CVUtil.putByte(flags, buffer, pos); + pos = CVUtil.putUTF8StringBytes(name, buffer, pos); + return pos; + } + + private ObjectFile.Element getTextSection() { + if (textSection == null) { + textSection = cvSections.getCVSymbolSection().getOwner().elementForName(SectionName.TEXT.getFormatDependentName(ObjectFile.Format.PECOFF)); + } + return textSection; + } + + @Override + public String toString() { + return String.format("S_GPROC32(name=%s parent=%d startaddr=0x%x end=0x%x len=0x%x offset=0x%x type=0x%x flags=0x%x)", name, pparent, debugStart, debugEnd, proclen, offset, typeIndex, flags); + } + } +/* + public static final class CVSymbolGProc32IDRecord extends CVSymbolGProc32Record { + + CVSymbolGProc32IDRecord(CVSections cvSections, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + super(cvSections, CVDebugConstants.S_GPROC32_ID, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); + } + + /* this is almost certainly bad; only for debugging * + CVSymbolGProc32IDRecord(CVSections cvSections, String name, int offset, int proclen) { + super(cvSections, CVDebugConstants.S_GPROC32_ID, name, 0, 0, 0, proclen, 0, 0, 0, offset, (short)0, (byte)0); + } + + @Override + public String toString() { + return String.format("S_GPROC32_ID(name=%s parent=%d startaddr=0x%x end=0x%x len=0x%x offset=0x%x type=0x%x flags=0x%x)", name, pparent, debugStart, debugEnd, proclen, offset, typeIndex, flags); + } + } +*/ + public static final class CVSymbolFrameProcRecord extends CVSymbolSubrecord { + + int framelen; + int padLen; + int padOffset; + int saveRegsCount; + int ehOffset; + short ehSection; + int flags; + + CVSymbolFrameProcRecord(CVSections cvSections, int framelen, int padLen, int padOffset, int saveRegsCount, int ehOffset, short ehSection, int flags) { + super(cvSections, CVDebugConstants.S_FRAMEPROC); + this.framelen = framelen; + this.padLen = padLen; + this.padOffset = padOffset; + this.saveRegsCount = saveRegsCount; + this.ehOffset = ehOffset; + this.ehSection = ehSection; + this.flags = flags; + } + + CVSymbolFrameProcRecord(CVSections cvSections, int framelen, int flags) { + this(cvSections, framelen, 0, 0, 0, 0, (short) 0, flags); + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(framelen, buffer, pos); + pos = CVUtil.putInt(padLen, buffer, pos); + pos = CVUtil.putInt(padOffset, buffer, pos); + pos = CVUtil.putInt(saveRegsCount, buffer, pos); + pos = CVUtil.putInt(ehOffset, buffer, pos); + pos = CVUtil.putShort(ehSection, buffer, pos); + pos = CVUtil.putInt(flags, buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("S_FRAMEPROC(len=0x%x padlen=0x%x paddOffset=0x%x regCount=%d flags=0x%x)", framelen, padLen, padOffset, saveRegsCount, flags); + } + } + + public static class CVSymbolEndRecord extends CVSymbolSubrecord { + + CVSymbolEndRecord(CVSections cvSections, short cmd) { + super(cvSections, cmd); + } + + CVSymbolEndRecord(CVSections cvSections) { + this(cvSections, CVDebugConstants.S_END); + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + // nothing + return pos; + } + + @Override + public String toString() { + return "S_END"; + } + } +/* + public static final class CVSymbolRegRel32Record extends CVSymbolSubrecord { + + int typeIndex; + short reg; + int offset; + String name; + + public CVSymbolRegRel32Record(CVSections cvSections, String name, int typeIndex, int offset, short reg) { + super(cvSections, CVDebugConstants.S_REGREL32); + this.name = name; + this.typeIndex = typeIndex; + this.offset = offset; + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(offset, buffer, pos); + pos = CVUtil.putInt(typeIndex, buffer, pos); + pos = CVUtil.putShort(reg, buffer, pos); + pos = CVUtil.putUTF8StringBytes(name, buffer, pos); + return pos; + } + + @Override + public String toString() { + return "S_REGREL32"; + } + } + + public static class CVSymbolProcIdEndRecord extends CVSymbolEndRecord { + CVSymbolProcIdEndRecord(CVSections cvSections) { + super(cvSections, CVDebugConstants.S_PROC_ID_END); + } + } + + public static final class CVSymbolConstantRecord extends CVSymbolSubrecord { + + int typeIndex; + short leaf; + String name; + + public CVSymbolConstantRecord(CVSections cvSections, String name, int typeIndex, short leaf) { + super(cvSections, CVDebugConstants.S_CONSTANT); + this.name = name; + this.typeIndex = typeIndex; + this.leaf = leaf; + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(typeIndex, buffer, pos); + pos = CVUtil.putShort(leaf, buffer, pos); + pos = CVUtil.putUTF8StringBytes(name, buffer, pos); + return pos; + } + + @Override + public String toString() { + return "S_CONSTANT"; + } + } + + private static abstract class CVSymbolDataRecord extends CVSymbolSubrecord { + + int typeIndex; + int offset; + short segment; + String name; + + CVSymbolDataRecord(CVSections cvSections, short recordType, String name, int typeIndex, int offset, short segment) { + super(cvSections, recordType); + this.name = name; + this.typeIndex = typeIndex; + this.offset = offset; + this.segment = segment; + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(typeIndex, buffer, pos); + pos = CVUtil.putInt(offset, buffer, pos); + pos = CVUtil.putShort(segment, buffer, pos); + pos = CVUtil.putUTF8StringBytes(name, buffer, pos); + return pos; + } + } + + public static final class CVSymbolLData32Record extends CVSymbolDataRecord { + + public CVSymbolLData32Record(CVSections cvSections, String name, int typeIndex, int offset, short segment) { + super(cvSections, CVDebugConstants.S_LDATA32, name, typeIndex, offset, segment); + } + + @Override + public String toString() { + return "S_LDATA32_ST"; + } + } + + public static final class CVSymbolLData32STRecord extends CVSymbolDataRecord { + + public CVSymbolLData32STRecord(CVSections cvSections, String name, int typeIndex, int offset, short segment) { + super(cvSections, CVDebugConstants.S_LDATA32_ST, name, typeIndex, offset, segment); + } + + @Override + public String toString() { + return "S_LDATA32_ST"; + } + } + + public static final class CVSymbolGData32Record extends CVSymbolDataRecord { + + public CVSymbolGData32Record(CVSections cvSections, String name, int typeIndex, int offset, short segment) { + super(cvSections, CVDebugConstants.S_GDATA32, name, typeIndex, offset, segment); + } + + @Override + public String toString() { + return "S_GDATA32"; + } + } + + public static final class CVSymbolSSearchRecord extends CVSymbolDataRecord { + + public CVSymbolSSearchRecord(CVSections cvSections, int offset, short segment) { + super(cvSections, CVDebugConstants.S_SSEARCH, null, 0, offset, segment); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(offset, buffer, pos); + pos = CVUtil.putShort(segment, buffer, pos); + return pos; + } + + @Override + public String toString() { + return "S_SSEARCH"; + } + } + + public static final class CVSymbolUDTRecord extends CVSymbolSubrecord { + + int typeIndex; + String name; + + public CVSymbolUDTRecord(CVSections cvSections, String name, int typeIndex) { + super(cvSections, CVDebugConstants.S_UDT); + this.name = name; + this.typeIndex = typeIndex; + } + + @Override + protected int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(typeIndex, buffer, pos); + pos = CVUtil.putUTF8StringBytes(name, buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("S_UDT(name=%s typeindex=0x%x)", name, typeIndex); + } + } + */ +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java new file mode 100644 index 000000000000..74349566ad18 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import java.util.ArrayList; + +/* + * A CVSymbolSubsection is s special record in debug$S containing nested symbol records + * (the nested records inherit from CVSymbolSubrecord + */ +class CVSymbolSubsection extends CVSymbolRecord { + + private ArrayList subcmds = new ArrayList<>(20); + + CVSymbolSubsection(CVSections cvSections) { + super(cvSections, DEBUG_S_SYMBOLS); + } + + void addRecord(CVSymbolSubrecord subcmd) { + subcmds.add(subcmd); + } + + void addSubrecords() { } + + @Override + protected int computeSize(int pos) { + addSubrecords(); + for (CVSymbolSubrecord subcmd : subcmds) { + pos = subcmd.computeFullSize(pos); + } + return pos; + } + + @Override + protected int computeContents(byte[] buffer, int pos) { + for (CVSymbolSubrecord subcmd : subcmds) { + pos = subcmd.computeFullContents(buffer, pos); + } + return pos; + } + + @Override + public String toString() { + return String.format("CVSymbolSubsection(type=0x%04x pos=0x%05x count=%d)", type, pos, subcmds.size()); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java new file mode 100644 index 000000000000..efaaacf17f71 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +public interface CVTypeConstants { + + /* type table */ + short T_NOTYPE = 0x0000; + short T_VOID = 0x0003; + //short T_CHAR = 0x0010; /* 8 bit signed (java type) */ + //short T_WCHAR = 0x0071; + //short T_CHAR16 = 0x007a; /* 16 bit unicode (Java type) */ + //short T_SHORT = 0x0011; /* 16 bit signed short (Java type) */ + //short T_LONG = 0x0014; /* 32 bit signed (java type? maybe T_short4?) */ + short T_QUAD = 0x0013; /* 64 bit signed long long (Java type) */ + //short T_REAL32 = 0x0040; /* 32 bit float (Java type) */ + //short T_REAL64 = 0x0041; /* 64 but double (Java type) */ + //short T_RCHAR = 0x0070; /* ?? "really a char" */ + + //short T_INT4 = T_LONG; /* ?? is tis right */ + short T_UQUAD = T_QUAD; /* ?? */ + + //short T_POINTER_BITS = 0x0700; + //short T_POINTER32 = 0x0400; /* 32 bit pointer */ + //short T_POINTER64 = 0x0600; /* 64 bit pointer */ + + short LF_MODIFIER = 0x1001; + short LF_POINTER = 0x1002; + short LF_PROCEDURE = 0x1008; + short LF_ARGLIST = 0x1201; + //short LF_FIELDLIST = 0x1203; + short LF_BITFIELD = 0x1205; + short LF_BCLASS = 0x1400; + short LF_ARRAY = 0x1503; + short LF_CLASS = 0x1504; + short LF_STRUCTURE = 0x1505; + //short LF_UNION = 0x1506; + //short LF_ENUM = 0x1507; + short LF_MEMBER = 0x150d; + short LF_TYPESERVER2 = 0x1515; + short LF_INTERFACE = 0x1519; + short LF_BINTERFACE = 0x151a; + +/* + short LF_CHAR = (short) 0x8000; + short LF_SHORT = (short) 0x8001; + short LF_USHORT = (short) 0x8002; + short LF_LONG = (short) 0x8003; + short LF_ULONG = (short) 0x8004; + short LF_REAL32 = (short) 0x8005; + short LF_REAL64 = (short) 0x8006; + short LF_QUADWORD = (short) 0x8009; + short LF_UQUADWORD = (short) 0x800a; + short LF_OCTWORD = (short) 0x8017; + short LF_UOCTWORD = (short) 0x8018; +*/ + + //byte LF_PAD0 = (byte) 0xf0; + byte LF_PAD1 = (byte) 0xf1; + byte LF_PAD2 = (byte) 0xf2; + byte LF_PAD3 = (byte) 0xf3; + /*byte LF_PAD4 = (byte) 0xf4; + byte LF_PAD5 = (byte) 0xf5; + byte LF_PAD6 = (byte) 0xf6; + byte LF_PAD7 = (byte) 0xf7; + byte LF_PAD8 = (byte) 0xf8; + byte LF_PAD9 = (byte) 0xf9; + byte LF_PAD10 = (byte) 0xfa; + byte LF_PAD11 = (byte) 0xfb; + byte LF_PAD12 = (byte) 0xfc; + byte LF_PAD13 = (byte) 0xfd; + byte LF_PAD14 = (byte) 0xfe; + byte LF_PAD15 = (byte) 0xff;*/ +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java new file mode 100644 index 000000000000..1a9dbbe988f9 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Arrays; + +/* + * CV Type Record format (little-endian): + * uint16 length + * uint16 leaf (a.k.a. record type) + * (contents) + */ +abstract class CVTypeRecord implements CVTypeConstants { + + protected final short type; + private int startPosition; + private int sequenceNumber; // 1000 on up + + CVTypeRecord(short type) { + this.type = type; + this.startPosition = -1; + this.sequenceNumber = -1; + } + + int getSequenceNumber() { + return sequenceNumber; + } + + void setSequenceNumber(int sequenceNumber) { + this.sequenceNumber = sequenceNumber; + } + + int computeFullSize(int pos) { + this.startPosition = pos; + pos += Short.BYTES * 2; /* save room for length and leaf type */ + pos = computeSize(pos); + pos = alignPadded4(null, pos); + return pos; + } + + int computeFullContents(byte[] buffer, int pos) { + int lenPos = pos; /* save position of length short */ + pos += Short.BYTES; /* save room for length short */ + pos = CVUtil.putShort(type, buffer, pos); + pos = computeContents(buffer, pos); + /* length does not include record length (2 bytes)) but does include end padding */ + pos = alignPadded4(buffer, pos); + int length = (short) (pos - lenPos - Short.BYTES); + CVUtil.putShort((short) length, buffer, lenPos); + return pos; + } + + protected abstract int computeSize(int pos); + protected abstract int computeContents(byte[] buffer, int pos); + + @Override + public String toString() { + return String.format("CVTypeRecord(type=0x%04x seq=0x%04x pos=0x%04x)", type, sequenceNumber, startPosition); + } + + public void dump(PrintStream out) { + out.format("%s\n", this); + } + + private int alignPadded4(byte[] buffer, int originalpos) { + int pos = originalpos; + int align = pos & 3; + if (align == 1) { + byte[] p3 = {LF_PAD3, LF_PAD2, LF_PAD1 }; + pos = CVUtil.putBytes(p3, buffer, pos); + } else if (align == 2) { + pos = CVUtil.putByte(LF_PAD2, buffer, pos); + pos = CVUtil.putByte(LF_PAD1, buffer, pos); + } else if (align == 3) { + pos = CVUtil.putByte(LF_PAD1, buffer, pos); + } + return pos; + } + + static final class CVTypeModifierRecord extends CVTypeRecord { + + int originalLeaf = -1; + boolean addConst = false; + boolean addVolatile = false; + boolean addUnaligned = false; + + CVTypeModifierRecord(int originalLeaf) { + super(LF_MODIFIER); + this.originalLeaf = originalLeaf; + } + + CVTypeModifierRecord(CVTypeRecord originalLeaf) { + super(LF_MODIFIER); + this.originalLeaf = originalLeaf.getSequenceNumber(); + } + + CVTypeModifierRecord addConst() { + this.addConst = true; + return this; + } + + CVTypeModifierRecord addVolatile() { + this.addVolatile = true; + return this; + } + + CVTypeModifierRecord addUnaligned() { + this.addUnaligned = true; + return this; + } + + @Override + public int computeSize(int pos) { + return pos + Integer.BYTES + Short.BYTES; + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(originalLeaf, buffer, pos); + int flags = (addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0); + pos = CVUtil.putShort((short) flags, buffer, pos); + return pos; + } + + @Override + public String toString() { + String s = String.format("LF_MODIFIER(0x%04x", getSequenceNumber()); + if (addConst) { + s += " const"; + } + if (addVolatile) { + s += " volatile"; + } + if (addUnaligned) { + s += "unaligned"; + } + s += String.format(" 0x%04x)", originalLeaf); + return s; + } + + @Override + public int hashCode() { + int h = originalLeaf; + int flags = (addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0); + h = 31 * h + flags; + return h; + } + } + + static final class CVTypePointerRecord extends CVTypeRecord { + + int originalLeaf = -1; + int kind = 0; + int mode = 0; + int modifiers = 0; + int size = 4; + int flags = 0; +/* + int kind = attributes & 0x00001f; + int mode = (attributes & 0x0000e0) >> 5; + int modifiers = (attributes & 0x001f00) >> 8; + int size = (attributes & 0x07e000) >> 13; + int flags = (attributes & 0x380000) >> 19; + out.printf("LF_POINTER len=%d leaf=0x%04x refType=0x%06x attrib=0x%06x\n", len, leaf, referentType, attributes); + out.printf(" kind=%d mode=%d modifiers=%d size=%d flags=%d\n", kind, mode, modifiers, size, flags); +*/ + CVTypePointerRecord(int originalLeaf) { + super(LF_POINTER); + this.originalLeaf = originalLeaf; + } + + CVTypePointerRecord(CVTypeRecord originalLeaf) { + super(LF_POINTER); + this.originalLeaf = originalLeaf.getSequenceNumber(); + } + + @Override + public int computeSize(int pos) { + return pos + Integer.BYTES * 2; + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(originalLeaf, buffer, pos); + int attributes = kind | (mode << 5) | (modifiers << 8) | (size << 13) | (flags << 19); + pos = CVUtil.putInt(attributes, buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("LF_POINTER(0x%04x * 0x%04x)", getSequenceNumber(), originalLeaf); + } + + @Override + public int hashCode() { + int h = originalLeaf; + int attributes = kind | (mode << 5) | (modifiers << 8) | (size << 13) | (flags << 19); + h = 31 * h + attributes; + return h; + } + } + + static final class CVTypeProcedureRecord extends CVTypeRecord { + + int returnType = -1; + CVTypeArglistRecord argList = null; + + CVTypeProcedureRecord() { + super(LF_PROCEDURE); + } + + public CVTypeProcedureRecord returnType(int leaf) { + this.returnType = leaf; + return this; + } + + public CVTypeProcedureRecord returnType(CVTypeRecord leaf) { + this.returnType = leaf.getSequenceNumber(); + return this; + } + + CVTypeProcedureRecord argList(CVTypeArglistRecord leaf) { + this.argList = leaf; + return this; + } + + @Override + public int computeSize(int pos) { + return pos + Integer.BYTES + Byte.BYTES + Byte.BYTES + Short.BYTES + Integer.BYTES; + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(returnType, buffer, pos); + pos = CVUtil.putByte((byte) 0, buffer, pos); // callType + pos = CVUtil.putByte((byte) 0, buffer, pos); // funcAttr + pos = CVUtil.putShort((short) argList.getSize(), buffer, pos); + pos = CVUtil.putInt(argList.getSequenceNumber(), buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("LF_PROCEDURE(0x%04x ret=0x%04x arg=0x%04x)", getSequenceNumber(), returnType, argList.getSequenceNumber()); + } + + @Override + public int hashCode() { + int h = returnType; + h = 31 * h + argList.hashCode(); + // h = 31 * h + // callType + funcAttr + return h; + } + } + + static final class CVTypeArglistRecord extends CVTypeRecord { + + ArrayList args = new ArrayList<>(); + + CVTypeArglistRecord() { + super(LF_ARGLIST); + } + + CVTypeArglistRecord add(int argType) { + args.add(argType); + return this; + } + + CVTypeArglistRecord add(CVTypeRecord argType) { + args.add(argType.getSequenceNumber()); + return this; + } + + @Override + public int computeSize(int pos) { + return pos + Integer.BYTES + Integer.BYTES * args.size(); + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(args.size(), buffer, pos); + for (Integer at : args) { + pos = CVUtil.putInt(at, buffer, pos); + } + return pos; + } + + int getSize() { + return args.size(); + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(String.format("LF_ARGLIST(0x%04x [", getSequenceNumber())); + for (Integer at : args) { + s.append(' ').append(at); + } + s.append("])"); + return s.toString(); + } + + @Override + public int hashCode() { + int h = 0; + for (Integer r : args) { + h = 31 * h + r.hashCode(); + } + return h; + } + } + + static final class CVMemberRecord extends CVTypeRecord { + + short propertyAttributes; /* property attribute field (prop_t) */ + int fieldIndex; /* type index of member type */ + /* TODO data */ + + CVMemberRecord(short attrs, int fieldIndex) { + super(LF_MEMBER); + this.propertyAttributes = attrs; + this.fieldIndex = fieldIndex; + } + + @Override + public int computeSize(int pos) { + return pos + Short.BYTES + Integer.BYTES; /* + TODO */ + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putShort(propertyAttributes, buffer, pos); + pos = CVUtil.putInt(fieldIndex, buffer, pos); + /* TODO */ + return pos; + } + + @Override + public String toString() { + return String.format("LF_MEMBER(0x%04x attr=0x%04x fld=0x%x)", getSequenceNumber(), propertyAttributes, fieldIndex); + } + + @Override + public int hashCode() { + int h = type; + h = 31 * h + propertyAttributes; + h = 31 * h + fieldIndex; + return h; + } + } + + static class CVBaseClassRecord extends CVTypeRecord { + + short propertyAttributes; /* property attribute field (prop_t) */ + int fieldIndex; /* type index of member type */ + /* TODO data */ + + CVBaseClassRecord(short ltype, short attrs, int fieldIndex) { + super(ltype); + this.propertyAttributes = attrs; + this.fieldIndex = fieldIndex; + } + + CVBaseClassRecord(short attrs, int fieldIndex) { + this(LF_BCLASS, attrs, fieldIndex); + } + + @Override + public int computeSize(int pos) { + return pos + Short.BYTES + Integer.BYTES; // + TODO + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putShort(propertyAttributes, buffer, pos); + pos = CVUtil.putInt(fieldIndex, buffer, pos); + // TODO + return pos; + } + + protected String toString(String leafStr) { + return String.format("%s(0x%04x attr=0x%04x fld=0x%x)", leafStr, getSequenceNumber(), propertyAttributes, fieldIndex); + } + + @Override + public String toString() { + return toString("LF_BASECLASS"); + } + + @Override + public int hashCode() { + int h = type; + h = 31 * h + propertyAttributes; + h = 31 * h + fieldIndex; + return h; + } + } + + static class CVBaseIntefaceRecord extends CVBaseClassRecord { + + CVBaseIntefaceRecord(short attrs, int fieldIndex) { + super(LF_BINTERFACE, attrs, fieldIndex); + } + + @Override + public String toString() { + return toString("LF_BINTERFACE"); + } + + } + + static class CVClassRecord extends CVTypeRecord { + + short count; /* count of number of elements in class */ + short propertyAttributes; /* property attribute field (prop_t) */ + int fieldIndex; /* type index of LF_FIELDLIST descriptor list */ + int derivedFromIndex; /* type index of derived from list if not zero */ + int vshapeIndex; /* type index of vshape table for this class */ + /* TODO data */ + + CVClassRecord(short recType, short count, short attrs, int fieldIndex, int derivedFromIndex, int vshapeIndex) { + super(recType); + this.count = count; + this.propertyAttributes = attrs; + this.fieldIndex = fieldIndex; + this.derivedFromIndex = derivedFromIndex; + this.vshapeIndex = vshapeIndex; + } + + CVClassRecord(short count, short attrs, int fieldIndex, int derivedFromIndex, int vshapeIndex) { + this(LF_CLASS, count, attrs, fieldIndex, derivedFromIndex, vshapeIndex); + } + + @Override + public int computeSize(int pos) { + return pos + Short.BYTES + Short.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES; // + TODO + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putShort(count, buffer, pos); + pos = CVUtil.putShort(propertyAttributes, buffer, pos); + pos = CVUtil.putInt(fieldIndex, buffer, pos); + pos = CVUtil.putInt(derivedFromIndex, buffer, pos); + pos = CVUtil.putInt(vshapeIndex, buffer, pos); + // TODO + return pos; + } + + protected String toString(String lfTypeStr) { + return String.format("%s(0x%04x count=%d attr=0x%04x fld=0x%x super=0x%x vshape=0x%x)", lfTypeStr, getSequenceNumber(), count, propertyAttributes, fieldIndex, derivedFromIndex, vshapeIndex); + } + + @Override + public String toString() { + return toString("LF_CLASS"); + } + + @Override + public int hashCode() { + int h = type; + h = 31 * h + count; + h = 31 * h + propertyAttributes; + h = 31 * h + fieldIndex; + h = 31 * h + derivedFromIndex; + h = 31 * h + vshapeIndex; + return h; + } + } + + static final class CVStructRecord extends CVClassRecord { + CVStructRecord(short count, short attrs, int fieldIndex, int derivedFromIndex, int vshape) { + super(LF_STRUCTURE, count, attrs, fieldIndex, derivedFromIndex, vshape); + } + + @Override + public String toString() { + return toString("LF_STRUCT"); + } + } + + static final class CVInterfaceRecord extends CVClassRecord { + CVInterfaceRecord(short count, short attrs, int fieldIndex, int derivedFromIndex, int vshape) { + super(LF_INTERFACE, count, attrs, fieldIndex, derivedFromIndex, vshape); + } + + @Override + public String toString() { + return toString("LF_INTERFACE"); + } + } + + static final class CVTypeBitfieldRecord extends CVTypeRecord { + + byte length; + byte position; + int typeIndex; + + CVTypeBitfieldRecord(int length, int position, int typeIndex) { + super(LF_BITFIELD); + this.length = (byte) length; + this.position = (byte) position; + this.typeIndex = typeIndex; + } + + @Override + public int computeSize(int pos) { + return pos + Integer.BYTES + Byte.BYTES + Byte.BYTES; + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(typeIndex, buffer, pos); + pos = CVUtil.putByte(length, buffer, pos); + pos = CVUtil.putByte(position, buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("LF_BITFIELD(0x%04x, type=0x%04x len=%d pos=%d)", getSequenceNumber(), typeIndex, length, position); + } + + @Override + public int hashCode() { + int h = type; + h = 31 * h + position; + h = 31 * h + length; + h = 31 * h + typeIndex; + return h; + } + } + + static final class CVTypeArrayRecord extends CVTypeRecord { + + int elementType = -1; + int indexType = -1; + int length = -1; + + CVTypeArrayRecord(int elementType, int indexType, int length) { + super(LF_ARRAY); + this.elementType = elementType; + this.indexType = indexType; + this.length = length; + } + + CVTypeArrayRecord(int elementType, int length) { + super(LF_ARRAY); + this.elementType = elementType; + this.indexType = T_UQUAD; + this.length = length; + } + + CVTypeArrayRecord(CVTypeRecord elementType, int length) { + super(LF_ARRAY); + this.elementType = elementType.getSequenceNumber(); + this.indexType = T_UQUAD; + this.length = length; + } + + @Override + public int computeSize(int pos) { + return pos + Integer.BYTES * 3; + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putInt(elementType, buffer, pos); + pos = CVUtil.putInt(indexType, buffer, pos); + pos = CVUtil.putInt(length, buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("LF_ARRAY(0x%04x type=0x%04x len=%d indexType=0x%04x)", getSequenceNumber(), elementType, length, indexType); + } + + @Override + public int hashCode() { + int h = elementType; + h = 31 * h + indexType; + h = 31 * h + length; + return h; + } + } + + static final class CVTypeServer2Record extends CVTypeRecord { + + byte[] guid; + int age; + String fileName; + + CVTypeServer2Record(byte[] guid, int age, String fileName) { + super(LF_TYPESERVER2); + assert (guid.length == 16); + this.guid = guid; + this.age = age; + this.fileName = fileName; + + /* for some very odd reason GUID is stored like this: + int guid1 = in.getInt(); + int guid2 = in.getShort(); + int guid3 = in.getShort(); + byte[] guid5[10] + */ + swap(this.guid, 0, 3); + swap(this.guid, 1, 2); + swap(this.guid, 4, 5); + swap(this.guid, 6, 7); + } + + @Override + public int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + public int computeContents(byte[] buffer, int pos) { + pos = CVUtil.putBytes(guid, buffer, pos); + pos = CVUtil.putInt(age, buffer, pos); + pos = CVUtil.putUTF8StringBytes(fileName, buffer, pos); + return pos; + } + + @Override + public String toString() { + return String.format("LF_TYPESERVER2(0x%04x '%s' age=%d)", getSequenceNumber(), fileName, age); + } + + @Override + public int hashCode() { + int h = Arrays.hashCode(guid); + h = 31 * h + age; + h = 31 * h + fileName.hashCode(); + return h; + } + + private void swap(byte[] b, int idx1, int idx2) { + byte tmp = b[idx1]; + b[idx1] = b[idx2]; + b[idx2] = tmp; + } + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java new file mode 100644 index 000000000000..2a376502495c --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import java.util.HashMap; +import java.util.Map; + +class CVTypeRecordBuilder { + + private static int sequenceCounter = 0x1000; + private CVTypeSectionImpl typeSection; + private Map typeMap = new HashMap<>(); + + CVTypeRecordBuilder(CVTypeSectionImpl typeSection) { + this.typeSection = typeSection; + } + + /* + * convenience method - return either the caller-created instance or a matching existing instance. + */ + /* we know every entry in typeMap is a T, because it is ONLY this function which inserts entries (of type T) */ + @SuppressWarnings("unchecked") + T buildFrom(T newRecord) { + final T record; + final int hashCode = newRecord.hashCode(); + if (typeMap.containsKey(hashCode)) { + record = (T) typeMap.get(hashCode); + } else { + newRecord.setSequenceNumber(sequenceCounter++); + typeMap.put(hashCode, newRecord); + typeSection.addUniqueRecord(newRecord); + record = newRecord; + } + return record; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java new file mode 100644 index 000000000000..5f16d19dc270 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.pecoff.PECoffObjectFile; +import com.oracle.objectfile.pecoff.cv.CVSections.CVSectionImplBase; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SIGNATURE_C13; +import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SYMBOL_SECTION_NAME; +import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_TYPE_SECTION_NAME; + +public final class CVTypeSectionImpl extends CVSectionImplBase implements CVTypeConstants { + + private static final int CV_VECTOR_DEFAULT_SIZE = 200; + private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); + private CVTypeRecordBuilder builder = new CVTypeRecordBuilder(this); + + CVTypeSectionImpl() { + } + + @Override + public String getSectionName() { + return CV_TYPE_SECTION_NAME; + } + + @Override + public void createContent() { + info("CVTypeSectionImpl.createContent() start"); + addRecords(); + int pos = 0; + pos += computeHeaderSize(); + for (CVTypeRecord record : cvRecords) { + pos = record.computeFullSize(pos); + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + info("CVTypeSectionImpl.createContent() end"); + } + + @Override + public void writeContent() { + info("CVTypeSectionImpl.writeContent() start"); + byte[] buffer = getContent(); + int pos = 0; + pos = CVUtil.putInt(CV_SIGNATURE_C13, buffer, pos); + for (CVTypeRecord record : cvRecords) { + pos = record.computeFullContents(buffer, pos); + } + info("CVTypeSectionImpl.writeContent() end"); + } + + public List getRecords() { + return Collections.unmodifiableList(cvRecords); + } + + void addUniqueRecord(CVTypeRecord r) { + cvRecords.add(r); + } + + T addRecord(T newRecord) { + //CVUtil.debug("adding type record: %s hash=%d\n", newRecord, newRecord.hashCode()); + T actual = builder.buildFrom(newRecord); + CVUtil.debug("added type record: %s hash=%d\n", actual, actual.hashCode()); + return actual; + } + + private void addClassRecords() { + /* we may have done this already when emiting globals in debug$S section */ + //for (DebugInfoBase.ClassEntry classEntry : cvSections.getPrimaryClasses()) { + // TODO - emit all members, all types, etc + //} + } + + private void addRecords() { + //final CVTypeRecord r0 = addRecord(new CVTypeRecord.CVTypeServer2Record("0123456789abcdef".getBytes(UTF_8), 1, "c:\\tmp\\graal-8\\vc100.pdb")); + addClassRecords(); + } + + private int computeHeaderSize() { + return Integer.BYTES; /* CV_SIGNATURE_C13 = 4; */ + } + + @Override + public Set getDependencies(Map decisions) { + Set deps = super.getDependencies(decisions); + PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(CV_SYMBOL_SECTION_NAME); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + /* make our content depend on the codeview symbol section */ + deps.add(BuildDependency.createOrGet(ourContent, decisions.get(targetSection).getDecision(LayoutDecision.Kind.CONTENT))); + /* make our size depend on our content */ + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + + return deps; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java new file mode 100644 index 000000000000..514ec59de8a9 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import static java.nio.charset.StandardCharsets.UTF_8; + +abstract class CVUtil { + + /* base level put methods that assume a non-null buffer */ + static int putByte(byte b, byte[] buffer, int initialPos) { + if (buffer == null) { + return initialPos + Byte.BYTES; + } + int pos = initialPos; + buffer[pos++] = b; + return pos; + } + + static int putShort(short s, byte[] buffer, int initialPos) { + if (buffer == null) { + return initialPos + Short.BYTES; + } + int pos = initialPos; + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + return pos; + } + + static int putInt(int i, byte[] buffer, int initialPos) { + if (buffer == null) { + return initialPos + Integer.BYTES; + } + int pos = initialPos; + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + return pos; + } + + static int putLong(long l, byte[] buffer, int initialPos) { + if (buffer == null) { + return initialPos + Long.BYTES; + } + int pos = initialPos; + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + return pos; + } + + static int putBytes(byte[] inbuff, byte[] buffer, int initialPos) { + if (buffer == null) { + return initialPos + inbuff.length; + } + int pos = initialPos; + for (int l = 0; l < inbuff.length; l++) { + buffer[pos++] = inbuff[l]; + } + return pos; + } + + static int putUTF8StringBytes(String s, byte[] buffer, int initialPos) { + return putUTF8StringBytes(s, 0, buffer, initialPos); + } + + private static int putUTF8StringBytes(String s, int startChar, byte[] buffer, int initialPos) { + byte[] buff = s.substring(startChar).getBytes(UTF_8); + if (buffer == null) { + return initialPos + buff.length + 1; + } + int pos = initialPos; + for (int l = 0; l < buff.length; l++) { + if (buff[l] == 0) { + throw new RuntimeException("oops : string has internal NULL character! " + s); + } + buffer[pos++] = buff[l]; + } + buffer[pos++] = '\0'; + return pos; + } + + static int getInt(byte[] buffer, int initialPos) { + int pos = initialPos; + int i = buffer[pos++] & 0xff; + i += (buffer[pos++] & 0xff) << 8; + i += (buffer[pos++] & 0xff) << 16; + i += (buffer[pos] & 0xff) << 24; + debug("getint returns %d\n", i); + return i; + } + + static short getShort(byte[] buffer, int initialPos) { + int pos = initialPos; + short i = (short) (buffer[pos++] & 0xff); + i = (short) (i + ((buffer[pos] & 0xff) << 8)); + debug("getshort returns %d\n", i); + return i; + } + + static void dump(String msg, byte[] buffer, int initialPos, int len) { + if (buffer == null) { + return; + } + debug("%s0x%06x", msg, initialPos); + for (int i = 0; i < len; i++) { + debug(" %02x", buffer[initialPos + i]); + } + debug("\n"); + } + + static void dump(byte[] buffer, int len) { + if (buffer == null) { + return; + } + for (int i = 0; i < len; i++) { + debug("%02x", buffer[i]); + } + } + + /** + * align on 4 byte boundary. + * @param initialPos initial unaligned position + * @return pos aligned on 4 byte boundary + */ + static int align4(int initialPos) { + int pos = initialPos; + while ((pos & 0x3) != 0) { + pos++; + } + return pos; + } + + public static void debug(String format, Object ... args) { + System.out.format(format, args); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java new file mode 100644 index 000000000000..e152c326aa3c --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -0,0 +1,786 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.debuginfo.DebugInfoProvider; + +import java.io.PrintStream; + +import java.util.Map; +import java.util.HashMap; +import java.util.LinkedList; + +/* TODO : share this with ELF/DWARF and Mach-O code */ +public abstract class DebugInfoBase { + + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + + debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> { + String fileName = debugCodeInfo.fileName(); + String className = debugCodeInfo.className(); + String methodName = debugCodeInfo.methodName(); + String paramNames = debugCodeInfo.paramNames(); + String returnTypeName = debugCodeInfo.returnTypeName(); + int lo = debugCodeInfo.addressLo(); + int hi = debugCodeInfo.addressHi(); + int primaryLine = debugCodeInfo.line(); + Range primary = new Range(fileName, className, methodName, paramNames, returnTypeName, lo, hi, primaryLine); + CVUtil.debug("primaryrange: [0x%08x,0x%08x,l=%d) %s.%s(%s) %s\n", lo, hi, primaryLine, className, methodName, paramNames, fileName); + /* create an infoSection entry for the method */ + addRange(primary); + + debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { + String fileNameAtLine = debugLineInfo.fileName(); + String classNameAtLine = debugLineInfo.className(); + String methodNameAtLine = debugLineInfo.methodName(); + int loAtLine = lo + debugLineInfo.addressLo(); + int hiAtLine = lo + debugLineInfo.addressHi(); + int line = debugLineInfo.line(); + if (fileNameAtLine.length() > 0 && primaryLine >= 0) { + //CVUtil.debug(" lineinfo: [0x%08x,0x%08x) %s.%s (%s:%d)\n", loAtLine, hiAtLine, classNameAtLine, methodNameAtLine, fileNameAtLine, line); + Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", loAtLine, hiAtLine, line, primary); + addSubRange(primary, subRange); + } + }); + }); + /* + ObjectFile.DebugInfoProvider.DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + for (ObjectFile.DebugInfoProvider.DebugDataInfo debugDataInfo : dataInfoProvider) { + String name = debugDataInfo.toString(); + //CVUtil.debug("debuginfo %s\n", name); + }*/ + } + + public LinkedList getPrimaryClasses() { + return primaryClasses; + } + + public LinkedList getFiles() { + return files; + } + + public LinkedList getPrimaryFiles() { + return primaryFiles; + } + + private void dumpFiles(PrintStream out, String descr, LinkedList files) { + int n = 50; + out.format("%s files count=%d\n", descr, files.size()); + for (FileEntry entry : files) { + if (n-- < 0) { + break; + } + out.format(" file:%s\n", entry); + } + } + + private void dumpClasses(PrintStream out, String descr, LinkedList classes) { + int n = 50; + out.format("%s classes count=%d\n", descr, classes.size()); + for (ClassEntry entry : classes) { + if (n-- < 0) { + break; + } + entry.dump(out); + } + } + + public void dumpAll(PrintStream out) { + //dump(out, "primary", getPrimaryFiles(), 0); + //dump(out, "all", getFiles(), 0); + //dump(out, "primary", primaryClasses); + } + + public void addRange(Range primary) { + assert primary.isPrimary(); + ClassEntry classEntry = ensureClassEntry(primary); + PrimaryEntry entry = classEntry.addPrimary(primary); + if (entry != null) { + /* track the entry for this range in address order */ + primaryEntries.add(entry); + } + } + + public void addSubRange(Range primary, Range subrange) { + assert primary.isPrimary(); + assert !subrange.isPrimary(); + String className = primary.getClassName(); + ClassEntry classEntry = primaryClassesIndex.get(className); + FileEntry subrangeEntry = ensureFileEntry(subrange); + /* the primary range should already have been seen */ + /* and associated with a primary class entry */ + assert classEntry.primaryIndex.get(primary) != null; + classEntry.addSubRange(subrange, subrangeEntry); + } + + public ClassEntry ensureClassEntry(Range range) { + String className = range.getClassName(); + /* see if we already have an entry */ + ClassEntry classEntry = primaryClassesIndex.get(className); + if (classEntry == null) { + /* create and index the entry associating it with the right file */ + FileEntry fileEntry = ensureFileEntry(range); + classEntry = new ClassEntry(className, fileEntry); + primaryClasses.add(classEntry); + primaryClassesIndex.put(className, classEntry); + } + assert classEntry.getClassName().equals(className); + return classEntry; + } + + public FileEntry ensureFileEntry(Range range) { + String fileName = range.getFileName(); + /* ensure we have an entry */ + FileEntry fileEntry = filesIndex.get(fileName); + if (fileEntry == null) { + int idx = files.size() + 1; + DirEntry dirEntry = ensureDirEntry(fileName); + fileEntry = new FileEntry(fileName, dirEntry); + fileEntry.setFileId(idx); + files.add(fileEntry); + filesIndex.put(fileName, fileEntry); + /* if this is a primary entry then add it to the primary list */ + if (range.isPrimary()) { + primaryFiles.add(fileEntry); + } else { + Range primaryRange = range.getPrimary(); + FileEntry primaryEntry = filesIndex.get(primaryRange.fileName); + assert primaryEntry != null; + } + } + return fileEntry; + } + + private DirEntry ensureDirEntry(String file) { + if (file.startsWith("/")) { + /* absolute path means use dir entry 0 */ + return null; + } + int pathLength = file.lastIndexOf('/'); + if (pathLength < 0) { + /* no path/package means use dir entry 0 */ + return null; + } + String filePath = file.substring(0, pathLength); + int idx = 0; + String dirPkgMatch = ""; + /* find matching package and see if we already have the right path */ + for (DirEntry dir : dirs) { + if (dir.packageMatches(filePath)) { + if (dir.dirMatches(filePath)) { + /* this is a best fit dir */ + return dir; + } + String dirPkg = dir.getPkg(); + if (dirPkg.length() > dirPkgMatch.length()) { + dirPkgMatch = dirPkg; + } + } + idx++; + } + + DirEntry newDir; + if (dirPkgMatch.length() == 0) { + /* no root package so this is user code */ + newDir = new DirEntry(filePath, false); + } else { + newDir = new DirEntry(dirPkgMatch, filePath); + } + + dirs.addLast(newDir); + return newDir; + } + + /* + * list detailing all dirs in which files are found to reside + * either as part of substrate/compiler or user code + */ + private LinkedList dirs = new LinkedList(); + + /* + * The obvious traversal structure for debug records is + * 1) by top level compiled method (primary Range) ordered by ascending address + * 2) by inlined method (sub range) within top level method ordered by ascending address + * this ensures that all debug records are generated in increasing address order + */ + + /* + * a list recording details of all primary ranges included in + * this file sorted by ascending address range + */ + private LinkedList primaryEntries = new LinkedList(); + + /* + * An alternative traversal option is + * 1) by top level class (String id) + * 2) by top level compiled method (primary Range) within a class ordered by ascending address + * 3) by inlined method (sub range) within top level method ordered by ascending address + * + * this relies on the (current) fact that methods of a given class always appear + * in a single continuous address range with no intervening code from other methods + * or data values. this means we can treat each class as a compilation unit, allowing + * data common to all methods of the class to be shared. + * + * Unfortunately, files cannot be treated as the compilation unit. A file F may contain + * multiple classes, say C1 and C2. There is no guarantee that methods for some other + * class C' in file F' will not be compiled into the address space interleaved between + * methods of C1 and C2. That is a shame because generating debug info records one file at a + * time would allow more sharing e.g. enabling all classes in a file to share a single copy + * of the file and dir tables. + */ + /* list of class entries detaling class info for primary ranges */ + private LinkedList primaryClasses = new LinkedList(); + /* index of already seen classes */ + private Map primaryClassesIndex = new HashMap<>(); + + /* List of files which contain primary ranges */ + private LinkedList primaryFiles = new LinkedList(); + /* List of files which contain primary or secondary ranges */ + private LinkedList files = new LinkedList(); + /* index of already seen files */ + private Map filesIndex = new HashMap<>(); + + // files may be located in a source directory associated + // with a well known substratevm or compiler root package + // in that case the the file's directory path will be something + // like "foo.bar.baz/src/foo/bar/baz/mumble/grumble/bletch" + // i.e. the root package and "src" will be inserted as a prefix + // before the dirs derived from the actual package + // files whose package does not match a well-known root package + // will be listed using the dirs derived from the package + // i.e. simply "foo/bar/baz/mumble/grumble/bletch" + + public static final class DirEntry { + // root package associated with substrate/compiler + // class or empty string for user class + private String pkg; + // element of dir path derived from class's package name + // which may be prefixed by a substrate/compiler path + // or may just be the user source path + private String dir; + // full path potentially including substrate/compiler + // prefix and "/src/" separator as prefix to value + // stored in dir or may just be the value in dir + private String fullPath; + + // create an entry for a root package path + // or a user path not under a root package + public DirEntry(String name, boolean isPkg) { + if (isPkg) { + assert pkg.indexOf('/') < 0; + this.pkg = name; + this.dir = name.replace('.', '/'); + this.fullPath = pkg + "/src/" + dir; + } else { + assert name.indexOf('.') > 0; + this.pkg = ""; + this.dir = name; + this.fullPath = name; + } + } + + // create an entry for a path located within a root package + // the supplied dir must be + public DirEntry(String pkg, String dir) { + this.pkg = pkg; + assert (packageMatches(dir)); + this.dir = dir; + this.fullPath = pkg + "/src/" + dir; + } + + // does this entry sit in a substrate/compiler root package + public boolean hasPackage() { + return pkg.length() == 0; + } + + // does this entry's package (if any) match the dir path + public boolean packageMatches(String dir) { + int l = pkg.length(); + // dir must extend l + if (dir.length() < l) { + return false; + } + // pkg may only differ from l by '.' for '/' + for (int i = 0; i < pkg.length(); i++) { + char c1 = dir.charAt(i); + char c2 = pkg.charAt(i); + if (c1 != c2) { + if (c1 != '/' || c2 != '.') { + return false; + } + } + } + // if the dir is any longer than the root + // package + if (l < dir.length()) { + if (dir.charAt(l) != '/') { + return false; + } + } + + return true; + } + + public boolean dirMatches(String dir) { + // caller must ensure this entry has an appropriate package + assert !hasPackage() || packageMatches(dir); + return this.dir.equals(dir); + } + public String getPkg() { + return pkg; + } + public String getFullPath() { + return fullPath; + } + + @Override + public String toString() { + return String.format("direntry(fullpath=%s)", fullPath); + } + } + + public static final class FileEntry { + // the name of the associated file + private String fileName; + // the directory entry associated with this file entry + private DirEntry dirEntry; + // the fileID assigned to this file + // the fileID in CV4 debug info is simply the offset from the start of the file table + // the file table is composed of fixed size entries, so can be calculated as sizeof(entry) * file index + private int fileId = -1; + + FileEntry(String fileName, DirEntry dirEntry) { + this.fileName = fileName; + this.dirEntry = dirEntry; + } + + String getDirName() { + return (dirEntry != null ? dirEntry.getFullPath() : ""); + } + + public String getFileName() { + return fileName; + } + + public String getPath() { + return fileName; + } + + public void setFileId(int fileId) { + assert (this.fileId == -1); + this.fileId = fileId; + } + + public int getFileId() { + return fileId; + } + + public String toString() { + final String idStr = fileId == -1 ? "" : "(id=" + fileId + ")"; + return String.format("fileentry(%s id=%s dir=%s)", fileName, idStr, dirEntry); + } + } + + public static final class ClassEntry { + // the name of the associated class + private String className; + // the associated file + FileEntry fileEntry; + // a list recording details of all primary ranges included in + // this class sorted by ascending address range + private LinkedList primaries; + // an index identifying primary ranges which have already been encountered + private Map primaryIndex; + // an index of all primary and secondary files referenced from this class's CU + private Map localFilesIndex; + // a list of the same files + private LinkedList localFiles; + // an index of all primary and secondary dirs referenced from this class's CU + private HashMap localDirsIndex; + // a list of the same dirs + private LinkedList localDirs; + // index of debug_info section compilation unit for this class + private int cuIndex; + // index into debug_line section for associated CU + private int lineIndex; + // size of line number info prologue region for associated CU + private int linePrologueSize; + // total size of line number info region for associated CU + private int totalSize; + + public ClassEntry(String className, FileEntry fileEntry) { + this.className = className; + this.fileEntry = fileEntry; + this.primaries = new LinkedList<>(); + this.primaryIndex = new HashMap<>(); + this.localFiles = new LinkedList<>(); + this.localFilesIndex = new HashMap<>(); + this.localDirs = new LinkedList<>(); + this.localDirsIndex = new HashMap<>(); + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.dirEntry; + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + this.cuIndex = -1; + this.lineIndex = -1; + this.linePrologueSize = -1; + this.totalSize = -1; + } + + public String toString() { + return String.format("classentry(%s file=%s)", className, fileEntry.getFileName()); + } + + void dump(PrintStream out) { + out.format(" class=%s file=%s nPrims=%d nLocals=%d CU=%d LI=%d Lsize=%d tsize=%d\n", + className, fileEntry.getFileName(), primaries.size(), localFiles.size(), + cuIndex, lineIndex, linePrologueSize, totalSize); + for (PrimaryEntry pe : primaries) { + out.format(" pe %s\n", pe.getPrimary()); + for (Range r : pe.getSubranges()) { + out.format(" subr %s\n", r); + } + } + } + + PrimaryEntry addPrimary(Range primary) { + if (primaryIndex.get(primary) == null) { + PrimaryEntry primaryEntry = new PrimaryEntry(primary, this); + primaries.add(primaryEntry); + primaryIndex.put(primary, primaryEntry); + return primaryEntry; + } + return null; + } + void addSubRange(Range subrange, FileEntry subFileEntry) { + Range primary = subrange.getPrimary(); + // the subrange should belong to a primary range + assert primary != null; + PrimaryEntry primaryEntry = primaryIndex.get(primary); + // we should already have seen the primary range + assert primaryEntry != null; + assert primaryEntry.getClassEntry() == this; + primaryEntry.addSubRange(subrange, subFileEntry); + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.dirEntry; + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + } + public int localDirsIdx(DirEntry dirEntry) { + if (dirEntry != null) { + return localDirsIndex.get(dirEntry); + } else { + return 0; + } + } + + public int localFilesIdx(FileEntry fileEntry) { + return localFilesIndex.get(fileEntry); + } + + public String getFileName() { + return fileEntry.getFileName(); + } + + String getDirName() { + return fileEntry.getDirName(); + } + + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + return lineIndex; + } + void setLineIndex(int lineIndex) { + this.lineIndex = lineIndex; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + public FileEntry getFileEntry() { + return fileEntry; + } + public String getClassName() { + return className; + } + public LinkedList getPrimaryEntries() { + return primaries; + } + } + + public static final class PrimaryEntry { + // the primary range detailed by this object + Range primary; + // details of the class owning this range + ClassEntry classEntry; + // a list of subranges associated with the primary range + LinkedList subranges; + // a mapping from subranges to their associated file entry + HashMap subrangeIndex; + // index of debug_info section compilation unit for this file + private int cuIndex; + // index into debug_line section for associated compilation unit + private int lineIndex; + // size of line number info prologue region for associated compilation unit + private int linePrologueSize; + // total size of line number info region for associated compilation unit + private int totalSize; + + public PrimaryEntry(Range primary, ClassEntry classEntry) { + this.primary = primary; + this.classEntry = classEntry; + this.subranges = new LinkedList<>(); + this.subrangeIndex = new HashMap<>(); + } + public void addSubRange(Range subrange, FileEntry subFileEntry) { + // we should not see a subrange more than once + assert !subranges.contains(subrange); + assert subrangeIndex.get(subrange) == null; + // we need to generate a file table entry + // for all ranges + subranges.add(subrange); + subrangeIndex.put(subrange, subFileEntry); + } + public Range getPrimary() { + return primary; + } + public ClassEntry getClassEntry() { + return classEntry; + } + public FileEntry getFileEntry() { + return classEntry.getFileEntry(); + } + public LinkedList getSubranges() { + return subranges; + } + public FileEntry getSubrangeFileEntry(Range subrange) { + return subrangeIndex.get(subrange); + } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + return lineIndex; + } + void setLineIndex(int lineIndex) { + this.lineIndex = lineIndex; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + } + + public static final class Range { + private String fileName; + private String className; + private String methodName; + private String paramNames; + private String returnTypeName; + private int lo; + private int hi; + private int line; + private Range primary; + + // create a primary range + Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, int lo, int hi, int line) { + this(fileName, className, methodName, paramNames, returnTypeName, lo, hi, line, null); + } + // create a primary or secondary range + + Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, int lo, int hi, int line, Range primary) { + this.fileName = fileName; + this.className = className; + this.methodName = methodName; + this.paramNames = paramNames; + this.returnTypeName = returnTypeName; + this.lo = lo; + this.hi = hi; + this.line = line; + this.primary = primary; + } + + public Range(Range other) { + this.fileName = other.fileName; + this.className = other.className; + this.methodName = other.methodName; + this.paramNames = other.paramNames; + this.returnTypeName = other.returnTypeName; + this.lo = other.lo; + this.hi = other.hi; + this.line = other.line; + this.primary = other.primary; + } + + public String toString() { + return String.format("range(fn=%s:%d lo=0x%x hi=0x%x %s m=%s(%s))", fileName, line, lo, hi, className, methodName, paramNames); + } + + public boolean sameClassName(Range other) { + return className.equals(other.className); + } + + public boolean sameMethodName(Range other) { + return methodName.equals(other.methodName); + } + + public boolean sameParamNames(Range other) { + return paramNames.equals(other.paramNames); + } + + public boolean sameReturnTypeName(Range other) { + return returnTypeName.equals(other.returnTypeName); + } + + public boolean sameFileName(Range other) { + return fileName.equals(other.fileName); + } + + public boolean sameMethod(Range other) { + return sameClassName(other) && + sameMethodName(other) && + sameParamNames(other) && + sameReturnTypeName(other); + } + + public boolean contains(Range other) { + return (lo <= other.lo && hi >= other.hi); + } + + public boolean isPrimary() { + return getPrimary() == null; + } + + public Range getPrimary() { + return primary; + } + + public String getFileName() { + return fileName; + } + public String getClassName() { + return className; + } + public String getMethodName() { + return methodName; + } + public String getParamNames() { + return paramNames; + } + public String getReturnTypeName() { + return returnTypeName; + } + public int getHi() { + return hi; + } + public void setLo(int lo) { + this.lo = lo; + } + public int getLo() { + return lo; + } + public void setHi(int hi) { + this.hi = hi; + } + public int getLine() { + return line; + } + public String getClassAndMethodName() { + return getExtendedMethodName(false, false); + } + public String getClassAndMethodNameWithParams() { + return getExtendedMethodName(true, false); + } + + public String getFullMethodName() { + return getExtendedMethodName(true, true); + } + + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { + StringBuilder builder = new StringBuilder(); + if (includeReturnType && returnTypeName.length() > 0) { + builder.append(returnTypeName); + builder.append(' '); + } + if (className != null) { + builder.append(className); + builder.append("."); + } + builder.append(methodName); + if (includeParams) { + builder.append('('); + if (paramNames != null) { + builder.append(paramNames); + } + builder.append(')'); + } + return builder.toString(); + } + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 841434ad941b..144c67183cd7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -50,6 +50,8 @@ import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.XOptions; +import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; + public class SubstrateOptions { @Option(help = "Class containing the default entry point method. Optional if --shared is used.", type = OptionType.User)// @@ -417,4 +419,15 @@ public static Predicate makeFilter(String[] definedFilters) { public static int codeAlignment() { return GraalOptions.LoopHeaderAlignment.getValue(HostedOptionValues.singleton()); } + @Option(help = "Insert debug info into the generated native image or library")// + public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey(0) { + @Override + protected void onValueUpdate(EconomicMap, Object> values, Integer oldValue, Integer newValue) { + // force update of TrackNodeSourcePosition + if (newValue > 0 && !Boolean.TRUE.equals(values.get(TrackNodeSourcePosition))) { + TrackNodeSourcePosition.update(values, true); + } + } + }; + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 4fe2e4cc14aa..c313e2f0aed5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.image; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.CONTRACT; import static com.oracle.svm.core.SubstrateUtil.mangleName; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; @@ -44,18 +46,29 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; + +import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.hosted.image.sources.SourceManager; +import com.oracle.svm.hosted.meta.HostedType; +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.serviceprovider.BufferUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -67,6 +80,10 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; import com.oracle.objectfile.ObjectFile.RelocationKind; @@ -456,6 +473,13 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { cGlobals.writeData(rwDataBuffer, (offset, symbolName) -> defineDataSymbol(symbolName, rwDataSection, offset + RWDATA_CGLOBALS_PARTITION_OFFSET)); defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET); + // if we have constructed any debug info then + // give the object file a chance to install it + if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { + ImageSingletons.add(SourceManager.class, new SourceManager()); + DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); + objectFile.installDebugInfo(provider); + } // - Write the heap, either to its own section, or to the ro and rw data sections. RelocatableBuffer heapSectionBuffer = null; ProgbitsSectionImpl heapSectionImpl = null; @@ -950,4 +974,254 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final ObjectFile objectFile; protected final NativeImageCodeCache codeCache; } + + /** + * implementation of the DebugInfoProvider API interface + * that allows type, code and heap data info to be passed to + * an ObjectFile when generation of debug info is enabled. + */ + private class NativeImageDebugInfoProvider implements DebugInfoProvider { + private final NativeImageCodeCache codeCache; + private final NativeImageHeap heap; + + NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { + super(); + this.codeCache = codeCache; + this.heap = heap; + } + + @Override + public Stream typeInfoProvider() { + return Stream.empty(); + } + + @Override + public Stream codeInfoProvider() { + return codeCache.compilations.entrySet().stream().map(entry -> new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue())); + } + + @Override + public Stream dataInfoProvider() { + return Stream.empty(); + } + } + + private static final String[] GRAAL_SRC_PACKAGE_PREFIXES = { + "org.graalvm", + "com.oracle.graal", + "com.oracle.objectfile", + "com.oracle.svm", + "com.oracle.truffle", + }; + + + /** + * implementation of the DebugCodeInfo API interface + * that allows code info to be passed to an ObjectFile + * when generation of debug info is enabled. + */ + private class NativeImageDebugCodeInfo implements DebugCodeInfo { + private final HostedMethod method; + private final CompilationResult compilation; + private Path fullFilePath; + + NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { + this.method = method; + this.compilation = compilation; + this.fullFilePath = null; + } + + @Override + public String fileName() { + if (fullFilePath == null) { + HostedType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; + } + @Override + public Path filePath() { + if (fullFilePath == null) { + HostedType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getParent(); + } + return null; + } + + @Override + public String className() { + return method.format("%H"); + } + + @Override + public String methodName() { + return method.format("%n"); + } + + @Override + public String paramNames() { + return method.format("%P"); + } + + @Override + public String returnTypeName() { + return method.format("%R"); + } + + @Override + public int addressLo() { + return method.getCodeAddressOffset(); + } + + @Override + public int addressHi() { + return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); + } + + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(0); + } + return -1; + } + + @Override + public Stream lineInfoProvider() { + if (fileName().toString().length() == 0) { + return Stream.empty(); + } + return compilation.getSourceMappings().stream().map(sourceMapping -> new NativeImageDebugLineInfo(sourceMapping)); + } + + public int getFrameSize() { + return compilation.getTotalFrameSize(); + } + + public List getFrameSizeChanges() { + List frameSizeChanges = new LinkedList<>(); + for (Mark mark : compilation.getMarks()) { + // we only need to observe stack increment or decrement points + if (mark.id.equals("PROLOGUE_DECD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); + frameSizeChanges.add(sizeChange); + // } else if (mark.id.equals("PROLOGUE_END")) { + // can ignore these + // } else if (mark.id.equals("EPILOGUE_START")) { + // can ignore these + } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); + frameSizeChanges.add(sizeChange); + // } else if(mark.id.equals("EPILOGUE_END")) { + } + } + return frameSizeChanges; + } + } + + /** + * implementation of the DebugLineInfo API interface + * that allows line number info to be passed to an + * ObjectFile when generation of debug info is enabled. + */ + private class NativeImageDebugLineInfo implements DebugLineInfo { + private final int bci; + private final ResolvedJavaMethod method; + private final int lo; + private final int hi; + private Path fullFilePath = null; + + NativeImageDebugLineInfo(SourceMapping sourceMapping) { + NodeSourcePosition position = sourceMapping.getSourcePosition(); + int bci = position.getBCI(); + this.bci = (bci >= 0 ? bci : 0); + this.method = position.getMethod(); + this.lo = sourceMapping.getStartOffset(); + this.hi = sourceMapping.getEndOffset(); + } + + @Override + public String fileName() { + if (fullFilePath == null) { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; + } + + public Path filePath() { + if (fullFilePath == null) { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getParent(); + } + return null; + } + + @Override + public String className() { + return method.format("%H"); + } + + @Override + public String methodName() { + return method.format("%n"); + } + + @Override + public int addressLo() { + return lo; + } + + @Override + public int addressHi() { + return hi; + } + + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(bci); + } + return -1; + } + } + + /** + * implementation of the DebugFrameSizeChange API interface + * that allows stack frame size change info to be passed to + * an ObjectFile when generation of debug info is enabled. + */ + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { + private int offset; + private Type type; + + NativeImageDebugFrameSizeChange(int offset, Type type) { + this.offset = offset; + this.type = type; + } + + @Override + public int getOffset() { + return offset; + } + + @Override + public Type getType() { + return type; + } + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java new file mode 100644 index 000000000000..1a9ebc2304fa --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ApplicationSourceCache extends SourceCache { + /** + * create an application source cache + */ + protected ApplicationSourceCache() { + super(SourceCache.APPLICATION_CACHE_KEY); + initSrcRoots(); + } + + private void initSrcRoots() { + String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); + assert javaClassPath != null; + String[] classPathEntries = javaClassPath.split(File.pathSeparator); + /* add dirs or jars found in the classpath */ + for (String classPathEntry : classPathEntries) { + Path entryPath = Paths.get(classPathEntry); + String fileNameString = entryPath.getFileName().toString(); + if (fileNameString.endsWith(".jar")) { + // application jar /path/to/xxx.jar should have + // sources /path/to/xxx-sources.jar + int length = fileNameString.length(); + String srcFileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; + Path srcPath = entryPath.getParent().resolve(srcFileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(root); + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } else { + /* + * for dir entries ending in classes or target/classes + * look for a parallel src tree + */ + if (entryPath.endsWith("classes")) { + Path parent = entryPath.getParent(); + if (parent.endsWith("target")) { + parent = parent.getParent(); + } + Path srcPath = (parent.resolve("src")); + File file = srcPath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(srcPath); + } + } + } + } + /* add the current working directory as a path of last resort */ + srcRoots.add(Paths.get(".")); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java new file mode 100644 index 000000000000..da8bfd6cde07 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; +public class GraalVMSourceCache extends SourceCache { + /** + * create a GraalVM source cache + */ + protected GraalVMSourceCache() { + super(SourceCache.GRAALVM_CACHE_KEY); + initSrcRoots(); + } + + private static final String JAVA_CLASSPATH_PROP = "java.class.path"; + + private void initSrcRoots() { + String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); + assert javaClassPath != null; + String[] classPathEntries = javaClassPath.split(File.pathSeparator); + for (String classPathEntry : classPathEntries) { + Path entryPath = Paths.get(classPathEntry); + String fileNameString = entryPath.getFileName().toString(); + if (fileNameString.endsWith(".jar")) { + // GraalVM jar /path/to/xxx.jar should have + // sources /path/to/xxx.src.zip.jar + int length = fileNameString.length(); + String srcFileNameString = fileNameString.substring(0, length - 3) + "src.zip"; + Path srcPath = entryPath.getParent().resolve(srcFileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + if (filterSrcRoot(root)) { + srcRoots.add(root); + } + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } else { + /* graal classpath dir entries should have a src and/or src_gen subdirectory */ + Path srcPath = entryPath.resolve("src"); + if (filterSrcRoot(srcPath)) { + srcRoots.add(srcPath); + } + srcPath = entryPath.resolve("src_gen"); + if (filterSrcRoot(srcPath)) { + srcRoots.add(srcPath); + } + } + } + } + /** + * Ensure that the supplied root dir contains + * at least one subdirectory that matches one + * of the expected Graal package dir hierarchies. + * + * @param root A root path under which to locate + * the desired subdirectory + * @return true if a + */ + private boolean filterSrcRoot(Path root) { + String separator = root.getFileSystem().getSeparator(); + + /* if any of the graal paths exist accept this root */ + for (String prefix : GRAALVM_SRC_PACKAGE_PREFIXES) { + String subDir = prefix.replaceAll("\\.", separator); + if (Files.isDirectory(root.resolve(subDir))) { + return true; + } + } + + return false; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java new file mode 100644 index 000000000000..e53d75f75c9b --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class JDKSourceCache extends SourceCache { + /** + * create a JDK runtime class source cache. + */ + protected JDKSourceCache() { + super(SourceCache.JDK_CACHE_KEY); + initSrcRoots(); + } + + private void initSrcRoots() { + String javaHome = System.getProperty(JAVA_HOME_PROP); + assert javaHome != null; + Path javaHomePath = Paths.get("", javaHome); + Path srcZipPath; + String javaSpecVersion = System.getProperty(JAVA_SPEC_VERSION_PROP); + if (javaSpecVersion.equals("1.8")) { + srcZipPath = javaHomePath.resolve("src.zip"); + } else { + assert javaSpecVersion.matches("[1-9][0-9]"); + srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); + } + if (srcZipPath.toFile().exists()) { + try { + FileSystem srcFileSystem = FileSystems.newFileSystem(srcZipPath, null); + for (Path root : srcFileSystem.getRootDirectories()) { + srcRoots.add(root); + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } +} + diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java new file mode 100644 index 000000000000..91384cfcb553 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2020, 2020, 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.List; +/** + * An abstract cache manager for some subspace of the + * JDK, GraalVM or application source file space. This class + * implements core behaviours that manage a cache of source + * files in a specific subdirectory of the local sources + * directory. It allows source files to be located + * when present in the local cache or cached when not + * already present. Subclasses are responsible for providing + * behaviours that identify an original source for addition + * to the cache and for verifying that a cached file is not + * out of date with respect to its original. + */ + +public abstract class SourceCache { + + /* + * properties needed to locate relevant JDK and app source roots + */ + protected static final String JAVA_CLASSPATH_PROP = "java.class.path"; + protected static final String JAVA_HOME_PROP = "java.home"; + protected static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + /** + * A list of root directories which may contain source files + * from which this cache can be populated + */ + protected List srcRoots; + + /** + * Create a source cache with a specific base type. + * @param key a String identifying the subdir under + * which sources should be cached which should also + * match the type of content being cached + */ + protected SourceCache(String key) { + basePath = Paths.get(SOURCE_CACHE_ROOT_DIR, key); + srcRoots = new ArrayList<>(); + + } + + /** + * A local directory serving as the root for all + * source trees maintained by the different + * available source caches. + */ + private static final String SOURCE_CACHE_ROOT_DIR = "sources"; + /** + * The top level path relative to the root directory + * under which files belonging to this specific cache + * are located. + */ + private Path basePath; + /** + * JDK runtime code sources are cached using this key as a + * leading path prefix with a module name as a sub-path + * prefix when we have a modular JDK. + * + * For example, the full file path to a file under the cache + * root directory might be jdk/java/lang/Throwable.java on jdk8 or + * jdk/java.base/java/lang/Throwable.java on jdk11 + */ + protected static final String JDK_CACHE_KEY = "jdk"; + /** + * GraalVM code sources are cached using this key as a + * leading path prefix with an enclosing package name + * and the name src or src_gen forming a sub-path prefix. + * + * For example, the full file path to a file under the cache + * root directory might be + * graal/com/oracle/svm/core/Isolates.java + * or + * graal/org/graalvm/compiler/core/phases/LowTier_OptionDescriptors.java + */ + protected static final String GRAALVM_CACHE_KEY = "graal"; + /** + * Application code sources are cached using this key as + * a leading path prefix with a name or sequence of + * names derived from a classpath jar or dir entry + * employed as a sub-path prefix. + * + * For example, the full file path to a file under the cache + * root directory might be + * src/Hello.java + * or + * src/hello/impl/HelloImpl.java + * or + * src/hibernate-core-5.4.4.Final/org/hibernate/annotations/Entity.java + */ + protected static final String APPLICATION_CACHE_KEY = "src"; + /** + * Cache the source file identified by the supplied prototype + * path if a legitimate candidate for inclusion in this cache + * can be identified and is not yet included in the cache or + * alternatively identify and validate any existing candidate + * cache entry to ensure it is not out of date refreshing it + * if need be. + * + * @param filePath a prototype path for a file to be included + * in the cache derived from the name of some associated class. + * @return a path identifying the cached file or null + * if the candidate cannot be found. + */ + public Path resolve(Path filePath) { + File cachedFile = findCandidate(filePath); + if (cachedFile == null) { + return tryCacheFile(filePath); + } else { + return checkCacheFile(filePath); + } + } + + /** + * Given a prototype path for a file to be resolved + * return a File identifying a cached candidate for + * for that Path or null if no cached candidate exists. + * @param filePath a prototype path for a file to be included + * in the cache derived from the name of some associated class. + * @return a File identifying a cached candidate or null. + */ + public File findCandidate(Path filePath) { + /* + * JDK source candidates are stored in the src.zip file + * using the path we are being asked for. A cached version + * should exist under this cache's root using that same + * path. + */ + File file = cachedFile(filePath); + if (file.exists()) { + return file; + } + return null; + } + public Path tryCacheFile(Path filePath) { + for (Path root : srcRoots) { + Path targetPath = cachedPath(filePath); + Path sourcePath = extendPath(root, filePath); + try { + if (checkSourcePath(sourcePath)) { + ensureTargetDirs(targetPath.getParent()); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + // return the original filePath + // we don't want the sources/jdk prefix to go into the debuginfo + return filePath; + } + } catch (IOException e) { + } + } + return null; + } + public Path checkCacheFile(Path filePath) { + for (Path root : srcRoots) { + Path targetPath = cachedPath(filePath); + Path sourcePath = extendPath(root, filePath); + try { + if (checkSourcePath(sourcePath)) { + FileTime sourceTime = Files.getLastModifiedTime(sourcePath); + FileTime destTime = Files.getLastModifiedTime(targetPath); + if (destTime.compareTo(sourceTime) < 0) { + try { + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + } catch (IOException e) { + return null; + } + } + return filePath; + } else { + /* delete the target file as it is out of date */ + targetPath.toFile().delete(); + } + } catch (IOException e) { + // hmm last modified time blew up? + return tryCacheFile(filePath); + } + } + return null; + } + /** + * Create and intialize the source cache used to locate and cache + * sources of a given type as determined by the supplied key. + * @param type an enum identifying both the type of Java sources + * cached by the returned cache and the subdir of the cached + * source subdirectory in which those sources are located. + * @return the desired source cache. + */ + public static SourceCache createSourceCache(SourceCacheType type) { + SourceCache sourceCache = null; + switch (type) { + case JDK: + sourceCache = new JDKSourceCache(); + break; + case GRAALVM: + sourceCache = new GraalVMSourceCache(); + break; + case APPLICATION: + sourceCache = new ApplicationSourceCache(); + break; + default: + assert false; + } + return sourceCache; + } + /** + * Extend a root path form one file system using a path potentially derived + * from another file system by converting he latter to a text string and + * replacing the file separator if necessary. + * @param root the path to be extended + * @param filePath the subpath to extend it with + * @return the extended path + */ + protected Path extendPath(Path root, Path filePath) { + String filePathString = filePath.toString(); + String fileSeparator = filePath.getFileSystem().getSeparator(); + String newSeparator = root.getFileSystem().getSeparator(); + if (!fileSeparator.equals(newSeparator)) { + filePathString = filePathString.replaceAll(fileSeparator, newSeparator); + } + return root.resolve(filePathString); + } + + /** + * convert a potential resolved candidate path to + * the corresponding local Path in this cache. + * @param candidate a resolved candidate path for + * some given resolution request + * @return the corresponding local Path + */ + protected Path cachedPath(Path candidate) { + return basePath.resolve(candidate); + } + /** + * convert a potential resolved candidate path to + * the corresponding local File in this cache. + * @param candidate a resolved candidate path for + * some given resolution request + * @return the corresponding local File + */ + protected File cachedFile(Path candidate) { + return cachedPath(candidate).toFile(); + } + /** + * indicate whether a source path identifies a fie in the associated file system + * @param sourcePath + * @return true if the path identifies a file or false if no such file can be found + * @throws IOException if there is some error in resolving the path + */ + private boolean checkSourcePath(Path sourcePath) throws IOException { + return Files.isRegularFile(sourcePath); + } + /** + * ensure the directory hierarchy for a path exists + * creating any missing directories if needed + * @param targetDir a path to the desired directory + * @throws IOException if it is not possible to create + * one or more directories in the path + */ + private void ensureTargetDirs(Path targetDir) throws IOException { + if (targetDir != null) { + File targetFile = targetDir.toFile(); + if (!targetFile.exists()) { + targetDir.toFile().mkdirs(); + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java new file mode 100644 index 000000000000..10863a5e572c --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +public enum SourceCacheType { + JDK, + GRAALVM, + APPLICATION +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java new file mode 100644 index 000000000000..459acebe6a08 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.svm.util.ModuleSupport; +import jdk.vm.ci.meta.ResolvedJavaType; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; + +/** + * A singleton class responsible for locating source files + * for classes included in a native image and copying them + * into the local sources. + */ +public class SourceManager { + /** + * Find and cache a source file for a give Java class and + * return a Path to the file relative to the source. + * @param resolvedType the Java type whose source file + * should be located and cached + * @return a path identifying the location of a successfully + * cached file for inclusion in the generated debug info or + * null if a source file cannot be found or cached. + */ + public Path findAndCacheSource(ResolvedJavaType resolvedType) { + Path path = null; + String fileName = computeBaseName(resolvedType); + /* + * null for the name means this class + * will not have a source so we skip on that + */ + if (fileName != null) { + /* + * we can only provide sources + * for known classes and interfaces + */ + if (resolvedType.isInstanceClass() || resolvedType.isInterface()) { + /* + * if we have an OriginalClassProvider we + * can use the underlying Java class + * to provide the details we need to locate + * a source + */ + if (resolvedType instanceof OriginalClassProvider) { + Class javaClass = ((OriginalClassProvider) resolvedType).getJavaClass(); + String packageName = computePackageName(javaClass); + SourceCacheType type = sourceCacheType(packageName, javaClass); + path = locateSource(fileName, packageName, type, javaClass); + } + /* + * if we could not locate a source via the cache + * then the fallback is to generate a path to the + * file based on the class name and let the + * user configure a path to the sources + */ + if (path == null) { + String name = resolvedType.toJavaName(); + int idx = name.lastIndexOf('.'); + if (idx >= 0 && idx < name.length() - 1) { + name = name.substring(0, idx); + path = Paths.get("", name.split("\\.")); + path = path.resolve(fileName); + } + } + } + } + return path; + } + + /** + * Construct the base file name for a resolved + * Java class excluding path elements using either + * the source name embedded in the class file or + * the class name itself. + * @param resolvedType the resolved java type whose + * source file name is required + * @return the file name or null if it the class cannot + * be associated with a source file + */ + private String computeBaseName(ResolvedJavaType resolvedType) { + String fileName = resolvedType.getSourceFileName(); + if (fileName == null) { + /* ok, try to construct it from the class name */ + fileName = resolvedType.toJavaName(); + int idx = fileName.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + fileName = fileName.substring(idx + 1); + } + idx = fileName.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + // + fileName = null; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + fileName = fileName.substring(0, idx); + } + fileName = fileName + ".java"; + } + } + return fileName; + } + /** + * Construct the package name for a Java class or + * the empty String if it has no package. + * @param javaClass the java class whose package + * name is required + * @return the package name or the empty String + * if it has no package + */ + private String computePackageName(Class javaClass) { + Package pkg = javaClass.getPackage(); + return (pkg == null ? "" : pkg.getName()); + } + /** + * Construct the prototype name for a Java source file + * which can be used to resolve and cache an actual source + * file. + * @param fileName the base file name for the source file + * @param packageName the name of the package for the associated Java class + * @param type the type of cache in which to lookup or cache this class's source file + * @param javaClass the java class whose prototype name is required + * @return a protoype name for the source file + */ + private Path computePrototypeName(String fileName, String packageName, SourceCacheType type, Class javaClass) { + String prefix = ""; + if (type == SourceCacheType.JDK) { + /* JDK paths may require the module name as prefix */ + String moduleName = ModuleSupport.getModuleName(javaClass); + if (moduleName != null) { + prefix = moduleName; + } + } + if (packageName.length() == 0) { + return Paths.get("", fileName); + } else { + return Paths.get(prefix, packageName.split("\\.")).resolve(fileName); + } + } + /** + * A whitelist of packages prefixes used to + * pre-filter JDK runtime class lookups. + */ + public static final String[] JDK_SRC_PACKAGE_PREFIXES = { + "java.", + "jdk.", + "javax.", + "sun.", + "com.sun.", + "org.ietf.", + "org.jcp.", + "org.omg.", + "org.w3c.", + "org.xml", + }; + /** + * A whitelist of packages prefixes used to + * pre-filter GraalVM class lookups. + */ + public static final String[] GRAALVM_SRC_PACKAGE_PREFIXES = { + "com.oracle.graal.", + "com.oracle.objectfile.", + "com.oracle.svm.", + "com.oracle.truffle.", + "org.graalvm.", + }; + + /** + * A whitelist of packages prefixes used to + * pre-filter app class lookups which + * includes just the empty string because + * any package will do. + */ + private static final String[] APP_SRC_PACKAGE_PREFIXES = { + "", + }; + + /** + * Check a package name against a whitelist of acceptable packages. + * @param packageName the package name of the class to be checked + * @param whitelist a list of prefixes one of which may form + * the initial prefix of the package name being checked + * @return true if the package name matches an entry in the + * whitelist otherwise false + */ + private boolean whiteListPackage(String packageName, String[] whitelist) { + for (String prefix : whitelist) { + if (packageName.startsWith(prefix)) { + return true; + } + } + return false; + } + + /** + * Identify which type of source cache should be used + * to locate a given class's source code. + */ + private SourceCacheType sourceCacheType(String packageName, Class javaClass) { + if (whiteListPackage(packageName, JDK_SRC_PACKAGE_PREFIXES)) { + return SourceCacheType.JDK; + } + if (whiteListPackage(packageName, GRAALVM_SRC_PACKAGE_PREFIXES)) { + return SourceCacheType.GRAALVM; + } + return SourceCacheType.APPLICATION; + } + /** + * A map from each of the top level root keys to a + * cache that knows how to handle lookup and caching + * of the associated type of source file. + */ + private static HashMap caches = new HashMap<>(); + + /** + * Retrieve the source cache used to locate and cache sources + * of a given type as determined by the supplied key, creating + * and initializing it if it does not already exist. + * @param type an enum identifying the type of Java sources + * cached by the returned cache. + * @return the desired source cache. + */ + private SourceCache getOrCreateCache(SourceCacheType type) { + SourceCache sourceCache = caches.get(type); + if (sourceCache == null) { + sourceCache = SourceCache.createSourceCache(type); + caches.put(type, sourceCache); + } + return sourceCache; + } + + private Path locateSource(String fileName, String packagename, SourceCacheType type, Class javaClass) { + SourceCache cache = getOrCreateCache(type); + Path prototypeName = computePrototypeName(fileName, packagename, type, javaClass); + return cache.resolve(prototypeName); + } +} + From 0c323d793e6c645ec4a4ce7d3b0d382925f0b503 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 27 Feb 2020 13:32:43 +0000 Subject: [PATCH 038/130] added -H:DebugInfoSourceSearchPath option, tweaked SourceCacheType enum, cleaned up SourceCache init and memoized source cache checks --- .../com/oracle/svm/core/SubstrateOptions.java | 3 + .../image/sources/ApplicationSourceCache.java | 97 +++++++++++++------ .../image/sources/GraalVMSourceCache.java | 79 ++++++++++----- .../hosted/image/sources/JDKSourceCache.java | 10 +- .../svm/hosted/image/sources/SourceCache.java | 55 ++--------- .../hosted/image/sources/SourceCacheType.java | 20 +++- .../hosted/image/sources/SourceManager.java | 25 ++++- 7 files changed, 184 insertions(+), 105 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 75d4144a0fac..cffe17d0beb4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -422,4 +422,7 @@ protected void onValueUpdate(EconomicMap, Object> values, Integer o } }; + @Option(help = "Search path for source files for Application or GraalVM classes (list of comma-separated directories or jar files)")// + public static final HostedOptionKey DebugInfoSourceSearchPath = new HostedOptionKey(null) { + }; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 1a9ebc2304fa..26ee2f706db1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -26,6 +26,9 @@ package com.oracle.svm.hosted.image.sources; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.option.OptionUtils; + import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -34,60 +37,92 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static com.oracle.svm.hosted.image.sources.SourceCacheType.APPLICATION; + public class ApplicationSourceCache extends SourceCache { /** - * create an application source cache + * Create an application source cache. */ protected ApplicationSourceCache() { - super(SourceCache.APPLICATION_CACHE_KEY); initSrcRoots(); } + @Override + protected final SourceCacheType getType() { + return APPLICATION; + } + private void initSrcRoots() { String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); assert javaClassPath != null; String[] classPathEntries = javaClassPath.split(File.pathSeparator); - /* add dirs or jars found in the classpath */ + /* Add dirs or jars found in the classpath */ for (String classPathEntry : classPathEntries) { - Path entryPath = Paths.get(classPathEntry); - String fileNameString = entryPath.getFileName().toString(); - if (fileNameString.endsWith(".jar")) { - // application jar /path/to/xxx.jar should have - // sources /path/to/xxx-sources.jar + tryClassPathRoot(classPathEntry); + } + if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { + for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { + trySourceRoot(searchPathEntry); + } + } + /* add the current working directory as a path of last resort */ + srcRoots.add(Paths.get(".")); + } + private void tryClassPathRoot(String sourceRoot) { + trySourceRoot(sourceRoot, true); + } + private void trySourceRoot(String sourceRoot) { + trySourceRoot(sourceRoot, false); + } + private void trySourceRoot(String sourceRoot, boolean fromClassPath) { + Path sourcePath = Paths.get(sourceRoot); + String fileNameString = sourcePath.getFileName().toString(); + if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".zip")) { + if (fromClassPath && fileNameString.endsWith(".jar")) { + /* + * application jar /path/to/xxx.jar should have + * sources /path/to/xxx-sources.jar + */ int length = fileNameString.length(); - String srcFileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; - Path srcPath = entryPath.getParent().resolve(srcFileNameString); - if (srcPath.toFile().exists()) { - try { - FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); - for (Path root : fileSystem.getRootDirectories()) { - srcRoots.add(root); - } - } catch (IOException ioe) { - /* ignore this entry */ - } catch (FileSystemNotFoundException fnfe) { - /* ignore this entry */ + fileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; + } + sourcePath = sourcePath.getParent().resolve(fileNameString); + if (sourcePath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(sourcePath, null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(root); } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ } - } else { + } + } else { + if (fromClassPath) { /* - * for dir entries ending in classes or target/classes - * look for a parallel src tree - */ - if (entryPath.endsWith("classes")) { - Path parent = entryPath.getParent(); + * for dir entries ending in classes or target/classes + * look for a parallel src tree + */ + if (sourcePath.endsWith("classes")) { + Path parent = sourcePath.getParent(); if (parent.endsWith("target")) { parent = parent.getParent(); } - Path srcPath = (parent.resolve("src")); - File file = srcPath.toFile(); + sourcePath = (parent.resolve("src")); + File file = sourcePath.toFile(); if (file.exists() && file.isDirectory()) { - srcRoots.add(srcPath); + srcRoots.add(sourcePath); } } + } else { + // try the path as provided + File file = sourcePath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(sourcePath); + } } } - /* add the current working directory as a path of last resort */ - srcRoots.add(Paths.get(".")); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index da8bfd6cde07..9ce7f603c848 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -26,6 +26,9 @@ package com.oracle.svm.hosted.image.sources; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.option.OptionUtils; + import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -35,16 +38,21 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static com.oracle.svm.hosted.image.sources.SourceCacheType.GRAALVM; import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; public class GraalVMSourceCache extends SourceCache { /** - * create a GraalVM source cache + * Create a GraalVM source cache. */ protected GraalVMSourceCache() { - super(SourceCache.GRAALVM_CACHE_KEY); initSrcRoots(); } + @Override + protected final SourceCacheType getType() { + return GRAALVM; + } + private static final String JAVA_CLASSPATH_PROP = "java.class.path"; private void initSrcRoots() { @@ -52,38 +60,63 @@ private void initSrcRoots() { assert javaClassPath != null; String[] classPathEntries = javaClassPath.split(File.pathSeparator); for (String classPathEntry : classPathEntries) { - Path entryPath = Paths.get(classPathEntry); - String fileNameString = entryPath.getFileName().toString(); - if (fileNameString.endsWith(".jar")) { - // GraalVM jar /path/to/xxx.jar should have - // sources /path/to/xxx.src.zip.jar + tryClassPathRoot(classPathEntry); + } + if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { + for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { + trySourceRoot(searchPathEntry); + } + } + } + private void tryClassPathRoot(String sourceRoot) { + trySourceRoot(sourceRoot, true); + } + private void trySourceRoot(String sourceRoot) { + trySourceRoot(sourceRoot, false); + } + private void trySourceRoot(String sourceRoot, boolean fromClassPath) { + Path sourcePath = Paths.get(sourceRoot); + String fileNameString = sourcePath.getFileName().toString(); + if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".src.zip")) { + if (fromClassPath && fileNameString.endsWith(".jar")) { + /* + * GraalVM jar /path/to/xxx.jar in classpath should + * have sources /path/to/xxx.src.zip + */ int length = fileNameString.length(); - String srcFileNameString = fileNameString.substring(0, length - 3) + "src.zip"; - Path srcPath = entryPath.getParent().resolve(srcFileNameString); - if (srcPath.toFile().exists()) { - try { - FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); - for (Path root : fileSystem.getRootDirectories()) { - if (filterSrcRoot(root)) { - srcRoots.add(root); - } + fileNameString = fileNameString.substring(0, length - 3) + "src.zip"; + } + Path srcPath = sourcePath.getParent().resolve(fileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + if (filterSrcRoot(root)) { + srcRoots.add(root); } - } catch (IOException ioe) { - /* ignore this entry */ - } catch (FileSystemNotFoundException fnfe) { - /* ignore this entry */ } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ } - } else { + } + } else { + if (fromClassPath) { /* graal classpath dir entries should have a src and/or src_gen subdirectory */ - Path srcPath = entryPath.resolve("src"); + Path srcPath = sourcePath.resolve("src"); if (filterSrcRoot(srcPath)) { srcRoots.add(srcPath); } - srcPath = entryPath.resolve("src_gen"); + srcPath = sourcePath.resolve("src_gen"); if (filterSrcRoot(srcPath)) { srcRoots.add(srcPath); } + } else { + // try the path as provided + if (filterSrcRoot(sourcePath)) { + srcRoots.add(sourcePath); + } } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index e53d75f75c9b..3268b70aea3f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -33,15 +33,21 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static com.oracle.svm.hosted.image.sources.SourceCacheType.JDK; + public class JDKSourceCache extends SourceCache { /** - * create a JDK runtime class source cache. + * Create a JDK runtime class source cache.. */ protected JDKSourceCache() { - super(SourceCache.JDK_CACHE_KEY); initSrcRoots(); } + @Override + protected final SourceCacheType getType() { + return JDK; + } + private void initSrcRoots() { String javaHome = System.getProperty(JAVA_HOME_PROP); assert javaHome != null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 91384cfcb553..9e55c9737489 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -62,17 +62,19 @@ public abstract class SourceCache { protected List srcRoots; /** - * Create a source cache with a specific base type. - * @param key a String identifying the subdir under - * which sources should be cached which should also - * match the type of content being cached + * Create some flavour of source cache. */ - protected SourceCache(String key) { - basePath = Paths.get(SOURCE_CACHE_ROOT_DIR, key); + protected SourceCache() { + basePath = Paths.get(SOURCE_CACHE_ROOT_DIR).resolve(getType().getSubdir()); srcRoots = new ArrayList<>(); - } + /** + * Idenitfy the specific type of this source cache + * @return + */ + protected abstract SourceCacheType getType(); + /** * A local directory serving as the root for all * source trees maintained by the different @@ -84,44 +86,7 @@ protected SourceCache(String key) { * under which files belonging to this specific cache * are located. */ - private Path basePath; - /** - * JDK runtime code sources are cached using this key as a - * leading path prefix with a module name as a sub-path - * prefix when we have a modular JDK. - * - * For example, the full file path to a file under the cache - * root directory might be jdk/java/lang/Throwable.java on jdk8 or - * jdk/java.base/java/lang/Throwable.java on jdk11 - */ - protected static final String JDK_CACHE_KEY = "jdk"; - /** - * GraalVM code sources are cached using this key as a - * leading path prefix with an enclosing package name - * and the name src or src_gen forming a sub-path prefix. - * - * For example, the full file path to a file under the cache - * root directory might be - * graal/com/oracle/svm/core/Isolates.java - * or - * graal/org/graalvm/compiler/core/phases/LowTier_OptionDescriptors.java - */ - protected static final String GRAALVM_CACHE_KEY = "graal"; - /** - * Application code sources are cached using this key as - * a leading path prefix with a name or sequence of - * names derived from a classpath jar or dir entry - * employed as a sub-path prefix. - * - * For example, the full file path to a file under the cache - * root directory might be - * src/Hello.java - * or - * src/hello/impl/HelloImpl.java - * or - * src/hibernate-core-5.4.4.Final/org/hibernate/annotations/Entity.java - */ - protected static final String APPLICATION_CACHE_KEY = "src"; + private final Path basePath; /** * Cache the source file identified by the supplied prototype * path if a legitimate candidate for inclusion in this cache diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java index 10863a5e572c..5e37d3883141 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java @@ -26,8 +26,22 @@ package com.oracle.svm.hosted.image.sources; +import java.nio.file.Path; +import java.nio.file.Paths; + public enum SourceCacheType { - JDK, - GRAALVM, - APPLICATION + JDK("jdk"), + GRAALVM("graal"), + APPLICATION("src"); + + final Path subdir; + + SourceCacheType(String subdir) { + this.subdir = Paths.get(subdir); + } + + public Path getSubdir() { + return subdir; + } + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java index 459acebe6a08..d3d4252f6685 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -50,7 +50,12 @@ public class SourceManager { * null if a source file cannot be found or cached. */ public Path findAndCacheSource(ResolvedJavaType resolvedType) { - Path path = null; + /* short circuit if we have already seen this type */ + Path path = verifiedPaths.get(resolvedType); + if (path != null) { + return (path != INVALID_PATH ? path : null); + } + String fileName = computeBaseName(resolvedType); /* * null for the name means this class @@ -91,6 +96,9 @@ public Path findAndCacheSource(ResolvedJavaType resolvedType) { } } } + /* memoize the lookup */ + verifiedPaths.put(resolvedType, (path != null ? path : INVALID_PATH)); + return path; } @@ -241,6 +249,21 @@ private SourceCacheType sourceCacheType(String packageName, Class javaClass) */ private static HashMap caches = new HashMap<>(); + /** + * A map from a Java type to an associated source paths which + * is known to have an up to date entry in the relevant source + * file cache. This is used to memoize previous lookups. + */ + private static HashMap verifiedPaths = new HashMap<>(); + + /** + * An invalid path used as a marker to track failed lookups + * so we don't waste time looking up the source again. + * Note that all legitimate paths will end with a ".java" + * suffix. + */ + private static final Path INVALID_PATH = Paths.get("invalid"); + /** * Retrieve the source cache used to locate and cache sources * of a given type as determined by the supplied key, creating From ceeefa3b55b117a5f4f76301faf04917db381142 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 27 Feb 2020 14:24:10 +0000 Subject: [PATCH 039/130] update readme to describe DebugInfoSourceSearchPath option --- substratevm/DEBUGINFO.md | 69 +++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 58e8bd48b63e..4ea2b3f640c3 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -2,22 +2,69 @@ Using the ptototype debug info feature -------------------------------------- To add debug info to a generated native image add flag --H:+GenerateDebugInfo to the native image command line. +-H:GenerateDebugInfo= to the native image command line (where N is +a positive integer value -- the default value 0 means generate no +debug info). For example, $ javac Hello.java $ mx native-image -H:GenerateDebugInfo=1 Hello The resulting image should contain code (method) debug records in a -format gdb understands (VS support is still under development). - -The flag also enables caching of sources for JDK runtime classes, -GraalVM classes and application classes which can be located during -native image generation. The cache is created under local subdirectory -sources and can be used to configure source file search path roots for -the debugger. Files in the cache are located in a directory hierarchy -that matches the file path information included in the native image -debug records - +format gdb understands (VS support is still under development). At +present it makes no difference which positive value is supplied as +argument to the GenerateDebugInfo option. + +The GenerateDebugInfo option also enables caching of sources for any +JDK runtime classes, GraalVM classes and application classes which can +be located during native image generation. The cache is created under +local subdirectory sources. It is used to configure source file search +path roots for the debugger. Files in the cache are located in a +directory hierarchy that matches the file path information included in +the native image debug records. The source cache should contain all +the files needed to debug the generated image and nothing more. This +local cache provides a convenient way of making just the necessary +sources available to the debugger/IDE when debugging a native image. + +The implementation tries to be smart about locating source files. It +uses the current JAVA_HOME to locate the JDK src.zip when searching +for JDK runtime sources. It also uses entries in the classpath to +suggest locations for GraalVM source files and application source +files (see below for precise details of the scheme used to identify +source locations). However, source layouts do vary and it may no tbe +possible to find all sources. Hence, users can specify the location of +source files explicitly on the command line using option +DebugInfoSourceSearchPath: + + $ javac --source-path apps/greeter/src \ + -d apps/greeter/classes org/my/greeter/*Greeter.java + $ javac -cp apps/greeter/classes \ + --source-path apps/hello/src \ + -d apps/hello/classes org/my/hello/Hello.java + $ mx native-image -H:GenerateDebugInfo=1 \ + -H:DebugInfoSourceSearchPath=apps/hello/src \ + -H:DebugInfoSourceSearchPath=apps/greeter/src \ + -cp apps/hello/classes:apps/greeter/classes org.my.hello.Hello + +Option DebugInfoSourceSearchPath can be repeated as many times as +required to notify all the target source locations. The value passed +to this option can be either an absolute or relative path. It can +identify either a directory, a source jar or a source zip file. It is +also possible to specify several source roots at once using a comma +separator: + + $ mx native-image -H:GenerateDebugInfo=1 \ + -H:DebugInfoSourceSearchPath=apps/hello/target/hello-sources.jar,apps/greeter/target/greeter-sources.jar \ + -cp apps/target/hello.jar:apps/target/greeter.jar \ + org.my.Hello + +Note that in both the examples above the DebugInfoSourceSearchPath +options are actually redundant. In the first case the classpath +entries for apps/hello/classes and apps/greeter/classes will be used +to derive the default search roots apps/hello/src and +apps/greeter/src. In the second case classpath entires +apps/target/hello.jar and apps/target/greeter.jar will be used to +derive the default search roots apps/target/hello-sources.jar and +apps/target/greeter-sources.jar. What is currently implemented ----------------------------- From 0e14d50c85c8bad6ea7598b1c3f4a8dbc4ae9b69 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 27 Feb 2020 12:24:56 -0500 Subject: [PATCH 040/130] added some debug behviour switches, null source cache implementation --- .../objectfile/pecoff/cv/CVConstants.java | 51 +++++++++++++--- .../objectfile/pecoff/cv/CVSymbolRecord.java | 9 ++- .../pecoff/cv/CVSymbolRecordBuilder.java | 7 ++- .../pecoff/cv/CVSymbolSubrecord.java | 4 +- .../objectfile/pecoff/cv/DebugInfoBase.java | 6 +- .../hosted/image/sources/NullSourceCache.java | 60 +++++++++++++++++++ .../svm/hosted/image/sources/SourceCache.java | 17 +++--- 7 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index efdc8913dd12..bf27fa998c2a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -40,15 +40,48 @@ public interface CVConstants { /* Codeview section header signature */ int CV_SIGNATURE_C13 = 4; - /* Knobs */ - String JDK_SOURCE_BASE = ""; //"C:\\tmp\\graal-8\\jdk8_jvmci\\src\\"; - String GRAAL_SOURCE_BASE = ""; //"C:\\tmp\\graal-8\\graal8\\"; + /* + * Knobs + * + * (some may become Graal options in the future) + */ + + /* + * path to JDK source code (for example unzipped src.zip) + * If set, source paths for JDK classes in the object file will be + * $JDK_SOURCE_BASE/java/package/someclass.java + * instead of + * (cache directory)/sources/jdk/java/package/someclass.java + * or (if source cache is disabled) + * java/package/someclass.java + * + * example + * JDK_SOURCE_BASE = C:\\tmp\\graal-8\\jdk8_jvmci\\src\\"; + */ + String JDK_SOURCE_BASE = ""; - boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ - boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ - boolean mergeAdjacentLineRecords = false; /* if a line record is the same line in the same file as the previous record, meerge them */ - String replaceMainFunctionName = null; //"javamain"; /* first main() becomes this name (with no arg list at all) */ + /* + * path to Graal source code base (for examplke checked out Graal source repository) + * if set source paths will be inferred from appropriate Graal package directories + * (behaves similarly to JDK_SOURCE_BASE) + * + * Example: + * GRAAL_SOURCE_BASE = "C:\\tmp\\graal-8\\graal8\\"; + */ + String GRAAL_SOURCE_BASE = ""; - /* setting functionNamesHashArgs causes link errors as the illegal characters in arg lists confuse link.exe */ - boolean functionNamesHashArgs = true; /* if true, arg lists become obscure integers */ + boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ + boolean skipJDKInternals = false; /* (unimplemented) if true, don't emit debug code for JDK classes */ + boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ + boolean mergeAdjacentLineRecords = false; /* if a line record is the same line in the same file as the previous record, meerge them */ + boolean emitUnadornedMain = true; /* if true, first main() does not have args in the debug name */ + String replaceMainFunctionName = null; /* first main() becomes this name (with no class name or arg list at all) (set null to disable) */ + + /* + * The standard link.exe can't handle odd characters (parentheses or commas, for example) in enternal names. + * Setting functionNamesHashArgs true replaces those names, + * so that "Foo.function(String[] args)" becomes "Foo.function_617849326". + * If functionNamesHashArgs is false, currently the linker will fail. + */ + boolean functionNamesHashArgs = true; /* if true, arg lists become obscure integers (and link.exe will not work properly) */ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index 1b4e5353e7bd..b83e05e29e54 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -142,6 +142,13 @@ static final class CVFileRecord extends CVSymbolRecord { this.strings = strings; } + /* + * Convert a simple path into an absolute path by determining if it's + * part of Graal, the JDK, or use code. + * + * This method is incompletely implemented. + * TODO: replace this with the new SourceCache system + */ private String fixPath(String fn) { String substrateDir = GRAAL_SOURCE_BASE + "substratevm\\src\\"; String compilerDir = GRAAL_SOURCE_BASE + "compiler\\src\\"; @@ -209,7 +216,7 @@ private byte[] calculateMD5Sum(String fn) { @Override public int computeContents(byte[] buffer, int pos) { - CVUtil.debug("XXXX file computeContents(%d) nf=%d\n", pos, cvSections.getFiles().size()); + CVUtil.debug("file computeContents(%d) nf=%d\n", pos, cvSections.getFiles().size()); for (FileEntry entry : cvSections.getFiles()) { pos = put(entry, buffer, pos); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index fe6b84087e61..552f0ab208d2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -32,6 +32,7 @@ import static com.oracle.objectfile.pecoff.cv.CVConstants.functionNamesHashArgs; import static com.oracle.objectfile.pecoff.cv.CVConstants.replaceMainFunctionName; +import static com.oracle.objectfile.pecoff.cv.CVConstants.emitUnadornedMain; import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.T_NOTYPE; import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.T_VOID; @@ -54,6 +55,10 @@ private String fixMethodName(Range range) { if (replaceMainFunctionName != null && noMainFound && range.getMethodName().equals("main")) { noMainFound = false; methodName = replaceMainFunctionName; + } else if (emitUnadornedMain && noMainFound && range.getMethodName().equals("main")) { + // TODO: check for static void main(String args[]) + noMainFound = false; + methodName = range.getClassAndMethodName(); } else if (functionNamesHashArgs) { long hash = ((long) range.getParamNames().hashCode()) & 0xffffffffL; methodName = range.getClassAndMethodName() + "." + hash; @@ -84,7 +89,7 @@ void build() { private void processFunction(String methodName, Range range) { - CVUtil.debug("XXXX addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); + CVUtil.debug("addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); int functionTypeIndex = addTypeRecords(); byte funcFlags = 0; CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvSections, methodName, 0, 0, 0, range.getHi() - range.getLo(), 0, 0, functionTypeIndex, range.getLo(), (short) 0, funcFlags); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index f0d3476e323c..10769f701235 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -313,12 +313,12 @@ protected int computeContents(byte[] buffer, int pos) { cvSections.getCVSymbolSection().getOwner().createDefinedSymbol(name, textSection, offset, proclen, true, true); } if (buffer != null) { - //CVUtil.debug("XXXX CVSymbolGProc32Record() adding SECREL reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); + //CVUtil.debug("CVSymbolGProc32Record() adding SECREL reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); cvSections.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, name, false, 1L); } pos = CVUtil.putInt(0, buffer, pos); if (buffer != null) { - //CVUtil.debug("XXXX CVSymbolGProc32Record() adding SECTION reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); + //CVUtil.debug("CVSymbolGProc32Record() adding SECTION reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); cvSections.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, name, false, 1L); } pos = CVUtil.putShort((short) 0, buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index e152c326aa3c..e73e60bdd297 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -37,9 +37,13 @@ /* TODO : share this with ELF/DWARF and Mach-O code */ public abstract class DebugInfoBase { + private boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { + return !debugCodeInfo.className().startsWith("com.oracle"); + } + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> { + debugInfoProvider.codeInfoProvider().filter(debugCodeInfo -> isWanted(debugCodeInfo)).forEach(debugCodeInfo -> { String fileName = debugCodeInfo.fileName(); String className = debugCodeInfo.className(); String methodName = debugCodeInfo.methodName(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java new file mode 100644 index 000000000000..f9c3268f1554 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class NullSourceCache extends SourceCache { + /** + * create a cache that does nothing and assumes the sources are in + * their original locations, to be resolved at debug time. + * + * Why would you want to do this? + * - Shorter compile turnaround + * - the original cache doesn't account for C/C++ native code + */ + protected NullSourceCache(String cacheKey) { + super(cacheKey); + } + + /** + * Just return the original path + * + * @param filePath a prototype path for a source file + * @return the original path + */ + @Override + public Path resolve(Path filePath) { + return filePath; + } +} + diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 91384cfcb553..4722d6a1cf82 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -152,7 +152,7 @@ public Path resolve(Path filePath) { * in the cache derived from the name of some associated class. * @return a File identifying a cached candidate or null. */ - public File findCandidate(Path filePath) { + private File findCandidate(Path filePath) { /* * JDK source candidates are stored in the src.zip file * using the path we are being asked for. A cached version @@ -165,7 +165,7 @@ public File findCandidate(Path filePath) { } return null; } - public Path tryCacheFile(Path filePath) { + private Path tryCacheFile(Path filePath) { for (Path root : srcRoots) { Path targetPath = cachedPath(filePath); Path sourcePath = extendPath(root, filePath); @@ -182,7 +182,7 @@ public Path tryCacheFile(Path filePath) { } return null; } - public Path checkCacheFile(Path filePath) { + private Path checkCacheFile(Path filePath) { for (Path root : srcRoots) { Path targetPath = cachedPath(filePath); Path sourcePath = extendPath(root, filePath); @@ -219,15 +219,16 @@ public Path checkCacheFile(Path filePath) { */ public static SourceCache createSourceCache(SourceCacheType type) { SourceCache sourceCache = null; + boolean DONT_CACHE = false; switch (type) { case JDK: - sourceCache = new JDKSourceCache(); + sourceCache = DONT_CACHE ? new NullSourceCache(JDK_CACHE_KEY) : new JDKSourceCache(); break; case GRAALVM: - sourceCache = new GraalVMSourceCache(); + sourceCache = DONT_CACHE ? new NullSourceCache(GRAALVM_CACHE_KEY) : new GraalVMSourceCache(); break; case APPLICATION: - sourceCache = new ApplicationSourceCache(); + sourceCache = DONT_CACHE ? new NullSourceCache(APPLICATION_CACHE_KEY) : new ApplicationSourceCache(); break; default: assert false; @@ -236,7 +237,7 @@ public static SourceCache createSourceCache(SourceCacheType type) { } /** * Extend a root path form one file system using a path potentially derived - * from another file system by converting he latter to a text string and + * from another file system by converting the latter to a text string and * replacing the file separator if necessary. * @param root the path to be extended * @param filePath the subpath to extend it with @@ -247,7 +248,7 @@ protected Path extendPath(Path root, Path filePath) { String fileSeparator = filePath.getFileSystem().getSeparator(); String newSeparator = root.getFileSystem().getSeparator(); if (!fileSeparator.equals(newSeparator)) { - filePathString = filePathString.replaceAll(fileSeparator, newSeparator); + filePathString = filePathString.replace(fileSeparator, newSeparator); } return root.resolve(filePathString); } From 7a70ada0bdd5083a283b22bfb5594581d62fce3f Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 27 Feb 2020 13:04:29 -0500 Subject: [PATCH 041/130] address some checkstyle errors --- .../objectfile/pecoff/cv/CVConstants.java | 2 +- .../oracle/objectfile/pecoff/cv/CVUtil.java | 2 +- .../objectfile/pecoff/cv/DebugInfoBase.java | 18 +++++++++++++++--- .../svm/hosted/image/NativeBootImage.java | 1 - .../image/sources/ApplicationSourceCache.java | 4 ++-- .../image/sources/GraalVMSourceCache.java | 2 +- .../hosted/image/sources/JDKSourceCache.java | 3 +-- .../hosted/image/sources/NullSourceCache.java | 15 +++++---------- .../svm/hosted/image/sources/SourceCache.java | 17 +++++++++++------ 9 files changed, 37 insertions(+), 27 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index bf27fa998c2a..11293abd40c7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -45,7 +45,7 @@ public interface CVConstants { * * (some may become Graal options in the future) */ - + /* * path to JDK source code (for example unzipped src.zip) * If set, source paths for JDK classes in the object file will be diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java index 514ec59de8a9..4aaf588b0c85 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java @@ -161,6 +161,6 @@ static int align4(int initialPos) { } public static void debug(String format, Object ... args) { - System.out.format(format, args); + //System.out.format(format, args); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index e73e60bdd297..6753ac031cc5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -34,11 +34,23 @@ import java.util.HashMap; import java.util.LinkedList; -/* TODO : share this with ELF/DWARF and Mach-O code */ +/** + * Accept debugCodeInfo (etc) and populate the local debug database. + */ + +/* + * TODO: + * - share this with ELF/DWARF and Mach-O code + * - abstract out the original code in elf.dwarf package and reuse it. + * - speed this up + * - move the nested classes outside + * - handle stack frames + */ public abstract class DebugInfoBase { private boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { - return !debugCodeInfo.className().startsWith("com.oracle"); + /* TODO: be much more clever; this is merely proof of concept */ + return !(CVConstants.skipGraalInternals && debugCodeInfo.className().startsWith("com.oracle")); } public void installDebugInfo(DebugInfoProvider debugInfoProvider) { @@ -56,7 +68,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { CVUtil.debug("primaryrange: [0x%08x,0x%08x,l=%d) %s.%s(%s) %s\n", lo, hi, primaryLine, className, methodName, paramNames, fileName); /* create an infoSection entry for the method */ addRange(primary); - + debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); String classNameAtLine = debugLineInfo.className(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index c313e2f0aed5..f85747e6bf73 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -64,7 +64,6 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 1a9ebc2304fa..3171c068dd6f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -36,7 +36,7 @@ public class ApplicationSourceCache extends SourceCache { /** - * create an application source cache + * Create an application source cache. */ protected ApplicationSourceCache() { super(SourceCache.APPLICATION_CACHE_KEY); @@ -88,6 +88,6 @@ private void initSrcRoots() { } } /* add the current working directory as a path of last resort */ - srcRoots.add(Paths.get(".")); + srcRoots.add(Paths.get(".")); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index da8bfd6cde07..83094d8b5114 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -38,7 +38,7 @@ import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; public class GraalVMSourceCache extends SourceCache { /** - * create a GraalVM source cache + * Create a GraalVM source cache. */ protected GraalVMSourceCache() { super(SourceCache.GRAALVM_CACHE_KEY); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index e53d75f75c9b..8426f1e0d912 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -35,7 +35,7 @@ public class JDKSourceCache extends SourceCache { /** - * create a JDK runtime class source cache. + * Create a JDK runtime class source cache. */ protected JDKSourceCache() { super(SourceCache.JDK_CACHE_KEY); @@ -68,4 +68,3 @@ private void initSrcRoots() { } } } - diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java index f9c3268f1554..18a72010f721 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java @@ -26,19 +26,15 @@ package com.oracle.svm.hosted.image.sources; -import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.FileSystems; import java.nio.file.Path; -import java.nio.file.Paths; public class NullSourceCache extends SourceCache { /** - * create a cache that does nothing and assumes the sources are in - * their original locations, to be resolved at debug time. + * Create a cache that does nothing. + * Assumes the sources are in their original locations, + * to be resolved at debug time. * - * Why would you want to do this? + * Why might this be useful? * - Shorter compile turnaround * - the original cache doesn't account for C/C++ native code */ @@ -47,7 +43,7 @@ protected NullSourceCache(String cacheKey) { } /** - * Just return the original path + * Just return the original path. * * @param filePath a prototype path for a source file * @return the original path @@ -57,4 +53,3 @@ public Path resolve(Path filePath) { return filePath; } } - diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 4722d6a1cf82..2c4eb1d281e4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -55,9 +55,15 @@ public abstract class SourceCache { protected static final String JAVA_CLASSPATH_PROP = "java.class.path"; protected static final String JAVA_HOME_PROP = "java.home"; protected static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + + /** + * Set to true to avoid building the source code cache. + */ + protected static final boolean DONT_CACHE = false; + /** - * A list of root directories which may contain source files - * from which this cache can be populated + * A list of root directories which may contain source files. + * files in these directories are used to populate this cache. */ protected List srcRoots; @@ -219,7 +225,6 @@ private Path checkCacheFile(Path filePath) { */ public static SourceCache createSourceCache(SourceCacheType type) { SourceCache sourceCache = null; - boolean DONT_CACHE = false; switch (type) { case JDK: sourceCache = DONT_CACHE ? new NullSourceCache(JDK_CACHE_KEY) : new JDKSourceCache(); @@ -274,7 +279,7 @@ protected File cachedFile(Path candidate) { return cachedPath(candidate).toFile(); } /** - * indicate whether a source path identifies a fie in the associated file system + * indicate whether a source path identifies a file in the associated file system. * @param sourcePath * @return true if the path identifies a file or false if no such file can be found * @throws IOException if there is some error in resolving the path @@ -283,8 +288,8 @@ private boolean checkSourcePath(Path sourcePath) throws IOException { return Files.isRegularFile(sourcePath); } /** - * ensure the directory hierarchy for a path exists - * creating any missing directories if needed + * Ensure the directory hierarchy for a path exists. + * Create any missing directories if needed. * @param targetDir a path to the desired directory * @throws IOException if it is not possible to create * one or more directories in the path From 6c381538763f876019b6b97012add5395cbb6cf1 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 27 Feb 2020 13:24:34 -0500 Subject: [PATCH 042/130] use string,replace() to avoid backslash error in regex on Windows --- .../src/com/oracle/svm/hosted/image/sources/SourceCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 91384cfcb553..7e2262141788 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -247,7 +247,7 @@ protected Path extendPath(Path root, Path filePath) { String fileSeparator = filePath.getFileSystem().getSeparator(); String newSeparator = root.getFileSystem().getSeparator(); if (!fileSeparator.equals(newSeparator)) { - filePathString = filePathString.replaceAll(fileSeparator, newSeparator); + filePathString = filePathString.replace(fileSeparator, newSeparator); } return root.resolve(filePathString); } From fd36ad9d5fb2570ea0f3d52e1ca98b119115bf87 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 28 Feb 2020 13:00:09 +0000 Subject: [PATCH 043/130] obtain classpath from image classloader, clean up source searches, ensure classpath dirs are used as is if no target/classes suffix --- .../image/sources/ApplicationSourceCache.java | 41 ++---- .../image/sources/GraalVMSourceCache.java | 17 +-- .../hosted/image/sources/JDKSourceCache.java | 6 + .../svm/hosted/image/sources/SourceCache.java | 118 +++++++++++++++--- 4 files changed, 124 insertions(+), 58 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 26ee2f706db1..50877485fd69 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -26,9 +26,6 @@ package com.oracle.svm.hosted.image.sources; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.option.OptionUtils; - import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -53,26 +50,19 @@ protected final SourceCacheType getType() { } private void initSrcRoots() { - String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); - assert javaClassPath != null; - String[] classPathEntries = javaClassPath.split(File.pathSeparator); /* Add dirs or jars found in the classpath */ for (String classPathEntry : classPathEntries) { tryClassPathRoot(classPathEntry); } - if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { - for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { - trySourceRoot(searchPathEntry); - } + for (String sourcePathEntry : sourcePathEntries) { + trySourceRoot(sourcePathEntry); } - /* add the current working directory as a path of last resort */ - srcRoots.add(Paths.get(".")); } - private void tryClassPathRoot(String sourceRoot) { - trySourceRoot(sourceRoot, true); + private void tryClassPathRoot(String classPathEntry) { + trySourceRoot(classPathEntry, true); } - private void trySourceRoot(String sourceRoot) { - trySourceRoot(sourceRoot, false); + private void trySourceRoot(String sourcePathEntry) { + trySourceRoot(sourcePathEntry, false); } private void trySourceRoot(String sourceRoot, boolean fromClassPath) { Path sourcePath = Paths.get(sourceRoot); @@ -103,7 +93,7 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { if (fromClassPath) { /* * for dir entries ending in classes or target/classes - * look for a parallel src tree + * translate to a parallel src tree */ if (sourcePath.endsWith("classes")) { Path parent = sourcePath.getParent(); @@ -111,18 +101,13 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { parent = parent.getParent(); } sourcePath = (parent.resolve("src")); - File file = sourcePath.toFile(); - if (file.exists() && file.isDirectory()) { - srcRoots.add(sourcePath); - } - } - } else { - // try the path as provided - File file = sourcePath.toFile(); - if (file.exists() && file.isDirectory()) { - srcRoots.add(sourcePath); } } + // try the path as provided + File file = sourcePath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(sourcePath); + } } } -} +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 9ce7f603c848..d92c21ab05ee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -26,9 +26,6 @@ package com.oracle.svm.hosted.image.sources; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.option.OptionUtils; - import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -62,17 +59,15 @@ private void initSrcRoots() { for (String classPathEntry : classPathEntries) { tryClassPathRoot(classPathEntry); } - if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { - for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { - trySourceRoot(searchPathEntry); - } + for (String sourcePathEntry : sourcePathEntries) { + tryClassPathRoot(sourcePathEntry); } } - private void tryClassPathRoot(String sourceRoot) { - trySourceRoot(sourceRoot, true); + private void tryClassPathRoot(String classPathEntry) { + trySourceRoot(classPathEntry, true); } - private void trySourceRoot(String sourceRoot) { - trySourceRoot(sourceRoot, false); + private void trySourceRoot(String sourcePathEntry) { + trySourceRoot(sourcePathEntry, false); } private void trySourceRoot(String sourceRoot, boolean fromClassPath) { Path sourcePath = Paths.get(sourceRoot); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index 3268b70aea3f..ef6cb07baa71 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -48,6 +48,12 @@ protected final SourceCacheType getType() { return JDK; } + /* + * properties needed to locate relevant JDK and app source roots + */ + private static final String JAVA_HOME_PROP = "java.home"; + private static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + private void initSrcRoots() { String javaHome = System.getProperty(JAVA_HOME_PROP); assert javaHome != null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index b2ca02ee3985..700cb123b7fd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -25,6 +26,13 @@ package com.oracle.svm.hosted.image.sources; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.option.OptionUtils; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.ImageClassLoader; +import org.graalvm.nativeimage.hosted.Feature; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -34,6 +42,7 @@ import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.List; + /** * An abstract cache manager for some subspace of the * JDK, GraalVM or application source file space. This class @@ -49,12 +58,16 @@ public abstract class SourceCache { - /* - * properties needed to locate relevant JDK and app source roots + /** + * A list of all entries in the classpath used + * by the native image classloader */ - protected static final String JAVA_CLASSPATH_PROP = "java.class.path"; - protected static final String JAVA_HOME_PROP = "java.home"; - protected static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + protected static final List classPathEntries = new ArrayList<>(); + /** + * A list of all entries in the classpath used + * by the native image classloader + */ + protected static final List sourcePathEntries = new ArrayList<>(); /** * A list of root directories which may contain source files * from which this cache can be populated @@ -70,8 +83,8 @@ protected SourceCache() { } /** - * Idenitfy the specific type of this source cache - * @return + * Identify the specific type of this source cache + * @return the source cache type */ protected abstract SourceCacheType getType(); @@ -130,6 +143,17 @@ public File findCandidate(Path filePath) { } return null; } + /** + * Attempt to copy a source file from one of this cache's + * source roots to the local sources directory storing + * it in the subdirectory that belongs to this cache. + * @param filePath a path appended to each of the cache's + * source roots in turn until an acceptable source file + * is found and copied to the local source directory. + * @return the supplied path if the file has been located + * and copied to the local sources directory or null if + * it was not found or the copy failed. + */ public Path tryCacheFile(Path filePath) { for (Path root : srcRoots) { Path targetPath = cachedPath(filePath); @@ -147,9 +171,21 @@ public Path tryCacheFile(Path filePath) { } return null; } + /** + * Check whether the copy of a given source file in the + * local source cache is up to date with respect to any + * original located in this cache's and if not copy the + * original to the subdirectory that belongs to this cache. + * @param filePath a path appended to each of the cache's + * source roots in turn until an matching original source + * is found for comparison against the local source directory. + * @return the supplied path if the file is up to date or if + * an updated version has been copied to the local sources + * directory or null if was not found or the copy failed. + */ public Path checkCacheFile(Path filePath) { + Path targetPath = cachedPath(filePath); for (Path root : srcRoots) { - Path targetPath = cachedPath(filePath); Path sourcePath = extendPath(root, filePath); try { if (checkSourcePath(sourcePath)) { @@ -159,19 +195,23 @@ public Path checkCacheFile(Path filePath) { try { Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); } catch (IOException e) { + /* delete the target file as it is invalid */ + targetPath.toFile().delete(); return null; } } return filePath; - } else { - /* delete the target file as it is out of date */ - targetPath.toFile().delete(); } } catch (IOException e) { - // hmm last modified time blew up? + /* delete the target file as it is invalid */ + targetPath.toFile().delete(); + /* have another go at caching it */ return tryCacheFile(filePath); } } + /* delete the target file as it is invalid */ + targetPath.toFile().delete(); + return null; } /** @@ -218,7 +258,7 @@ protected Path extendPath(Path root, Path filePath) { } /** - * convert a potential resolved candidate path to + * Convert a potential resolved candidate path to * the corresponding local Path in this cache. * @param candidate a resolved candidate path for * some given resolution request @@ -228,7 +268,7 @@ protected Path cachedPath(Path candidate) { return basePath.resolve(candidate); } /** - * convert a potential resolved candidate path to + * Convert a potential resolved candidate path to * the corresponding local File in this cache. * @param candidate a resolved candidate path for * some given resolution request @@ -238,17 +278,20 @@ protected File cachedFile(Path candidate) { return cachedPath(candidate).toFile(); } /** - * indicate whether a source path identifies a fie in the associated file system + * Indicate whether a source path identifies a + * file in the associated file system. * @param sourcePath - * @return true if the path identifies a file or false if no such file can be found - * @throws IOException if there is some error in resolving the path + * @return true if the path identifies a file or + * false if no such file can be found. + * @throws IOException if there is some error in + * resolving the path. */ private boolean checkSourcePath(Path sourcePath) throws IOException { return Files.isRegularFile(sourcePath); } /** - * ensure the directory hierarchy for a path exists - * creating any missing directories if needed + * Ensure the directory hierarchy for a path exists + * creating any missing directories if needed. * @param targetDir a path to the desired directory * @throws IOException if it is not possible to create * one or more directories in the path @@ -261,4 +304,41 @@ private void ensureTargetDirs(Path targetDir) throws IOException { } } } + /** + * Add a path to the list of classpath entries + * @param path The path to add. + */ + private static void addClassPathEntry(String path) { + classPathEntries.add(path); + } + + /** + * Add a path to the list of source path entries + * @param path The path to add. + */ + private static void addSourcePathEntry(String path) { + sourcePathEntries.add(path); + } + + /** + * An automatic feature class which acquires the image + * loader class path via the afterAnalysis callback. + */ + @AutomaticFeature + public static class SourceCacheFeature implements Feature { + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; + ImageClassLoader loader = accessImpl.getImageClassLoader(); + for (String entry : loader.getClasspath()) { + addClassPathEntry(entry); + } + // also add any necessary source path entries + if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { + for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { + addSourcePathEntry(searchPathEntry); + } + } + } + } } From 9579a99b3f661b3864dd66da750fff2327a16b51 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 3 Mar 2020 12:13:14 -0500 Subject: [PATCH 044/130] Move ClassEntry and siblings to package com.oracle.objectfile.debugentry --- .../{elf/dwarf => debugentry}/ClassEntry.java | 16 ++++++++-------- .../{elf/dwarf => debugentry}/DirEntry.java | 2 +- .../{elf/dwarf => debugentry}/FileEntry.java | 2 +- .../{elf/dwarf => debugentry}/PrimaryEntry.java | 6 +++--- .../{elf/dwarf => debugentry}/Range.java | 6 +++--- .../{elf/dwarf => debugentry}/StringEntry.java | 2 +- .../{elf/dwarf => debugentry}/StringTable.java | 2 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 3 +++ .../elf/dwarf/DwarfFrameSectionImpl.java | 2 ++ .../elf/dwarf/DwarfInfoSectionImpl.java | 3 +++ .../elf/dwarf/DwarfLineSectionImpl.java | 5 +++++ .../objectfile/elf/dwarf/DwarfSectionImpl.java | 1 + .../objectfile/elf/dwarf/DwarfSections.java | 6 ++++++ .../elf/dwarf/DwarfStrSectionImpl.java | 1 + 14 files changed, 39 insertions(+), 18 deletions(-) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/ClassEntry.java (94%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/DirEntry.java (97%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/FileEntry.java (97%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/PrimaryEntry.java (96%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/Range.java (91%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/StringEntry.java (98%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/StringTable.java (98%) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java similarity index 94% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java index 6d8714c5ae38..f5034a8254e7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -117,7 +117,7 @@ public ClassEntry(String className, FileEntry fileEntry) { this.totalSize = -1; } - PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { + public PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { if (primaryIndex.get(primary) == null) { PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); primaryEntries.add(primaryEntry); @@ -127,7 +127,7 @@ PrimaryEntry addPrimary(Range primary, List frameSizeInfos return null; } - void addSubRange(Range subrange, FileEntry subFileEntry) { + public void addSubRange(Range subrange, FileEntry subFileEntry) { Range primary = subrange.getPrimary(); /* * the subrange should belong to a primary range @@ -163,7 +163,7 @@ public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { return localFilesIndex.get(fileEntry); } - String getFileName() { + public String getFileName() { return fileEntry.getFileName(); } @@ -175,24 +175,24 @@ String getDirName() { return fileEntry.getPathName(); } - void setCUIndex(int cuIndex) { + public void setCUIndex(int cuIndex) { // should only get set once to a non-negative value assert cuIndex >= 0; assert this.cuIndex == -1; this.cuIndex = cuIndex; } - int getCUIndex() { + public int getCUIndex() { // should have been set before being read assert cuIndex >= 0; return cuIndex; } - int getLineIndex() { + public int getLineIndex() { return lineIndex; } - void setLineIndex(int lineIndex) { + public void setLineIndex(int lineIndex) { this.lineIndex = lineIndex; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java similarity index 97% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index c033986b8be6..c5f6fa045c67 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import java.nio.file.Path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java similarity index 97% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index bc53ec654e64..8c28e018100a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; /** * Tracks debug info associated with a Java source file. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java similarity index 96% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index cd356dd00535..ebebdfec72b5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -104,11 +104,11 @@ public FileEntry getSubrangeFileEntry(Range subrange) { return subrangeIndex.get(subrange); } - List getFrameSizeInfos() { + public List getFrameSizeInfos() { return frameSizeInfos; } - int getFrameSize() { + public int getFrameSize() { return frameSize; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java similarity index 91% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 2608be71322b..a79e6f00219c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,14 +54,14 @@ public class Range { /* * create a primary range */ - Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { + public Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { this(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); } /* * create a primary or secondary range */ - Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { + public Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { /* * currently file name and full method name need to go into the debug_str section * other strings just need to be deduplicated to save space diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java similarity index 98% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java index f08fa4da79c7..d1ebb16be685 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; /** * Used to retain a unique (up to equals) copy of a diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java similarity index 98% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java index b2e0479e5e31..721c77940ee5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import java.util.HashMap; import java.util.Iterator; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 8ae11c436937..c20e9b27af0a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -29,6 +29,9 @@ 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.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import java.util.LinkedList; import java.util.Map; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 3923045bacd4..d8d7ad23af74 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_id; 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 6a07284cb46a..025450fca2de 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 @@ -27,6 +27,9 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import java.util.LinkedList; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 10305904c0ea..aff33ce4f828 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -29,6 +29,11 @@ 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.debugentry.DirEntry; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import java.util.Map; 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 b508ef12f6a9..7b4a1d6fd8b1 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 @@ -31,6 +31,7 @@ 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.ELFObjectFile; import java.nio.ByteOrder; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 0ba4bd7543ea..faa546479b50 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -26,6 +26,12 @@ package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.DirEntry; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; +import com.oracle.objectfile.debugentry.StringTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.elf.ELFMachine; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 0bcdbccb5992..1ee212b112b5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -27,6 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debugentry.StringEntry; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; From e1868eac45bf3d5c77b656cf1caddd74de06d883 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 3 Mar 2020 14:22:25 -0500 Subject: [PATCH 045/130] fix merge issues --- .../com/oracle/svm/core/SubstrateOptions.java | 9 ++- .../hosted/image/sources/NullSourceCache.java | 55 ------------------- 2 files changed, 8 insertions(+), 56 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index cffe17d0beb4..3c2c863dca76 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -49,6 +49,7 @@ import com.oracle.svm.core.option.XOptions; import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; +import static org.graalvm.compiler.options.OptionType.User; public class SubstrateOptions { @@ -394,12 +395,18 @@ public static Predicate makeFilter(String[] definedFilters) { @Option(help = "Fold SecurityManager getter.", stability = OptionStability.EXPERIMENTAL, type = OptionType.Expert) // public static final HostedOptionKey FoldSecurityManagerGetter = new HostedOptionKey<>(true); + @APIOption(name = "native-compiler-path")// @Option(help = "Provide custom path to C compiler used for query code compilation and linking.", type = OptionType.User)// public static final HostedOptionKey CCompilerPath = new HostedOptionKey<>(null); + @APIOption(name = "native-compiler-options")// @Option(help = "Provide custom C compiler option used for query code compilation.", type = OptionType.User)// public static final HostedOptionKey CCompilerOption = new HostedOptionKey<>(new String[0]); - @Option(help = "Provide a path for the libmusl bundle so the resulting object file is linked against it.", type = OptionType.Expert)// + @APIOption(name = "native-image-info")// + @Option(help = "Show native-toolchain information and image-build settings", type = User)// + public static final HostedOptionKey DumpTargetInfo = new HostedOptionKey<>(false); + + @Option(help = "file:doc-files/UseMuslCHelp.txt", type = OptionType.Expert)// public static final HostedOptionKey UseMuslC = new HostedOptionKey<>(null); /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java deleted file mode 100644 index 18a72010f721..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/NullSourceCache.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 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.svm.hosted.image.sources; - -import java.nio.file.Path; - -public class NullSourceCache extends SourceCache { - /** - * Create a cache that does nothing. - * Assumes the sources are in their original locations, - * to be resolved at debug time. - * - * Why might this be useful? - * - Shorter compile turnaround - * - the original cache doesn't account for C/C++ native code - */ - protected NullSourceCache(String cacheKey) { - super(cacheKey); - } - - /** - * Just return the original path. - * - * @param filePath a prototype path for a source file - * @return the original path - */ - @Override - public Path resolve(Path filePath) { - return filePath; - } -} From 79cd4122f1c964403311c2a3bf02d21108a4703c Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 3 Mar 2020 14:23:18 -0500 Subject: [PATCH 046/130] if generating debug info, don't strip local symbols --- .../src/com/oracle/svm/core/SubstrateOptions.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 3c2c863dca76..761fcb445899 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -426,6 +426,9 @@ protected void onValueUpdate(EconomicMap, Object> values, Integer o if (newValue > 0 && !Boolean.TRUE.equals(values.get(TrackNodeSourcePosition))) { TrackNodeSourcePosition.update(values, true); } + if (newValue > 0 && !Boolean.FALSE.equals(values.get(DeleteLocalSymbols))) { + DeleteLocalSymbols.update(values, false); + } } }; From 38b197493ed49588a89c6daaf258743713449460 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 3 Mar 2020 17:35:47 -0500 Subject: [PATCH 047/130] refctor codeview code to use existing Range/ClassEntry classes --- .../oracle/objectfile/debugentry/Range.java | 39 +- .../objectfile/pecoff/cv/CVFileRecord.java | 146 ++++ .../objectfile/pecoff/cv/CVLineRecord.java | 14 +- .../pecoff/cv/CVLineRecordBuilder.java | 15 +- .../pecoff/cv/CVStringTableRecord.java | 71 ++ .../objectfile/pecoff/cv/CVSymbolRecord.java | 164 +--- .../pecoff/cv/CVSymbolRecordBuilder.java | 19 +- .../pecoff/cv/CVSymbolSectionImpl.java | 12 +- .../pecoff/cv/CVSymbolSubrecord.java | 9 +- .../objectfile/pecoff/cv/DebugInfoBase.java | 818 ++++-------------- 10 files changed, 462 insertions(+), 845 deletions(-) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index a79e6f00219c..8e52023ee5e6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -36,6 +36,10 @@ */ public class Range { + + /* TODO this should be '.' for PECOFF files */ + private static final String CLASS_DELIMITER = "::"; + private String fileName; private Path filePath; private String className; @@ -79,6 +83,26 @@ public Range(String fileName, Path filePath, String className, String methodName this.primary = primary; } + /* + * Create a slightly different copy of a previously constructed range. + * Because the previous range was constructed by one of the other constructors, + * a valid assumption is that all the strings have previously been inserted int he stringTable, + * and we can avoid doing that again. + */ + public Range(Range other, int lo, int hi) { + this.fileName = other.fileName; + this.filePath = other.filePath; + this.className = other.className; + this.methodName = other.methodName; + this.paramNames = other.paramNames; + this.returnTypeName = other.returnTypeName; + this.fullMethodName = other.fullMethodName; + this.lo = lo; + this.hi = hi; + this.line = other.line; + this.primary = other.primary; + } + public boolean contains(Range other) { return (lo <= other.lo && hi >= other.hi); } @@ -131,6 +155,19 @@ public String getFullMethodName() { return fullMethodName; } + public String getParamNames() { + return paramNames; + } + + public String getClassAndMethodName() { + StringBuilder builder = new StringBuilder(); + if (className != null) { + builder.append(className).append(CLASS_DELIMITER); + } + builder.append(methodName); + return builder.toString(); + } + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); if (includeReturnType && returnTypeName.length() > 0) { @@ -139,7 +176,7 @@ public String getExtendedMethodName(boolean includeParams, boolean includeReturn } if (className != null) { builder.append(className); - builder.append("::"); + builder.append(CLASS_DELIMITER); } builder.append(methodName); if (includeParams && !paramNames.isEmpty()) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java new file mode 100644 index 000000000000..b3c2e7c04e73 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.debugentry.FileEntry; + +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.util.Hashtable; +import java.util.Map; + +final class CVFileRecord extends CVSymbolRecord { + + private static final byte CHECKSUM_NONE = 0x00; + private static final byte CHECKSUM_MD5 = 0x01; + private static final byte CB_VALUE = 0x10; + + private static final int FILE_RECORD_LENGTH = 24; + + private static final int CHECKSUM_LENGTH = 16; + private static final byte[] EMPTY_CHECKSUM = new byte[CHECKSUM_LENGTH]; + + private final CVSections cvSections; + private final CVSymbolSectionImpl.CVStringTable strings; + private Map fileToOFfsetMap; + + CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { + super(cvSections, DEBUG_S_FILECHKSMS); + this.cvSections = cvSections; + this.strings = strings; + } + + /* + * Convert a simple path into an absolute path by determining if it's + * part of Graal, the JDK, or use code. + * + * Currently, don't even try; use the SourceCache system + */ + private String fixPath(String fn) { + return fn; + } + + public int getFileEntryOffset(FileEntry entry) { + return fileToOFfsetMap.get(entry); + } + + @Override + public int computeSize(int initialPos) { + if (cvSections.getFiles().isEmpty()) { + return initialPos; + } + /* first, insert fileIds into file id array for use by line number table */ + fileToOFfsetMap = new Hashtable<>(cvSections.getFiles().size()); + int fileId = 0; + int fileIndex = 0; + for (FileEntry entry : cvSections.getFiles()) { + fileToOFfsetMap.put(entry, fileId); + strings.add(fixPath(entry.getFileName())); // create required stringtable entries + fileId += FILE_RECORD_LENGTH; + } + return initialPos + (cvSections.getFiles().size() * FILE_RECORD_LENGTH); + } + + private int put(FileEntry entry, byte[] buffer, int initialPos) { + String fn = fixPath(entry.getFileName()); + int stringId = strings.add(fn); + int pos = CVUtil.putInt(stringId, buffer, initialPos); /* stringtable index */ + pos = CVUtil.putByte(CB_VALUE, buffer, pos); /* Cb (unknown what this is) */ + byte[] checksum = calculateMD5Sum(fn); + if (checksum != null) { + pos = CVUtil.putByte(CHECKSUM_MD5, buffer, pos); /* checksum type (0x01 == MD5) */ + pos = CVUtil.putBytes(checksum, buffer, pos); + } else { + pos = CVUtil.putByte(CHECKSUM_NONE, buffer, pos); + pos = CVUtil.putBytes(EMPTY_CHECKSUM, buffer, pos); + } + pos = CVUtil.align4(pos); + return pos; + } + + private byte[] calculateMD5Sum(String fn) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(Files.readAllBytes(Paths.get(fn))); + return md.digest(); + } catch (NoSuchFileException e) { + return null; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + @Override + public int computeContents(byte[] buffer, int pos) { + CVUtil.debug("file computeContents(%d) nf=%d\n", pos, cvSections.getFiles().size()); + for (FileEntry entry : cvSections.getFiles()) { + pos = put(entry, buffer, pos); + } + return pos; + } + + @Override + public String toString() { + return "CVFileRecord(type=" + type + ",pos=" + pos + ", size=" + 999 + ")"; + } + + @Override + public void dump(PrintStream out) { + int idx = 0; + int offset = 0; + out.format("%s:\n", this); + for (FileEntry entry : cvSections.getFiles()) { + out.format("%4d 0x%08x %2d %2d %s\n", idx, offset, 0x10, 1, entry.getFileName()); + idx += 1; + offset += 24; + } + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 8ef5cefbfd36..1cf488d192d7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -26,8 +26,8 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.FileEntry; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.PrimaryEntry; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.ObjectFile; import java.util.ArrayList; @@ -60,9 +60,11 @@ private static class FileBlock { ArrayList lineEntries = new ArrayList<>(DEFAULT_LINE_ENTRY_COUNT); int highAddr = 0; FileEntry file; + int fileId; - FileBlock(FileEntry file) { + FileBlock(FileEntry file, int fileId) { this.file = file; + this.fileId = fileId; } void addEntry(LineEntry le) { @@ -72,7 +74,7 @@ void addEntry(LineEntry le) { int computeContents(byte[] buffer, int initialPos) { int pos = initialPos; - pos = CVUtil.putInt(file.getFileId(), buffer, pos); + pos = CVUtil.putInt(fileId, buffer, pos); pos = CVUtil.putInt(lineEntries.size(), buffer, pos); /* if HAS_COLUMNS is true, this formula is incorrect */ assert !HAS_COLUMNS; @@ -134,7 +136,9 @@ int computeContents(byte[] buffer, int initialPos) { } void addNewFile(FileEntry file) { - fileBlocks.add(new FileBlock(file)); + CVFileRecord fr = cvSections.getCVSymbolSection().getFileRecord(); + int fileId = fr.getFileEntryOffset(file); + fileBlocks.add(new FileBlock(file, fileId)); } void addNewLine(int addr, int line) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index b0bc8cf4e7fe..6df205e06b7e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -26,9 +26,9 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.FileEntry; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.PrimaryEntry; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.Range; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import static com.oracle.objectfile.pecoff.cv.CVConstants.skipGraalInternals; import static com.oracle.objectfile.pecoff.cv.CVConstants.skipGraalIntrinsics; @@ -105,15 +105,12 @@ private void processRange(Range range) { /* should we merge this range with the previous entry? */ if (shouldMerge(previousRange, range)) { - Range newRange = new Range(previousRange); - newRange.setLo(range.getLo()); - newRange.setHi(range.getHi()); - range = newRange; + range = new Range(previousRange, range.getLo(), range.getHi()); } else if (range.getLine() == -1) { return; } - boolean wantNewFile = previousRange == null || !previousRange.sameFileName(range); + boolean wantNewFile = previousRange == null || !previousRange.getFileName().equals(range.getFileName()); if (wantNewFile) { FileEntry file = cvSections.ensureFileEntry(range); previousRange = null; @@ -140,7 +137,7 @@ private boolean shouldMerge(Range previousRange, Range range) { if (skipGraalIntrinsics && isGraalIntrinsic(range.getClassName())) { return true; } - return previousRange.sameFileName(range) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); + return previousRange.getFileName().equals(range.getFileName()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); } private boolean wantNewRange(Range previous, Range range) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java new file mode 100644 index 000000000000..22403573b4ce --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import java.io.PrintStream; + +final class CVStringTableRecord extends CVSymbolRecord { + + private final CVSymbolSectionImpl.CVStringTable stringTable; + + CVStringTableRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable stringTable) { + super(cvSections, DEBUG_S_STRINGTABLE); + this.stringTable = stringTable; + } + + int add(String string) { + return stringTable.add(string); + } + + @Override + public int computeSize(int pos) { + return computeContents(null, pos); + } + + @Override + public int computeContents(byte[] buffer, int pos) { + for (CVSymbolSectionImpl.CVStringTable.StringTableEntry entry : stringTable.values()) { + pos = CVUtil.putUTF8StringBytes(entry.text, buffer, pos); + } + return pos; + } + + @Override + public String toString() { + return String.format("CVStringTableRecord(type=0x%04x pos=0x%06x size=%d)", type, pos, stringTable.size()); + } + + @Override + public void dump(PrintStream out) { + int idx = 0; + out.format("%s:\n", this); + for (CVSymbolSectionImpl.CVStringTable.StringTableEntry entry : stringTable.values()) { + out.format("%4d 0x%08x %s\n", idx, entry.offset, entry.text); + idx += 1; + } + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index b83e05e29e54..00407fdc652c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -26,7 +26,7 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.FileEntry; +import com.oracle.objectfile.debugentry.FileEntry; import java.io.PrintStream; import java.nio.file.Files; @@ -78,166 +78,4 @@ public void dump(PrintStream out) { out.format("%s\n", this); } - static final class CVStringTableRecord extends CVSymbolRecord { - - private final CVSymbolSectionImpl.CVStringTable stringTable; - - CVStringTableRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable stringTable) { - super(cvSections, DEBUG_S_STRINGTABLE); - this.stringTable = stringTable; - } - - int add(String string) { - return stringTable.add(string); - } - - @Override - public int computeSize(int pos) { - return computeContents(null, pos); - } - - @Override - public int computeContents(byte[] buffer, int pos) { - for (CVSymbolSectionImpl.CVStringTable.StringTableEntry entry : stringTable.values()) { - pos = CVUtil.putUTF8StringBytes(entry.text, buffer, pos); - } - return pos; - } - - @Override - public String toString() { - return String.format("CVStringTableRecord(type=0x%04x pos=0x%06x size=%d)", type, pos, stringTable.size()); - } - - @Override - public void dump(PrintStream out) { - int idx = 0; - out.format("%s:\n", this); - for (CVSymbolSectionImpl.CVStringTable.StringTableEntry entry : stringTable.values()) { - out.format("%4d 0x%08x %s\n", idx, entry.offset, entry.text); - idx += 1; - } - } - } - - static final class CVFileRecord extends CVSymbolRecord { - - static final boolean debug = false; - - static final byte CHECKSUM_NONE = 0x00; - static final byte CHECKSUM_MD5 = 0x01; - static final byte CB_VALUE = 0x10; - - static final int FILE_RECORD_LENGTH = 24; - - static final int CHECKSUM_LENGTH = 16; - static final byte[] EMPTY_CHECKSUM = new byte[CHECKSUM_LENGTH]; - - final CVSections cvSections; - final CVSymbolSectionImpl.CVStringTable strings; - - CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { - super(cvSections, DEBUG_S_FILECHKSMS); - this.cvSections = cvSections; - this.strings = strings; - } - - /* - * Convert a simple path into an absolute path by determining if it's - * part of Graal, the JDK, or use code. - * - * This method is incompletely implemented. - * TODO: replace this with the new SourceCache system - */ - private String fixPath(String fn) { - String substrateDir = GRAAL_SOURCE_BASE + "substratevm\\src\\"; - String compilerDir = GRAAL_SOURCE_BASE + "compiler\\src\\"; - String newFn; - if (fn.startsWith("com/oracle/svm/core/snippets")) { - newFn = substrateDir + "com.oracle.svm.core.snippets\\src\\" + fn.replace("/", "\\"); - } else if (fn.startsWith("org/graalvm/compiler/replacements")) { - newFn = compilerDir + "org.graalvm.compiler.replacements\\src\\" + fn.replace("/", "\\"); - } else if (fn.startsWith("com/oracle/svm/core/genscavenge")) { - newFn = substrateDir + "com.oracle.svm.core.genscavenge\\src\\" + fn.replace("/", "\\"); - } else if (fn.startsWith("com/oracle/svm/core")) { - newFn = substrateDir + "com.oracle.svm.core\\src\\" + fn.replace("/", "\\"); - } else if (CVRootPackages.isJavaFile(fn)) { - newFn = JDK_SOURCE_BASE + fn.replace("/", "\\"); - } else { - newFn = fn; - } - return newFn; - } - - @Override - public int computeSize(int initialPos) { - if (cvSections.getFiles().isEmpty()) { - return initialPos; - } - /* first, insert fileIds into file table for use by line number table */ - int fileId = 0; - for (FileEntry entry : cvSections.getFiles()) { - entry.setFileId(fileId); - strings.add(fixPath(entry.getFileName())); // create required stringtable entries - fileId += FILE_RECORD_LENGTH; - } - return initialPos + (cvSections.getFiles().size() * FILE_RECORD_LENGTH); - } - - private int put(FileEntry entry, byte[] buffer, int initialPos) { - String fn = fixPath(entry.getFileName()); - int stringId = strings.add(fn); - int pos = CVUtil.putInt(stringId, buffer, initialPos); /* stringtable index */ - pos = CVUtil.putByte(CB_VALUE, buffer, pos); /* Cb (unknown what this is) */ - byte[] checksum = calculateMD5Sum(fn); - if (checksum != null) { - pos = CVUtil.putByte(CHECKSUM_MD5, buffer, pos); /* checksum type (0x01 == MD5) */ - pos = CVUtil.putBytes(checksum, buffer, pos); - } else { - pos = CVUtil.putByte(CHECKSUM_NONE, buffer, pos); - pos = CVUtil.putBytes(EMPTY_CHECKSUM, buffer, pos); - } - pos = CVUtil.align4(pos); - return pos; - } - - private byte[] calculateMD5Sum(String fn) { - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(Files.readAllBytes(Paths.get(fn))); - return md.digest(); - } catch (NoSuchFileException e) { - return null; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public int computeContents(byte[] buffer, int pos) { - CVUtil.debug("file computeContents(%d) nf=%d\n", pos, cvSections.getFiles().size()); - for (FileEntry entry : cvSections.getFiles()) { - pos = put(entry, buffer, pos); - } - return pos; - } - - @Override - public String toString() { - return "CVFileRecord(type=" + type + ",pos=" + pos + ", size=" + 999 + ")"; - } - - @Override - public void dump(PrintStream out) { - int idx = 0; - int offset = 0; - out.format("%s:\n", this); - for (FileEntry entry : cvSections.getFiles()) { - out.format("%4d 0x%08x %2d %2d %s\n", idx, offset, 0x10, 1, entry.getFileName()); - idx += 1; - offset += 24; - } - } - } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 552f0ab208d2..b07138a1df76 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -26,9 +26,9 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.ClassEntry; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.PrimaryEntry; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.Range; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import static com.oracle.objectfile.pecoff.cv.CVConstants.functionNamesHashArgs; import static com.oracle.objectfile.pecoff.cv.CVConstants.replaceMainFunctionName; @@ -50,6 +50,15 @@ final class CVSymbolRecordBuilder { private boolean noMainFound = true; + /** + * renames a method name ot something user friendly in the debugger + * (does not affect external symbols + * first main function becomes class.main (unless replaceMainFunctionName is non-null) + * if functionNamesHashArgs is true (which it must be for the linker to work properly) + * all other functions become class.function.999 (where 999 is a hash of the arglist) + * @param range Range contained in the method of interest + * @return user debugger friendly method name + */ private String fixMethodName(Range range) { final String methodName; if (replaceMainFunctionName != null && noMainFound && range.getMethodName().equals("main")) { @@ -63,9 +72,9 @@ private String fixMethodName(Range range) { long hash = ((long) range.getParamNames().hashCode()) & 0xffffffffL; methodName = range.getClassAndMethodName() + "." + hash; } else { - methodName = range.getClassAndMethodNameWithParams(); + methodName = range.getFullMethodName(); } - CVUtil.debug("replacing %s with %s\n", range.getClassAndMethodNameWithParams(), methodName); + CVUtil.debug("replacing %s with %s\n", range.getFullMethodName(), methodName); return methodName; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java index dbde248830dc..2c5ab84194ae 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java @@ -44,6 +44,8 @@ public final class CVSymbolSectionImpl extends CVSectionImplBase { private static final int CV_STRINGTABLE_DEFAULT_SIZE = 200; private CVSections cvSections; + private CVFileRecord fileRecord; + private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); private CVStringTable stringTable = new CVStringTable(CV_STRINGTABLE_DEFAULT_SIZE); @@ -127,12 +129,16 @@ private void addTypeRecords() { } private void addFileRecords() { - CVSymbolRecord fileChecksums = new CVSymbolRecord.CVFileRecord(cvSections, stringTable); - addRecord(fileChecksums); + this.fileRecord = new CVFileRecord(cvSections, stringTable); + addRecord(fileRecord); + } + + public CVFileRecord getFileRecord() { + return fileRecord; } private void addStringTableRecord() { - CVSymbolRecord stringTableRecord = new CVSymbolRecord.CVStringTableRecord(cvSections, stringTable); + CVSymbolRecord stringTableRecord = new CVStringTableRecord(cvSections, stringTable); addRecord(stringTableRecord); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index 10769f701235..8b436669df1a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -26,10 +26,9 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.pecoff.cv.DebugInfoBase.ClassEntry; - import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.SectionName; +import com.oracle.objectfile.debugentry.ClassEntry; import java.util.HashMap; import java.util.Map; @@ -37,7 +36,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; /* - * a CVSymbolSubrecord is a record in a DEBUG_S_SYMBOL record within a debug$S section + * a CVSymbolSubrecord is a record in a DEBUG_S_SYMBOL record within a .debug$S section within a PECOFF file */ abstract class CVSymbolSubrecord { @@ -76,7 +75,7 @@ public String toString() { public static final class CVObjectNameRecord extends CVSymbolSubrecord { - String objName; /* TODO: how to find this? full path to object file we will produce */ + String objName; /* TODO: how to find the full path to object file we will produce */ CVObjectNameRecord(CVSections cvSections, String objName) { super(cvSections, CVDebugConstants.S_OBJNAME); @@ -211,7 +210,7 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { /* argument list */ //map.put("cmd", "-Zi -MT -wishfulthinking"); - /* find first source file */ + /* find first source file - which, for Graal would be a class file on the command line */ String fn = findFirstFile(cvSections); if (fn != null) { map.put("src", fn); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index 6753ac031cc5..031f834e3df7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -26,10 +26,17 @@ package com.oracle.objectfile.pecoff.cv; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.DirEntry; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; +import com.oracle.objectfile.debugentry.StringTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import java.io.PrintStream; - +import java.nio.ByteOrder; +import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.LinkedList; @@ -55,44 +62,60 @@ private boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + /* + * ensure we have a null string in the string section + */ + uniqueDebugString(""); + debugInfoProvider.codeInfoProvider().filter(debugCodeInfo -> isWanted(debugCodeInfo)).forEach(debugCodeInfo -> { + /* + * primary file name and full method name need to be written to the debug_str section + */ String fileName = debugCodeInfo.fileName(); - String className = debugCodeInfo.className(); + Path filePath = debugCodeInfo.filePath(); + // switch '$' in class names for '.' + String className = debugCodeInfo.className().replaceAll("\\$", "."); String methodName = debugCodeInfo.methodName(); String paramNames = debugCodeInfo.paramNames(); String returnTypeName = debugCodeInfo.returnTypeName(); int lo = debugCodeInfo.addressLo(); int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); - Range primary = new Range(fileName, className, methodName, paramNames, returnTypeName, lo, hi, primaryLine); CVUtil.debug("primaryrange: [0x%08x,0x%08x,l=%d) %s.%s(%s) %s\n", lo, hi, primaryLine, className, methodName, paramNames, fileName); - /* create an infoSection entry for the method */ - addRange(primary); - + Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); + /* + * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, + * returnTypeName, className, methodName, paramNames, fileName); + * create an infoSection entry for the method + */ + addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); - String classNameAtLine = debugLineInfo.className(); + Path filePathAtLine = debugLineInfo.filePath(); + // switch '$' in class names for '.' + String classNameAtLine = debugLineInfo.className().replaceAll("\\$", "."); String methodNameAtLine = debugLineInfo.methodName(); int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); int line = debugLineInfo.line(); + /* + * record all subranges even if they have no line or file so we at least get a + * symbol for them + */ if (fileNameAtLine.length() > 0 && primaryLine >= 0) { //CVUtil.debug(" lineinfo: [0x%08x,0x%08x) %s.%s (%s:%d)\n", loAtLine, hiAtLine, classNameAtLine, methodNameAtLine, fileNameAtLine, line); - Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", loAtLine, hiAtLine, line, primary); - addSubRange(primary, subRange); + Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); + addSubRange(primaryRange, subRange); } }); }); /* - ObjectFile.DebugInfoProvider.DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - for (ObjectFile.DebugInfoProvider.DebugDataInfo debugDataInfo : dataInfoProvider) { - String name = debugDataInfo.toString(); - //CVUtil.debug("debuginfo %s\n", name); - }*/ - } - - public LinkedList getPrimaryClasses() { - return primaryClasses; + * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + * for (DebugDataInfo debugDataInfo : dataInfoProvider) { + * install details of heap elements + * String name = debugDataInfo.toString(); + * } + */ } public LinkedList getFiles() { @@ -103,63 +126,17 @@ public LinkedList getPrimaryFiles() { return primaryFiles; } - private void dumpFiles(PrintStream out, String descr, LinkedList files) { - int n = 50; - out.format("%s files count=%d\n", descr, files.size()); - for (FileEntry entry : files) { - if (n-- < 0) { - break; - } - out.format(" file:%s\n", entry); - } - } - - private void dumpClasses(PrintStream out, String descr, LinkedList classes) { - int n = 50; - out.format("%s classes count=%d\n", descr, classes.size()); - for (ClassEntry entry : classes) { - if (n-- < 0) { - break; - } - entry.dump(out); - } - } - - public void dumpAll(PrintStream out) { - //dump(out, "primary", getPrimaryFiles(), 0); - //dump(out, "all", getFiles(), 0); - //dump(out, "primary", primaryClasses); - } - - public void addRange(Range primary) { - assert primary.isPrimary(); - ClassEntry classEntry = ensureClassEntry(primary); - PrimaryEntry entry = classEntry.addPrimary(primary); - if (entry != null) { - /* track the entry for this range in address order */ - primaryEntries.add(entry); - } - } - - public void addSubRange(Range primary, Range subrange) { - assert primary.isPrimary(); - assert !subrange.isPrimary(); - String className = primary.getClassName(); - ClassEntry classEntry = primaryClassesIndex.get(className); - FileEntry subrangeEntry = ensureFileEntry(subrange); - /* the primary range should already have been seen */ - /* and associated with a primary class entry */ - assert classEntry.primaryIndex.get(primary) != null; - classEntry.addSubRange(subrange, subrangeEntry); - } - - public ClassEntry ensureClassEntry(Range range) { + private ClassEntry ensureClassEntry(Range range) { String className = range.getClassName(); - /* see if we already have an entry */ + /* + * see if we already have an entry + */ ClassEntry classEntry = primaryClassesIndex.get(className); if (classEntry == null) { - /* create and index the entry associating it with the right file */ - FileEntry fileEntry = ensureFileEntry(range); + /* + * create and index the entry associating it with the right file + */ + FileEntry fileEntry = ensureFileEntry(range); classEntry = new ClassEntry(className, fileEntry); primaryClasses.add(classEntry); primaryClassesIndex.put(className, classEntry); @@ -168,90 +145,99 @@ public ClassEntry ensureClassEntry(Range range) { return classEntry; } - public FileEntry ensureFileEntry(Range range) { + FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); - /* ensure we have an entry */ - FileEntry fileEntry = filesIndex.get(fileName); + Path filePath = range.getFilePath(); + Path fileAsPath = range.getFileAsPath(); + /* + * ensure we have an entry + */ + FileEntry fileEntry = filesIndex.get(fileAsPath); if (fileEntry == null) { - int idx = files.size() + 1; - DirEntry dirEntry = ensureDirEntry(fileName); + DirEntry dirEntry = ensureDirEntry(filePath); fileEntry = new FileEntry(fileName, dirEntry); - fileEntry.setFileId(idx); files.add(fileEntry); - filesIndex.put(fileName, fileEntry); - /* if this is a primary entry then add it to the primary list */ + filesIndex.put(fileAsPath, fileEntry); + /* + * if this is a primary entry then add it to the primary list + */ if (range.isPrimary()) { primaryFiles.add(fileEntry); } else { Range primaryRange = range.getPrimary(); - FileEntry primaryEntry = filesIndex.get(primaryRange.fileName); + FileEntry primaryEntry = filesIndex.get(primaryRange.getFileAsPath()); assert primaryEntry != null; } } return fileEntry; } - private DirEntry ensureDirEntry(String file) { - if (file.startsWith("/")) { - /* absolute path means use dir entry 0 */ - return null; - } - int pathLength = file.lastIndexOf('/'); - if (pathLength < 0) { - /* no path/package means use dir entry 0 */ + private void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { + assert primaryRange.isPrimary(); + ClassEntry classEntry = ensureClassEntry(primaryRange); + PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); + } + + private void addSubRange(Range primaryRange, Range subrange) { + assert primaryRange.isPrimary(); + assert !subrange.isPrimary(); + String className = primaryRange.getClassName(); + ClassEntry classEntry = primaryClassesIndex.get(className); + FileEntry subrangeEntry = ensureFileEntry(subrange); + /* + * the primary range should already have been seen + * and associated with a primary class entry + */ + assert classEntry.primaryIndexFor(primaryRange) != null; + classEntry.addSubRange(subrange, subrangeEntry); + } + + private DirEntry ensureDirEntry(Path filePath) { + if (filePath == null) { return null; } - String filePath = file.substring(0, pathLength); - int idx = 0; - String dirPkgMatch = ""; - /* find matching package and see if we already have the right path */ - for (DirEntry dir : dirs) { - if (dir.packageMatches(filePath)) { - if (dir.dirMatches(filePath)) { - /* this is a best fit dir */ - return dir; - } - String dirPkg = dir.getPkg(); - if (dirPkg.length() > dirPkgMatch.length()) { - dirPkgMatch = dirPkg; - } - } - idx++; + DirEntry dirEntry = dirsIndex.get(filePath); + if (dirEntry == null) { + dirEntry = new DirEntry(filePath); + dirsIndex.put(filePath, dirEntry); + dirs.add(dirEntry); } - - DirEntry newDir; - if (dirPkgMatch.length() == 0) { - /* no root package so this is user code */ - newDir = new DirEntry(filePath, false); - } else { - newDir = new DirEntry(dirPkgMatch, filePath); - } - - dirs.addLast(newDir); - return newDir; + return dirEntry; + } + public StringTable getStringTable() { + return stringTable; + } + public LinkedList getPrimaryClasses() { + return primaryClasses; } - /* - * list detailing all dirs in which files are found to reside - * either as part of substrate/compiler or user code - */ - private LinkedList dirs = new LinkedList(); - - /* - * The obvious traversal structure for debug records is - * 1) by top level compiled method (primary Range) ordered by ascending address - * 2) by inlined method (sub range) within top level method ordered by ascending address - * this ensures that all debug records are generated in increasing address order + /** + * a table listing all known strings, some of + * which may be marked for insertion into the + * debug_str section. */ + private StringTable stringTable = new StringTable(); - /* - * a list recording details of all primary ranges included in - * this file sorted by ascending address range + /** + * list detailing all dirs in which files are found to reside + * either as part of substrate/compiler or user code. + */ + private LinkedList dirs = new LinkedList<>(); + /** + * index of already seen dirs. */ - private LinkedList primaryEntries = new LinkedList(); + private Map dirsIndex = new HashMap<>(); /* + * The obvious traversal structure for debug records is: + * + * 1) by top level compiled method (primary Range) ordered by ascending address + * 2) by inlined method (sub range) within top level method ordered by ascending address + * + * these can be used to ensure that all debug records are generated in increasing address order + * * An alternative traversal option is + * * 1) by top level class (String id) * 2) by top level compiled method (primary Range) within a class ordered by ascending address * 3) by inlined method (sub range) within top level method ordered by ascending address @@ -261,6 +247,7 @@ private DirEntry ensureDirEntry(String file) { * or data values. this means we can treat each class as a compilation unit, allowing * data common to all methods of the class to be shared. * + * A third option appears to be to traverse via files, then top level class within file etc. * Unfortunately, files cannot be treated as the compilation unit. A file F may contain * multiple classes, say C1 and C2. There is no guarantee that methods for some other * class C' in file F' will not be compiled into the address space interleaved between @@ -268,535 +255,58 @@ private DirEntry ensureDirEntry(String file) { * time would allow more sharing e.g. enabling all classes in a file to share a single copy * of the file and dir tables. */ - /* list of class entries detaling class info for primary ranges */ - private LinkedList primaryClasses = new LinkedList(); - /* index of already seen classes */ - private Map primaryClassesIndex = new HashMap<>(); - - /* List of files which contain primary ranges */ - private LinkedList primaryFiles = new LinkedList(); - /* List of files which contain primary or secondary ranges */ - private LinkedList files = new LinkedList(); - /* index of already seen files */ - private Map filesIndex = new HashMap<>(); - - // files may be located in a source directory associated - // with a well known substratevm or compiler root package - // in that case the the file's directory path will be something - // like "foo.bar.baz/src/foo/bar/baz/mumble/grumble/bletch" - // i.e. the root package and "src" will be inserted as a prefix - // before the dirs derived from the actual package - // files whose package does not match a well-known root package - // will be listed using the dirs derived from the package - // i.e. simply "foo/bar/baz/mumble/grumble/bletch" - - public static final class DirEntry { - // root package associated with substrate/compiler - // class or empty string for user class - private String pkg; - // element of dir path derived from class's package name - // which may be prefixed by a substrate/compiler path - // or may just be the user source path - private String dir; - // full path potentially including substrate/compiler - // prefix and "/src/" separator as prefix to value - // stored in dir or may just be the value in dir - private String fullPath; - // create an entry for a root package path - // or a user path not under a root package - public DirEntry(String name, boolean isPkg) { - if (isPkg) { - assert pkg.indexOf('/') < 0; - this.pkg = name; - this.dir = name.replace('.', '/'); - this.fullPath = pkg + "/src/" + dir; - } else { - assert name.indexOf('.') > 0; - this.pkg = ""; - this.dir = name; - this.fullPath = name; - } - } - - // create an entry for a path located within a root package - // the supplied dir must be - public DirEntry(String pkg, String dir) { - this.pkg = pkg; - assert (packageMatches(dir)); - this.dir = dir; - this.fullPath = pkg + "/src/" + dir; - } - - // does this entry sit in a substrate/compiler root package - public boolean hasPackage() { - return pkg.length() == 0; - } - - // does this entry's package (if any) match the dir path - public boolean packageMatches(String dir) { - int l = pkg.length(); - // dir must extend l - if (dir.length() < l) { - return false; - } - // pkg may only differ from l by '.' for '/' - for (int i = 0; i < pkg.length(); i++) { - char c1 = dir.charAt(i); - char c2 = pkg.charAt(i); - if (c1 != c2) { - if (c1 != '/' || c2 != '.') { - return false; - } - } - } - // if the dir is any longer than the root - // package - if (l < dir.length()) { - if (dir.charAt(l) != '/') { - return false; - } - } - - return true; - } - - public boolean dirMatches(String dir) { - // caller must ensure this entry has an appropriate package - assert !hasPackage() || packageMatches(dir); - return this.dir.equals(dir); - } - public String getPkg() { - return pkg; - } - public String getFullPath() { - return fullPath; - } - - @Override - public String toString() { - return String.format("direntry(fullpath=%s)", fullPath); - } - } - - public static final class FileEntry { - // the name of the associated file - private String fileName; - // the directory entry associated with this file entry - private DirEntry dirEntry; - // the fileID assigned to this file - // the fileID in CV4 debug info is simply the offset from the start of the file table - // the file table is composed of fixed size entries, so can be calculated as sizeof(entry) * file index - private int fileId = -1; - - FileEntry(String fileName, DirEntry dirEntry) { - this.fileName = fileName; - this.dirEntry = dirEntry; - } - - String getDirName() { - return (dirEntry != null ? dirEntry.getFullPath() : ""); - } - - public String getFileName() { - return fileName; - } - - public String getPath() { - return fileName; - } - - public void setFileId(int fileId) { - assert (this.fileId == -1); - this.fileId = fileId; - } + /** + * list of class entries detailing class info for primary ranges. + */ + private LinkedList primaryClasses = new LinkedList<>(); + /** + * index of already seen classes. + */ + private Map primaryClassesIndex = new HashMap<>(); - public int getFileId() { - return fileId; - } + /** + * list of files which contain primary ranges. + */ + private LinkedList primaryFiles = new LinkedList<>(); + /** + * List of files which contain primary or secondary ranges. + */ + private LinkedList files = new LinkedList<>(); + /** + * index of already seen files. + */ + private Map filesIndex = new HashMap<>(); - public String toString() { - final String idStr = fileId == -1 ? "" : "(id=" + fileId + ")"; - return String.format("fileentry(%s id=%s dir=%s)", fileName, idStr, dirEntry); - } + /** + * indirects this call to the string table. + * @param string the string to be inserted + * @return a unique equivalent String + */ + public String uniqueString(String string) { + return stringTable.uniqueString(string); } - public static final class ClassEntry { - // the name of the associated class - private String className; - // the associated file - FileEntry fileEntry; - // a list recording details of all primary ranges included in - // this class sorted by ascending address range - private LinkedList primaries; - // an index identifying primary ranges which have already been encountered - private Map primaryIndex; - // an index of all primary and secondary files referenced from this class's CU - private Map localFilesIndex; - // a list of the same files - private LinkedList localFiles; - // an index of all primary and secondary dirs referenced from this class's CU - private HashMap localDirsIndex; - // a list of the same dirs - private LinkedList localDirs; - // index of debug_info section compilation unit for this class - private int cuIndex; - // index into debug_line section for associated CU - private int lineIndex; - // size of line number info prologue region for associated CU - private int linePrologueSize; - // total size of line number info region for associated CU - private int totalSize; - - public ClassEntry(String className, FileEntry fileEntry) { - this.className = className; - this.fileEntry = fileEntry; - this.primaries = new LinkedList<>(); - this.primaryIndex = new HashMap<>(); - this.localFiles = new LinkedList<>(); - this.localFilesIndex = new HashMap<>(); - this.localDirs = new LinkedList<>(); - this.localDirsIndex = new HashMap<>(); - localFiles.add(fileEntry); - localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.dirEntry; - if (dirEntry != null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } - this.cuIndex = -1; - this.lineIndex = -1; - this.linePrologueSize = -1; - this.totalSize = -1; - } - - public String toString() { - return String.format("classentry(%s file=%s)", className, fileEntry.getFileName()); - } - - void dump(PrintStream out) { - out.format(" class=%s file=%s nPrims=%d nLocals=%d CU=%d LI=%d Lsize=%d tsize=%d\n", - className, fileEntry.getFileName(), primaries.size(), localFiles.size(), - cuIndex, lineIndex, linePrologueSize, totalSize); - for (PrimaryEntry pe : primaries) { - out.format(" pe %s\n", pe.getPrimary()); - for (Range r : pe.getSubranges()) { - out.format(" subr %s\n", r); - } - } - } - - PrimaryEntry addPrimary(Range primary) { - if (primaryIndex.get(primary) == null) { - PrimaryEntry primaryEntry = new PrimaryEntry(primary, this); - primaries.add(primaryEntry); - primaryIndex.put(primary, primaryEntry); - return primaryEntry; - } - return null; - } - void addSubRange(Range subrange, FileEntry subFileEntry) { - Range primary = subrange.getPrimary(); - // the subrange should belong to a primary range - assert primary != null; - PrimaryEntry primaryEntry = primaryIndex.get(primary); - // we should already have seen the primary range - assert primaryEntry != null; - assert primaryEntry.getClassEntry() == this; - primaryEntry.addSubRange(subrange, subFileEntry); - if (localFilesIndex.get(subFileEntry) == null) { - localFiles.add(subFileEntry); - localFilesIndex.put(subFileEntry, localFiles.size()); - } - DirEntry dirEntry = subFileEntry.dirEntry; - if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } - } - public int localDirsIdx(DirEntry dirEntry) { - if (dirEntry != null) { - return localDirsIndex.get(dirEntry); - } else { - return 0; - } - } - - public int localFilesIdx(FileEntry fileEntry) { - return localFilesIndex.get(fileEntry); - } - - public String getFileName() { - return fileEntry.getFileName(); - } - - String getDirName() { - return fileEntry.getDirName(); - } - - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - int getLineIndex() { - return lineIndex; - } - void setLineIndex(int lineIndex) { - this.lineIndex = lineIndex; - } - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - public int getLinePrologueSize() { - return linePrologueSize; - } - public int getTotalSize() { - return totalSize; - } - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } - public FileEntry getFileEntry() { - return fileEntry; - } - public String getClassName() { - return className; - } - public LinkedList getPrimaryEntries() { - return primaries; - } + /** + * indirects this call to the string table, ensuring + * the table entry is marked for inclusion in the + * debug_str section. + * @param string the string to be inserted and + * marked for inclusion in the debug_str section + * @return a unique equivalent String + */ + public String uniqueDebugString(String string) { + return stringTable.uniqueDebugString(string); } - public static final class PrimaryEntry { - // the primary range detailed by this object - Range primary; - // details of the class owning this range - ClassEntry classEntry; - // a list of subranges associated with the primary range - LinkedList subranges; - // a mapping from subranges to their associated file entry - HashMap subrangeIndex; - // index of debug_info section compilation unit for this file - private int cuIndex; - // index into debug_line section for associated compilation unit - private int lineIndex; - // size of line number info prologue region for associated compilation unit - private int linePrologueSize; - // total size of line number info region for associated compilation unit - private int totalSize; - - public PrimaryEntry(Range primary, ClassEntry classEntry) { - this.primary = primary; - this.classEntry = classEntry; - this.subranges = new LinkedList<>(); - this.subrangeIndex = new HashMap<>(); - } - public void addSubRange(Range subrange, FileEntry subFileEntry) { - // we should not see a subrange more than once - assert !subranges.contains(subrange); - assert subrangeIndex.get(subrange) == null; - // we need to generate a file table entry - // for all ranges - subranges.add(subrange); - subrangeIndex.put(subrange, subFileEntry); - } - public Range getPrimary() { - return primary; - } - public ClassEntry getClassEntry() { - return classEntry; - } - public FileEntry getFileEntry() { - return classEntry.getFileEntry(); - } - public LinkedList getSubranges() { - return subranges; - } - public FileEntry getSubrangeFileEntry(Range subrange) { - return subrangeIndex.get(subrange); - } - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - int getLineIndex() { - return lineIndex; - } - void setLineIndex(int lineIndex) { - this.lineIndex = lineIndex; - } - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - public int getLinePrologueSize() { - return linePrologueSize; - } - public int getTotalSize() { - return totalSize; - } - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } + /** + * indirects this call to the string table. + * @param string the string whose index is required + * @return the offset of the string in the .debug_str + * section + */ + public int debugStringIndex(String string) { + return stringTable.debugStringIndex(string); } - public static final class Range { - private String fileName; - private String className; - private String methodName; - private String paramNames; - private String returnTypeName; - private int lo; - private int hi; - private int line; - private Range primary; - - // create a primary range - Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, int lo, int hi, int line) { - this(fileName, className, methodName, paramNames, returnTypeName, lo, hi, line, null); - } - // create a primary or secondary range - - Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, int lo, int hi, int line, Range primary) { - this.fileName = fileName; - this.className = className; - this.methodName = methodName; - this.paramNames = paramNames; - this.returnTypeName = returnTypeName; - this.lo = lo; - this.hi = hi; - this.line = line; - this.primary = primary; - } - - public Range(Range other) { - this.fileName = other.fileName; - this.className = other.className; - this.methodName = other.methodName; - this.paramNames = other.paramNames; - this.returnTypeName = other.returnTypeName; - this.lo = other.lo; - this.hi = other.hi; - this.line = other.line; - this.primary = other.primary; - } - - public String toString() { - return String.format("range(fn=%s:%d lo=0x%x hi=0x%x %s m=%s(%s))", fileName, line, lo, hi, className, methodName, paramNames); - } - - public boolean sameClassName(Range other) { - return className.equals(other.className); - } - - public boolean sameMethodName(Range other) { - return methodName.equals(other.methodName); - } - - public boolean sameParamNames(Range other) { - return paramNames.equals(other.paramNames); - } - - public boolean sameReturnTypeName(Range other) { - return returnTypeName.equals(other.returnTypeName); - } - - public boolean sameFileName(Range other) { - return fileName.equals(other.fileName); - } - - public boolean sameMethod(Range other) { - return sameClassName(other) && - sameMethodName(other) && - sameParamNames(other) && - sameReturnTypeName(other); - } - - public boolean contains(Range other) { - return (lo <= other.lo && hi >= other.hi); - } - - public boolean isPrimary() { - return getPrimary() == null; - } - - public Range getPrimary() { - return primary; - } - - public String getFileName() { - return fileName; - } - public String getClassName() { - return className; - } - public String getMethodName() { - return methodName; - } - public String getParamNames() { - return paramNames; - } - public String getReturnTypeName() { - return returnTypeName; - } - public int getHi() { - return hi; - } - public void setLo(int lo) { - this.lo = lo; - } - public int getLo() { - return lo; - } - public void setHi(int hi) { - this.hi = hi; - } - public int getLine() { - return line; - } - public String getClassAndMethodName() { - return getExtendedMethodName(false, false); - } - public String getClassAndMethodNameWithParams() { - return getExtendedMethodName(true, false); - } - - public String getFullMethodName() { - return getExtendedMethodName(true, true); - } - - public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { - StringBuilder builder = new StringBuilder(); - if (includeReturnType && returnTypeName.length() > 0) { - builder.append(returnTypeName); - builder.append(' '); - } - if (className != null) { - builder.append(className); - builder.append("."); - } - builder.append(methodName); - if (includeParams) { - builder.append('('); - if (paramNames != null) { - builder.append(paramNames); - } - builder.append(')'); - } - return builder.toString(); - } - } } From 56f545810314fe037f6c22b69e9d52e7a8576ed9 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 5 Mar 2020 08:04:50 -0500 Subject: [PATCH 048/130] fix issues caused by refactoring --- .../objectfile/pecoff/cv/CVFileRecord.java | 56 ++++++++++--------- .../objectfile/pecoff/cv/CVLineRecord.java | 2 +- .../objectfile/pecoff/cv/CVSymbolRecord.java | 9 --- .../pecoff/cv/CVSymbolRecordBuilder.java | 36 ++++++------ .../pecoff/cv/CVSymbolSectionImpl.java | 11 +++- 5 files changed, 57 insertions(+), 57 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index b3c2e7c04e73..e6b75b975cd4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -33,7 +33,7 @@ import java.nio.file.NoSuchFileException; import java.nio.file.Paths; import java.security.MessageDigest; -import java.util.Hashtable; +import java.util.LinkedHashMap; import java.util.Map; final class CVFileRecord extends CVSymbolRecord { @@ -47,9 +47,12 @@ final class CVFileRecord extends CVSymbolRecord { private static final int CHECKSUM_LENGTH = 16; private static final byte[] EMPTY_CHECKSUM = new byte[CHECKSUM_LENGTH]; - private final CVSections cvSections; + private static final int FILE_TABLE_INITIAL_SIZE = 200; + private final CVSymbolSectionImpl.CVStringTable strings; - private Map fileToOFfsetMap; + + private int currentOffset = 0; + private Map fileEntryToOffsetMap = new LinkedHashMap<>(FILE_TABLE_INITIAL_SIZE); CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { super(cvSections, DEBUG_S_FILECHKSMS); @@ -67,25 +70,35 @@ private String fixPath(String fn) { return fn; } - public int getFileEntryOffset(FileEntry entry) { - return fileToOFfsetMap.get(entry); + public int addFile(FileEntry entry) { + if (fileEntryToOffsetMap.containsKey(entry)) { + return fileEntryToOffsetMap.get(entry); + } else { + fileEntryToOffsetMap.put(entry, currentOffset); + strings.add(fixPath(entry.getFileName())); /* create required stringtable entry */ + currentOffset += FILE_RECORD_LENGTH; + return currentOffset - FILE_RECORD_LENGTH; + } } @Override public int computeSize(int initialPos) { - if (cvSections.getFiles().isEmpty()) { - return initialPos; - } - /* first, insert fileIds into file id array for use by line number table */ - fileToOFfsetMap = new Hashtable<>(cvSections.getFiles().size()); - int fileId = 0; - int fileIndex = 0; + /* add all fileEntries; duplicates are ignored */ + /* probably don't need to do this because if it isn't already here it's probably referenced by the debug info */ + /* consider moving this to CVSymbolSectionImpl */ for (FileEntry entry : cvSections.getFiles()) { - fileToOFfsetMap.put(entry, fileId); - strings.add(fixPath(entry.getFileName())); // create required stringtable entries - fileId += FILE_RECORD_LENGTH; + addFile(entry); } - return initialPos + (cvSections.getFiles().size() * FILE_RECORD_LENGTH); + return initialPos + (fileEntryToOffsetMap.size() * FILE_RECORD_LENGTH); + } + + @Override + public int computeContents(byte[] buffer, int pos) { + CVUtil.debug("file computeContents(%d) nf=%d\n", pos, fileEntryToOffsetMap.size()); + for (FileEntry entry : fileEntryToOffsetMap.keySet()) { + pos = put(entry, buffer, pos); + } + return pos; } private int put(FileEntry entry, byte[] buffer, int initialPos) { @@ -118,15 +131,6 @@ private byte[] calculateMD5Sum(String fn) { } } - @Override - public int computeContents(byte[] buffer, int pos) { - CVUtil.debug("file computeContents(%d) nf=%d\n", pos, cvSections.getFiles().size()); - for (FileEntry entry : cvSections.getFiles()) { - pos = put(entry, buffer, pos); - } - return pos; - } - @Override public String toString() { return "CVFileRecord(type=" + type + ",pos=" + pos + ", size=" + 999 + ")"; @@ -137,7 +141,7 @@ public void dump(PrintStream out) { int idx = 0; int offset = 0; out.format("%s:\n", this); - for (FileEntry entry : cvSections.getFiles()) { + for (FileEntry entry : fileEntryToOffsetMap.keySet()) { out.format("%4d 0x%08x %2d %2d %s\n", idx, offset, 0x10, 1, entry.getFileName()); idx += 1; offset += 24; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 1cf488d192d7..2560d438e8f9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -137,7 +137,7 @@ int computeContents(byte[] buffer, int initialPos) { void addNewFile(FileEntry file) { CVFileRecord fr = cvSections.getCVSymbolSection().getFileRecord(); - int fileId = fr.getFileEntryOffset(file); + int fileId = fr.addFile(file); fileBlocks.add(new FileBlock(file, fileId)); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index 00407fdc652c..59f90d96f7a9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -26,16 +26,7 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.debugentry.FileEntry; - import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.nio.file.NoSuchFileException; -import java.security.MessageDigest; - -import static com.oracle.objectfile.pecoff.cv.CVConstants.GRAAL_SOURCE_BASE; -import static com.oracle.objectfile.pecoff.cv.CVConstants.JDK_SOURCE_BASE; /* * A Symbol record is a top-level record in the CodeView .debug$S section diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index b07138a1df76..db46b6bc83f2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -48,6 +48,24 @@ final class CVSymbolRecordBuilder { this.typeSection = cvSections.getCVTypeSection(); } + void build() { + /* A module has a set of (function def, block def, linenumbers) for each function */ + String previousMethodName = ""; + for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { + for (PrimaryEntry primary : classEntry.getPrimaryEntries()) { + Range range = primary.getPrimary(); + // for each function + String newMethodName = fixMethodName(range); + if (!newMethodName.equals(previousMethodName)) { + previousMethodName = newMethodName; + processFunction(newMethodName, range); + addLineNumberRecords(newMethodName, primary); + } + } + } + cvSections.getCVSymbolSection().addRecord(symbolRecord); + } + private boolean noMainFound = true; /** @@ -78,24 +96,6 @@ private String fixMethodName(Range range) { return methodName; } - void build() { - /* A module has a set of (function def, block def, linenumbers) for each function */ - String previousMethodName = ""; - for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { - for (PrimaryEntry primary : classEntry.getPrimaryEntries()) { - Range range = primary.getPrimary(); - // for each function - String newMethodName = fixMethodName(range); - if (!newMethodName.equals(previousMethodName)) { - previousMethodName = newMethodName; - processFunction(newMethodName, range); - addLineNumberRecords(newMethodName, primary); - } - } - } - cvSections.getCVSymbolSection().addRecord(symbolRecord); - } - private void processFunction(String methodName, Range range) { CVUtil.debug("addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java index 2c5ab84194ae..6572640e9148 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java @@ -71,6 +71,7 @@ public void createContent() { pos += Integer.BYTES; /* add sum of all record sizes */ for (CVSymbolRecord record : cvRecords) { + info("CVSymbolSectionImpl.createContent() computeFullSize %s", record); pos = CVUtil.align4(pos); pos = record.computeFullSize(pos); } @@ -89,6 +90,7 @@ public void writeContent() { pos = CVUtil.putInt(CV_SIGNATURE_C13, buffer, pos); /* write all records */ for (CVSymbolRecord record : cvRecords) { + info("CVSymbolSectionImpl.createContent() computeFullContentt %s", record); pos = CVUtil.align4(pos); pos = record.computeFullContents(buffer, pos); } @@ -129,11 +131,13 @@ private void addTypeRecords() { } private void addFileRecords() { - this.fileRecord = new CVFileRecord(cvSections, stringTable); - addRecord(fileRecord); + addRecord(getFileRecord()); } - public CVFileRecord getFileRecord() { + CVFileRecord getFileRecord() { + if (fileRecord == null) { + this.fileRecord = new CVFileRecord(cvSections, stringTable); + } return fileRecord; } @@ -142,6 +146,7 @@ private void addStringTableRecord() { addRecord(stringTableRecord); } + /* TODO: use ...objectfile.debugentry.StringTable instead */ static final class CVStringTable { static final class StringTableEntry { public int offset; From a965b477ab867b329f7eda2156ebabd1566580d7 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 6 Mar 2020 16:22:37 -0500 Subject: [PATCH 049/130] merge latest from Andrew Dinn (adinn@redhat.com) --- .../objectfile/debugentry/ClassEntry.java | 50 ++++++++---- .../objectfile/debugentry/PrimaryEntry.java | 4 - .../oracle/objectfile/debugentry/Range.java | 10 ++- .../elf/dwarf/DwarfLineSectionImpl.java | 11 ++- .../objectfile/elf/dwarf/DwarfSections.java | 7 +- .../objectfile/pecoff/cv/DebugInfoBase.java | 10 +-- .../svm/hosted/image/NativeBootImage.java | 52 +++++++----- .../hosted/image/sources/SourceManager.java | 79 +++++++++---------- 8 files changed, 130 insertions(+), 93 deletions(-) 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 f5034a8254e7..b1a9cf22a1ee 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 @@ -104,12 +104,14 @@ public ClassEntry(String className, FileEntry fileEntry) { this.localFilesIndex = new HashMap<>(); this.localDirs = new LinkedList<>(); this.localDirsIndex = new HashMap<>(); - localFiles.add(fileEntry); - localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.getDirEntry(); - if (dirEntry != null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); + if (fileEntry != null) { + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.getDirEntry(); + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } } this.cuIndex = -1; this.lineIndex = -1; @@ -140,14 +142,16 @@ public void addSubRange(Range subrange, FileEntry subFileEntry) { assert primaryEntry != null; assert primaryEntry.getClassEntry() == this; primaryEntry.addSubRange(subrange, subFileEntry); - if (localFilesIndex.get(subFileEntry) == null) { - localFiles.add(subFileEntry); - localFilesIndex.put(subFileEntry, localFiles.size()); - } - DirEntry dirEntry = subFileEntry.getDirEntry(); - if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); + if (subFileEntry != null) { + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.getDirEntry(); + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } } } @@ -164,15 +168,27 @@ public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { } public String getFileName() { - return fileEntry.getFileName(); + if (fileEntry != null) { + return fileEntry.getFileName(); + } else { + return ""; + } } String getFullFileName() { - return fileEntry.getFullName(); + if (fileEntry != null) { + return fileEntry.getFullName(); + } else { + return null; + } } String getDirName() { - return fileEntry.getPathName(); + if (fileEntry != null) { + return fileEntry.getPathName(); + } else { + return ""; + } } public void setCUIndex(int cuIndex) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index ebebdfec72b5..93696d7f8889 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -92,10 +92,6 @@ public ClassEntry getClassEntry() { return classEntry; } - public FileEntry getFileEntry() { - return classEntry.getFileEntry(); - } - public List getSubranges() { return subranges; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 8e52023ee5e6..abd8d0da6a20 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -37,8 +37,8 @@ public class Range { - /* TODO this should be '.' for PECOFF files */ - private static final String CLASS_DELIMITER = "::"; + /* Use '.' for PECOFF files */ + private static final String CLASS_DELIMITER = System.getProperty("os.name").contains("indows") ? "." : "::"; private String fileName; private Path filePath; @@ -70,7 +70,7 @@ public Range(String fileName, Path filePath, String className, String methodName * currently file name and full method name need to go into the debug_str section * other strings just need to be deduplicated to save space */ - this.fileName = stringTable.uniqueDebugString(fileName); + this.fileName = (fileName == null ? fileName : stringTable.uniqueDebugString(fileName)); this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); @@ -126,8 +126,10 @@ public Path getFilePath() { public Path getFileAsPath() { if (filePath != null) { return filePath.resolve(fileName); - } else { + } else if (fileName != null) { return Paths.get(fileName); + } else { + return null; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index aff33ce4f828..97818d1f280e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -226,6 +226,8 @@ public int computeFileTableSize(ClassEntry classEntry) { */ String baseName = localEntry.getFileName(); int length = baseName.length(); + /* we should never have a null or zero length entry in local files */ + assert length > 0; fileSize += length + 1; DirEntry dirEntry = localEntry.getDirEntry(); int idx = classEntry.localDirsIdx(dirEntry); @@ -416,10 +418,14 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; + FileEntry fileEntry = classEntry.getFileEntry(); + if (fileEntry == null) { + return pos; + } /* * the primary file entry should always be first in the local files list */ - assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; + assert classEntry.localFilesIdx(fileEntry) == 1; String primaryClassName = classEntry.getClassName(); String primaryFileName = classEntry.getFileName(); String file = primaryFileName; @@ -475,6 +481,9 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { assert subrange.getLo() >= primaryRange.getLo(); assert subrange.getHi() <= primaryRange.getHi(); FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); + if (subFileEntry == null) { + continue; + } String subfile = subFileEntry.getFileName(); int subFileIdx = classEntry.localFilesIdx(subFileEntry); long subLine = subrange.getLine(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index faa546479b50..6aa82609fa38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -406,6 +406,9 @@ public ClassEntry ensureClassEntry(Range range) { public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); + if (fileName == null) { + return null; + } Path filePath = range.getFilePath(); Path fileAsPath = range.getFileAsPath(); /* @@ -448,7 +451,9 @@ public void addSubRange(Range primaryRange, Range subrange) { * and associated with a primary class entry */ assert classEntry.primaryIndexFor(primaryRange) != null; - classEntry.addSubRange(subrange, subrangeEntry); + if (subrangeEntry != null) { + classEntry.addSubRange(subrange, subrangeEntry); + } } public DirEntry ensureDirEntry(Path filePath) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index 031f834e3df7..330c691da36a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -92,7 +92,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); Path filePathAtLine = debugLineInfo.filePath(); - // switch '$' in class names for '.' + /* switch '$' in class names for '.' */ String classNameAtLine = debugLineInfo.className().replaceAll("\\$", "."); String methodNameAtLine = debugLineInfo.methodName(); int loAtLine = lo + debugLineInfo.addressLo(); @@ -102,11 +102,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * record all subranges even if they have no line or file so we at least get a * symbol for them */ - if (fileNameAtLine.length() > 0 && primaryLine >= 0) { - //CVUtil.debug(" lineinfo: [0x%08x,0x%08x) %s.%s (%s:%d)\n", loAtLine, hiAtLine, classNameAtLine, methodNameAtLine, fileNameAtLine, line); - Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); - addSubRange(primaryRange, subRange); - } + //CVUtil.debug(" lineinfo: [0x%08x,0x%08x) %s.%s (%s:%d)\n", loAtLine, hiAtLine, classNameAtLine, methodNameAtLine, fileNameAtLine, line); + Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); + addSubRange(primaryRange, subRange); }); }); /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index b5844d7b0a5d..c2158c5c3268 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -54,6 +54,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.hosted.image.sources.SourceManager; import com.oracle.svm.hosted.meta.HostedType; @@ -1020,21 +1021,21 @@ public Stream dataInfoProvider() { */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; + private final ResolvedJavaType javaType; private final CompilationResult compilation; private Path fullFilePath; NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; + HostedType declaringClass = method.getDeclaringClass(); + Class clazz = declaringClass.getJavaClass(); + this.javaType = declaringClass.getWrapped(); this.compilation = compilation; - this.fullFilePath = null; + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(javaType, clazz); } @Override public String fileName() { - if (fullFilePath == null) { - HostedType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } if (fullFilePath != null) { return fullFilePath.getFileName().toString(); } @@ -1042,10 +1043,6 @@ public String fileName() { } @Override public Path filePath() { - if (fullFilePath == null) { - HostedType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } if (fullFilePath != null) { return fullFilePath.getParent(); } @@ -1054,7 +1051,7 @@ public Path filePath() { @Override public String className() { - return method.format("%H"); + return javaType.toClassName(); } @Override @@ -1134,7 +1131,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { private final ResolvedJavaMethod method; private final int lo; private final int hi; - private Path fullFilePath = null; + private Path fullFilePath; NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); @@ -1143,25 +1140,18 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { this.method = position.getMethod(); this.lo = sourceMapping.getStartOffset(); this.hi = sourceMapping.getEndOffset(); + computeFullFilePath(); } @Override public String fileName() { - if (fullFilePath == null) { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } - if (fullFilePath != null) { + if (fullFilePath != null) { return fullFilePath.getFileName().toString(); } return null; } public Path filePath() { - if (fullFilePath == null) { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } if (fullFilePath != null) { return fullFilePath.getParent(); } @@ -1196,6 +1186,28 @@ public int line() { } return -1; } + + private void computeFullFilePath() { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + Class clazz = null; + if (declaringClass instanceof OriginalClassProvider) { + clazz = ((OriginalClassProvider) declaringClass).getJavaClass(); + } + /* + * HostedType and AnalysisType punt calls to + * getSourceFilename to the wrapped class so + * for consistency we need to do the path lookup + * relative to the wrapped class + */ + if (declaringClass instanceof HostedType) { + declaringClass = ((HostedType) declaringClass).getWrapped(); + } + if (declaringClass instanceof AnalysisType) { + declaringClass = ((AnalysisType) declaringClass).getWrapped(); + } + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass, clazz); + } + } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java index aa741782f483..ee13937d7ea5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -27,6 +27,7 @@ package com.oracle.svm.hosted.image.sources; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.meta.ResolvedJavaType; @@ -45,11 +46,12 @@ public class SourceManager { * return a Path to the file relative to the source. * @param resolvedType the Java type whose source file * should be located and cached + * @param clazz the Java class associated with the resolved type * @return a path identifying the location of a successfully * cached file for inclusion in the generated debug info or * null if a source file cannot be found or cached. */ - public Path findAndCacheSource(ResolvedJavaType resolvedType) { + public Path findAndCacheSource(ResolvedJavaType resolvedType, Class clazz) { /* short circuit if we have already seen this type */ Path path = verifiedPaths.get(resolvedType); if (path != null) { @@ -67,30 +69,13 @@ public Path findAndCacheSource(ResolvedJavaType resolvedType) { * for known classes and interfaces */ if (resolvedType.isInstanceClass() || resolvedType.isInterface()) { - /* - * if we have an OriginalClassProvider we - * can use the underlying Java class - * to provide the details we need to locate - * a source - */ - if (resolvedType instanceof OriginalClassProvider) { - Class javaClass = ((OriginalClassProvider) resolvedType).getJavaClass(); - String packageName = computePackageName(javaClass); - SourceCacheType type = sourceCacheType(packageName, javaClass); - path = locateSource(fileName, packageName, type, javaClass); - } - /* - * if we could not locate a source via the cache - * then the fallback is to generate a path to the - * file based on the class name and let the - * user configure a path to the sources - */ + String packageName = computePackageName(resolvedType); + SourceCacheType sourceCacheType = sourceCacheType(packageName); + path = locateSource(fileName, packageName, sourceCacheType, resolvedType, clazz); if (path == null) { - String name = resolvedType.toJavaName(); - int idx = name.lastIndexOf('.'); - if (idx >= 0 && idx < name.length() - 1) { - name = name.substring(0, idx); - path = Paths.get("", name.split("\\.")); + // as a last ditch effort derive path from the Java class name + if (packageName.length() > 0) { + path = Paths.get("", packageName.split("\\.")); path = path.resolve(fileName); } } @@ -138,16 +123,21 @@ private String computeBaseName(ResolvedJavaType resolvedType) { return fileName; } /** - * Construct the package name for a Java class or + * Construct the package name for a Java type or * the empty String if it has no package. - * @param javaClass the java class whose package + * @param javaType the Java type whose package * name is required * @return the package name or the empty String * if it has no package */ - private String computePackageName(Class javaClass) { - Package pkg = javaClass.getPackage(); - return (pkg == null ? "" : pkg.getName()); + private String computePackageName(ResolvedJavaType javaType) { + String name = javaType.toClassName(); + int idx = name.lastIndexOf('.'); + if (idx > 0) { + return name.substring(0, idx); + } else { + return ""; + } } /** * Construct the prototype name for a Java source file @@ -155,15 +145,17 @@ private String computePackageName(Class javaClass) { * file. * @param fileName the base file name for the source file * @param packageName the name of the package for the associated Java class - * @param type the type of cache in which to lookup or cache this class's source file - * @param javaClass the java class whose prototype name is required + * @param sourceCacheType the sourceCacheType of cache in which to lookup or cache this class's source file + * @param javaType the java sourceCacheType whose prototype name is required + * @param clazz the class associated with the sourceCacheType used to + * identify the module prefix for JDK classes * @return a protoype name for the source file */ - private Path computePrototypeName(String fileName, String packageName, SourceCacheType type, Class javaClass) { + private Path computePrototypeName(String fileName, String packageName, SourceCacheType sourceCacheType, ResolvedJavaType javaType, Class clazz) { String prefix = ""; - if (type == SourceCacheType.JDK) { - /* JDK paths may require the module name as prefix */ - String moduleName = ModuleSupport.getModuleName(javaClass); + if (sourceCacheType == SourceCacheType.JDK && clazz != null) { + /* JDK11+ paths will require the module name as prefix */ + String moduleName = ModuleSupport.getModuleName(clazz); if (moduleName != null) { prefix = moduleName; } @@ -231,9 +223,12 @@ private boolean whiteListPackage(String packageName, String[] whitelist) { /** * Identify which type of source cache should be used - * to locate a given class's source code. + * to locate a given class's source code as determined + * by it's package name. + * @param packageName the package name of the class. + * @return the corresponding source cache type */ - private SourceCacheType sourceCacheType(String packageName, Class javaClass) { + private SourceCacheType sourceCacheType(String packageName) { if (whiteListPackage(packageName, JDK_SRC_PACKAGE_PREFIXES)) { return SourceCacheType.JDK; } @@ -281,10 +276,14 @@ private SourceCache getOrCreateCache(SourceCacheType type) { return sourceCache; } - private Path locateSource(String fileName, String packagename, SourceCacheType type, Class javaClass) { + private Path locateSource(String fileName, String packagename, SourceCacheType type, ResolvedJavaType javaType, Class clazz) { SourceCache cache = getOrCreateCache(type); - Path prototypeName = computePrototypeName(fileName, packagename, type, javaClass); - return cache.resolve(prototypeName); + Path prototypeName = computePrototypeName(fileName, packagename, type, javaType, clazz); + if (prototypeName != null) { + return cache.resolve(prototypeName); + } else { + return null; + } } } From 2117e6a575c3cd55c14b632303ff800736897190 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 6 Mar 2020 16:25:25 -0500 Subject: [PATCH 050/130] CodeView debug fixes after latest merge --- .../com/oracle/objectfile/debugentry/Range.java | 2 +- .../objectfile/pecoff/cv/CVLineRecordBuilder.java | 2 +- .../pecoff/cv/CVSymbolRecordBuilder.java | 14 ++++++++------ .../oracle/objectfile/pecoff/cv/DebugInfoBase.java | 7 ++++++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index abd8d0da6a20..01012127b6ed 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -38,7 +38,7 @@ public class Range { /* Use '.' for PECOFF files */ - private static final String CLASS_DELIMITER = System.getProperty("os.name").contains("indows") ? "." : "::"; + private static final String CLASS_DELIMITER = System.getProperty("os.name").toLowerCase().contains("windows") ? "." : "::"; private String fileName; private Path filePath; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 6df205e06b7e..4f974099bd06 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -76,7 +76,7 @@ CVLineRecord build(String methodName, PrimaryEntry primaryEntry) { CVUtil.debug(" skipping Graal internal class %s\n", primaryRange); return null; } - CVUtil.debug(" DEBUG_S_LINES linerecord for 0x%05x file: %s:%d\n", primaryRange.getLo(), primaryEntry.getFileEntry().getFileName(), primaryRange.getLine()); + CVUtil.debug(" DEBUG_S_LINES linerecord for 0x%05x file: %s:%d\n", primaryRange.getLo(), primaryRange.getFileName(), primaryRange.getLine()); this.lineRecord = new CVLineRecord(cvSections, methodName, primaryEntry); CVUtil.debug(" CVLineRecord.computeContents: processing primary range %s\n", primaryRange); processRange(primaryRange); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index db46b6bc83f2..2199bc9e1e61 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -54,12 +54,14 @@ void build() { for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { for (PrimaryEntry primary : classEntry.getPrimaryEntries()) { Range range = primary.getPrimary(); - // for each function - String newMethodName = fixMethodName(range); - if (!newMethodName.equals(previousMethodName)) { - previousMethodName = newMethodName; - processFunction(newMethodName, range); - addLineNumberRecords(newMethodName, primary); + if (range.getFileName() != null) { + // for each function + String newMethodName = fixMethodName(range); + if (!newMethodName.equals(previousMethodName)) { + previousMethodName = newMethodName; + processFunction(newMethodName, range); + addLineNumberRecords(newMethodName, primary); + } } } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index 330c691da36a..648584b77eb4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -145,6 +145,9 @@ private ClassEntry ensureClassEntry(Range range) { FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); + if (fileName == null) { + return null; + } Path filePath = range.getFilePath(); Path fileAsPath = range.getFileAsPath(); /* @@ -187,7 +190,9 @@ private void addSubRange(Range primaryRange, Range subrange) { * and associated with a primary class entry */ assert classEntry.primaryIndexFor(primaryRange) != null; - classEntry.addSubRange(subrange, subrangeEntry); + if (subrangeEntry != null) { + classEntry.addSubRange(subrange, subrangeEntry); + } } private DirEntry ensureDirEntry(Path filePath) { From 587e41a80701f6ff272cda8fb9bc14a627d2913e Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 10 Mar 2020 13:17:34 -0400 Subject: [PATCH 051/130] cleanup, add toString for Range and FileEntry --- .../objectfile/debugentry/FileEntry.java | 10 +++++ .../oracle/objectfile/debugentry/Range.java | 5 +++ .../objectfile/pecoff/cv/CVTypeRecord.java | 37 ++++++++++++------- .../objectfile/pecoff/cv/DebugInfoBase.java | 4 +- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index 8c28e018100a..04126352885e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -58,4 +58,14 @@ public String getFullName() { public DirEntry getDirEntry() { return dirEntry; } + + @Override + public String toString() { + if (getDirEntry() == null) { + return getFileName() == null ? "-" : getFileName(); + } else if (getFileName() == null) { + return "--"; + } + return String.format("FileEntry(%s)", getFullName()); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 01012127b6ed..f5e87b74d822 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -192,4 +192,9 @@ public String getExtendedMethodName(boolean includeParams, boolean includeReturn private String constructClassAndMethodNameWithParams() { return getExtendedMethodName(true, false); } + + @Override + public String toString() { + return String.format("Range(lo=0x%05x hi=0x%05x %s %s:%d)", lo, hi, constructClassAndMethodNameWithParams(), getFileAsPath(), line); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java index 1a9dbbe988f9..fc61ae4c01e6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java @@ -135,6 +135,9 @@ CVTypeModifierRecord addUnaligned() { return this; } + private short computeFlags() { + return (short) ((addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0)); + } @Override public int computeSize(int pos) { return pos + Integer.BYTES + Short.BYTES; @@ -143,8 +146,7 @@ public int computeSize(int pos) { @Override public int computeContents(byte[] buffer, int pos) { pos = CVUtil.putInt(originalLeaf, buffer, pos); - int flags = (addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0); - pos = CVUtil.putShort((short) flags, buffer, pos); + pos = CVUtil.putShort(computeFlags(), buffer, pos); return pos; } @@ -166,9 +168,9 @@ public String toString() { @Override public int hashCode() { - int h = originalLeaf; - int flags = (addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0); - h = 31 * h + flags; + int h = type; + h = 31 * h + originalLeaf; + h = 31 * h + computeFlags(); return h; } } @@ -200,6 +202,10 @@ static final class CVTypePointerRecord extends CVTypeRecord { this.originalLeaf = originalLeaf.getSequenceNumber(); } + private int computeAttributes() { + return kind | (mode << 5) | (modifiers << 8) | (size << 13) | (flags << 19); + } + @Override public int computeSize(int pos) { return pos + Integer.BYTES * 2; @@ -208,8 +214,7 @@ public int computeSize(int pos) { @Override public int computeContents(byte[] buffer, int pos) { pos = CVUtil.putInt(originalLeaf, buffer, pos); - int attributes = kind | (mode << 5) | (modifiers << 8) | (size << 13) | (flags << 19); - pos = CVUtil.putInt(attributes, buffer, pos); + pos = CVUtil.putInt(computeAttributes(), buffer, pos); return pos; } @@ -220,9 +225,9 @@ public String toString() { @Override public int hashCode() { - int h = originalLeaf; - int attributes = kind | (mode << 5) | (modifiers << 8) | (size << 13) | (flags << 19); - h = 31 * h + attributes; + int h = type; + h = 31 * h + originalLeaf; + h = 31 * h + computeAttributes(); return h; } } @@ -273,7 +278,8 @@ public String toString() { @Override public int hashCode() { - int h = returnType; + int h = type; + h = 31 * h + returnType; h = 31 * h + argList.hashCode(); // h = 31 * h + // callType + funcAttr return h; @@ -328,7 +334,8 @@ public String toString() { @Override public int hashCode() { - int h = 0; + int h = type; + h = h * 31 + args.size(); for (Integer r : args) { h = 31 * h + r.hashCode(); } @@ -604,7 +611,8 @@ public String toString() { @Override public int hashCode() { - int h = elementType; + int h = type; + h = 31 * h + elementType; h = 31 * h + indexType; h = 31 * h + length; return h; @@ -656,7 +664,8 @@ public String toString() { @Override public int hashCode() { - int h = Arrays.hashCode(guid); + int h = type; + h = 31 * h + Arrays.hashCode(guid); h = 31 * h + age; h = 31 * h + fileName.hashCode(); return h; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index 648584b77eb4..2ce1cd693114 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -34,7 +34,6 @@ import com.oracle.objectfile.debugentry.StringTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import java.nio.ByteOrder; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -57,7 +56,8 @@ public abstract class DebugInfoBase { private boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { /* TODO: be much more clever; this is merely proof of concept */ - return !(CVConstants.skipGraalInternals && debugCodeInfo.className().startsWith("com.oracle")); + //return !(CVConstants.skipGraalInternals && debugCodeInfo.className().startsWith("com.oracle")); + return true; } public void installDebugInfo(DebugInfoProvider debugInfoProvider) { From a9ff44a3061fd4d7899abf3b1cf11248bb2a32c8 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 10 Mar 2020 13:18:07 -0400 Subject: [PATCH 052/130] fix line numbers --- .../objectfile/pecoff/cv/CVConstants.java | 8 +- .../objectfile/pecoff/cv/CVFileRecord.java | 13 ++- .../objectfile/pecoff/cv/CVLineRecord.java | 8 +- .../pecoff/cv/CVLineRecordBuilder.java | 104 +++++++++++------- .../objectfile/pecoff/cv/CVRootPackages.java | 45 +++++++- .../pecoff/cv/CVSymbolRecordBuilder.java | 93 ++++++++++------ 6 files changed, 188 insertions(+), 83 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index 11293abd40c7..9cadb23ab13b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -28,7 +28,7 @@ public interface CVConstants { - /* names of relevant codeview sections */ + /* names of relevant CodeView sections */ String CV_SYMBOL_SECTION_NAME = ".debug$S"; String CV_TYPE_SECTION_NAME = ".debug$T"; //String CV_RDATA_SECTION_NAME = ".rdata"; @@ -37,7 +37,7 @@ public interface CVConstants { //String TEXT_SECTION_NAME = ".text"; //String DATA_SECTION_NAME = ".data"; - /* Codeview section header signature */ + /* CodeView section header signature */ int CV_SIGNATURE_C13 = 4; /* @@ -73,12 +73,12 @@ public interface CVConstants { boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ boolean skipJDKInternals = false; /* (unimplemented) if true, don't emit debug code for JDK classes */ boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ - boolean mergeAdjacentLineRecords = false; /* if a line record is the same line in the same file as the previous record, meerge them */ + boolean mergeAdjacentLineRecords = true; /* if a line record is the same line in the same file as the previous record, merge them */ boolean emitUnadornedMain = true; /* if true, first main() does not have args in the debug name */ String replaceMainFunctionName = null; /* first main() becomes this name (with no class name or arg list at all) (set null to disable) */ /* - * The standard link.exe can't handle odd characters (parentheses or commas, for example) in enternal names. + * The standard link.exe can't handle odd characters (parentheses or commas, for example) in external names. * Setting functionNamesHashArgs true replaces those names, * so that "Foo.function(String[] args)" becomes "Foo.function_617849326". * If functionNamesHashArgs is false, currently the linker will fail. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index e6b75b975cd4..67d179ca6d0b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -66,7 +66,13 @@ final class CVFileRecord extends CVSymbolRecord { * * Currently, don't even try; use the SourceCache system */ - private String fixPath(String fn) { + private String fixPath(FileEntry fileEntry) { + final String fn; + if (fileEntry.getDirEntry() == null) { + fn = fileEntry.getFileName(); + } else { + fn = fileEntry.getFullName(); + } return fn; } @@ -75,7 +81,8 @@ public int addFile(FileEntry entry) { return fileEntryToOffsetMap.get(entry); } else { fileEntryToOffsetMap.put(entry, currentOffset); - strings.add(fixPath(entry.getFileName())); /* create required stringtable entry */ + /* create required stringtable entry */ + strings.add(fixPath(entry)); currentOffset += FILE_RECORD_LENGTH; return currentOffset - FILE_RECORD_LENGTH; } @@ -102,7 +109,7 @@ public int computeContents(byte[] buffer, int pos) { } private int put(FileEntry entry, byte[] buffer, int initialPos) { - String fn = fixPath(entry.getFileName()); + String fn = fixPath(entry); int stringId = strings.add(fn); int pos = CVUtil.putInt(stringId, buffer, initialPos); /* stringtable index */ pos = CVUtil.putByte(CB_VALUE, buffer, pos); /* Cb (unknown what this is) */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 2560d438e8f9..c7f0dcc49def 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -52,8 +52,8 @@ final class CVLineRecord extends CVSymbolRecord { /* * FileBlock is a section of contiguous code in a compilation unit, associated with a single source file. - * if a function includes inlined code, that code needs its own FileBlock, surroneded by FileBlocks descibing the inclosing source file - * A fileBlock consists of a list of LineEntries + * if a function includes inlined code, that code needs its own FileBlock, surrounded by FileBlocks describing the enclosing source file + * A FileBlock consists of a list of LineEntries */ private static class FileBlock { @@ -146,9 +146,9 @@ void addNewLine(int addr, int line) { } @Override - protected int computeSize(int startPos) { + protected int computeSize(int initialPos) { /* header */ - int pos = startPos + Integer.BYTES + Short.BYTES * 2 + Integer.BYTES; + int pos = initialPos + Integer.BYTES + Short.BYTES * 2 + Integer.BYTES; /* all blocks */ for (FileBlock fileBlock : fileBlocks) { pos = fileBlock.computeSize(pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 4f974099bd06..af913c5d0362 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -30,13 +30,12 @@ import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import static com.oracle.objectfile.pecoff.cv.CVConstants.mergeAdjacentLineRecords; import static com.oracle.objectfile.pecoff.cv.CVConstants.skipGraalInternals; import static com.oracle.objectfile.pecoff.cv.CVConstants.skipGraalIntrinsics; -import static com.oracle.objectfile.pecoff.cv.CVRootPackages.isJavaPackage; public class CVLineRecordBuilder { - private static final boolean debug = true; private static final boolean HAS_COLUMNS = false; private CVSections cvSections; @@ -59,20 +58,21 @@ public class CVLineRecordBuilder { */ /** - * Feed Range structures to processRange. - * @param primaryEntry input containing sub ranges - * @return CVLineRecord containing any entries generated, or null if o entries + * build line number records for a function + * @param primaryEntry function to build line number table for + * @return CVLineRecord containing any entries generated, or null if no entries generated */ - CVLineRecord build(String methodName, PrimaryEntry primaryEntry) { - long lowAddr = Long.MAX_VALUE; - long highAddr = 0; + CVLineRecord build(PrimaryEntry primaryEntry, String methodName) { + // long lowAddr = Long.MAX_VALUE; + // long highAddr = 0; this.primaryEntry = primaryEntry; - previousRange = null; assert (!HAS_COLUMNS); /* can't handle columns yet */ Range primaryRange = primaryEntry.getPrimary(); - if (skipGraalInternals && isGraalIntrinsic(primaryRange.getClassName())) { + previousRange = null; + /* option to not even bother with debug code for Graal */ + if (skipGraalInternals && CVRootPackages.isGraalClass(primaryRange.getClassName())) { CVUtil.debug(" skipping Graal internal class %s\n", primaryRange); return null; } @@ -80,14 +80,18 @@ CVLineRecord build(String methodName, PrimaryEntry primaryEntry) { this.lineRecord = new CVLineRecord(cvSections, methodName, primaryEntry); CVUtil.debug(" CVLineRecord.computeContents: processing primary range %s\n", primaryRange); processRange(primaryRange); - lowAddr = Math.min(lowAddr, primaryRange.getLo()); - highAddr = Math.max(highAddr, primaryRange.getHi()); + // lowAddr = Math.min(lowAddr, primaryRange.getLo()); + // highAddr = Math.max(highAddr, primaryRange.getHi()); for (Range subRange : primaryEntry.getSubranges()) { CVUtil.debug(" CVLineRecord.computeContents: processing range %s\n", subRange); + FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subRange); + if (subFileEntry == null) { + continue; + } processRange(subRange); - lowAddr = Math.min(lowAddr, subRange.getLo()); - highAddr = Math.max(highAddr, subRange.getHi()); + // lowAddr = Math.min(lowAddr, subRange.getLo()); + // highAddr = Math.max(highAddr, subRange.getHi()); } return lineRecord; } @@ -99,47 +103,73 @@ CVLineRecord build(String methodName, PrimaryEntry primaryEntry) { * - if a Range has a negative linenumber * - if a range is part of Graal or the JDK, and skipGraalOption is true * - if a range has the same line number, source file and function + * * @param range to be merged or added to line number record */ private void processRange(Range range) { /* should we merge this range with the previous entry? */ + /* i.e. same line in same file, same class and function */ if (shouldMerge(previousRange, range)) { - range = new Range(previousRange, range.getLo(), range.getHi()); - } else if (range.getLine() == -1) { + CVUtil.debug(" processRange: merging with previous\n"); return; - } + //range = new Range(previousRange, range.getLo(), range.getHi()); + } /*else if (range.getLine() == -1) { + CVUtil.debug(" processRange: ignoring: bad line number\n"); + return; + }*/ - boolean wantNewFile = previousRange == null || !previousRange.getFileName().equals(range.getFileName()); + /* is this a new file? if so we emit a new file record */ + boolean wantNewFile = previousRange == null || !previousRange.getFileAsPath().equals(range.getFileAsPath()); if (wantNewFile) { FileEntry file = cvSections.ensureFileEntry(range); - previousRange = null; - CVUtil.debug(" adding linerecord for file: %s\n", file.getFileName()); - lineRecord.addNewFile(file); + if (file != null && file.getFileName() != null) { + previousRange = null; + CVUtil.debug(" processRange: addNewFile: %s\n", file); + lineRecord.addNewFile(file); + } else { + CVUtil.debug(" processRange: range has no file: %s\n", range); + return; + } } if (wantNewRange(previousRange, range)) { previousRange = range; - int lineLo = range.getLo() - primaryEntry.getPrimary().getLo(); - CVUtil.debug(" line: 0x%05x %s\n", lineLo, range.getLine()); - lineRecord.addNewLine(lineLo, range.getLine()); + int lineLoAddr = range.getLo() - primaryEntry.getPrimary().getLo(); + int line = range.getLine() < 1 ? 1 : range.getLine(); + CVUtil.debug(" processRange: addNewLine: 0x%05x %s\n", lineLoAddr, line); + lineRecord.addNewLine(lineLoAddr, line); } } - private boolean isGraalIntrinsic(String className) { - return className.startsWith("com.oracle.svm") || className.startsWith("org.graalvm") || isJavaPackage(className); - } - + /** + * test to see if two ranges are adjacent, and can be combined into one + * @param previousRange the first range (lower address) + * @param range the second range (higher address) + * @return true if the two ranges can be combined + */ private boolean shouldMerge(Range previousRange, Range range) { + if (!mergeAdjacentLineRecords) { + return false; + } if (previousRange == null) { return false; } - if (skipGraalIntrinsics && isGraalIntrinsic(range.getClassName())) { + /* if we're in a different class that the primary Class, this is inlined code */ + final boolean isInlinedCode = !range.getClassName().equals(primaryEntry.getClassEntry().getClassName()); + // if (isInlinedCode && skipInlinedCode) { return true; } + if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { return true; } - return previousRange.getFileName().equals(range.getFileName()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); + return previousRange.getFileAsPath().equals(range.getFileAsPath()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); } + /** + * test to see if a new line record should be emitted + * @param previous previous range + * @param range current range + * @return true if the current range is on a different line or file from the previous one + */ private boolean wantNewRange(Range previous, Range range) { return true; /*if (debug) { @@ -147,21 +177,21 @@ private boolean wantNewRange(Range previous, Range range) { CVUtil.debug("wantNewRange() prevnull:true"); } else { CVUtil.debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previous.getLine() != range.getLine()) - + " fndiffer:" + (!previous.sameFileName(range)) + " contig:" + (previous.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); + + " fndiffer:" + (previous.getFilePath() != range.getFilePath()) + " contig:" + (previous.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); } - }*/ - /* + }* if (previous == null) return true; if (previous.getLine() != range.getLine()) return true; - if (!previous.sameFileName(range)) + if (previous.getFilePath() != range.getFilePath()) return true; + /* it might actually be fine to merge if there's a gap between ranges * if (previous.getHi() < range.getLo()) return true; - long delta = range.getHi() - previousRange.getLo(); - return delta >= 127; - */ + //long delta = range.getHi() - previousRange.getLo(); + //return delta >= 127; + return false; */ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java index 27da4409d1e6..957c981137c2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -30,7 +30,7 @@ import java.util.HashSet; abstract class CVRootPackages { - private static String[] rootPackageNames = { + private static final String[] rootPackageNames = { /* substrate root packages */ "com.oracle.graal.pointsto", "com.oracle.objectfile", @@ -157,22 +157,59 @@ abstract class CVRootPackages { "org.graalvm.util", }; + private static final String[] intrinsicClassNames = { + "com.oracle.svm.core.genscavenge.AlignedHeapChunk", + "com.oracle.svm.core.genscavenge.CardTable", + "com.oracle.svm.core.genscavenge.ObjectHeaderImpl", + "com.oracle.svm.core.genscavenge.graal.GenScavengeAllocationSnippets", + "com.oracle.svm.core.genscavenge.graal.BarrierSnippets", + "com.oracle.svm.core.snippets.KnownIntrinsics", + "com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets", + "com.oracle.svm.core.threadlocal.FastThreadLocalBytes", + "org.graalvm.compiler.replacements.AllocationSnippets", + "org.graalvm.compiler.nodes.PrefetchAllocateNode", + "com.oracle.svm.core.os.CopyingImageHeapProvider" + }; + private static final HashSet rootPackageSet; + private static final HashSet intrinsicClassNameSet; static { rootPackageSet = new HashSet<>(rootPackageNames.length); Collections.addAll(rootPackageSet, rootPackageNames); + intrinsicClassNameSet = new HashSet<>(intrinsicClassNames.length); + Collections.addAll(intrinsicClassNameSet, intrinsicClassNames); } - static boolean isRootPackage(String pn) { + static boolean isGraalPackage(String pn) { return rootPackageSet.contains(pn); } + private static String getPackagename(String className) { + return className.contains(".") ? className.substring(0, className.lastIndexOf('.')) : className; + } + + static boolean isGraalClass(String cn) { + final String pn = getPackagename(cn); + return isGraalPackage(pn); + } + + /** + * is class a Graal intrinsic class + * + * @param cn class name of code + * @return true if this is Graal intrinsic code + */ + static boolean isGraalIntrinsic(String cn) { + System.out.println("XXXXX isGraalIntrinsic " + cn + " " + intrinsicClassNameSet.contains(cn)); + return intrinsicClassNameSet.contains(cn); + } + static boolean isJavaPackage(String pn) { return pn.startsWith("java.") || pn.startsWith("javax.") || pn.startsWith("sun."); } - +/* static boolean isJavaFile(String pn) { return pn.startsWith("java/") || pn.startsWith("javax/") || pn.startsWith("sun/"); - } + }*/ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 2199bc9e1e61..59f67ef0edb8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -48,34 +48,73 @@ final class CVSymbolRecordBuilder { this.typeSection = cvSections.getCVTypeSection(); } + /** + * build DEBUG_S_SYMBOLS record from all classEntries + * (could probably build one per class or one per function) + */ void build() { - /* A module has a set of (function def, block def, linenumbers) for each function */ - String previousMethodName = ""; for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { - for (PrimaryEntry primary : classEntry.getPrimaryEntries()) { - Range range = primary.getPrimary(); - if (range.getFileName() != null) { - // for each function - String newMethodName = fixMethodName(range); - if (!newMethodName.equals(previousMethodName)) { - previousMethodName = newMethodName; - processFunction(newMethodName, range); - addLineNumberRecords(newMethodName, primary); - } + build(classEntry); + } + cvSections.getCVSymbolSection().addRecord(symbolRecord); + } + + /** + * build all debug info for a classEntry + * (does not yet handle member variables) + * + * @param classEntry current class + */ + private void build(ClassEntry classEntry) { + String previousMethodName = ""; + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + Range primaryRange = primaryEntry.getPrimary(); + if (primaryRange.getFileName() != null) { + // for each function + String newMethodName = fixMethodName(primaryRange); + if (!newMethodName.equals(previousMethodName)) { + previousMethodName = newMethodName; + build(primaryEntry, newMethodName); } } } - cvSections.getCVSymbolSection().addRecord(symbolRecord); + } + + /** + * emit records for each function: + * PROC32 + * S_FRAMEPROC + * S_END + * (later: type records as required) + * line number records + * + * @param primaryEntry primary entry for this function + * @param methodName method name alias as it will be seen by the user + */ + private void build(PrimaryEntry primaryEntry, String methodName) { + final Range primaryRange = primaryEntry.getPrimary(); + CVUtil.debug("addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); + int functionTypeIndex = addTypeRecords(primaryEntry); + byte funcFlags = 0; + CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvSections, methodName, 0, 0, 0, primaryRange.getHi() - primaryRange.getLo(), 0, 0, functionTypeIndex, primaryRange.getLo(), (short) 0, funcFlags); + addToSymbolRecord(proc32); + int frameFlags = 0; /* LLVM uses 0x14000; */ + addToSymbolRecord(new CVSymbolSubrecord.CVSymbolFrameProcRecord(cvSections, primaryRange.getHi() - primaryRange.getLo(), frameFlags)); + /* TODO: add local variables, and their types */ + addToSymbolRecord(new CVSymbolSubrecord.CVSymbolEndRecord(cvSections)); + addLineNumberRecords(primaryEntry, methodName); } private boolean noMainFound = true; /** * renames a method name ot something user friendly in the debugger - * (does not affect external symbols + * (does not affect external symbols used by linker) + * * first main function becomes class.main (unless replaceMainFunctionName is non-null) * if functionNamesHashArgs is true (which it must be for the linker to work properly) * all other functions become class.function.999 (where 999 is a hash of the arglist) + * * @param range Range contained in the method of interest * @return user debugger friendly method name */ @@ -98,21 +137,8 @@ private String fixMethodName(Range range) { return methodName; } - private void processFunction(String methodName, Range range) { - - CVUtil.debug("addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); - int functionTypeIndex = addTypeRecords(); - byte funcFlags = 0; - CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvSections, methodName, 0, 0, 0, range.getHi() - range.getLo(), 0, 0, functionTypeIndex, range.getLo(), (short) 0, funcFlags); - addToSymbolRecord(proc32); - int frameFlags = 0; /* LLVM uses 0x14000; */ - addToSymbolRecord(new CVSymbolSubrecord.CVSymbolFrameProcRecord(cvSections, range.getHi() - range.getLo(), frameFlags)); - /* TODO: add local variavles, and their types */ - addToSymbolRecord(new CVSymbolSubrecord.CVSymbolEndRecord(cvSections)); - } - - private void addLineNumberRecords(String methodName, PrimaryEntry primary) { - CVLineRecord record = new CVLineRecordBuilder(cvSections).build(methodName, primary); + private void addLineNumberRecords(PrimaryEntry primaryEntry, String methodName) { + CVLineRecord record = new CVLineRecordBuilder(cvSections).build(primaryEntry, methodName); /* * if the builder decides this entry is uninteresting, we don't build a record. * for example, Graal intrinsics may be uninteresting. @@ -127,8 +153,13 @@ private void addToSymbolRecord(CVSymbolSubrecord record) { symbolRecord.addRecord(record); } - private int addTypeRecords() { - /* add type records for function (later add arglist, and arrlist and local types) */ + /** + * add type records for function + * (later add arglist, and arrlist and local types) + * + * @return type index of function type + */ + private int addTypeRecords(PrimaryEntry unused) { CVTypeRecord.CVTypeArglistRecord argListType = addTypeRecord(new CVTypeRecord.CVTypeArglistRecord().add(T_NOTYPE)); CVTypeRecord funcType = addTypeRecord(new CVTypeRecord.CVTypeProcedureRecord().returnType(T_VOID).argList(argListType)); return funcType.getSequenceNumber(); From c53dd3468b73706cacd750ba03a3cfb5d446ad1f Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 10 Mar 2020 13:48:14 -0400 Subject: [PATCH 053/130] fix line numbers - add some usage info, get rid of debug line --- substratevm/DEBUGINFO.md | 2 +- substratevm/DEBUGINFO_WINDOWS.md | 35 +++++++++++++++++++ .../objectfile/pecoff/cv/CVRootPackages.java | 2 +- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 substratevm/DEBUGINFO_WINDOWS.md diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 4ea2b3f640c3..c0d2bd0470fa 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -1,4 +1,4 @@ -Using the ptototype debug info feature +Using the prototype debug info feature -------------------------------------- To add debug info to a generated native image add flag diff --git a/substratevm/DEBUGINFO_WINDOWS.md b/substratevm/DEBUGINFO_WINDOWS.md new file mode 100644 index 000000000000..80a3ce0b680a --- /dev/null +++ b/substratevm/DEBUGINFO_WINDOWS.md @@ -0,0 +1,35 @@ +Using the prototype debug info feature on windows. +-------------------------------------- + +To add debug info to a generated native image add flag +-H:GenerateDebugInfo= to the native image command line (where N is +a positive integer value -- the default value 0 means generate no +debug info). For example, + + $ javac Hello.java + $ mx native-image -H:GenerateDebugInfo=1 Hello + +The resulting image should contain CodeView4 debug records in a +format Visual Studio understands. + +Please read the standard DEBUGINFO file; this file only documents differences. + +Because of limitations in the linker, function names are mangled into the equivalent of + _package.class.Function_999_, where '999' is a hash of the function arguments. The exception is the first main() function encountered, + which is mangled to _package.class.main_, with no argument hash. + +As an experimental feature, the Windows debug info ignores inlined Graal code. +This is currently a Graal compile-time flag in CVConstants.java: _skipGraalIntrinsics_. + +To enable Visual Studio to access the cached sources, right click on the solution +in the "Solution Explorer", and select "Properties", then "Debug Source Files". +in the Debug Source Files plane, add the cache directories to the source directory list. + +___Unimplemented functionality___ + +- Currently stack frames are not properly expressed in the debug info. +The stack frame display may have extraneous information in it, and "Step Out", may work incorrectly. + +- Currently there is no type information in the debug info. + +- Currently variables and members do not appear in the type information. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java index 957c981137c2..f3fd55f3baf3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -201,7 +201,7 @@ static boolean isGraalClass(String cn) { * @return true if this is Graal intrinsic code */ static boolean isGraalIntrinsic(String cn) { - System.out.println("XXXXX isGraalIntrinsic " + cn + " " + intrinsicClassNameSet.contains(cn)); + //CVUtil.debug("XXXXX isGraalIntrinsic " + cn + " " + intrinsicClassNameSet.contains(cn)); return intrinsicClassNameSet.contains(cn); } From 9195a9c30bf1b11157f302011ce92b8e6b9b096b Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:11:44 +0000 Subject: [PATCH 054/130] define interfaces used to communicate debug info to object file and provide API method to install it --- .../src/com/oracle/objectfile/ObjectFile.java | 7 ++ .../debuginfo/DebugInfoProvider.java | 68 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index cbf13d644688..912e15f559b9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -45,6 +45,7 @@ import java.util.TreeSet; import java.util.stream.StreamSupport; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.elf.ELFObjectFile; import com.oracle.objectfile.macho.MachOObjectFile; import com.oracle.objectfile.pecoff.PECoffObjectFile; @@ -1086,6 +1087,12 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // flag compatibility } + // support for consuming debug info + + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + // do nothing by default + } + protected static Iterable allDecisions(final Map decisions) { return () -> StreamSupport.stream(decisions.values().spliterator(), false) .flatMap(layoutDecisionMap -> StreamSupport.stream(layoutDecisionMap.spliterator(), false)).iterator(); 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 new file mode 100644 index 000000000000..8d9c097a60c6 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debuginfo/DebugInfoProvider.java @@ -0,0 +1,68 @@ +package com.oracle.objectfile.debuginfo; +import java.util.List; + +// class defining interfaces used to allow a native image +// to communicate details of types, code and data to +// the underlying object file so that the object file +// can insert appropriate debug info +public interface DebugInfoProvider { + // access details of a specific type + interface DebugTypeInfo { + } + + // access details of a specific compiled method + interface DebugCodeInfo { + String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); + DebugLineInfoProvider lineInfoProvider(); + String paramNames(); + String returnTypeName(); + int getFrameSize(); + List getFrameSizeChanges(); + } + + // access details of a specific heap object + interface DebugDataInfo { + } + + // access details of a specific outer or inlined method at a given line number + interface DebugLineInfo { + String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); + } + + interface DebugFrameSizeChange + { + enum Type {EXTEND, CONTRACT}; + int getOffset(); + DebugFrameSizeChange.Type getType(); + } + + // convenience interface defining iterator type + interface DebugTypeInfoProvider extends Iterable { + } + + // convenience interface defining iterator type + interface DebugCodeInfoProvider extends Iterable { + } + + // convenience interface defining iterator type + interface DebugLineInfoProvider extends Iterable{ + } + + // convenience interface defining iterator type + interface DebugDataInfoProvider extends Iterable { + } + + DebugTypeInfoProvider typeInfoProvider(); + DebugCodeInfoProvider codeInfoProvider(); + DebugDataInfoProvider dataInfoProvider(); +} From 8fddfd3729c2e9ff0a2fcf192e7022606b3b5a8b Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:15:39 +0000 Subject: [PATCH 055/130] implement generation of basic DWARF sections in ELF object files --- .../oracle/objectfile/elf/ELFObjectFile.java | 38 + .../objectfile/elf/dwarf/ClassEntry.java | 159 ++ .../oracle/objectfile/elf/dwarf/DirEntry.java | 28 + .../objectfile/elf/dwarf/DwarfSections.java | 2267 +++++++++++++++++ .../objectfile/elf/dwarf/FileEntry.java | 28 + .../objectfile/elf/dwarf/PrimaryEntry.java | 106 + .../oracle/objectfile/elf/dwarf/Range.java | 135 + .../objectfile/elf/dwarf/StringEntry.java | 51 + .../objectfile/elf/dwarf/StringTable.java | 48 + 9 files changed, 2860 insertions(+) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 6a2f99a778ba..68ebf4f0967f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -42,6 +42,8 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.StringTable; import com.oracle.objectfile.SymbolTable; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.elf.dwarf.DwarfSections; import com.oracle.objectfile.io.AssemblyBuffer; import com.oracle.objectfile.io.OutputAssembler; @@ -1156,4 +1158,40 @@ public SymbolTable getSymbolTable() { protected int getMinimumFileSize() { return 0; } + + @Override + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + DwarfSections dwarfSections = new DwarfSections(getMachine()); + // we need an implementation for each section + DwarfSections.DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); + DwarfSections.DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); + DwarfSections.DwarfFrameSectionImpl frameSectionImpl = dwarfSections.getFrameSectionImpl(); + DwarfSections.DwarfInfoSectionImpl elfInfoSectionImpl = dwarfSections.getInfoSectionImpl(); + DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); + DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); + // now we can create the section elements with empty content + ELFSection strSection = (ELFSection)newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + ELFSection abbrevSection = (ELFSection)newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + ELFSection locSection= (ELFSection)newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + ELFSection infoSection = (ELFSection)newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + ELFSection aRangesSection = (ELFSection)newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + ELFSection debugSection = (ELFSection)newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + // the byte[] for each implementation's content are created and + // written under getOrDecideContent. doing that ensures that all + // dependent sections are filled in and then sized according to the + // declared dependencies. however, if we leave it at that then + // associated reloc sections only get created when the first reloc + // is inserted during content write that's too late for them to have + // layout constraints included in the layout decision set and causes + // an NPE during reloc section write. so we need to create the relevant + // reloc sections here in advance + elfStrSectionImpl.getOrCreateRelocationElement(false); + elfAbbrevSectionImpl.getOrCreateRelocationElement(false); + frameSectionImpl.getOrCreateRelocationElement(false); + elfInfoSectionImpl.getOrCreateRelocationElement(false); + elfARangesSectionImpl.getOrCreateRelocationElement(false); + elfLineSectionImpl.getOrCreateRelocationElement(false); + // ok now we can populate the implementations + dwarfSections.installDebugInfo(debugInfoProvider); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java new file mode 100644 index 000000000000..f70b5cd387d8 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -0,0 +1,159 @@ +package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ClassEntry + { + // the name of the associated class + private String className; + // the associated file + FileEntry fileEntry; + // a list recording details of all primary ranges included in + // this class sorted by ascending address range + private LinkedList primaryEntries; + // an index identifying primary ranges which have already been encountered + private Map primaryIndex; + // an index of all primary and secondary files referenced from this class's CU + private Map localFilesIndex; + // a list of the same files + private LinkedList localFiles; + // an index of all primary and secondary dirs referenced from this class's CU + private HashMap localDirsIndex; + // a list of the same dirs + private LinkedList localDirs; + // index of debug_info section compilation unit for this class + private int cuIndex; + // index into debug_line section for associated CU + private int lineIndex; + // size of line number info prologue region for associated CU + private int linePrologueSize; + // total size of line number info region for associated CU + private int totalSize; + + public ClassEntry(String className, FileEntry fileEntry) + { + this.className = className; + this.fileEntry = fileEntry; + this.primaryEntries = new LinkedList<>(); + this.primaryIndex = new HashMap<>(); + this.localFiles = new LinkedList<>(); + this.localFilesIndex = new HashMap<>(); + this.localDirs = new LinkedList<>(); + this.localDirsIndex = new HashMap<>(); + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.dirEntry; + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + this.cuIndex = -1; + this.lineIndex = -1; + this.linePrologueSize = -1; + this.totalSize = -1; + } + + PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) + { + if(primaryIndex.get(primary) == null) { + PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); + primaryEntries.add(primaryEntry); + primaryIndex.put(primary, primaryEntry); + return primaryEntry; + } + return null; + } + void addSubRange(Range subrange, FileEntry subFileEntry) { + Range primary = subrange.getPrimary(); + // the subrange should belong to a primary range + assert primary != null; + PrimaryEntry primaryEntry = primaryIndex.get(primary); + // we should already have seen the primary range + assert primaryEntry != null; + assert primaryEntry.getClassEntry() == this; + primaryEntry.addSubRange(subrange, subFileEntry); + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.dirEntry; + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + } + public int localDirsIdx(DirEntry dirEntry) { + if (dirEntry != null) { + return localDirsIndex.get(dirEntry); + } else { + return 0; + } + } + + public int localFilesIdx(FileEntry fileEntry) { + return localFilesIndex.get(fileEntry); + } + + String getFileName() + { + return fileEntry.getFileName(); + } + + String getDirName() { + return fileEntry.getDirName(); + } + + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + return lineIndex; + } + void setLineIndex(int lineIndex) { + this.lineIndex = lineIndex; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + public FileEntry getFileEntry() { + return fileEntry; + } + public String getClassName() { + return className; + } + public LinkedList getPrimaryEntries() { + return primaryEntries; + } + public Object primaryIndexFor(Range primaryRange) { + return primaryIndex.get(primaryRange); + } + public LinkedList getLocalDirs() + { + return localDirs; + } + public LinkedList getLocalFiles() + { + return localFiles; + } + } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java new file mode 100644 index 000000000000..45ad9a44b088 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -0,0 +1,28 @@ +package com.oracle.objectfile.elf.dwarf; + +// files may be located in a source directory associated +// with a well known substratevm or compiler root package +// in that case the the file's directory path will be something +// like "foo.bar.baz/src/foo/bar/baz/mumble/grumble/bletch" +// i.e. the root package and "src" will be inserted as a prefix +// before the dirs derived from the actual package +// files whose package does not match a well-known root package +// will be listed using the dirs derived from the package +// i.e. simply "foo/bar/baz/mumble/grumble/bletch" + +public class DirEntry +{ + private String path; + + // create an entry for a root package path + // or a user path not under a root package + public DirEntry(String path) { + this.path = path; + } + + public String getPath() + { + return path; + } +} + diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java new file mode 100644 index 000000000000..8ba6c884aca9 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -0,0 +1,2267 @@ +package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; +import com.oracle.objectfile.ObjectFile.Element; +import com.oracle.objectfile.elf.ELFMachine; +import com.oracle.objectfile.elf.ELFObjectFile.ELFSection; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class DwarfSections +{ + // names of the different sections we create or reference + // in reverse dependency order + public static final String TEXT_SECTION_NAME = ".text"; + public static final String DW_STR_SECTION_NAME = ".debug_str"; + public static final String DW_LINE_SECTION_NAME = ".debug_line"; + public static final String DW_FRAME_SECTION_NAME = ".debug_frame"; + public static final String DW_ABBREV_SECTION_NAME = ".debug_abbrev"; + public static final String DW_INFO_SECTION_NAME = ".debug_info"; + public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; + + // dwarf version 2 is all we need for debug info + private static final short DW_VERSION_2 = 2; + + // define all the abbrev section codes we need for our DIEs + private static final int DW_ABBREV_CODE_null = 0; + private static final int DW_ABBREV_CODE_compile_unit = 1; + private static final int DW_ABBREV_CODE_subprogram = 2; + + // define all the Dwarf tags we need for our DIEs + private static final int DW_TAG_compile_unit = 0x11; + private static final int DW_TAG_subprogram = 0x2e; + // define all the Dwarf attributes we need for our DIEs + private static final int DW_AT_null = 0x0; + private static final int DW_AT_name = 0x3; + private static final int DW_AT_comp_dir = 0x1b; + private static final int DW_AT_stmt_list = 0x10; + private static final int DW_AT_low_pc = 0x11; + private static final int DW_AT_hi_pc = 0x12; + private static final int DW_AT_language = 0x13; + private static final int DW_AT_external = 0x3f; + // private static final int DW_AT_return_addr = 0x2a; + private static final int DW_AT_frame_base = 0x40; + // define all the Dwarf attribute forms we need for our DIEs + private static final int DW_FORM_null = 0x0; + private static final int DW_FORM_string = 0x8; + private static final int DW_FORM_strp = 0xe; // not currently used + private static final int DW_FORM_addr = 0x1; + private static final int DW_FORM_data1 = 0x0b; // use flag instead + private static final int DW_FORM_data4 = 0x6; + private static final int DW_FORM_data8 = 0x7; + private static final int DW_FORM_block1 = 0x0a; + private static final int DW_FORM_flag = 0xc; + + // define specific attribute values for given attribute or form types + // DIE header has_children attribute values + private static final byte DW_CHILDREN_no = 0; + private static final byte DW_CHILDREN_yes = 1; + // DW_FORM_flag attribute values + private static final byte DW_FLAG_false = 0; + private static final byte DW_FLAG_true = 1; + // value for DW_AT_language attribute with form DATA1 + private final static byte DW_LANG_Java = 0xb; + // access not needed until we make functions members + // DW_AT_Accessibility attribute values + // private static final byte DW_ACCESS_public = 1; + // private static final byte DW_ACCESS_protected = 2; + // private static final byte DW_ACCESS_private = 3; + + + // not yet needed + // private static final int DW_AT_type = 0; // only present for non-void functions + // private static final int DW_AT_accessibility = 0; + + // CIE and FDE entries + + public final static int DW_CFA_CIE_id = -1; + public final static int DW_CFA_FDE_id = 0; + + public final static byte DW_CFA_CIE_version = 1; + + // values for high 2 bits + public final static byte DW_CFA_advance_loc = 0x1; + public final static byte DW_CFA_offset = 0x2; + public final static byte DW_CFA_restore = 0x3; + + // values for low 6 bits + public final static byte DW_CFA_nop = 0x0; + public final static byte DW_CFA_set_loc1 = 0x1; + public final static byte DW_CFA_advance_loc1 = 0x2; + public final static byte DW_CFA_advance_loc2 = 0x3; + public final static byte DW_CFA_advance_loc4 = 0x4; + public final static byte DW_CFA_offset_extended = 0x5; + public final static byte DW_CFA_restore_extended = 0x6; + public final static byte DW_CFA_undefined = 0x7; + public final static byte DW_CFA_same_value = 0x8; + public final static byte DW_CFA_register = 0x9; + public final static byte DW_CFA_def_cfa = 0xc; + public final static byte DW_CFA_def_cfa_register = 0xd; + public final static byte DW_CFA_def_cfa_offset = 0xe; + + private ELFMachine elfMachine; + private DwarfStrSectionImpl dwarfStrSection; + private DwarfAbbrevSectionImpl dwarfAbbrevSection; + private DwarfInfoSectionImpl dwarfInfoSection; + private DwarfARangesSectionImpl dwarfARangesSection; + private DwarfLineSectionImpl dwarfLineSection; + private DwarfFrameSectionImpl dwarfFameSection; + + public DwarfSections(ELFMachine elfMachine) { + this.elfMachine = elfMachine; + dwarfStrSection = new DwarfStrSectionImpl(); + dwarfAbbrevSection = new DwarfAbbrevSectionImpl(); + dwarfInfoSection = new DwarfInfoSectionImpl(); + dwarfARangesSection = new DwarfARangesSectionImpl(); + dwarfLineSection = new DwarfLineSectionImpl(); + dwarfFameSection = (elfMachine == ELFMachine.AArch64 + ? new DwarfFrameSectionImplAArch64() + : new DwarfFrameSectionImplX86_64()); + } + + public DwarfStrSectionImpl getStrSectionImpl() { + return dwarfStrSection; + } + + public DwarfAbbrevSectionImpl getAbbrevSectionImpl() { + return dwarfAbbrevSection; + } + + public DwarfFrameSectionImpl getFrameSectionImpl() { + return dwarfFameSection; + } + + public DwarfInfoSectionImpl getInfoSectionImpl() { + return dwarfInfoSection; + } + + public DwarfARangesSectionImpl getARangesSectionImpl() { + return dwarfARangesSection; + } + + public DwarfLineSectionImpl getLineSectionImpl() { + return dwarfLineSection; + } + + public ELFMachine getElfMachine() { + return elfMachine; + } + + // a scratch buffer used during computation of a section's size + protected final static byte[] scratch = new byte[10]; + + // table listing all known strings + private StringTable stringTable = new StringTable(); + + // list detailing all dirs in which files are found to reside + // either as part of substrate/compiler or user code + private LinkedList dirs = new LinkedList(); + // index of already seen dirs + private Map dirsIndex = new HashMap<>(); + + // The obvious traversal structure for debug records is + // 1) by top level compiled method (primary Range) ordered by ascending address + // 2) by inlined method (sub range) within top level method ordered by ascending address + // this ensures that all debug records are generated in increasing address order + + // a list recording details of all primary ranges included in + // this file sorted by ascending address range + private LinkedList primaryEntries = new LinkedList(); + + // An alternative traversal option is + // 1) by top level class (String id) + // 2) by top level compiled method (primary Range) within a class ordered by ascending address + // 3) by inlined method (sub range) within top level method ordered by ascending address + // + // this relies on the (current) fact that methods of a given class always appear + // in a single continuous address range with no intervening code from other methods + // or data values. this means we can treat each class as a compilation unit, allowing + // data common to all methods of the class to be shared. + // + // Unfortunately, files cannot be treated as the compilation unit. A file F may contain + // multiple classes, say C1 and C2. There is no guarantee that methods for some other + // class C' in file F' will not be compiled into the address space interleaved between + // methods of C1 and C2. That is a shame because generating debug info records one file at a + // time would allow more sharing e.g. enabling all classes in a file to share a single copy + // of the file and dir tables. + + // list of class entries detailing class info for primary ranges + private LinkedList primaryClasses = new LinkedList(); + // index of already seen classes + private Map primaryClassesIndex = new HashMap<>(); + + // List of files which contain primary ranges + private LinkedList primaryFiles = new LinkedList(); + // List of files which contain primary or secondary ranges + private LinkedList files = new LinkedList(); + // index of already seen files + private Map filesIndex = new HashMap<>(); + + private static String[] root_pkgs = { + // substrate root packages + "com.oracle.graal.pointsto", + "com.oracle.objectfile", + "com.oracle.svm.agent", + "com.oracle.svm.configure", + "com.oracle.svm.core", + "com.oracle.svm.core.genscavenge", + "com.oracle.svm.core.graal", + "com.oracle.svm.core.graal.aarch64", + "com.oracle.svm.core.graal.amd64", + "com.oracle.svm.core.graal.llvm", + "com.oracle.svm.core.jdk11", + "com.oracle.svm.core.jdk8", + "com.oracle.svm.core.posix", + "com.oracle.svm.core.posix.jdk11", + "com.oracle.svm.core.windows", + "com.oracle.svm.driver", + "com.oracle.svm.graal", + "com.oracle.svm.graal.hotspot.libgraal", + "com.oracle.svm.hosted", + "com.oracle.svm.jline", + "com.oracle.svm.jni", + "com.oracle.svm.junit", + "com.oracle.svm.libffi", + "com.oracle.svm.native.jvm.posix", + "com.oracle.svm.native.jvm.windows", + "com.oracle.svm.native.libchelper", + "com.oracle.svm.native.strictmath", + "com.oracle.svm.polyglot", + "com.oracle.svm.reflect", + "com.oracle.svm.test", + "com.oracle.svm.test.jdk11", + "com.oracle.svm.thirdparty", + "com.oracle.svm.truffle", + "com.oracle.svm.truffle.nfi", + "com.oracle.svm.truffle.nfi.posix", + "com.oracle.svm.truffle.nfi.windows", + "com.oracle.svm.tutorial", + "com.oracle.svm.util", + "com.oracle.svm.util.jdk11", + "org.graalvm.polyglot.nativeapi", + // compiler root packages + "jdk.tools.jaotc", + "jdk.tools.jaotc.binformat", + "jdk.tools.jaotc", + "org.graalvm.compiler.api.directives", + "org.graalvm.compiler.api.replacements", + "org.graalvm.compiler.api.runtime", + "org.graalvm.compiler.asm", + "org.graalvm.compiler.asm.aarch64", + "org.graalvm.compiler.asm.amd64", + "org.graalvm.compiler.asm.sparc", + "org.graalvm.compiler.bytecode", + "org.graalvm.compiler.code", + "org.graalvm.compiler.core", + "org.graalvm.compiler.core.aarch64", + "org.graalvm.compiler.core.amd64", + "org.graalvm.compiler.core.common", + "org.graalvm.compiler.core.llvm", + "org.graalvm.compiler.core.match.processor", + "org.graalvm.compiler.core.sparc", + "org.graalvm.compiler.debug", + "org.graalvm.compiler.graph", + "org.graalvm.compiler.hotspot", + "org.graalvm.compiler.hotspot.aarch64", + "org.graalvm.compiler.hotspot.amd64", + "org.graalvm.compiler.hotspot.jdk8", + "org.graalvm.compiler.hotspot.management", + "org.graalvm.compiler.hotspot.sparc", + "org.graalvm.compiler.java", + "org.graalvm.compiler.jtt", + "org.graalvm.compiler.lir", + "org.graalvm.compiler.lir.aarch64", + "org.graalvm.compiler.lir.amd64", + "org.graalvm.compiler.lir.jtt", + "org.graalvm.compiler.lir.sparc", + "org.graalvm.compiler.loop", + "org.graalvm.compiler.loop.phases", + "org.graalvm.compiler.microbenchmarks", + "org.graalvm.compiler.nodeinfo", + "org.graalvm.compiler.nodeinfo.processor", + "org.graalvm.compiler.nodes", + "org.graalvm.compiler.options", + "org.graalvm.compiler.options.processor", + "org.graalvm.compiler.phases", + "org.graalvm.compiler.phases.common", + "org.graalvm.compiler.printer", + "org.graalvm.compiler.processor", + "org.graalvm.compiler.replacements", + "org.graalvm.compiler.replacements.aarch64", + "org.graalvm.compiler.replacements.amd64", + "org.graalvm.compiler.replacements.processor", + "org.graalvm.compiler.replacements.sparc", + "org.graalvm.compiler.runtime", + "org.graalvm.compiler.serviceprovider", + "org.graalvm.compiler.serviceprovider.jdk8", + "org.graalvm.compiler.serviceprovider.processor", + "org.graalvm.compiler.truffle.common", + "org.graalvm.compiler.truffle.common.hotspot", + "org.graalvm.compiler.truffle.common.hotspot.libgraal", + "org.graalvm.compiler.truffle.common.processor", + "org.graalvm.compiler.truffle.compiler", + "org.graalvm.compiler.truffle.compiler.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot", + "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", + "org.graalvm.compiler.truffle.compiler.hotspot.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", + "org.graalvm.compiler.truffle.compiler.hotspot.sparc", + "org.graalvm.compiler.truffle.runtime", + "org.graalvm.compiler.truffle.runtime.hotspot", + "org.graalvm.compiler.truffle.runtime.hotspot.java", + "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", + "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", + "org.graalvm.compiler.truffle.runtime.serviceprovider", + "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", + "org.graalvm.compiler.virtual", + "org.graalvm.compiler.virtual.bench", + "org.graalvm.compiler.word", + "org.graalvm.graphio", + "org.graalvm.libgraal", + "org.graalvm.libgraal.jdk8", + "org.graalvm.micro.benchmarks", + "org.graalvm.util", + // sdk root packages + "org.graalvm.collections", + "org.graalvm.launcher", + "org.graalvm.options", + "org.graalvm.polyglot", + "org.graalvm.home", + "org.graalvm.nativeimage", + "org.graalvm.polyglot.tck", + "org.graalvm.word", + }; + + public String uniqueString(String string) { + return stringTable.uniqueString(string); + } + + public String uniqueDebugString(String string) { + return stringTable.uniqueDebugString(string); + } + + private int debugStringIndex(String string) { + return stringTable.debugStringIndex(string); + } + + public void installDebugInfo(DebugInfoProvider debugInfoProvider) + { + DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); + for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { + // install types + } + + // ensure we have a null string in the string section + uniqueDebugString(""); + + DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); + for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { + // primary file name and full method name need to be written to the debug_str section + // + String fileName = debugCodeInfo.fileName(); + String className = debugCodeInfo.className(); + String methodName = debugCodeInfo.methodName(); + String paramNames = debugCodeInfo.paramNames(); + String returnTypeName = debugCodeInfo.returnTypeName(); + int lo = debugCodeInfo.addressLo(); + int hi = debugCodeInfo.addressHi(); + int primaryLine = debugCodeInfo.line(); + Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); + // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, returnTypeName, className, methodName, paramNames, fileName); + // create an infoSection entry for the method + addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); + for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { + String fileNameAtLine = debugLineInfo.fileName(); + String classNameAtLine = debugLineInfo.className(); + String methodNameAtLine = debugLineInfo.methodName(); + int loAtLine = lo + debugLineInfo.addressLo(); + int hiAtLine = lo + debugLineInfo.addressHi(); + int line = debugLineInfo.line(); + // record all subranges even if they have no line or file so we at least get a symbol for them + Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); + addSubRange(primaryRange, subRange); + } + } + DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + for (DebugDataInfo debugDataInfo : dataInfoProvider) { + // install details of heap elements + String name = debugDataInfo.toString(); + } + } + + public ClassEntry ensureClassEntry(Range range) { + String className = range.getClassName(); + // see if we already have an entry + ClassEntry classEntry = primaryClassesIndex.get(className); + if (classEntry == null) { + // create and index the entry associating it with the right file + FileEntry fileEntry = ensureFileEntry(range); + classEntry = new ClassEntry(className, fileEntry); + primaryClasses.add(classEntry); + primaryClassesIndex.put(className, classEntry); + } + assert classEntry.getClassName().equals(className); + return classEntry; + } + + public FileEntry ensureFileEntry(Range range) { + String fileName = range.getFileName(); + // ensure we have an entry + FileEntry fileEntry = filesIndex.get(fileName); + if(fileEntry == null) { + DirEntry dirEntry = ensureDirEntry(fileName); + String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); + fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), + stringTable.uniqueString(baseName), + dirEntry); + files.add(fileEntry); + filesIndex.put(fileName, fileEntry); + // if this is a primary entry then add it to the primary list + if(range.isPrimary()) { + primaryFiles.add(fileEntry); + } else { + Range primaryRange = range.getPrimary(); + FileEntry primaryEntry = filesIndex.get(primaryRange.getFileName()); + assert primaryEntry != null; + } + } + return fileEntry; + } + + public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) + { + assert primaryRange.isPrimary(); + ClassEntry classEntry = ensureClassEntry(primaryRange); + PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); + if (entry != null) { + // track the entry for this range in address order + primaryEntries.add(entry); + } + } + + public void addSubRange(Range primaryRange, Range subrange) + { + assert primaryRange.isPrimary(); + assert !subrange.isPrimary(); + String className = primaryRange.getClassName(); + ClassEntry classEntry = primaryClassesIndex.get(className); + FileEntry subrangeEntry = ensureFileEntry(subrange); + // the primary range should already have been seen + // and associated with a primary class entry + assert classEntry.primaryIndexFor(primaryRange) != null; + classEntry.addSubRange(subrange, subrangeEntry); + } + + private DirEntry ensureDirEntry(String file) + { + int pathLength = file.lastIndexOf('/'); + if(pathLength < 0) { + // no path/package means use dir entry 0 + return null; + } + String filePath = file.substring(0, pathLength); + DirEntry dirEntry = dirsIndex.get(filePath); + if (dirEntry == null) { + dirEntry = new DirEntry(stringTable.uniqueString(filePath)); + dirsIndex.put(filePath, dirEntry); + dirs.add(dirEntry); + } + return dirEntry; + } + + // shared implementation methods to manage content creation + public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { + public boolean debug = false; + public long debug_text_base = 0; + public long debug_address = 0; + public int debug_base = 0; + + public DwarfSectionImpl() { + } + + public abstract void createContent(); + public abstract void writeContent(); + public void checkDebug(int pos) { + // if the env var relevant to this element + // type is set then switch on debugging + String name = getSectionName(); + String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); + if (System.getenv(envVarName) != null) { + debug = true; + debug_base = pos; + debug_address = debug_text_base; + } + } + + protected void debug(String format, Object ... args) + { + if(debug) { + System.out.format(format, args); + } + } + + // base level put methods that assume a non-null buffer + public int putByte(byte b, byte[] buffer, int pos) { + buffer[pos++] = b; + return pos; + } + public int putShort(short s, byte[] buffer, int pos) { + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + return pos; + } + public int putInt(int i, byte[] buffer, int pos) { + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + return pos; + } + public int putLong(long l, byte[] buffer, int pos) { + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + return pos; + } + public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { + // mark address so it is relocated relative to the start of the text segment + markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); + pos = putLong(0, buffer, pos); + return pos; + } + public int putULEB(long l, byte[] buffer, int pos) { + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >>> 7; + boolean done = (l == 0); + if(!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if(done) { + break; + } + } + return pos; + } + public int putSLEB(long l, byte[] buffer, int pos) { + boolean negative = l < 0; + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >> 7; + boolean bIsSigned = (b & 0x40) != 0; + boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); + if(!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if(done) { + break; + } + } + return pos; + } + public int putAsciiStringBytes(String s, byte[] buffer, int pos) { + return putAsciiStringBytes(s, 0, buffer, pos); + } + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { + for (int l = startChar; l < s.length(); l++) { + char c = s.charAt(l); + if(c > 127) { + throw new RuntimeException("oops : expected ASCII string! " + s); + } + buffer[pos++] = (byte) c; + } + buffer[pos++] = '\0'; + return pos; + } + + // common write methods that check for a null buffer + + public void patchLength(int lengthPos, byte[] buffer, int pos) { + if (buffer != null) { + int length = pos - (lengthPos + 4); + putInt(length, buffer, lengthPos); + } + } + + public int writeAbbrevCode(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeTag(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + public int writeFlag(byte flag, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(flag, scratch, 0); + } else { + return putByte(flag, buffer, pos); + } + } + + public int writeAttr_addr(long address, byte[] buffer, int pos) { + if (buffer == null) { + return pos + 8; + } else { + return putRelocatableCodeOffset(address, buffer, pos); + } + } + + public int writeAttr_data8(long value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putLong(value, scratch, 0); + } else { + return putLong(value, buffer, pos); + } + } + + public int writeAttr_data4(int value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putInt(value, scratch, 0); + } else { + return putInt(value, buffer, pos); + } + } + + public int writeAttr_data1(byte value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(value, scratch, 0); + } else { + return putByte(value, buffer, pos); + } + } + + public int writeAttr_null(byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(0, scratch, 0); + } else { + return putSLEB(0, buffer, pos); + } + } + + public abstract String targetSectionName(); + public abstract LayoutDecision.Kind[] targetSectionKinds(); + + public abstract String getSectionName(); + + /* + @Override + public int getOrDecideSize(Map alreadyDecided, int sizeHint) { + return super.getOrDecideSize(alreadyDecided, sizeHint); + } + */ + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + // ensure content byte[] has been created before calling super method + createContent(); + + // ensure content byte[] has been written before calling super method + writeContent(); + + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public Set getDependencies(Map decisions) + { + Set deps = super.getDependencies(decisions); + String targetName = targetSectionName(); + ELFSection targetSection = (ELFSection)getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + // make our content depend on the size and content of the target + for (LayoutDecision.Kind targetKind : targetKinds) { + LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + } + // make our size depend on our content + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + + return deps; + } + } + + public class DwarfStrSectionImpl extends DwarfSectionImpl { + public DwarfStrSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_STR_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + for (StringEntry stringEntry : stringTable) { + if (stringEntry.isAddToStrSection()){ + stringEntry.setOffset(pos); + String string = stringEntry.getString(); + pos += string.length() + 1; + } + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + for (StringEntry stringEntry : stringTable) { + if (stringEntry.isAddToStrSection()){ + assert stringEntry.getOffset() == pos; + String string = stringEntry.getString(); + pos = putAsciiStringBytes(string, buffer, pos); + } + } + assert pos == size; + } + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_str section content depends on text section content and offset + public final static String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { + + public DwarfAbbrevSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_ABBREV_SECTION_NAME; + } + + @Override + public void createContent() + { + int pos = 0; + // an abbrev table contains abbrev entries for one or + // more CUs. the table includes a sequence of abbrev + // entries each of which defines a specific DIE layout + // employed to describe some DIE in a CU. a table is + // terminated by a null entry + // + // a null entry has consists of just a 0 abbrev code + // LEB128 abbrev_code; // == 0 + // + // non-null entries have the following format + // LEB128 abbrev_code; // unique noncode for this layout != 0 + // 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 DIE + // * // zero or more attributes + // // terminator + // + // An attribute_spec consists of an attribute name and form + // LEB128 attr_name; // 0 for the null attribute name + // LEB128 attr_form; // 0 for the null attribute form + // + // For the moment we only use one abbrev table for all CUs. + // It contains two DIEs, the first to describe the compilation + // unit itself and the second to describe each method within + // that compilation unit. + // + // The DIE layouts are as follows: + // + // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + // DW_AT_language : DW_FORM_data1 + // DW_AT_name : DW_FORM_strp + // DW_AT_low_pc : DW_FORM_address + // DW_AT_hi_pc : DW_FORM_address + // DW_AT_stmt_list : DW_FORM_data4 + // + // abbrev_code == 2, tag == DW_TAG_subprogram, no_children + // DW_AT_name : DW_FORM_strp + // DW_AT_low_pc : DW_FORM_addr + // DW_AT_hi_pc : DW_FORM_addr + // DW_AT_external : DW_FORM_flag + + pos = writeAbbrev1(null, pos); + pos = writeAbbrev2(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + pos = writeAbbrev1(buffer, pos); + pos = writeAbbrev2(buffer, pos); + assert pos == size; + } + + public int writeAttrType(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAttrForm(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAbbrev1(byte[] buffer, int pos) { + // abbrev 1 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + pos = writeTag(DW_TAG_compile_unit, buffer, pos); + pos = writeFlag(DW_CHILDREN_yes, buffer, pos); + pos = writeAttrType(DW_AT_language, buffer, pos); + pos = writeAttrForm(DW_FORM_data1, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_stmt_list, buffer, pos); + pos = writeAttrForm(DW_FORM_data4, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + public int writeAbbrev2(byte[] buffer, int pos) { + // abbrev 2 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + pos = writeTag(DW_TAG_subprogram, buffer, pos); + pos = writeFlag(DW_CHILDREN_no, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_external, buffer, pos); + pos = writeAttrForm(DW_FORM_flag, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_abbrev section content depends on .debug_frame section content and offset + public final static String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { + + public DwarfFrameSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_FRAME_SECTION_NAME; + } + + @Override + public void createContent() + { + int pos = 0; + + // the frame section contains one CIE at offset 0 + // followed by an FIE for each method + pos = writeCIE(null, pos); + pos = writeMethodFrames(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + // there are entries for the prologue region where the + // stack is being built, the method body region(s) where + // the code executes with a fixed size frame and the + // epilogue region(s) where the stack is torn down + pos = writeCIE(buffer, pos); + pos = writeMethodFrames(buffer, pos); + + assert pos == size; + } + + public int writeCIE(byte[] buffer, int pos) { + // we only need a vanilla CIE with default fields + // because we have to have at least one + // the layout is + // + // uint32 : length // length of remaining fields in this CIE + // uint32 : CIE_id // unique id for CIE == 0xffffff + // uint8 : version // == 1 + // uint8[] : augmentation // == "" so always 1 byte + // ULEB : code_alignment_factor // 1 (could use 4 for Aarch64) + // ULEB : data_alignment_factor // -8 + // byte : ret_addr reg id // x86_64 => 16 AArch64 => 32 + // byte[] : initial_instructions // includes pad to 8-byte boundary + if (buffer == null) { + pos += putInt(0, scratch, 0); // don't care about length + pos += putInt(DW_CFA_CIE_id, scratch, 0); + pos += putByte(DW_CFA_CIE_version, scratch, 0); + pos += putAsciiStringBytes("", scratch, 0); + pos += putULEB(1, scratch, 0); + pos += putULEB(-8, scratch, 0); + pos += putByte((byte)getPCIdx(), scratch, 0); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + // no need to write length + return pos; + } else { + int lengthPos = pos; + pos = putInt(0, buffer, pos); + pos = putInt(DW_CFA_CIE_id, buffer, pos); + pos = putByte(DW_CFA_CIE_version, buffer, pos); + pos = putAsciiStringBytes("", buffer, pos); + pos = putULEB(1, buffer, pos); + pos = putSLEB(-8, buffer, pos); + pos = putByte((byte)getPCIdx(), buffer, pos); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + return pos; + } + } + + public int writeMethodFrames(byte[] buffer, int pos) { + for (ClassEntry classEntry : primaryClasses) { + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + long lo = primaryEntry.getPrimary().getLo(); + long hi = primaryEntry.getPrimary().getHi(); + int frameSize = primaryEntry.getFrameSize(); + int currentOffset = 0; + int lengthPos = pos; + pos = writeFDEHeader((int)lo, (int)hi, buffer, pos); + for (DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { + int advance = debugFrameSizeInfo.getOffset() - currentOffset; + currentOffset += advance; + pos = writeAdvanceLoc(advance, buffer, pos); + if (debugFrameSizeInfo.getType() == DebugFrameSizeChange.Type.EXTEND) { + // SP has been extended so rebase CFA using full frame + pos = writeDefCFAOffset(frameSize, buffer, pos); + } else { + // SP has been contracted so rebase CFA using empty frame + pos = writeDefCFAOffset(8, buffer, pos); + } + } + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + } + } + return pos; + } + + public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { + // we only need a vanilla FDE header with default fields + // the layout is + // + // uint32 : length // length of remaining fields in this FDE + // uint32 : CIE_offset // alwasy 0 i.e. identifies our only CIE header + // uint64 : initial_location // i.e. method lo address + // uint64 : address_range // i.e. method hi - lo + // byte[] : instructions // includes pad to 8-byte boundary + + int lengthPos = pos; + if (buffer == null) { + pos += putInt(0, scratch, 0); // dummy length + pos += putInt(0, scratch, 0); // CIE_offset + pos += putLong(lo, scratch, 0); // initial address + return pos + putLong(hi - lo, scratch, 0); // address range + } else { + pos = putInt(0, buffer, pos); // dummy length + pos = putInt(0, buffer, pos); // CIE_offset + pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address + return putLong(hi - lo, buffer, pos); // address range + } + } + + public int writePaddingNops(int alignment, byte[] buffer, int pos) { + assert (alignment & (alignment - 1)) == 0; + while ((pos & (alignment - 1)) != 0) { + if (buffer == null) { + pos++; + } else { + pos = putByte(DW_CFA_nop, buffer, pos); + } + } + return pos; + } + + public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa, scratch, 0); + pos += putSLEB(register, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa, buffer, pos); + pos = putULEB(register, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa_offset, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { + if (offset <= 0x3f) { + return writeAdvanceLoc0((byte) offset, buffer, pos); + } else if(offset <= 0xff) { + return writeAdvanceLoc1((byte) offset, buffer, pos); + } else if(offset <= 0xffff) { + return writeAdvanceLoc2((short) offset, buffer, pos); + } else { + return writeAdvanceLoc4(offset, buffer, pos); + } + } + public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { + byte op = advanceLoc0Op(offset); + if (buffer == null) { + return pos + putByte(op, scratch, 0); + } else { + return putByte(op, buffer, pos); + } + } + public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { + byte op = DW_CFA_advance_loc1; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putByte(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putByte(offset, buffer, pos); + } + } + public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { + byte op = DW_CFA_advance_loc2; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putShort(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putShort(offset, buffer, pos); + } + } + public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { + byte op = DW_CFA_advance_loc4; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putInt(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putInt(offset, buffer, pos); + } + } + public int writeOffset(int register, int offset, byte[] buffer, int pos) { + byte op = offsetOp(register); + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { + if (buffer == null) { + pos += putByte(DW_CFA_register, scratch, 0); + pos += putULEB(savedReg, scratch, 0); + return pos + putULEB(savedToReg, scratch, 0); + } else { + pos = putByte(DW_CFA_register, buffer, pos); + pos = putULEB(savedReg, buffer, pos); + return putULEB(savedToReg, buffer, pos); + } + } + + public abstract int getPCIdx(); + public abstract int getSPIdx(); + public abstract int writeInitialInstructions(byte[] buffer, int pos); + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + // .debug_frame section content depends on .debug_line section content and offset + public final static String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + private byte offsetOp(int register) { + assert (register >> 6) == 0; + return (byte)((DW_CFA_offset << 6) | register); + } + private byte advanceLoc0Op(int offset) { + assert (offset >= 0 && offset <= 0x3f); + return (byte)((DW_CFA_advance_loc << 6) | offset); + } + } + public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl + { + public final static int DW_CFA_RSP_IDX = 7; + public final static int DW_CFA_RIP_IDX = 16; + + public DwarfFrameSectionImplX86_64() { + super(); + } + @Override + public int getPCIdx() { + return DW_CFA_RIP_IDX; + } + @Override + public int getSPIdx() { + return DW_CFA_RSP_IDX; + } + @Override + public int writeInitialInstructions(byte[] buffer, int pos) + { + // rsp points at the word containing the saved rip + // so the frame base (cfa) is at rsp + 8 (why not - ???) + // def_cfa r7 (sp) offset 8 + pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); + // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa (why not -1 ???) + // offset r16 (rip) cfa - 8 + pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); + return pos; + } + } + public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl + { + public final static int DW_CFA_FP_IDX = 29; + public final static int DW_CFA_LR_IDX = 30; + public final static int DW_CFA_SP_IDX = 31; + public final static int DW_CFA_PC_IDX = 32; + + public DwarfFrameSectionImplAArch64() { + super(); + } + @Override + public int getPCIdx(){ + return DW_CFA_PC_IDX; + } + @Override + public int getSPIdx(){ + return DW_CFA_SP_IDX; + } + @Override + public int writeInitialInstructions(byte[] buffer, int pos) + { + // rsp has not been updated + // caller pc is in lr + // register r32 (rpc), r30 (lr) + pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); + return pos; + } + } + + public class DwarfInfoSectionImpl extends DwarfSectionImpl + { + // header section always contains fixed number of bytes + private static final int DW_DIE_HEADER_SIZE = 11; + + public DwarfInfoSectionImpl() + { + super(); + } + + @Override + public String getSectionName() + { + return DW_INFO_SECTION_NAME; + } + + @Override + public void createContent() + { + // we need a single level 0 DIE for each compilation unit (CU) + // Each CU's Level 0 DIE is preceded by a fixed header: + // and terminated by a null DIE + // uint32 length // excluding this length field + // uint16 dwarf_version // always 2 ?? + // uint32 abbrev offset // always 0 ?? + // uint8 address_size // always 8 + // * // sequence of top-level and nested child entries + // // == 0 + // + // a DIE is a recursively defined structure + // it starts with a code for the associated + // abbrev entry followed by a series of attribute + // values as determined by the entry terminated by + // a null value and followed by zero or more child + // DIEs (zero iff has_children == no_children) + // + // LEB128 abbrev_code != 0 // non-zero value indexes tag + attr layout of DIE + // * // value sequence as determined by abbrev entry + // * // sequence of child DIEs (if appropriate) + // // == 0 + // + // note that a null_DIE looks like + // LEB128 abbrev_code == 0 + // i.e. it also looks like a null_value + + byte[] buffer = null; + int pos = 0; + + for (ClassEntry classEntry : primaryClasses) { + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // no need to backpatch length at lengthPos + } + buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_INFO\n", pos); + debug(" [0x%08x] size = 0x%08x\n", pos, size); + for (ClassEntry classEntry : primaryClasses) { + // save the offset of this file's CU so it can + // be used when writing the aranges section + classEntry.setCUIndex(pos); + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + debug(" [0x%08x] Compilation Unit\n", pos, size); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // backpatch length at lengthPos (excluding length field) + patchLength(lengthPos, buffer, pos); + } + assert pos == size; + } + + public int writeCUHeader(byte[] buffer, int pos) { + if (buffer == null) { + pos += putInt(0, scratch, 0); // CU length + pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version + pos += putInt(0, scratch, 0); // abbrev offset + return pos + putByte((byte)8, scratch, 0); // address size + } else { + pos = putInt(0, buffer, pos); // CU length + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version + pos = putInt(0, buffer, pos); // abbrev offset + return putByte((byte)8, buffer, pos); // address size + } + } + public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) + { + LinkedList primaryEntries = classEntry.getPrimaryEntries(); + debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); + pos = writeAttr_data1(DW_LANG_Java, buffer, pos); + debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); + pos = writeAttr_strp(classEntry.getFileName(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, primaryEntries.getFirst().getPrimary().getLo()); + pos = writeAttr_addr(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + debug(" [0x%08x] hi_pc 0x%08x\n", pos, primaryEntries.getLast().getPrimary().getHi()); + pos = writeAttr_addr(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); + debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); + pos = writeAttr_data4(classEntry.getLineIndex(), buffer, pos); + for (PrimaryEntry primary : primaryEntries) { + pos = writePrimary(primary, buffer, pos); + } + // write a terminating null attribute for the the level 2 primaries + return writeAttr_null(buffer, pos); + + } + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) + { + Range primary = primaryEntry.getPrimary(); + debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getClassAndMethodNameWithParams()), primary.getClassAndMethodNameWithParams()); + pos = writeAttr_strp(primary.getClassAndMethodNameWithParams(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); + pos = writeAttr_addr(primary.getLo(), buffer, pos); + debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); + pos = writeAttr_addr(primary.getHi(), buffer, pos); + // need to pass true only if method is public + debug(" [0x%08x] external true\n", pos); + return writeFlag(DW_FLAG_true, buffer, pos); + } + public int writeAttr_strp(String value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putInt(0, scratch, 0); + } else { + int idx = debugStringIndex(value); + return putInt(idx, buffer, pos); + } + } + public int writeAttr_string(String value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + value.length() + 1; + } else { + return putAsciiStringBytes(value, buffer, pos); + } + } + protected void debug(String format, Object... args) { + if (((int) args[0] - debug_base) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + // .debug_info section content depends on abbrev section content and offset + public final static String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public class DwarfARangesSectionImpl extends DwarfSectionImpl { + private static final int DW_AR_HEADER_SIZE = 12; + private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size + + public DwarfARangesSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_ARANGES_SECTION_NAME; + } + + public void createContent() + { + int pos = 0; + // we need an entry for each compilation unit + // + // uint32 length // in bytes (not counting these 4 bytes) + // uint16 dwarf_version // always 2 + // uint32 info_offset // offset of compilation unit on debug_info + // uint8 address_size // always 8 + // uint8 segment_desc_size // ??? + // + // i.e. 12 bytes followed by padding + // aligning up to 2 * address size + // + // uint8 pad[4] + // + // followed by N + 1 times + // + // uint64 lo // lo address of range + // uint64 length // number of bytes in range + // + // where N is the number of ranges belonging to the compilation unit + // and the last range contains two zeroes + + for(ClassEntry classEntry : primaryClasses) { + pos += DW_AR_HEADER_SIZE; + // align to 2 * address size + pos += DW_AR_HEADER_PAD_SIZE; + pos += classEntry.getPrimaryEntries().size() * 2 * 8; + pos += 2 * 8; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) + { + Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debug_text_base = ((Number)valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + public void writeContent() + { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_ARANGES\n", pos); + for(ClassEntry classEntry : primaryClasses) { + int lastpos = pos; + int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; + int cuIndex = classEntry.getCUIndex(); + LinkedList primaryEntries = classEntry.getPrimaryEntries(); + // add room for each entry into length count + length += primaryEntries.size() * 2 * 8; + length += 2 * 8; + debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); + pos = putInt(length, buffer, pos); + pos = putShort(DW_VERSION_2,buffer, pos); // dwarf version is always 2 + pos = putInt(cuIndex, buffer, pos); + pos = putByte((byte)8, buffer, pos); // address size is always 8 + pos = putByte((byte)0, buffer, pos); // segment size is always 0 + assert (pos - lastpos) == DW_AR_HEADER_SIZE; + // align to 2 * address size + for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { + pos = putByte((byte)0, buffer, pos); + } + debug(" [0x%08x] Address Length Name\n", pos); + for (PrimaryEntry primaryEntry : primaryEntries) { + Range primary = primaryEntry.getPrimary(); + debug(" [0x%08x] %016x %016x %s\n", pos, debug_text_base + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); + pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); + pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); + } + pos = putLong(0, buffer, pos); + pos = putLong(0, buffer, pos); + } + + assert pos == size; + } + + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_aranges section content depends on .debug_info section content and offset + public final static String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } + + public class DwarfLineSectionImpl extends DwarfSectionImpl { + // header section always contains fixed number of bytes + private static final int DW_LN_HEADER_SIZE = 27; + // line base is -5 + private static final int DW_LN_LINE_BASE = -5; + // opcode line range is 14 giving full range -5 to 8 + private static final int DW_LN_LINE_RANGE = 14; + // opcode base should equal DW_LNS_define_file + 1 + private static final int DW_LN_OPCODE_BASE = 13; + + /* + * standard opcodes defined by Dwarf 2 + */ + private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an invalid opcode + private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for extended opcodes + private static final byte DW_LNS_copy = 1; // append current state as matrix row 0 args + private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg + private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg + private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg + private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg + private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args + private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row + private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode 255 0 args + private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg + + /* + * extended opcodes defined by Dwarf 2 + */ + private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 + private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses + private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 + private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 + + DwarfLineSectionImpl() { + super(); + } + + @Override + public String getSectionName() { + return DW_LINE_SECTION_NAME; + } + + public void createContent() { + // we need to create a header, dir table, file table and line + // number table encoding for each CU + + // write entries for each file listed in the primary list + int pos = 0; + for (ClassEntry classEntry : primaryClasses) { + int startPos = pos; + classEntry.setLineIndex(startPos); + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(classEntry); + int fileTableSize = computeFileTableSize(classEntry); + int prologueSize = headerSize + dirTableSize + fileTableSize; + classEntry.setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(classEntry); + int totalSize = prologueSize + lineNumberTableSize; + classEntry.setTotalSize(totalSize); + pos += totalSize; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + public int headerSize() { + // header size is standard 31 bytes + // uint32 total_length + // uint16 version + // uint32 prologue_length + // uint8 min_insn_length + // uint8 default_is_stmt + // int8 line_base + // uint8 line_range + // uint8 opcode_base + // uint8 li_opcode_base + // uint8[opcode_base-1] standard_opcode_lengths + + return DW_LN_HEADER_SIZE; + } + + public int computeDirTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int dirSize = 0; + for (DirEntry dir : classEntry.getLocalDirs()) { + dirSize += dir.getPath().length() + 1; + } + // allow for separator nul + dirSize++; + return dirSize; + } + + public int computeFileTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int fileSize = 0; + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we want the file base name excluding path + String baseName = localEntry.getBaseName(); + int length = baseName.length(); + fileSize += length + 1; + DirEntry dirEntry = localEntry.dirEntry; + int idx = classEntry.localDirsIdx(dirEntry); + fileSize += putULEB(idx, scratch, 0); + // the two zero timestamps require 1 byte each + fileSize += 2; + } + // allow for terminator nul + fileSize++; + return fileSize; + } + + public int computeLineNUmberTableSize(ClassEntry classEntry) { + // sigh -- we have to do this by generating the + // content even though we cannot write it into a byte[] + return writeLineNumberTable(classEntry,null, 0); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) + { + Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debug_text_base = ((Number)valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + public void writeContent() { + byte[] buffer = getContent(); + + int pos = 0; + checkDebug(pos); + debug(" [0x%08x] DEBUG_LINE\n", pos); + + for (ClassEntry classEntry : primaryClasses) { + int startPos = pos; + assert classEntry.getLineIndex() == startPos; + debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + pos = writeHeader(classEntry, buffer, pos); + debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + int dirTablePos = pos; + pos = writeDirTable(classEntry, buffer, pos); + debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(classEntry, buffer, pos); + debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(classEntry, buffer, pos); + debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); + debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + } + assert pos == buffer.length; + } + + public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) + { + // 4 ubyte length field + pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); + // 2 ubyte version is always 2 + pos = putShort(DW_VERSION_2, buffer, pos); + // 4 ubyte prologue length includes rest of header and + // dir + file table section + int prologueSize = classEntry.getLinePrologueSize() - 6; + pos = putInt(prologueSize, buffer, pos); + // 1 ubyte min instruction length is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte default is_stmt is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte line base is always -5 + pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); + // 1 ubyte line range is always 14 giving range -5 to 8 + pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); + // 1 ubyte opcode base is always 13 + pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); + // specify opcode arg sizes for the standard opcodes + putByte((byte) 0, buffer, pos); // DW_LNS_copy + putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc + putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line + putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file + putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column + putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt + putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block + putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc + putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc + putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence + putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address + pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file + return pos; + } + + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) + { + debug(" [0x%08x] Dir Name\n", pos); + // write out the list of dirs referenced form this file entry + int dirIdx = 1; + for (DirEntry dir : classEntry.getLocalDirs()) { + // write nul terminated string text. + debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); + pos = putAsciiStringBytes(dir.getPath(), buffer, pos); + dirIdx++; + } + // separate dirs from files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) + { + int fileIdx = 1; + debug(" [0x%08x] Entry Dir Name\n", pos); + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we need the file name minus path, the associated dir index, and 0 for time stamps + String baseName = localEntry.getBaseName(); + DirEntry dirEntry = localEntry.dirEntry; + int dirIdx = classEntry.localDirsIdx(dirEntry); + debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); + pos = putAsciiStringBytes(baseName, buffer, pos); + pos = putULEB(dirIdx, buffer, pos); + pos = putULEB(0, buffer, pos); + pos = putULEB(0, buffer, pos); + fileIdx++; + } + // terminate files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int debug_line = 1; + public int debug_copy_count = 0; + + + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) + { + // the primary file entry should always be first in the local files list + assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; + String primaryClassName = classEntry.getClassName(); + String primaryFileName = classEntry.getFileName(); + String file = primaryFileName; + int fileIdx = 1; + debug(" [0x%08x] primary class %s\n", pos, primaryClassName); + debug(" [0x%08x] primary file %s\n", pos, primaryFileName); + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + Range primaryRange = primaryEntry.getPrimary(); + assert primaryRange.getFileName().equals(primaryFileName); + // each primary represents a method i.e. a contiguous + // sequence of subranges. we assume the default state + // at the start of each sequence because we always post an + // end_sequence when we finish all the subranges in the method + long line = primaryRange.getLine(); + if(line < 0 && primaryEntry.getSubranges().size() > 0) { + line = primaryEntry.getSubranges().get(0).getLine(); + } + if(line < 0) { + line = 0; + } + long address = primaryRange.getLo(); + long hiAddress = address; + // int column = 0; + // boolean is_stmt = true; + // boolean is_basic_block = false; + // boolean end_sequence = false; + // set state for primary + + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + primaryRange.getLo(), debug_text_base + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); + + // initialize and write a row for the start of the primary method + pos = putSetFile(file, fileIdx, buffer, pos); + pos = putSetBasicBlock(buffer, pos); + // address is currently 0 + pos = putSetAddress(address, buffer, pos); + // state machine value of line is currently 1 + // increment to desired line + if(line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putCopy(buffer, pos); + + // now write a row for each subrange lo and hi + + for (Range subrange : primaryEntry.getSubranges()) { + assert subrange.getLo() >= primaryRange.getLo(); + assert subrange.getHi() <= primaryRange.getHi(); + FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); + String subfile = subFileEntry.getFileName(); + int subFileIdx = classEntry.localFilesIdx(subFileEntry); + long subLine = subrange.getLine(); + long subAddressLo = subrange.getLo(); + long subAddressHi = subrange.getHi(); + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + subAddressLo, debug_text_base + subAddressHi, subrange.getClassAndMethodName(), subLine); + if(subLine < 0) { + // no line info so stay at previous file:line + subLine = line; + subfile = file; + subFileIdx = fileIdx; + debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); + } + /* + // there is a temptation to append end sequence at here + // when the hiAddress lies strictly between the current + // address and the start of the next subrange because, + // ostensibly, we have void space between the end of + // the current subrange and the start of the next one. + // however, debug works better if we treat all the insns up + // to the next range start as belonging to the current line + // so the code below is not actually needed. it is left in + // to clarify i) that this is a deliberate choice and ii) what + // that deliberate choice is avoiding. + if(address < hiAddress && hiAddress < subAddressLo) { + long addressDelta = hiAddress - address; + // increment address to hi address, write an + // end sequence and update state to new range + pos = putAdvancePC(addressDelta, buffer, pos); + pos = putEndSequence(buffer, pos); + file = subfile; + fileIdx = subFileIdx; + pos = putSetFile(file, fileIdx, buffer, pos); + line = subLine; + // state machine value of line is currently 1 + // increment to desired line + if (line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putSetBasicBlock(buffer, pos); + // use a reloc to ensure address is relative to text base + address = hiAddress; + pos = putSetAddress(hiAddress, buffer, pos); + } + */ + // if we have to update to a new file then do so + if(subFileIdx != fileIdx) { + // update the current file + pos = putSetFile(subfile, (long) subFileIdx, buffer, pos); + file = subfile; + fileIdx = subFileIdx; + } + // check if we can advance line and/or address in + // one byte with a special opcode + long lineDelta = subLine - line; + long addressDelta = subAddressLo - address; + byte opcode = isSpecialOpcode(addressDelta, lineDelta); + if(opcode != DW_LNS_undefined) { + // ignore pointless write when addressDelta == lineDelta == 0 + if(addressDelta != 0 || lineDelta != 0) { + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // does it help to divide and conquer using + // a fixed address increment + int remainder = isConstAddPC(addressDelta); + if(remainder > 0) { + pos = putConstAddPC(buffer, pos); + // the remaining address can be handled with a + // special opcode but what about the line delta + opcode = isSpecialOpcode(remainder, lineDelta); + if(opcode != DW_LNS_undefined) { + // address remainder and line now fit + pos = putSpecialOpcode(opcode, buffer, pos); + } else { + // ok, bump the line separately then use a + // special opcode for the address remainder + opcode = isSpecialOpcode(remainder, 0); + assert opcode != DW_LNS_undefined; + pos = putAdvanceLine(lineDelta, buffer, pos); + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // increment line and pc separately + if(lineDelta != 0) { + pos = putAdvanceLine(lineDelta, buffer, pos); + } + // n.b. we might just have had an out of range line increment + // with a zero address increment + if(addressDelta > 0) { + // see if we can use a ushort for the increment + if(isFixedAdvancePC(addressDelta)) { + pos = putFixedAdvancePC((short) addressDelta, buffer, pos); + } else { + pos = putAdvancePC(addressDelta, buffer, pos); + } + } + pos = putCopy(buffer, pos); + } + } + // move line and address range on + line += lineDelta; + address += addressDelta; + hiAddress = subAddressHi; + } + // append a final end sequence just below the next primary range + if(address < primaryRange.getHi()) { + long addressDelta = primaryRange.getHi() - address; + // increment address before we write the end sequence + pos = putAdvancePC(addressDelta, buffer, pos); + } + pos = putEndSequence(buffer, pos); + } + debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); + + return pos; + } + + protected void debug(String format, Object... args) + { + if (((int) args[0] - debug_base) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + public int putCopy(byte[] buffer, int pos) + { + byte opcode = DW_LNS_copy; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debug_copy_count++; + debug(" [0x%08x] Copy %d\n", pos, debug_copy_count); + return putByte(opcode, buffer, pos); + } + } + + public int putAdvancePC(long uleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_advance_pc; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debug_address += uleb; + debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debug_address); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putAdvanceLine(long sleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_advance_line; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putSLEB(sleb, scratch, 0); + } else { + debug_line += sleb; + debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debug_line); + pos = putByte(opcode, buffer, pos); + return putSLEB(sleb, buffer, pos); + } + } + + public int putSetFile(String file, long uleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_set_file; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putSetColumn(long uleb, byte[] buffer, int pos) + { + byte opcode = DW_LNS_set_column; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putNegateStmt(byte[] buffer, int pos) + { + byte opcode = DW_LNS_negate_stmt; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + return putByte(opcode, buffer, pos); + } + } + + public int putSetBasicBlock(byte[] buffer, int pos) + { + byte opcode = DW_LNS_set_basic_block; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Set basic block\n", pos); + return putByte(opcode, buffer, pos); + } + } + + public int putConstAddPC(byte[] buffer, int pos) + { + byte opcode = DW_LNS_const_add_pc; + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + int advance = opcodeAddress((byte) 255); + debug_address += advance; + debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debug_address); + return putByte(opcode, buffer, pos); + } + } + + public int putFixedAdvancePC(short arg, byte[] buffer, int pos) + { + byte opcode = DW_LNS_fixed_advance_pc; + if(buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putShort(arg, scratch, 0); + } else { + debug_address += arg; + debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debug_address); + pos = putByte(opcode, buffer, pos); + return putShort(arg, buffer, pos); + } + } + + public int putEndSequence(byte[] buffer, int pos) + { + byte opcode = DW_LNE_end_sequence; + if(buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(1, scratch, 0); + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); + debug_address = debug_text_base; + debug_line = 1; + debug_copy_count = 0; + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(1, buffer, pos); + return putByte(opcode, buffer, pos); + } + } + + public int putSetAddress(long arg, byte[] buffer, int pos) + { + byte opcode = DW_LNE_set_address; + if(buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(9, scratch, 0); + pos = pos + putByte(opcode, scratch, 0); + return pos + putLong(arg, scratch, 0); + } else { + debug_address = debug_text_base + (int) arg; + debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debug_address); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(9, buffer, pos); + pos = putByte(opcode, buffer, pos); + return putRelocatableCodeOffset(arg, buffer, pos); + } + } + + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) + { + byte opcode = DW_LNE_define_file; + // calculate bytes needed for opcode + args + int fileBytes = file.length() + 1; + long insnBytes = 1; + insnBytes += fileBytes; + insnBytes += putULEB(uleb1, scratch, 0); + insnBytes += putULEB(uleb2, scratch, 0); + insnBytes += putULEB(uleb3, scratch, 0); + if(buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // write insnBytes as a ULEB + pos += putULEB(insnBytes, scratch, 0); + return pos + (int) insnBytes; + } else { + debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert insn length as uleb + pos = putULEB(insnBytes, buffer, pos); + // insert opcode and args + pos = putByte(opcode, buffer, pos); + pos = putAsciiStringBytes(file, buffer, pos); + pos = putULEB(uleb1, buffer, pos); + pos = putULEB(uleb2, buffer, pos); + return putULEB(uleb3, buffer, pos); + } + } + + public int opcodeId(byte opcode) + { + int iopcode = opcode & 0xff; + return iopcode - DW_LN_OPCODE_BASE; + } + + public int opcodeAddress(byte opcode) + { + int iopcode = opcode & 0xff; + return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + } + + public int opcodeLine(byte opcode) + { + int iopcode = opcode & 0xff; + return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; + } + + public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) + { + if(buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + if (debug && opcode== 0) { + debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debug_address, debug_line); + } + debug_address += opcodeAddress(opcode); + debug_line += opcodeLine(opcode); + debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", + pos, opcodeId(opcode), opcodeAddress(opcode), debug_address, opcodeLine(opcode), debug_line); + return putByte(opcode, buffer, pos); + } + } + + private final static int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + private final static int MAX_ADDPC_DELTA= MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); + + public byte isSpecialOpcode(long addressDelta, long lineDelta) + { + if(addressDelta < 0) { + return DW_LNS_undefined; + } + if(lineDelta >= DW_LN_LINE_BASE) { + long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; + if(offsetLineDelta < DW_LN_LINE_RANGE) { + // line_delta can be encoded + // check if address is ok + if(addressDelta <= MAX_ADDRESS_ONLY_DELTA) { + long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; + if(opcode <= 255) { + return (byte) opcode; + } + } + } + } + + // return invalid opcode + return DW_LNS_undefined; + } + + public int isConstAddPC(long addressDelta) + { + if(addressDelta < MAX_ADDRESS_ONLY_DELTA) { + return 0; + } + if(addressDelta <= MAX_ADDPC_DELTA) { + return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); + } else { + return 0; + } + } + + public boolean isFixedAdvancePC(long addressDiff) + { + return addressDiff >= 0 && addressDiff < 0xffff; + } + + // .debug_line section content depends on .debug_str section content and offset + public final static String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address + }; + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return TARGET_SECTION_KINDS; + } + } +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java new file mode 100644 index 000000000000..982305ac9015 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -0,0 +1,28 @@ +package com.oracle.objectfile.elf.dwarf; + +public class FileEntry +{ + // the name of the associated file including path + private String fileName; + // the name of the associated file excluding path + private String baseName; + // the directory entry associated with this file entry + DirEntry dirEntry; + + public FileEntry(String fileName, String baseName, DirEntry dirEntry) + { + this.fileName = fileName; + this.baseName = baseName; + this.dirEntry = dirEntry; + } + + public String getFileName() { + return fileName; + } + public String getBaseName() { + return baseName; + } + String getDirName() { + return (dirEntry != null ? dirEntry.getPath() : ""); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java new file mode 100644 index 000000000000..963e71714957 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -0,0 +1,106 @@ +package com.oracle.objectfile.elf.dwarf; + +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +public class PrimaryEntry + { + // the primary range detailed by this object + Range primary; + // details of the class owning this range + ClassEntry classEntry; + // a list of subranges associated with the primary range + List subranges; + // a mapping from subranges to their associated file entry + HashMap subrangeIndex; + // details of of compiled method frame size changes + private List frameSizeInfos; + // size of compiled method frame + private int frameSize; + // index of debug_info section compilation unit for this file + private int cuIndex; + // index into debug_line section for associated compilation unit + private int lineIndex; + // size of line number info prologue region for associated compilation unit + private int linePrologueSize; + // total size of line number info region for associated compilation unit + private int totalSize; + + public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { + this.primary = primary; + this.classEntry = classEntry; + this.subranges = new LinkedList<>(); + this.subrangeIndex = new HashMap<>(); + this.frameSizeInfos = frameSizeInfos; + this.frameSize = frameSize; + // initialize indices into other sections to illegal values + this.cuIndex = -1; + this.lineIndex = -1; + } + public void addSubRange(Range subrange, FileEntry subFileEntry) { + // we should not see a subrange more than once + assert !subranges.contains(subrange); + assert subrangeIndex.get(subrange) == null; + // we need to generate a file table entry + // for all ranges + subranges.add(subrange); + subrangeIndex.put(subrange, subFileEntry); + } + public Range getPrimary() { + return primary; + } + public ClassEntry getClassEntry() { + return classEntry; + } + public FileEntry getFileEntry() { + return classEntry.getFileEntry(); + } + public List getSubranges() { + return subranges; + } + public FileEntry getSubrangeFileEntry(Range subrange) { + return subrangeIndex.get(subrange); + } + List getFrameSizeInfos() { + return frameSizeInfos; + } + int getFrameSize() { + return frameSize; + } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + // should have been set before being read + assert lineIndex >= 0; + return lineIndex; + } + void setLineIndex(int lineIndex) { + // should only get set once to a non-negative value + assert lineIndex >= 0; + assert this.lineIndex == -1; + this.lineIndex = lineIndex; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java new file mode 100644 index 000000000000..7fc543efd256 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -0,0 +1,135 @@ +package com.oracle.objectfile.elf.dwarf; + +// details of a specific address range in a compiled method +// either a primary range identifying a whole method +// or a sub-range identifying a sequence of +// instructions that belong to an inlined method + +public class Range { + private String fileName; + private String className; + private String methodName; + private String paramNames; + private String returnTypeName; + private String fullMethodName; + private int lo; + private int hi; + private int line; + // this is null for a primary range + private Range primary; + + // create a primary range + Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { + this(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); + } + + // create a primary or secondary range + Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { + // currently file name and full method name need to go into the debug_str section + // other strings just need to be deduplicated to save space + this.fileName = stringTable.uniqueDebugString(fileName); + this.className = stringTable.uniqueString(className); + this.methodName = stringTable.uniqueString(methodName); + this.paramNames = stringTable.uniqueString(paramNames); + this.returnTypeName = stringTable.uniqueString(returnTypeName); + this.fullMethodName = stringTable.uniqueDebugString(getClassAndMethodNameWithParams()); + this.lo = lo; + this.hi = hi; + this.line = line; + this.primary = primary; + } + + + public boolean sameClassName(Range other) { + return className.equals(other.className); + } + + public boolean sameMethodName(Range other) { + return methodName.equals(other.methodName); + } + + public boolean sameParamNames(Range other) { + return paramNames.equals(other.paramNames); + } + + public boolean sameReturnTypeName(Range other) { + return returnTypeName.equals(other.returnTypeName); + } + + public boolean sameFileName(Range other) { + return fileName.equals(other.fileName); + } + + public boolean sameMethod(Range other) { + return sameClassName(other) && + sameMethodName(other) && + sameParamNames(other) && + sameReturnTypeName(other); + } + + public boolean contains(Range other) { + return (lo <= other.lo && hi >= other.hi); + } + + public boolean isPrimary() { + return getPrimary() == null; + } + + public Range getPrimary() { + return primary; + } + + public String getFileName() { + return fileName; + } + public String getClassName() { + return className; + } + public String getMethodName() { + return methodName; + } + public String getParamNames() { + return paramNames; + } + public String getReturnTypeName() { + return returnTypeName; + } + public int getHi() { + return hi; + } + public int getLo() { + return lo; + } + public int getLine() { + return line; + } + public String getClassAndMethodName() { + return getExtendedMethodName(false, false); + } + public String getClassAndMethodNameWithParams() { + return getExtendedMethodName(true, false); + } + + public String getFullMethodName() { + return getExtendedMethodName(true, true); + } + + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { + StringBuilder builder = new StringBuilder(); + if (includeReturnType && returnTypeName.length() > 0) { + builder.append(returnTypeName); + builder.append(' '); + } + if (className != null) { + builder.append(className); + builder.append("::"); + } + builder.append(methodName); + if (includeParams && !paramNames.isEmpty()) { + builder.append('('); + builder.append(paramNames); + builder.append(')'); + } + return builder.toString(); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java new file mode 100644 index 000000000000..ec564851e641 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -0,0 +1,51 @@ +package com.oracle.objectfile.elf.dwarf; + +// class used to ensure we keep only one copy of a String +// amd track it's locations in the string section should +// it need to be entered +public class StringEntry { + private String string; + private int offset; + private boolean addToStrSection; + + StringEntry(String string) { + this.string = string; + this.offset = -1; + } + public String getString() { + return string; + } + public int getOffset() { + // offset must be set before this can be fetched + assert offset >= 0; + return offset; + } + public void setOffset(int offset) { + assert this.offset < 0; + assert offset >= 0; + this.offset = offset; + } + public boolean isAddToStrSection() { + return addToStrSection; + } + public void setAddToStrSection() { + this.addToStrSection = true; + } + public boolean equals(Object object) { + if (object == null || !(object instanceof StringEntry)) { + return false; + } else { + StringEntry other = (StringEntry)object; + return this == other || string.equals(other.string); + } + } + public int hashCode() { + return string.hashCode() + 37; + } + public String toString() { + return string; + } + public boolean isEmpty() { + return string.length() == 0; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java new file mode 100644 index 000000000000..ba7285bdb1aa --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -0,0 +1,48 @@ +package com.oracle.objectfile.elf.dwarf; + +import java.util.HashMap; +import java.util.Iterator; + +// class which reduces incoming strings to unique +// instances and also marks strings which need +// to be written to the debug_str section +public class StringTable implements Iterable { + + private final HashMap table; + + public StringTable() { + this.table = new HashMap(); + } + + public String uniqueString(String string) { + return ensureString(string, false); + } + + public String uniqueDebugString(String string) { + return ensureString(string, true); + } + + private String ensureString(String string, boolean addToStrSection) { + StringEntry stringEntry = table.get(string); + if (stringEntry == null) { + stringEntry = new StringEntry(string); + table.put(string, stringEntry); + } + if (addToStrSection && !stringEntry.isAddToStrSection()) { + stringEntry.setAddToStrSection(); + } + return stringEntry.getString(); + } + + public int debugStringIndex(String string) { + StringEntry stringEntry = table.get(string); + assert stringEntry != null; + if (stringEntry == null) { + return -1; + } + return stringEntry.getOffset(); + } + public Iterator iterator() { + return table.values().iterator(); + } +} From 9e590de8b1b123d76827d0e90ec04924d96a36c6 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:23:46 +0000 Subject: [PATCH 056/130] drive native image debug info generation when -H:+TrackNodeSourcePosition is enabled --- .../svm/hosted/image/NativeBootImage.java | 278 ++++++++++++++++++ 1 file changed, 278 insertions(+) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 4fe2e4cc14aa..5ce766497ce4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -24,6 +24,8 @@ */ package com.oracle.svm.hosted.image; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.CONTRACT; import static com.oracle.svm.core.SubstrateUtil.mangleName; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; @@ -44,18 +46,27 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.hosted.meta.HostedType; +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.serviceprovider.BufferUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -67,6 +78,10 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; +import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; import com.oracle.objectfile.ObjectFile.RelocationKind; @@ -456,6 +471,12 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { cGlobals.writeData(rwDataBuffer, (offset, symbolName) -> defineDataSymbol(symbolName, rwDataSection, offset + RWDATA_CGLOBALS_PARTITION_OFFSET)); defineDataSymbol(CGlobalDataInfo.CGLOBALDATA_BASE_SYMBOL_NAME, rwDataSection, RWDATA_CGLOBALS_PARTITION_OFFSET); + // if we have constructed any debug info then + // give the object file a chance to install it + if (GraalOptions.TrackNodeSourcePosition.getValue(HostedOptionValues.singleton())) { + DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); + objectFile.installDebugInfo(provider); + } // - Write the heap, either to its own section, or to the ro and rw data sections. RelocatableBuffer heapSectionBuffer = null; ProgbitsSectionImpl heapSectionImpl = null; @@ -950,4 +971,261 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final ObjectFile objectFile; protected final NativeImageCodeCache codeCache; } + + private class NativeImageDebugInfoProvider implements DebugInfoProvider { + private final NativeImageCodeCache codeCache; + private final NativeImageHeap heap; + private final Iterator> codeCacheIterator; + private final Iterator> heapIterator; + + public NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { + super(); + this.codeCache = codeCache; + this.heap = heap; + this.codeCacheIterator = codeCache.compilations.entrySet().iterator(); + this.heapIterator = heap.objects.entrySet().iterator(); + } + @Override + public DebugTypeInfoProvider typeInfoProvider() + { + return () -> new Iterator() { + @Override + public boolean hasNext() { + return false; + } + @Override + public DebugTypeInfo next() { + return null; + } + }; + } + @Override + public DebugCodeInfoProvider codeInfoProvider() { + return () -> new Iterator() { + @Override + public boolean hasNext() { + return codeCacheIterator.hasNext(); + } + @Override + public DebugCodeInfo next() { + Map.Entry entry = codeCacheIterator.next(); + return new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue()); + } + }; + } + @Override + public DebugDataInfoProvider dataInfoProvider() + { + return () -> new Iterator() { + @Override + public boolean hasNext() { + return false; + } + @Override + public DebugDataInfo next() { + return null; + } + }; + } + } + + private class NativeImageDebugCodeInfo implements DebugCodeInfo + { + private final HostedMethod method; + private final CompilationResult compilation; + public NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { + this.method = method; + this.compilation = compilation; + } + @Override + public String fileName() { + HostedType declaringClass = method.getDeclaringClass(); + String name = declaringClass.getSourceFileName(); + if (name != null) { + // the file name will not include any path + // use the package to create a path prefix + Package pkg = declaringClass.getJavaClass().getPackage(); + if (pkg != null) { + String prefix = pkg.getName(); + prefix = prefix.replace('.', '/'); + name = prefix + "/" + name; + } + } else { + // build file name from the class name which includes the package + name = className(); + // try to map inner classes back to their parent class's file + int idx = name.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + return ""; + } + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + name = name.substring(0, idx); + } + name = name.replace('.','/') + ".java"; + } + return name; + } + @Override + public String className() + { + return method.format("%H"); + } + @Override + public String methodName() { + return method.format("%n"); + } + @Override + public String paramNames() { + return method.format("%P"); + } + @Override + public String returnTypeName() { + return method.format("%R"); + } + @Override + public int addressLo() { + return method.getCodeAddressOffset(); + } + @Override + public int addressHi() { + return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); + } + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(0); + } + return -1; + } + @Override + public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { + if (fileName().length() == 0) { + return () -> new Iterator() + { + @Override + public boolean hasNext() + { + return false; + } + @Override + public DebugLineInfo next() + { + return null; + } + }; + } + return () -> new Iterator() { + final Iterator sourceIterator = compilation.getSourceMappings().iterator(); + @Override + public boolean hasNext() + { + return sourceIterator.hasNext(); + } + @Override + public DebugLineInfo next() + { + return new NativeImageDebugLineInfo(sourceIterator.next()); + } + }; + } + public int getFrameSize() { + return compilation.getTotalFrameSize(); + } + public List getFrameSizeChanges() { + List frameSizeChanges = new LinkedList<>(); + for (Mark mark : compilation.getMarks()) { + // we only need to observe stack increment or decrement points + if(mark.id.equals("PROLOGUE_DECD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); + frameSizeChanges.add(sizeChange); + // } else if (mark.id.equals("PROLOGUE_END")) { + // can ignore these + // } else if (mark.id.equals("EPILOGUE_START")) { + // can ignore these + } else if(mark.id.equals("EPILOGUE_INCD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); + frameSizeChanges.add(sizeChange); + // } else if(mark.id.equals("EPILOGUE_END")) { + } + } + return frameSizeChanges; + } + } + private class NativeImageDebugLineInfo implements DebugLineInfo { + private final int bci; + private final ResolvedJavaMethod method; + private final int lo; + private final int hi; + public NativeImageDebugLineInfo(SourceMapping sourceMapping) { + NodeSourcePosition position = sourceMapping.getSourcePosition(); + int bci = position.getBCI(); + this.bci = (bci >= 0 ? bci : 0); + this.method = position.getMethod(); + this.lo = sourceMapping.getStartOffset(); + this.hi = sourceMapping.getEndOffset(); + } + @Override + public String fileName() { + String name = className(); + int idx = name.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + return ""; + } + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + name = name.substring(0, idx); + } + return name.replace('.','/') + ".java"; + } + @Override + public String className() + { + return method.format("%H"); + } + @Override + public String methodName() + { + return method.format("%n"); + } + @Override + public int addressLo() + { + return lo; + } + @Override + public int addressHi() + { + return hi; + } + @Override + public int line() + { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(bci); + } + return -1; + } + } + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange + { + private int offset; + private Type type; + public NativeImageDebugFrameSizeChange(int offset, Type type) { + this.offset = offset; + this.type = type; + } + @Override + public int getOffset() { + return offset; + } + @Override + public Type getType() { + return type; + } + } } From 5849bf0355e7ac7aa8e9093c9bd137941eb0bbc5 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 21 Jan 2020 17:26:06 +0000 Subject: [PATCH 057/130] script that writes a 'set directories' command into file .gdbsourcepath for use when debugging native image with gdb --- substratevm/write_gdbsourcepath | 199 ++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 substratevm/write_gdbsourcepath diff --git a/substratevm/write_gdbsourcepath b/substratevm/write_gdbsourcepath new file mode 100644 index 000000000000..2cf9c728e1a4 --- /dev/null +++ b/substratevm/write_gdbsourcepath @@ -0,0 +1,199 @@ +#!/bin/bash + + +function usage() +{ + echo "write_gdbsourcepath [-h | -v]" + echo "writes command to set source path to .gdbsourcepath" + echo "set GRAAL_SRC_ROOT to graal git repo root" + echo " defaults to .. when . = sdk, compile, substratevm, truffle" + echo "set GRAAL_JDK_SRC_ROOT to unzipped src.zip root" + echo " defaults to JAVA_HOME/src" + exit $1 +} + +function check_args() +{ + while [ $# -ge 1 ]; do + if [ "$1" == "-v" ]; then + VERBOSE=1 + shift + elif [ "$1" == "-h" ]; then + usage 0 + else + usage 1 + fi + done +} + +typeset -i VERBOSE +VERBOSE=0 + +# debug +function verbose() +{ + if [ $VERBOSE -eq 1 ]; then + echo $* + fi +} + +# check which java we are using and set up JAVA_VERSION +function check_java_version() +{ + JAVA_VERSION_STRING=$(java -version |& grep version | cut -d' ' -f3) + if [ "${JAVA_VERSION_STRING#\"1.8.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=8 + elif [ "${JAVA_VERSION_STRING#\"9.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=9 + elif [ "${JAVA_VERSION_STRING#\"11.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=11 + elif [ "${JAVA_VERSION_STRING#\"14.}" != "${JAVA_VERSION_STRING}" ]; then + JAVA_VERSION=14 + else + echo "Unrecognized java version : $JAVA_VERSION_STRING" + exit 1 + fi +} + +# check for the required source trees and +# set up GRAAL_SRC_ROOT and GRAAL_JDK_SRC_ROOT +function check_source_dirs() +{ + if [ -z "$GRAAL_SRC_ROOT" ]; then + # see if we are in one of the Graal trees + if [ "${PWD#*/sdk}" != "$PWD" -o \ + "${PWD#*/compiler}" != "$PWD" -o \ + "${PWD#*/substratevm}" != "$PWD" -o \ + "${PWD#*/truffle}" != "$PWD" ]; then + GRAAL_SRC_ROOT=$(cd ..; pwd) + echo "defaulting GRAAL_SRC_ROOT to .. : $GRAAL_SRC_ROOT" + else + echo "Please set GRAAL_SRC_ROOT to git repo checkout dir" + exit 1 + fi + fi + + if [ -z "$GRAAL_JDK_SRC_ROOT" ]; then + if [ ! -z "$JAVA_HOME" ]; then + GRAAL_JDK_SRC_ROOT=$JAVA_HOME/src + echo "defaulting GRAAL_JDK_SRC_ROOT to JAVA_HOME : $GRAAL_JDK_SRC_ROOT" + else + JAVA_EXE=`which java` + GRAAL_JDK_SRC_ROOT=${JAVA_EXE%/bin/java}/src + fi + fi +} + +# add sources from a supplied graal source dir +function add_sources() +{ + # sanity check + if [ ! -d $1 ]; then + echo "hmm, was expecting a graal component directory, not this : $1" + fi + if [ ! -d $1/src ]; then + echo "hmm, was expecting to find a graal component source tree, not this : $1/src" + fi + root=$1 + for dir in $1/src/* + do + typeset -i ignore + ignore=0 + verbose "considering $dir" + set -x + if [ ! -d ${dir}/src ]; then + ignore=1 + else + # look for test or jdk in the trailing path + tail=${dir#$root} + if [ "${tail%*test}" != "$tail" -o \ + "${tail#*test}" != "$tail" ] ; then + # ignore test dirs + ignore=1 + elif [ "${tail#*jdk}" != "$tail" ]; then + # check for a specific jdk release + if [ "${tail#jdk.}" != "$tail" ]; then + # jdk. as part of a package name is ok + echo '+++' + if ["${tail#jdk.}" != "$tail" ]; then + echo allow $dir + fi + echo /// + ignore=0 + elif [ "${tail#*jdk}" != "${JAVA_VERSION}" ]; then + # jdk must match JAVA_VERSION + echo '+++' + if [ "${dir#jdk.}" != "$dir" ]; then + echo disallow $dir + fi + echo /// + ignore=1 + fi + fi + fi + set +x + if [ $ignore -eq 1 ] ; then + verbose "ignoring $dir" + else + verbose "including $dir" + SOURCEPATH=${SOURCEPATH}:$dir/src + fi + done +} + +# add sources from a supplied java source dir +function add_java_sources() +{ + # sanity check + if [ ! -d $1 ]; then + echo "hmm, was expecting to find a JDK source dir, not this : $1" + fi + SOURCEPATH=${SOURCEPATH}:$1 +} + +check_args $* + +check_java_version + +check_source_dirs + +GRAAL_SDK_SRC_ROOT=${GRAAL_SRC_ROOT}/sdk +GRAAL_COMPILER_SRC_ROOT=${GRAAL_SRC_ROOT}/compiler +GRAAL_SUBSTRATEVM_SRC_ROOT=${GRAAL_SRC_ROOT}/substratevm +GRAAL_TRUFFLE_SRC_ROOT=${GRAAL_SRC_ROOT}/truffle + +SOURCEPATH= + +if [ -d ${GRAAL_SDK_SRC_ROOT} ]; then + add_sources ${GRAAL_SDK_SRC_ROOT} +else + echo "Unable to find sdk sources in ${GRAAL_SDK_SRC_ROOT}" +fi +if [ -d ${GRAAL_COMPILER_SRC_ROOT} ]; then + add_sources ${GRAAL_COMPILER_SRC_ROOT} +else + echo "Unable to find compiler sources in ${GRAAL_COMPILER_SRC_ROOT}" +fi +if [ -d ${GRAAL_SUBSTRATEVM_SRC_ROOT} ]; then + add_sources ${GRAAL_SUBSTRATEVM_SRC_ROOT} +else + echo "Unable to find substratevm sources in ${GRAAL_SUBSTRATEVM_SRC_ROOT}" +fi +if [ -d ${GRAAL_TRUFFLE_SRC_ROOT} ]; then + add_sources ${GRAAL_TRUFFLE_SRC_ROOT} +else + echo "Unable to find truffle sources in ${GRAAL_TRUFFLE_SRC_ROOT}" +fi + +if [ -d ${GRAAL_JDK_SRC_ROOT} ]; then + add_java_sources ${GRAAL_JDK_SRC_ROOT} +else + echo "Unable to find JDK sources in ${GRAAL_JDK_SRC_ROOT}/src" + echo "unzip src.zip into \${GRAAL_JDK_SRC_ROOT}/src" +fi + +SOURCEPATH=${SOURCEPATH#:*} +echo "set directories $SOURCEPATH" > .gdbsourcepath +if [ $VERBOSE -gt 0 ]; then + cat .gdbsourcepath +fi From 434d2342f7ac5f9aac698022a9974d1f54a05e69 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 10:32:26 +0000 Subject: [PATCH 058/130] instructions for using debug info prototype --- substratevm/DEBUGINFO.md | 127 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 substratevm/DEBUGINFO.md diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md new file mode 100644 index 000000000000..5b859cd3cd7a --- /dev/null +++ b/substratevm/DEBUGINFO.md @@ -0,0 +1,127 @@ +Using the ptototype debug info feature +-------------------------------------- + +To add debug info to a generated native image add flag +-H:+TrackNodeSourcePosition to the native image command line. + + mx native-image -H:+TrackNodeSourcePosition Hello.java + +The resulting image should contain code (method) debug symbols. + +What is currently implemented +----------------------------- + +The currently implemented features include: + + - break points configured by file and line or by method name + - single stepping by line including both into and over function calls + - stack backtraces (not including frames detailing inlined code) + +Note that single stepping within a compiled method includes file and +line number info for inlined code, including inlined Graal methods. +So, gdb may switch files even though you are still in the same +compiled method. + +Identifying the location of source code +--------------------------------------- + +In order for gdb to be able to locate the source files for your app +methods, Graal methods and JDK runtime methods you need to provide gdb +with a list of source root dirs a 'set directories' command: + + (gdb) set directories /home/adinn/hello/src:/home/adinn/graal/sdk/src/org/graalvm.word/src:/home/adinn/graal/sdk/src/org.graalvm.options/src:... + +The argument is a comma separated list of source roots. It needs to +identify: + + - sources for your app + - sources under the Graal sdk, compiler, substratevm and truffle trees + - sources in the JDK src.zip file + +Needless to say the list for Graal is long and complex. Also, the JDK +sources are in a zip file and gdb does not understand zip sources. So +you need to extract the JDK sources as a preparatory step, + +You can use shell script write_gdbsourcepath (added to Graal dir +substratevm) to auto-generate settings for the GRaal and JDK sources. + + $ bash write_gdbsourcepath + +It creates a local file .gdbsourcepath which sets the relevant +directories. Before running it you can set two env vars to tell it +where to locate the source trees it needs to include: + + - GRAAL_JAVA_SRC_ROOT should point to the dir into which you have + unzipped the src.zip from your Graal JDK release + - GRAAL_SRC_ROOT should point to the dir in which your Graal git + tree checkout is located + +Note that the script ignores test source dirs and jdk dirs that do not +match the release level of the JDK (i.e. if you use jdk8 it will ony +include jdk8 src dirs). The script runs the java command available via +JAVA_HOME to idenitfy which JDK is in use). + +If you run the script from the substratevm dir of your Graal git repo +checkout the script will default GRAAL_SRC_ROOT to the parent dir. + +If JAVA_HOME is set the script will default GRAAL_JAVA_SRC_ROOT to +$JAVA_HOME/src + +Checking debug info +------------------- + +The objdump command can be used to display the dbeug info embedded +into a native image. The following commands (which all assume the +target binary is called hello) can be used to display all currentyl +generated content: + + $ objdump --dwarf=info hello > info + $ objdump --dwarf=abbrev hello > abbrev + $ objdump --dwarf=ranges hello > ranges + $ objdump --dwarf=decodedline hello > decodedline + $ objdump --dwarf=rawline hello > rawline + $ objdump --dwarf=str hello > str + $ objdump --dwarf=frames hello > frames + +The *info* section includes details of all compiled Java methods. + +The *abbrev* sectio defines the layout of records in the info section +that describe Java files (compilation units) and methods. + +The *ranges* section details the start and end addresses of method +code segments + +The *decodedline* section maps subsegments of method code range +segments to files and line numbers. This mapping includes entries +for files and line numbers for inlined methods. + +The *rawline* segment provides deatails of how the line table is +generated using DWARF state machine instuctions that encode file, +line and address transitions. + +The *str* section provides a lookup table for strings referenced +from records in the info section + +The *frames* section lists transition points in compiled methods +where a (fixed size) stack frame is pushed or popped, allowing +the debugger to identify each frame's current and previous stack +pointers and it's return address. + +Note that some of the content embedded in the debug records is +generated by the C compiler and belongs to code that is either in +libraries or the C lib bootstrap code that is bundled in with the +Java method code. + +Currently supported targets +--------------------------- + +The prototype is currently implemented only for gdb on Linux. + + - Linux/x86_64 suppoort has been tested and should work + correctly. + + - Linux/AArch64 support is present but has not yet been fully + verified (break points should work ok but stack backtraces + may be incorrect). + +Windows support is still under development. From c1ab03a822aa4a4ed4d01c603a3a956c1c4bacc5 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 12:12:28 +0000 Subject: [PATCH 059/130] fix check-style errors --- .../debuginfo/DebugInfoProvider.java | 29 +- .../oracle/objectfile/elf/ELFObjectFile.java | 12 +- .../objectfile/elf/dwarf/ClassEntry.java | 304 ++++---- .../oracle/objectfile/elf/dwarf/DirEntry.java | 32 +- .../objectfile/elf/dwarf/DwarfSections.java | 653 +++++++----------- .../objectfile/elf/dwarf/FileEntry.java | 32 +- .../objectfile/elf/dwarf/PrimaryEntry.java | 219 +++--- .../oracle/objectfile/elf/dwarf/Range.java | 26 + .../objectfile/elf/dwarf/StringEntry.java | 28 +- .../objectfile/elf/dwarf/StringTable.java | 26 + .../svm/hosted/image/NativeBootImage.java | 61 +- 11 files changed, 722 insertions(+), 700 deletions(-) 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 8d9c097a60c6..3a4cc6eac521 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 @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.debuginfo; import java.util.List; @@ -39,8 +65,7 @@ interface DebugLineInfo { int line(); } - interface DebugFrameSizeChange - { + interface DebugFrameSizeChange { enum Type {EXTEND, CONTRACT}; int getOffset(); DebugFrameSizeChange.Type getType(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 68ebf4f0967f..2bdca7526dce 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1170,12 +1170,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - ELFSection strSection = (ELFSection)newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - ELFSection abbrevSection = (ELFSection)newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - ELFSection locSection= (ELFSection)newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - ELFSection infoSection = (ELFSection)newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - ELFSection aRangesSection = (ELFSection)newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - ELFSection debugSection = (ELFSection)newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index f70b5cd387d8..90fc7a8d6318 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -6,154 +32,148 @@ import java.util.List; import java.util.Map; -public class ClassEntry - { - // the name of the associated class - private String className; - // the associated file - FileEntry fileEntry; - // a list recording details of all primary ranges included in - // this class sorted by ascending address range - private LinkedList primaryEntries; - // an index identifying primary ranges which have already been encountered - private Map primaryIndex; - // an index of all primary and secondary files referenced from this class's CU - private Map localFilesIndex; - // a list of the same files - private LinkedList localFiles; - // an index of all primary and secondary dirs referenced from this class's CU - private HashMap localDirsIndex; - // a list of the same dirs - private LinkedList localDirs; - // index of debug_info section compilation unit for this class - private int cuIndex; - // index into debug_line section for associated CU - private int lineIndex; - // size of line number info prologue region for associated CU - private int linePrologueSize; - // total size of line number info region for associated CU - private int totalSize; +public class ClassEntry { + // the name of the associated class + private String className; + // the associated file + FileEntry fileEntry; + // a list recording details of all primary ranges included in + // this class sorted by ascending address range + private LinkedList primaryEntries; + // an index identifying primary ranges which have already been encountered + private Map primaryIndex; + // an index of all primary and secondary files referenced from this class's CU + private Map localFilesIndex; + // a list of the same files + private LinkedList localFiles; + // an index of all primary and secondary dirs referenced from this class's CU + private HashMap localDirsIndex; + // a list of the same dirs + private LinkedList localDirs; + // index of debug_info section compilation unit for this class + private int cuIndex; + // index into debug_line section for associated CU + private int lineIndex; + // size of line number info prologue region for associated CU + private int linePrologueSize; + // total size of line number info region for associated CU + private int totalSize; - public ClassEntry(String className, FileEntry fileEntry) - { - this.className = className; - this.fileEntry = fileEntry; - this.primaryEntries = new LinkedList<>(); - this.primaryIndex = new HashMap<>(); - this.localFiles = new LinkedList<>(); - this.localFilesIndex = new HashMap<>(); - this.localDirs = new LinkedList<>(); - this.localDirsIndex = new HashMap<>(); - localFiles.add(fileEntry); - localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.dirEntry; - if (dirEntry != null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } - this.cuIndex = -1; - this.lineIndex = -1; - this.linePrologueSize = -1; - this.totalSize = -1; - } + public ClassEntry(String className, FileEntry fileEntry) { + this.className = className; + this.fileEntry = fileEntry; + this.primaryEntries = new LinkedList<>(); + this.primaryIndex = new HashMap<>(); + this.localFiles = new LinkedList<>(); + this.localFilesIndex = new HashMap<>(); + this.localDirs = new LinkedList<>(); + this.localDirsIndex = new HashMap<>(); + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.dirEntry; + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } + this.cuIndex = -1; + this.lineIndex = -1; + this.linePrologueSize = -1; + this.totalSize = -1; + } - PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) - { - if(primaryIndex.get(primary) == null) { - PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); - primaryEntries.add(primaryEntry); - primaryIndex.put(primary, primaryEntry); - return primaryEntry; - } - return null; - } - void addSubRange(Range subrange, FileEntry subFileEntry) { - Range primary = subrange.getPrimary(); - // the subrange should belong to a primary range - assert primary != null; - PrimaryEntry primaryEntry = primaryIndex.get(primary); - // we should already have seen the primary range - assert primaryEntry != null; - assert primaryEntry.getClassEntry() == this; - primaryEntry.addSubRange(subrange, subFileEntry); - if (localFilesIndex.get(subFileEntry) == null) { - localFiles.add(subFileEntry); - localFilesIndex.put(subFileEntry, localFiles.size()); - } - DirEntry dirEntry = subFileEntry.dirEntry; - if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); - } + PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { + if (primaryIndex.get(primary) == null) { + PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); + primaryEntries.add(primaryEntry); + primaryIndex.put(primary, primaryEntry); + return primaryEntry; + } + return null; + } + void addSubRange(Range subrange, FileEntry subFileEntry) { + Range primary = subrange.getPrimary(); + // the subrange should belong to a primary range + assert primary != null; + PrimaryEntry primaryEntry = primaryIndex.get(primary); + // we should already have seen the primary range + assert primaryEntry != null; + assert primaryEntry.getClassEntry() == this; + primaryEntry.addSubRange(subrange, subFileEntry); + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.dirEntry; + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); } - public int localDirsIdx(DirEntry dirEntry) { - if (dirEntry != null) { - return localDirsIndex.get(dirEntry); - } else { - return 0; - } + } + public int localDirsIdx(DirEntry dirEntry) { + if (dirEntry != null) { + return localDirsIndex.get(dirEntry); + } else { + return 0; } + } - public int localFilesIdx(FileEntry fileEntry) { - return localFilesIndex.get(fileEntry); - } + public int localFilesIdx(FileEntry fileEntry) { + return localFilesIndex.get(fileEntry); + } - String getFileName() - { - return fileEntry.getFileName(); - } + String getFileName() { + return fileEntry.getFileName(); + } - String getDirName() { - return fileEntry.getDirName(); - } + String getDirName() { + return fileEntry.getDirName(); + } - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - int getLineIndex() { - return lineIndex; - } - void setLineIndex(int lineIndex) { - this.lineIndex = lineIndex; - } - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - public int getLinePrologueSize() { - return linePrologueSize; - } - public int getTotalSize() { - return totalSize; - } - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } - public FileEntry getFileEntry() { - return fileEntry; - } - public String getClassName() { - return className; - } - public LinkedList getPrimaryEntries() { - return primaryEntries; - } - public Object primaryIndexFor(Range primaryRange) { - return primaryIndex.get(primaryRange); - } - public LinkedList getLocalDirs() - { - return localDirs; - } - public LinkedList getLocalFiles() - { - return localFiles; - } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + return lineIndex; + } + void setLineIndex(int lineIndex) { + this.lineIndex = lineIndex; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; + } + public FileEntry getFileEntry() { + return fileEntry; + } + public String getClassName() { + return className; + } + public LinkedList getPrimaryEntries() { + return primaryEntries; + } + public Object primaryIndexFor(Range primaryRange) { + return primaryIndex.get(primaryRange); + } + public LinkedList getLocalDirs() { + return localDirs; + } + public LinkedList getLocalFiles() { + return localFiles; } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 45ad9a44b088..1ce68980f93a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; // files may be located in a source directory associated @@ -10,8 +36,7 @@ // will be listed using the dirs derived from the package // i.e. simply "foo/bar/baz/mumble/grumble/bletch" -public class DirEntry -{ +public class DirEntry { private String path; // create an entry for a root package path @@ -20,8 +45,7 @@ public DirEntry(String path) { this.path = path; } - public String getPath() - { + public String getPath() { return path; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 8ba6c884aca9..c668f92c0785 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.BasicProgbitsSectionImpl; import com.oracle.objectfile.BuildDependency; @@ -23,8 +49,7 @@ import java.util.Map; import java.util.Set; -public class DwarfSections -{ +public class DwarfSections { // names of the different sections we create or reference // in reverse dependency order public static final String TEXT_SECTION_NAME = ".text"; @@ -76,7 +101,7 @@ public class DwarfSections private static final byte DW_FLAG_false = 0; private static final byte DW_FLAG_true = 1; // value for DW_AT_language attribute with form DATA1 - private final static byte DW_LANG_Java = 0xb; + private static final byte DW_LANG_Java = 0xb; // access not needed until we make functions members // DW_AT_Accessibility attribute values // private static final byte DW_ACCESS_public = 1; @@ -90,30 +115,30 @@ public class DwarfSections // CIE and FDE entries - public final static int DW_CFA_CIE_id = -1; - public final static int DW_CFA_FDE_id = 0; + public static final int DW_CFA_CIE_id = -1; + public static final int DW_CFA_FDE_id = 0; - public final static byte DW_CFA_CIE_version = 1; + public static final byte DW_CFA_CIE_version = 1; // values for high 2 bits - public final static byte DW_CFA_advance_loc = 0x1; - public final static byte DW_CFA_offset = 0x2; - public final static byte DW_CFA_restore = 0x3; + public static final byte DW_CFA_advance_loc = 0x1; + public static final byte DW_CFA_offset = 0x2; + public static final byte DW_CFA_restore = 0x3; // values for low 6 bits - public final static byte DW_CFA_nop = 0x0; - public final static byte DW_CFA_set_loc1 = 0x1; - public final static byte DW_CFA_advance_loc1 = 0x2; - public final static byte DW_CFA_advance_loc2 = 0x3; - public final static byte DW_CFA_advance_loc4 = 0x4; - public final static byte DW_CFA_offset_extended = 0x5; - public final static byte DW_CFA_restore_extended = 0x6; - public final static byte DW_CFA_undefined = 0x7; - public final static byte DW_CFA_same_value = 0x8; - public final static byte DW_CFA_register = 0x9; - public final static byte DW_CFA_def_cfa = 0xc; - public final static byte DW_CFA_def_cfa_register = 0xd; - public final static byte DW_CFA_def_cfa_offset = 0xe; + public static final byte DW_CFA_nop = 0x0; + public static final byte DW_CFA_set_loc1 = 0x1; + public static final byte DW_CFA_advance_loc1 = 0x2; + public static final byte DW_CFA_advance_loc2 = 0x3; + public static final byte DW_CFA_advance_loc4 = 0x4; + public static final byte DW_CFA_offset_extended = 0x5; + public static final byte DW_CFA_restore_extended = 0x6; + public static final byte DW_CFA_undefined = 0x7; + public static final byte DW_CFA_same_value = 0x8; + public static final byte DW_CFA_register = 0x9; + public static final byte DW_CFA_def_cfa = 0xc; + public static final byte DW_CFA_def_cfa_register = 0xd; + public static final byte DW_CFA_def_cfa_offset = 0xe; private ELFMachine elfMachine; private DwarfStrSectionImpl dwarfStrSection; @@ -164,7 +189,7 @@ public ELFMachine getElfMachine() { } // a scratch buffer used during computation of a section's size - protected final static byte[] scratch = new byte[10]; + protected static final byte[] scratch = new byte[10]; // table listing all known strings private StringTable stringTable = new StringTable(); @@ -213,142 +238,6 @@ public ELFMachine getElfMachine() { // index of already seen files private Map filesIndex = new HashMap<>(); - private static String[] root_pkgs = { - // substrate root packages - "com.oracle.graal.pointsto", - "com.oracle.objectfile", - "com.oracle.svm.agent", - "com.oracle.svm.configure", - "com.oracle.svm.core", - "com.oracle.svm.core.genscavenge", - "com.oracle.svm.core.graal", - "com.oracle.svm.core.graal.aarch64", - "com.oracle.svm.core.graal.amd64", - "com.oracle.svm.core.graal.llvm", - "com.oracle.svm.core.jdk11", - "com.oracle.svm.core.jdk8", - "com.oracle.svm.core.posix", - "com.oracle.svm.core.posix.jdk11", - "com.oracle.svm.core.windows", - "com.oracle.svm.driver", - "com.oracle.svm.graal", - "com.oracle.svm.graal.hotspot.libgraal", - "com.oracle.svm.hosted", - "com.oracle.svm.jline", - "com.oracle.svm.jni", - "com.oracle.svm.junit", - "com.oracle.svm.libffi", - "com.oracle.svm.native.jvm.posix", - "com.oracle.svm.native.jvm.windows", - "com.oracle.svm.native.libchelper", - "com.oracle.svm.native.strictmath", - "com.oracle.svm.polyglot", - "com.oracle.svm.reflect", - "com.oracle.svm.test", - "com.oracle.svm.test.jdk11", - "com.oracle.svm.thirdparty", - "com.oracle.svm.truffle", - "com.oracle.svm.truffle.nfi", - "com.oracle.svm.truffle.nfi.posix", - "com.oracle.svm.truffle.nfi.windows", - "com.oracle.svm.tutorial", - "com.oracle.svm.util", - "com.oracle.svm.util.jdk11", - "org.graalvm.polyglot.nativeapi", - // compiler root packages - "jdk.tools.jaotc", - "jdk.tools.jaotc.binformat", - "jdk.tools.jaotc", - "org.graalvm.compiler.api.directives", - "org.graalvm.compiler.api.replacements", - "org.graalvm.compiler.api.runtime", - "org.graalvm.compiler.asm", - "org.graalvm.compiler.asm.aarch64", - "org.graalvm.compiler.asm.amd64", - "org.graalvm.compiler.asm.sparc", - "org.graalvm.compiler.bytecode", - "org.graalvm.compiler.code", - "org.graalvm.compiler.core", - "org.graalvm.compiler.core.aarch64", - "org.graalvm.compiler.core.amd64", - "org.graalvm.compiler.core.common", - "org.graalvm.compiler.core.llvm", - "org.graalvm.compiler.core.match.processor", - "org.graalvm.compiler.core.sparc", - "org.graalvm.compiler.debug", - "org.graalvm.compiler.graph", - "org.graalvm.compiler.hotspot", - "org.graalvm.compiler.hotspot.aarch64", - "org.graalvm.compiler.hotspot.amd64", - "org.graalvm.compiler.hotspot.jdk8", - "org.graalvm.compiler.hotspot.management", - "org.graalvm.compiler.hotspot.sparc", - "org.graalvm.compiler.java", - "org.graalvm.compiler.jtt", - "org.graalvm.compiler.lir", - "org.graalvm.compiler.lir.aarch64", - "org.graalvm.compiler.lir.amd64", - "org.graalvm.compiler.lir.jtt", - "org.graalvm.compiler.lir.sparc", - "org.graalvm.compiler.loop", - "org.graalvm.compiler.loop.phases", - "org.graalvm.compiler.microbenchmarks", - "org.graalvm.compiler.nodeinfo", - "org.graalvm.compiler.nodeinfo.processor", - "org.graalvm.compiler.nodes", - "org.graalvm.compiler.options", - "org.graalvm.compiler.options.processor", - "org.graalvm.compiler.phases", - "org.graalvm.compiler.phases.common", - "org.graalvm.compiler.printer", - "org.graalvm.compiler.processor", - "org.graalvm.compiler.replacements", - "org.graalvm.compiler.replacements.aarch64", - "org.graalvm.compiler.replacements.amd64", - "org.graalvm.compiler.replacements.processor", - "org.graalvm.compiler.replacements.sparc", - "org.graalvm.compiler.runtime", - "org.graalvm.compiler.serviceprovider", - "org.graalvm.compiler.serviceprovider.jdk8", - "org.graalvm.compiler.serviceprovider.processor", - "org.graalvm.compiler.truffle.common", - "org.graalvm.compiler.truffle.common.hotspot", - "org.graalvm.compiler.truffle.common.hotspot.libgraal", - "org.graalvm.compiler.truffle.common.processor", - "org.graalvm.compiler.truffle.compiler", - "org.graalvm.compiler.truffle.compiler.amd64", - "org.graalvm.compiler.truffle.compiler.hotspot", - "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", - "org.graalvm.compiler.truffle.compiler.hotspot.amd64", - "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", - "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", - "org.graalvm.compiler.truffle.compiler.hotspot.sparc", - "org.graalvm.compiler.truffle.runtime", - "org.graalvm.compiler.truffle.runtime.hotspot", - "org.graalvm.compiler.truffle.runtime.hotspot.java", - "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", - "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", - "org.graalvm.compiler.truffle.runtime.serviceprovider", - "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", - "org.graalvm.compiler.virtual", - "org.graalvm.compiler.virtual.bench", - "org.graalvm.compiler.word", - "org.graalvm.graphio", - "org.graalvm.libgraal", - "org.graalvm.libgraal.jdk8", - "org.graalvm.micro.benchmarks", - "org.graalvm.util", - // sdk root packages - "org.graalvm.collections", - "org.graalvm.launcher", - "org.graalvm.options", - "org.graalvm.polyglot", - "org.graalvm.home", - "org.graalvm.nativeimage", - "org.graalvm.polyglot.tck", - "org.graalvm.word", - }; - public String uniqueString(String string) { return stringTable.uniqueString(string); } @@ -361,8 +250,7 @@ private int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } - public void installDebugInfo(DebugInfoProvider debugInfoProvider) - { + public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { // install types @@ -370,11 +258,10 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) // ensure we have a null string in the string section uniqueDebugString(""); - + DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { // primary file name and full method name need to be written to the debug_str section - // String fileName = debugCodeInfo.fileName(); String className = debugCodeInfo.className(); String methodName = debugCodeInfo.methodName(); @@ -425,7 +312,7 @@ public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); // ensure we have an entry FileEntry fileEntry = filesIndex.get(fileName); - if(fileEntry == null) { + if (fileEntry == null) { DirEntry dirEntry = ensureDirEntry(fileName); String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), @@ -434,7 +321,7 @@ public FileEntry ensureFileEntry(Range range) { files.add(fileEntry); filesIndex.put(fileName, fileEntry); // if this is a primary entry then add it to the primary list - if(range.isPrimary()) { + if (range.isPrimary()) { primaryFiles.add(fileEntry); } else { Range primaryRange = range.getPrimary(); @@ -445,8 +332,7 @@ public FileEntry ensureFileEntry(Range range) { return fileEntry; } - public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) - { + public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); @@ -456,8 +342,7 @@ public void addRange(Range primaryRange, List frameSizeInf } } - public void addSubRange(Range primaryRange, Range subrange) - { + public void addSubRange(Range primaryRange, Range subrange) { assert primaryRange.isPrimary(); assert !subrange.isPrimary(); String className = primaryRange.getClassName(); @@ -469,10 +354,9 @@ public void addSubRange(Range primaryRange, Range subrange) classEntry.addSubRange(subrange, subrangeEntry); } - private DirEntry ensureDirEntry(String file) - { + private DirEntry ensureDirEntry(String file) { int pathLength = file.lastIndexOf('/'); - if(pathLength < 0) { + if (pathLength < 0) { // no path/package means use dir entry 0 return null; } @@ -489,9 +373,9 @@ private DirEntry ensureDirEntry(String file) // shared implementation methods to manage content creation public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { public boolean debug = false; - public long debug_text_base = 0; - public long debug_address = 0; - public int debug_base = 0; + public long debugTextBase = 0; + public long debugAddress = 0; + public int debugBase = 0; public DwarfSectionImpl() { } @@ -505,14 +389,13 @@ public void checkDebug(int pos) { String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { debug = true; - debug_base = pos; - debug_address = debug_text_base; + debugBase = pos; + debugAddress = debugTextBase; } } - protected void debug(String format, Object ... args) - { - if(debug) { + protected void debug(String format, Object ... args) { + if (debug) { System.out.format(format, args); } } @@ -556,11 +439,11 @@ public int putULEB(long l, byte[] buffer, int pos) { byte b = (byte) (l & 0x7f); l = l >>> 7; boolean done = (l == 0); - if(!done) { + if (!done) { b = (byte) (b | 0x80); } pos = putByte(b, buffer, pos); - if(done) { + if (done) { break; } } @@ -573,11 +456,11 @@ public int putSLEB(long l, byte[] buffer, int pos) { l = l >> 7; boolean bIsSigned = (b & 0x40) != 0; boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); - if(!done) { + if (!done) { b = (byte) (b | 0x80); } pos = putByte(b, buffer, pos); - if(done) { + if (done) { break; } } @@ -589,7 +472,7 @@ public int putAsciiStringBytes(String s, byte[] buffer, int pos) { public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); - if(c > 127) { + if (c > 127) { throw new RuntimeException("oops : expected ASCII string! " + s); } buffer[pos++] = (byte) c; @@ -630,7 +513,7 @@ public int writeFlag(byte flag, byte[] buffer, int pos) { } } - public int writeAttr_addr(long address, byte[] buffer, int pos) { + public int writeAttrAddress(long address, byte[] buffer, int pos) { if (buffer == null) { return pos + 8; } else { @@ -638,7 +521,7 @@ public int writeAttr_addr(long address, byte[] buffer, int pos) { } } - public int writeAttr_data8(long value, byte[] buffer, int pos) { + public int writeAttrData8(long value, byte[] buffer, int pos) { if (buffer == null) { return pos + putLong(value, scratch, 0); } else { @@ -646,7 +529,7 @@ public int writeAttr_data8(long value, byte[] buffer, int pos) { } } - public int writeAttr_data4(int value, byte[] buffer, int pos) { + public int writeAttrData4(int value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(value, scratch, 0); } else { @@ -654,7 +537,7 @@ public int writeAttr_data4(int value, byte[] buffer, int pos) { } } - public int writeAttr_data1(byte value, byte[] buffer, int pos) { + public int writeAttrData1(byte value, byte[] buffer, int pos) { if (buffer == null) { return pos + putByte(value, scratch, 0); } else { @@ -662,7 +545,7 @@ public int writeAttr_data1(byte value, byte[] buffer, int pos) { } } - public int writeAttr_null(byte[] buffer, int pos) { + public int writeAttrNull(byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(0, scratch, 0); } else { @@ -693,11 +576,10 @@ public byte[] getOrDecideContent(Map alreadyDecided, } @Override - public Set getDependencies(Map decisions) - { + public Set getDependencies(Map decisions) { Set deps = super.getDependencies(decisions); String targetName = targetSectionName(); - ELFSection targetSection = (ELFSection)getElement().getOwner().elementForName(targetName); + ELFSection targetSection = (ELFSection) getElement().getOwner().elementForName(targetName); LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); LayoutDecision.Kind[] targetKinds = targetSectionKinds(); @@ -727,7 +609,7 @@ public String getSectionName() { public void createContent() { int pos = 0; for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()){ + if (stringEntry.isAddToStrSection()) { stringEntry.setOffset(pos); String string = stringEntry.getString(); pos += string.length() + 1; @@ -746,7 +628,7 @@ public void writeContent() { checkDebug(pos); for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()){ + if (stringEntry.isAddToStrSection()) { assert stringEntry.getOffset() == pos; String string = stringEntry.getString(); pos = putAsciiStringBytes(string, buffer, pos); @@ -760,18 +642,18 @@ protected void debug(String format, Object... args) { } // .debug_str section content depends on text section content and offset - public final static String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -787,8 +669,7 @@ public String getSectionName() { } @Override - public void createContent() - { + public void createContent() { int pos = 0; // an abbrev table contains abbrev entries for one or // more CUs. the table includes a sequence of abbrev @@ -838,8 +719,7 @@ public void createContent() } @Override - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -912,18 +792,18 @@ protected void debug(String format, Object... args) { } // .debug_abbrev section content depends on .debug_frame section content and offset - public final static String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -939,8 +819,7 @@ public String getSectionName() { } @Override - public void createContent() - { + public void createContent() { int pos = 0; // the frame section contains one CIE at offset 0 @@ -953,8 +832,7 @@ public void createContent() } @Override - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -991,7 +869,7 @@ public int writeCIE(byte[] buffer, int pos) { pos += putAsciiStringBytes("", scratch, 0); pos += putULEB(1, scratch, 0); pos += putULEB(-8, scratch, 0); - pos += putByte((byte)getPCIdx(), scratch, 0); + pos += putByte((byte) getPCIdx(), scratch, 0); // write insns to set up empty frame pos = writeInitialInstructions(buffer, pos); // pad to word alignment @@ -1006,7 +884,7 @@ public int writeCIE(byte[] buffer, int pos) { pos = putAsciiStringBytes("", buffer, pos); pos = putULEB(1, buffer, pos); pos = putSLEB(-8, buffer, pos); - pos = putByte((byte)getPCIdx(), buffer, pos); + pos = putByte((byte) getPCIdx(), buffer, pos); // write insns to set up empty frame pos = writeInitialInstructions(buffer, pos); // pad to word alignment @@ -1024,7 +902,7 @@ public int writeMethodFrames(byte[] buffer, int pos) { int frameSize = primaryEntry.getFrameSize(); int currentOffset = 0; int lengthPos = pos; - pos = writeFDEHeader((int)lo, (int)hi, buffer, pos); + pos = writeFDEHeader((int) lo, (int) hi, buffer, pos); for (DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { int advance = debugFrameSizeInfo.getOffset() - currentOffset; currentOffset += advance; @@ -1103,9 +981,9 @@ public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { if (offset <= 0x3f) { return writeAdvanceLoc0((byte) offset, buffer, pos); - } else if(offset <= 0xff) { + } else if (offset <= 0xff) { return writeAdvanceLoc1((byte) offset, buffer, pos); - } else if(offset <= 0xffff) { + } else if (offset <= 0xffff) { return writeAdvanceLoc2((short) offset, buffer, pos); } else { return writeAdvanceLoc4(offset, buffer, pos); @@ -1179,32 +1057,32 @@ protected void debug(String format, Object... args) { super.debug(format, args); } // .debug_frame section content depends on .debug_line section content and offset - public final static String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } private byte offsetOp(int register) { assert (register >> 6) == 0; - return (byte)((DW_CFA_offset << 6) | register); + return (byte) ((DW_CFA_offset << 6) | register); } private byte advanceLoc0Op(int offset) { assert (offset >= 0 && offset <= 0x3f); - return (byte)((DW_CFA_advance_loc << 6) | offset); + return (byte) ((DW_CFA_advance_loc << 6) | offset); } } - public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl - { - public final static int DW_CFA_RSP_IDX = 7; - public final static int DW_CFA_RIP_IDX = 16; + + public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_RSP_IDX = 7; + public static final int DW_CFA_RIP_IDX = 16; public DwarfFrameSectionImplX86_64() { super(); @@ -1218,8 +1096,7 @@ public int getSPIdx() { return DW_CFA_RSP_IDX; } @Override - public int writeInitialInstructions(byte[] buffer, int pos) - { + public int writeInitialInstructions(byte[] buffer, int pos) { // rsp points at the word containing the saved rip // so the frame base (cfa) is at rsp + 8 (why not - ???) // def_cfa r7 (sp) offset 8 @@ -1230,27 +1107,26 @@ public int writeInitialInstructions(byte[] buffer, int pos) return pos; } } - public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl - { - public final static int DW_CFA_FP_IDX = 29; - public final static int DW_CFA_LR_IDX = 30; - public final static int DW_CFA_SP_IDX = 31; - public final static int DW_CFA_PC_IDX = 32; + + public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_FP_IDX = 29; + public static final int DW_CFA_LR_IDX = 30; + public static final int DW_CFA_SP_IDX = 31; + public static final int DW_CFA_PC_IDX = 32; public DwarfFrameSectionImplAArch64() { super(); } @Override - public int getPCIdx(){ + public int getPCIdx() { return DW_CFA_PC_IDX; } @Override - public int getSPIdx(){ + public int getSPIdx() { return DW_CFA_SP_IDX; } @Override - public int writeInitialInstructions(byte[] buffer, int pos) - { + public int writeInitialInstructions(byte[] buffer, int pos) { // rsp has not been updated // caller pc is in lr // register r32 (rpc), r30 (lr) @@ -1259,25 +1135,21 @@ public int writeInitialInstructions(byte[] buffer, int pos) } } - public class DwarfInfoSectionImpl extends DwarfSectionImpl - { + public class DwarfInfoSectionImpl extends DwarfSectionImpl { // header section always contains fixed number of bytes private static final int DW_DIE_HEADER_SIZE = 11; - public DwarfInfoSectionImpl() - { + public DwarfInfoSectionImpl() { super(); } @Override - public String getSectionName() - { + public String getSectionName() { return DW_INFO_SECTION_NAME; } @Override - public void createContent() - { + public void createContent() { // we need a single level 0 DIE for each compilation unit (CU) // Each CU's Level 0 DIE is preceded by a fixed header: // and terminated by a null DIE @@ -1319,8 +1191,7 @@ public void createContent() } @Override - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -1346,55 +1217,53 @@ public void writeContent() public int writeCUHeader(byte[] buffer, int pos) { if (buffer == null) { - pos += putInt(0, scratch, 0); // CU length - pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version - pos += putInt(0, scratch, 0); // abbrev offset - return pos + putByte((byte)8, scratch, 0); // address size + pos += putInt(0, scratch, 0); // CU length + pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version + pos += putInt(0, scratch, 0); // abbrev offset + return pos + putByte((byte) 8, scratch, 0); // address size } else { - pos = putInt(0, buffer, pos); // CU length - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version - pos = putInt(0, buffer, pos); // abbrev offset - return putByte((byte)8, buffer, pos); // address size + pos = putInt(0, buffer, pos); // CU length + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version + pos = putInt(0, buffer, pos); // abbrev offset + return putByte((byte) 8, buffer, pos); // address size } } - public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { LinkedList primaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); - pos = writeAttr_data1(DW_LANG_Java, buffer, pos); + pos = writeAttrData1(DW_LANG_Java, buffer, pos); debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); - pos = writeAttr_strp(classEntry.getFileName(), buffer, pos); + pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); debug(" [0x%08x] low_pc 0x%08x\n", pos, primaryEntries.getFirst().getPrimary().getLo()); - pos = writeAttr_addr(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + pos = writeAttrAddress(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); debug(" [0x%08x] hi_pc 0x%08x\n", pos, primaryEntries.getLast().getPrimary().getHi()); - pos = writeAttr_addr(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); + pos = writeAttrAddress(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); - pos = writeAttr_data4(classEntry.getLineIndex(), buffer, pos); + pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); for (PrimaryEntry primary : primaryEntries) { pos = writePrimary(primary, buffer, pos); } // write a terminating null attribute for the the level 2 primaries - return writeAttr_null(buffer, pos); + return writeAttrNull(buffer, pos); } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) - { + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getClassAndMethodNameWithParams()), primary.getClassAndMethodNameWithParams()); - pos = writeAttr_strp(primary.getClassAndMethodNameWithParams(), buffer, pos); + pos = writeAttrStrp(primary.getClassAndMethodNameWithParams(), buffer, pos); debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); - pos = writeAttr_addr(primary.getLo(), buffer, pos); + pos = writeAttrAddress(primary.getLo(), buffer, pos); debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); - pos = writeAttr_addr(primary.getHi(), buffer, pos); + pos = writeAttrAddress(primary.getHi(), buffer, pos); // need to pass true only if method is public debug(" [0x%08x] external true\n", pos); return writeFlag(DW_FLAG_true, buffer, pos); } - public int writeAttr_strp(String value, byte[] buffer, int pos) { + public int writeAttrStrp(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(0, scratch, 0); } else { @@ -1402,7 +1271,7 @@ public int writeAttr_strp(String value, byte[] buffer, int pos) { return putInt(idx, buffer, pos); } } - public int writeAttr_string(String value, byte[] buffer, int pos) { + public int writeAttrString(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + value.length() + 1; } else { @@ -1410,7 +1279,7 @@ public int writeAttr_string(String value, byte[] buffer, int pos) { } } protected void debug(String format, Object... args) { - if (((int) args[0] - debug_base) < 0x100000) { + if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); } else if (format.startsWith(" [0x%08x] primary file")) { super.debug(format, args); @@ -1418,18 +1287,18 @@ protected void debug(String format, Object... args) { } // .debug_info section content depends on abbrev section content and offset - public final static String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -1446,8 +1315,7 @@ public String getSectionName() { return DW_ARANGES_SECTION_NAME; } - public void createContent() - { + public void createContent() { int pos = 0; // we need an entry for each compilation unit // @@ -1470,7 +1338,7 @@ public void createContent() // where N is the number of ranges belonging to the compilation unit // and the last range contains two zeroes - for(ClassEntry classEntry : primaryClasses) { + for (ClassEntry classEntry : primaryClasses) { pos += DW_AR_HEADER_SIZE; // align to 2 * address size pos += DW_AR_HEADER_PAD_SIZE; @@ -1482,8 +1350,7 @@ public void createContent() } @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) - { + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { Element textElement = getElement().getOwner().elementForName(".text"); LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); if (decisionMap != null) { @@ -1492,14 +1359,13 @@ public byte[] getOrDecideContent(Map alreadyDecided, // this may not be the final vaddr for the text segment // but it will be close enough to make debug easier // i.e. to within a 4k page or two - debug_text_base = ((Number)valueObj).longValue(); + debugTextBase = ((Number) valueObj).longValue(); } } return super.getOrDecideContent(alreadyDecided, contentHint); } - public void writeContent() - { + public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; @@ -1507,7 +1373,7 @@ public void writeContent() checkDebug(pos); debug(" [0x%08x] DEBUG_ARANGES\n", pos); - for(ClassEntry classEntry : primaryClasses) { + for (ClassEntry classEntry : primaryClasses) { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = classEntry.getCUIndex(); @@ -1517,19 +1383,19 @@ public void writeContent() length += 2 * 8; debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); - pos = putShort(DW_VERSION_2,buffer, pos); // dwarf version is always 2 + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 pos = putInt(cuIndex, buffer, pos); - pos = putByte((byte)8, buffer, pos); // address size is always 8 - pos = putByte((byte)0, buffer, pos); // segment size is always 0 + pos = putByte((byte) 8, buffer, pos); // address size is always 8 + pos = putByte((byte) 0, buffer, pos); // segment size is always 0 assert (pos - lastpos) == DW_AR_HEADER_SIZE; // align to 2 * address size for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { - pos = putByte((byte)0, buffer, pos); + pos = putByte((byte) 0, buffer, pos); } debug(" [0x%08x] Address Length Name\n", pos); for (PrimaryEntry primaryEntry : primaryEntries) { Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debug_text_base + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); + debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); } @@ -1545,18 +1411,18 @@ protected void debug(String format, Object... args) { } // .debug_aranges section content depends on .debug_info section content and offset - public final static String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } @@ -1686,12 +1552,11 @@ public int computeFileTableSize(ClassEntry classEntry) { public int computeLineNUmberTableSize(ClassEntry classEntry) { // sigh -- we have to do this by generating the // content even though we cannot write it into a byte[] - return writeLineNumberTable(classEntry,null, 0); + return writeLineNumberTable(classEntry, null, 0); } @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) - { + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { Element textElement = getElement().getOwner().elementForName(".text"); LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); if (decisionMap != null) { @@ -1700,7 +1565,7 @@ public byte[] getOrDecideContent(Map alreadyDecided, // this may not be the final vaddr for the text segment // but it will be close enough to make debug easier // i.e. to within a 4k page or two - debug_text_base = ((Number)valueObj).longValue(); + debugTextBase = ((Number) valueObj).longValue(); } } return super.getOrDecideContent(alreadyDecided, contentHint); @@ -1733,8 +1598,7 @@ public void writeContent() { assert pos == buffer.length; } - public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) { // 4 ubyte length field pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); // 2 ubyte version is always 2 @@ -1769,8 +1633,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) { debug(" [0x%08x] Dir Name\n", pos); // write out the list of dirs referenced form this file entry int dirIdx = 1; @@ -1785,8 +1648,7 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { int fileIdx = 1; debug(" [0x%08x] Entry Dir Name\n", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { @@ -1806,12 +1668,11 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - public int debug_line = 1; - public int debug_copy_count = 0; + public int debugLine = 1; + public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) - { + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // the primary file entry should always be first in the local files list assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; String primaryClassName = classEntry.getClassName(); @@ -1828,10 +1689,10 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) // at the start of each sequence because we always post an // end_sequence when we finish all the subranges in the method long line = primaryRange.getLine(); - if(line < 0 && primaryEntry.getSubranges().size() > 0) { + if (line < 0 && primaryEntry.getSubranges().size() > 0) { line = primaryEntry.getSubranges().get(0).getLine(); } - if(line < 0) { + if (line < 0) { line = 0; } long address = primaryRange.getLo(); @@ -1842,7 +1703,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) // boolean end_sequence = false; // set state for primary - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + primaryRange.getLo(), debug_text_base + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); // initialize and write a row for the start of the primary method pos = putSetFile(file, fileIdx, buffer, pos); @@ -1851,7 +1712,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) pos = putSetAddress(address, buffer, pos); // state machine value of line is currently 1 // increment to desired line - if(line != 1) { + if (line != 1) { pos = putAdvanceLine(line - 1, buffer, pos); } pos = putCopy(buffer, pos); @@ -1867,8 +1728,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debug_text_base + subAddressLo, debug_text_base + subAddressHi, subrange.getClassAndMethodName(), subLine); - if(subLine < 0) { + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getClassAndMethodName(), subLine); + if (subLine < 0) { // no line info so stay at previous file:line subLine = line; subfile = file; @@ -1886,7 +1747,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) // so the code below is not actually needed. it is left in // to clarify i) that this is a deliberate choice and ii) what // that deliberate choice is avoiding. - if(address < hiAddress && hiAddress < subAddressLo) { + if (address < hiAddress && hiAddress < subAddressLo) { long addressDelta = hiAddress - address; // increment address to hi address, write an // end sequence and update state to new range @@ -1908,7 +1769,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) } */ // if we have to update to a new file then do so - if(subFileIdx != fileIdx) { + if (subFileIdx != fileIdx) { // update the current file pos = putSetFile(subfile, (long) subFileIdx, buffer, pos); file = subfile; @@ -1919,21 +1780,21 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) long lineDelta = subLine - line; long addressDelta = subAddressLo - address; byte opcode = isSpecialOpcode(addressDelta, lineDelta); - if(opcode != DW_LNS_undefined) { + if (opcode != DW_LNS_undefined) { // ignore pointless write when addressDelta == lineDelta == 0 - if(addressDelta != 0 || lineDelta != 0) { + if (addressDelta != 0 || lineDelta != 0) { pos = putSpecialOpcode(opcode, buffer, pos); } } else { // does it help to divide and conquer using // a fixed address increment int remainder = isConstAddPC(addressDelta); - if(remainder > 0) { + if (remainder > 0) { pos = putConstAddPC(buffer, pos); // the remaining address can be handled with a // special opcode but what about the line delta opcode = isSpecialOpcode(remainder, lineDelta); - if(opcode != DW_LNS_undefined) { + if (opcode != DW_LNS_undefined) { // address remainder and line now fit pos = putSpecialOpcode(opcode, buffer, pos); } else { @@ -1946,14 +1807,14 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) } } else { // increment line and pc separately - if(lineDelta != 0) { + if (lineDelta != 0) { pos = putAdvanceLine(lineDelta, buffer, pos); } // n.b. we might just have had an out of range line increment // with a zero address increment - if(addressDelta > 0) { + if (addressDelta > 0) { // see if we can use a ushort for the increment - if(isFixedAdvancePC(addressDelta)) { + if (isFixedAdvancePC(addressDelta)) { pos = putFixedAdvancePC((short) addressDelta, buffer, pos); } else { pos = putAdvancePC(addressDelta, buffer, pos); @@ -1968,7 +1829,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) hiAddress = subAddressHi; } // append a final end sequence just below the next primary range - if(address < primaryRange.getHi()) { + if (address < primaryRange.getHi()) { long addressDelta = primaryRange.getHi() - address; // increment address before we write the end sequence pos = putAdvancePC(addressDelta, buffer, pos); @@ -1980,59 +1841,54 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) return pos; } - protected void debug(String format, Object... args) - { - if (((int) args[0] - debug_base) < 0x100000) { + protected void debug(String format, Object... args) { + if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); } else if (format.startsWith(" [0x%08x] primary file")) { super.debug(format, args); } } - public int putCopy(byte[] buffer, int pos) - { + public int putCopy(byte[] buffer, int pos) { byte opcode = DW_LNS_copy; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { - debug_copy_count++; - debug(" [0x%08x] Copy %d\n", pos, debug_copy_count); + debugCopyCount++; + debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); return putByte(opcode, buffer, pos); } } - public int putAdvancePC(long uleb, byte[] buffer, int pos) - { + public int putAdvancePC(long uleb, byte[] buffer, int pos) { byte opcode = DW_LNS_advance_pc; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { - debug_address += uleb; - debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debug_address); + debugAddress += uleb; + debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); pos = putByte(opcode, buffer, pos); return putULEB(uleb, buffer, pos); } } - public int putAdvanceLine(long sleb, byte[] buffer, int pos) - { + public int putAdvanceLine(long sleb, byte[] buffer, int pos) { byte opcode = DW_LNS_advance_line; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putSLEB(sleb, scratch, 0); } else { - debug_line += sleb; - debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debug_line); + debugLine += sleb; + debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); pos = putByte(opcode, buffer, pos); return putSLEB(sleb, buffer, pos); } } - public int putSetFile(String file, long uleb, byte[] buffer, int pos) - { + public int putSetFile(String file, long uleb, byte[] buffer, int pos) { byte opcode = DW_LNS_set_file; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { @@ -2042,10 +1898,9 @@ public int putSetFile(String file, long uleb, byte[] buffer, int pos) } } - public int putSetColumn(long uleb, byte[] buffer, int pos) - { + public int putSetColumn(long uleb, byte[] buffer, int pos) { byte opcode = DW_LNS_set_column; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { @@ -2054,20 +1909,18 @@ public int putSetColumn(long uleb, byte[] buffer, int pos) } } - public int putNegateStmt(byte[] buffer, int pos) - { + public int putNegateStmt(byte[] buffer, int pos) { byte opcode = DW_LNS_negate_stmt; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { return putByte(opcode, buffer, pos); } } - public int putSetBasicBlock(byte[] buffer, int pos) - { + public int putSetBasicBlock(byte[] buffer, int pos) { byte opcode = DW_LNS_set_basic_block; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { debug(" [0x%08x] Set basic block\n", pos); @@ -2075,46 +1928,43 @@ public int putSetBasicBlock(byte[] buffer, int pos) } } - public int putConstAddPC(byte[] buffer, int pos) - { + public int putConstAddPC(byte[] buffer, int pos) { byte opcode = DW_LNS_const_add_pc; - if(buffer == null) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { int advance = opcodeAddress((byte) 255); - debug_address += advance; - debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debug_address); + debugAddress += advance; + debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); return putByte(opcode, buffer, pos); } } - public int putFixedAdvancePC(short arg, byte[] buffer, int pos) - { + public int putFixedAdvancePC(short arg, byte[] buffer, int pos) { byte opcode = DW_LNS_fixed_advance_pc; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putShort(arg, scratch, 0); } else { - debug_address += arg; - debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debug_address); + debugAddress += arg; + debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); pos = putByte(opcode, buffer, pos); return putShort(arg, buffer, pos); } } - public int putEndSequence(byte[] buffer, int pos) - { + public int putEndSequence(byte[] buffer, int pos) { byte opcode = DW_LNE_end_sequence; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB pos = pos + putULEB(1, scratch, 0); return pos + putByte(opcode, scratch, 0); } else { debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); - debug_address = debug_text_base; - debug_line = 1; - debug_copy_count = 0; + debugAddress = debugTextBase; + debugLine = 1; + debugCopyCount = 0; pos = putByte(DW_LNS_extended_prefix, buffer, pos); // insert extended insn byte count as ULEB pos = putULEB(1, buffer, pos); @@ -2122,18 +1972,17 @@ public int putEndSequence(byte[] buffer, int pos) } } - public int putSetAddress(long arg, byte[] buffer, int pos) - { + public int putSetAddress(long arg, byte[] buffer, int pos) { byte opcode = DW_LNE_set_address; - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB pos = pos + putULEB(9, scratch, 0); pos = pos + putByte(opcode, scratch, 0); return pos + putLong(arg, scratch, 0); } else { - debug_address = debug_text_base + (int) arg; - debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debug_address); + debugAddress = debugTextBase + (int) arg; + debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); pos = putByte(DW_LNS_extended_prefix, buffer, pos); // insert extended insn byte count as ULEB pos = putULEB(9, buffer, pos); @@ -2142,8 +1991,7 @@ public int putSetAddress(long arg, byte[] buffer, int pos) } } - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) - { + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) { byte opcode = DW_LNE_define_file; // calculate bytes needed for opcode + args int fileBytes = file.length() + 1; @@ -2152,7 +2000,7 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] insnBytes += putULEB(uleb1, scratch, 0); insnBytes += putULEB(uleb2, scratch, 0); insnBytes += putULEB(uleb3, scratch, 0); - if(buffer == null) { + if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // write insnBytes as a ULEB pos += putULEB(insnBytes, scratch, 0); @@ -2171,56 +2019,51 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] } } - public int opcodeId(byte opcode) - { + public int opcodeId(byte opcode) { int iopcode = opcode & 0xff; return iopcode - DW_LN_OPCODE_BASE; } - public int opcodeAddress(byte opcode) - { + public int opcodeAddress(byte opcode) { int iopcode = opcode & 0xff; return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; } - public int opcodeLine(byte opcode) - { + public int opcodeLine(byte opcode) { int iopcode = opcode & 0xff; return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) - { - if(buffer == null) { + public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) { + if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { - if (debug && opcode== 0) { - debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debug_address, debug_line); + if (debug && opcode == 0) { + debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); } - debug_address += opcodeAddress(opcode); - debug_line += opcodeLine(opcode); + debugAddress += opcodeAddress(opcode); + debugLine += opcodeLine(opcode); debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debug_address, opcodeLine(opcode), debug_line); + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, pos); } } - private final static int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; - private final static int MAX_ADDPC_DELTA= MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); + private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - public byte isSpecialOpcode(long addressDelta, long lineDelta) - { - if(addressDelta < 0) { + public byte isSpecialOpcode(long addressDelta, long lineDelta) { + if (addressDelta < 0) { return DW_LNS_undefined; } - if(lineDelta >= DW_LN_LINE_BASE) { + if (lineDelta >= DW_LN_LINE_BASE) { long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; - if(offsetLineDelta < DW_LN_LINE_RANGE) { + if (offsetLineDelta < DW_LN_LINE_RANGE) { // line_delta can be encoded // check if address is ok - if(addressDelta <= MAX_ADDRESS_ONLY_DELTA) { + if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; - if(opcode <= 255) { + if (opcode <= 255) { return (byte) opcode; } } @@ -2231,37 +2074,35 @@ public byte isSpecialOpcode(long addressDelta, long lineDelta) return DW_LNS_undefined; } - public int isConstAddPC(long addressDelta) - { - if(addressDelta < MAX_ADDRESS_ONLY_DELTA) { + public int isConstAddPC(long addressDelta) { + if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { return 0; } - if(addressDelta <= MAX_ADDPC_DELTA) { + if (addressDelta <= MAX_ADDPC_DELTA) { return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); } else { return 0; } } - public boolean isFixedAdvancePC(long addressDiff) - { + public boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } // .debug_line section content depends on .debug_str section content and offset - public final static String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] TARGET_SECTION_KINDS = { + public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, LayoutDecision.Kind.VADDR, // add this so we can use the base address }; @Override public LayoutDecision.Kind[] targetSectionKinds() { - return TARGET_SECTION_KINDS; + return targetSectionKinds; } } -} \ No newline at end of file +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index 982305ac9015..5a4ed796d8dc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -1,7 +1,32 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; -public class FileEntry -{ +public class FileEntry { // the name of the associated file including path private String fileName; // the name of the associated file excluding path @@ -9,8 +34,7 @@ public class FileEntry // the directory entry associated with this file entry DirEntry dirEntry; - public FileEntry(String fileName, String baseName, DirEntry dirEntry) - { + public FileEntry(String fileName, String baseName, DirEntry dirEntry) { this.fileName = fileName; this.baseName = baseName; this.dirEntry = dirEntry; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index 963e71714957..cdc84b9c4961 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -5,102 +31,101 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; -public class PrimaryEntry - { - // the primary range detailed by this object - Range primary; - // details of the class owning this range - ClassEntry classEntry; - // a list of subranges associated with the primary range - List subranges; - // a mapping from subranges to their associated file entry - HashMap subrangeIndex; - // details of of compiled method frame size changes - private List frameSizeInfos; - // size of compiled method frame - private int frameSize; - // index of debug_info section compilation unit for this file - private int cuIndex; - // index into debug_line section for associated compilation unit - private int lineIndex; - // size of line number info prologue region for associated compilation unit - private int linePrologueSize; - // total size of line number info region for associated compilation unit - private int totalSize; +public class PrimaryEntry { + // the primary range detailed by this object + Range primary; + // details of the class owning this range + ClassEntry classEntry; + // a list of subranges associated with the primary range + List subranges; + // a mapping from subranges to their associated file entry + HashMap subrangeIndex; + // details of of compiled method frame size changes + private List frameSizeInfos; + // size of compiled method frame + private int frameSize; + // index of debug_info section compilation unit for this file + private int cuIndex; + // index into debug_line section for associated compilation unit + private int lineIndex; + // size of line number info prologue region for associated compilation unit + private int linePrologueSize; + // total size of line number info region for associated compilation unit + private int totalSize; - public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { - this.primary = primary; - this.classEntry = classEntry; - this.subranges = new LinkedList<>(); - this.subrangeIndex = new HashMap<>(); - this.frameSizeInfos = frameSizeInfos; - this.frameSize = frameSize; - // initialize indices into other sections to illegal values - this.cuIndex = -1; - this.lineIndex = -1; - } - public void addSubRange(Range subrange, FileEntry subFileEntry) { - // we should not see a subrange more than once - assert !subranges.contains(subrange); - assert subrangeIndex.get(subrange) == null; - // we need to generate a file table entry - // for all ranges - subranges.add(subrange); - subrangeIndex.put(subrange, subFileEntry); - } - public Range getPrimary() { - return primary; - } - public ClassEntry getClassEntry() { - return classEntry; - } - public FileEntry getFileEntry() { - return classEntry.getFileEntry(); - } - public List getSubranges() { - return subranges; - } - public FileEntry getSubrangeFileEntry(Range subrange) { - return subrangeIndex.get(subrange); - } - List getFrameSizeInfos() { - return frameSizeInfos; - } - int getFrameSize() { - return frameSize; - } - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - int getLineIndex() { - // should have been set before being read - assert lineIndex >= 0; - return lineIndex; - } - void setLineIndex(int lineIndex) { - // should only get set once to a non-negative value - assert lineIndex >= 0; - assert this.lineIndex == -1; - this.lineIndex = lineIndex; - } - public int getLinePrologueSize() { - return linePrologueSize; - } - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - public int getTotalSize() { - return totalSize; - } - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } + public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { + this.primary = primary; + this.classEntry = classEntry; + this.subranges = new LinkedList<>(); + this.subrangeIndex = new HashMap<>(); + this.frameSizeInfos = frameSizeInfos; + this.frameSize = frameSize; + // initialize indices into other sections to illegal values + this.cuIndex = -1; + this.lineIndex = -1; + } + public void addSubRange(Range subrange, FileEntry subFileEntry) { + // we should not see a subrange more than once + assert !subranges.contains(subrange); + assert subrangeIndex.get(subrange) == null; + // we need to generate a file table entry + // for all ranges + subranges.add(subrange); + subrangeIndex.put(subrange, subFileEntry); + } + public Range getPrimary() { + return primary; + } + public ClassEntry getClassEntry() { + return classEntry; + } + public FileEntry getFileEntry() { + return classEntry.getFileEntry(); + } + public List getSubranges() { + return subranges; + } + public FileEntry getSubrangeFileEntry(Range subrange) { + return subrangeIndex.get(subrange); + } + List getFrameSizeInfos() { + return frameSizeInfos; + } + int getFrameSize() { + return frameSize; + } + void setCUIndex(int cuIndex) { + // should only get set once to a non-negative value + assert cuIndex >= 0; + assert this.cuIndex == -1; + this.cuIndex = cuIndex; + } + int getCUIndex() { + // should have been set before being read + assert cuIndex >= 0; + return cuIndex; + } + int getLineIndex() { + // should have been set before being read + assert lineIndex >= 0; + return lineIndex; + } + void setLineIndex(int lineIndex) { + // should only get set once to a non-negative value + assert lineIndex >= 0; + assert this.lineIndex == -1; + this.lineIndex = lineIndex; + } + public int getLinePrologueSize() { + return linePrologueSize; + } + public void setLinePrologueSize(int linePrologueSize) { + this.linePrologueSize = linePrologueSize; + } + public int getTotalSize() { + return totalSize; + } + public void setTotalSize(int totalSize) { + this.totalSize = totalSize; } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 7fc543efd256..e068ded3b845 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; // details of a specific address range in a compiled method diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index ec564851e641..09710793cba7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; // class used to ensure we keep only one copy of a String @@ -35,7 +61,7 @@ public boolean equals(Object object) { if (object == null || !(object instanceof StringEntry)) { return false; } else { - StringEntry other = (StringEntry)object; + StringEntry other = (StringEntry) object; return this == other || string.equals(other.string); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index ba7285bdb1aa..faa2b8ef3b61 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -1,3 +1,29 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.util.HashMap; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 5ce766497ce4..4633280eebce 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -978,7 +978,7 @@ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final Iterator> codeCacheIterator; private final Iterator> heapIterator; - public NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { + NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { super(); this.codeCache = codeCache; this.heap = heap; @@ -986,8 +986,7 @@ public NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageH this.heapIterator = heap.objects.entrySet().iterator(); } @Override - public DebugTypeInfoProvider typeInfoProvider() - { + public DebugTypeInfoProvider typeInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { @@ -1014,8 +1013,7 @@ public DebugCodeInfo next() { }; } @Override - public DebugDataInfoProvider dataInfoProvider() - { + public DebugDataInfoProvider dataInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { @@ -1029,11 +1027,10 @@ public DebugDataInfo next() { } } - private class NativeImageDebugCodeInfo implements DebugCodeInfo - { + private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; - public NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { + NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; this.compilation = compilation; } @@ -1063,13 +1060,12 @@ public String fileName() { // name is XXX$YYY so use outer class to derive file name name = name.substring(0, idx); } - name = name.replace('.','/') + ".java"; + name = name.replace('.', '/') + ".java"; } return name; } @Override - public String className() - { + public String className() { return method.format("%H"); } @Override @@ -1103,16 +1099,13 @@ public int line() { @Override public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { if (fileName().length() == 0) { - return () -> new Iterator() - { + return () -> new Iterator() { @Override - public boolean hasNext() - { + public boolean hasNext() { return false; } @Override - public DebugLineInfo next() - { + public DebugLineInfo next() { return null; } }; @@ -1120,13 +1113,11 @@ public DebugLineInfo next() return () -> new Iterator() { final Iterator sourceIterator = compilation.getSourceMappings().iterator(); @Override - public boolean hasNext() - { + public boolean hasNext() { return sourceIterator.hasNext(); } @Override - public DebugLineInfo next() - { + public DebugLineInfo next() { return new NativeImageDebugLineInfo(sourceIterator.next()); } }; @@ -1138,14 +1129,14 @@ public List getFrameSizeChanges() { List frameSizeChanges = new LinkedList<>(); for (Mark mark : compilation.getMarks()) { // we only need to observe stack increment or decrement points - if(mark.id.equals("PROLOGUE_DECD_RSP")) { + if (mark.id.equals("PROLOGUE_DECD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); frameSizeChanges.add(sizeChange); // } else if (mark.id.equals("PROLOGUE_END")) { // can ignore these // } else if (mark.id.equals("EPILOGUE_START")) { // can ignore these - } else if(mark.id.equals("EPILOGUE_INCD_RSP")) { + } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); frameSizeChanges.add(sizeChange); // } else if(mark.id.equals("EPILOGUE_END")) { @@ -1159,7 +1150,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { private final ResolvedJavaMethod method; private final int lo; private final int hi; - public NativeImageDebugLineInfo(SourceMapping sourceMapping) { + NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); int bci = position.getBCI(); this.bci = (bci >= 0 ? bci : 0); @@ -1179,31 +1170,26 @@ public String fileName() { // name is XXX$YYY so use outer class to derive file name name = name.substring(0, idx); } - return name.replace('.','/') + ".java"; + return name.replace('.', '/') + ".java"; } @Override - public String className() - { + public String className() { return method.format("%H"); } @Override - public String methodName() - { + public String methodName() { return method.format("%n"); } @Override - public int addressLo() - { + public int addressLo() { return lo; } @Override - public int addressHi() - { + public int addressHi() { return hi; } @Override - public int line() - { + public int line() { LineNumberTable lineNumberTable = method.getLineNumberTable(); if (lineNumberTable != null) { return lineNumberTable.getLineNumber(bci); @@ -1211,11 +1197,10 @@ public int line() return -1; } } - private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange - { + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; private Type type; - public NativeImageDebugFrameSizeChange(int offset, Type type) { + NativeImageDebugFrameSizeChange(int offset, Type type) { this.offset = offset; this.type = type; } From 0e6e8dcea1dbc33fb61cfedd245a9f12bbcf65e9 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 14:39:40 +0000 Subject: [PATCH 060/130] fixed eclipseformat style issues --- .../src/com/oracle/objectfile/ObjectFile.java | 2 +- .../debuginfo/DebugInfoProvider.java | 2 +- .../oracle/objectfile/elf/ELFObjectFile.java | 12 ++--- .../objectfile/elf/dwarf/ClassEntry.java | 2 +- .../objectfile/elf/dwarf/DwarfSections.java | 51 +++++++++++-------- .../oracle/objectfile/elf/dwarf/Range.java | 51 +++---------------- .../objectfile/elf/dwarf/StringEntry.java | 3 ++ .../objectfile/elf/dwarf/StringTable.java | 3 +- 8 files changed, 52 insertions(+), 74 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 912e15f559b9..0ad1476936a2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1089,7 +1089,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // support for consuming debug info - public void installDebugInfo(DebugInfoProvider debugInfoProvider) { + public void installDebugInfo( @SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default } 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 3a4cc6eac521..7c4d3757e227 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 @@ -66,7 +66,7 @@ interface DebugLineInfo { } interface DebugFrameSizeChange { - enum Type {EXTEND, CONTRACT}; + enum Type {EXTEND, CONTRACT} int getOffset(); DebugFrameSizeChange.Type getType(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 2bdca7526dce..7d1ca73a467e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1170,12 +1170,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + @SuppressWarnings("unused") ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + @SuppressWarnings("unused") ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + @SuppressWarnings("unused") ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + @SuppressWarnings("unused") ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + @SuppressWarnings("unused") ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + @SuppressWarnings("unused") ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 90fc7a8d6318..4421181710e7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -117,7 +117,7 @@ public int localDirsIdx(DirEntry dirEntry) { } } - public int localFilesIdx(FileEntry fileEntry) { + public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { return localFilesIndex.get(fileEntry); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index c668f92c0785..19008f6ba50d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -196,7 +196,7 @@ public ELFMachine getElfMachine() { // list detailing all dirs in which files are found to reside // either as part of substrate/compiler or user code - private LinkedList dirs = new LinkedList(); + private LinkedList dirs = new LinkedList<>(); // index of already seen dirs private Map dirsIndex = new HashMap<>(); @@ -207,7 +207,7 @@ public ELFMachine getElfMachine() { // a list recording details of all primary ranges included in // this file sorted by ascending address range - private LinkedList primaryEntries = new LinkedList(); + private LinkedList primaryEntries = new LinkedList<>(); // An alternative traversal option is // 1) by top level class (String id) @@ -227,14 +227,14 @@ public ELFMachine getElfMachine() { // of the file and dir tables. // list of class entries detailing class info for primary ranges - private LinkedList primaryClasses = new LinkedList(); + private LinkedList primaryClasses = new LinkedList<>(); // index of already seen classes private Map primaryClassesIndex = new HashMap<>(); // List of files which contain primary ranges - private LinkedList primaryFiles = new LinkedList(); + private LinkedList primaryFiles = new LinkedList<>(); // List of files which contain primary or secondary ranges - private LinkedList files = new LinkedList(); + private LinkedList files = new LinkedList<>(); // index of already seen files private Map filesIndex = new HashMap<>(); @@ -637,6 +637,7 @@ public void writeContent() { assert pos == size; } + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -787,6 +788,7 @@ public int writeAbbrev2(byte[] buffer, int pos) { return pos; } + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -1053,6 +1055,7 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { public abstract int getSPIdx(); public abstract int writeInitialInstructions(byte[] buffer, int pos); + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -1229,21 +1232,21 @@ public int writeCUHeader(byte[] buffer, int pos) { } } public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { - LinkedList primaryEntries = classEntry.getPrimaryEntries(); + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); pos = writeAttrData1(DW_LANG_Java, buffer, pos); debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, primaryEntries.getFirst().getPrimary().getLo()); - pos = writeAttrAddress(primaryEntries.getFirst().getPrimary().getLo(), buffer, pos); - debug(" [0x%08x] hi_pc 0x%08x\n", pos, primaryEntries.getLast().getPrimary().getHi()); - pos = writeAttrAddress(primaryEntries.getLast().getPrimary().getHi(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); + pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); + pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); - for (PrimaryEntry primary : primaryEntries) { - pos = writePrimary(primary, buffer, pos); + for (PrimaryEntry primaryEntry : classPrimaryEntries) { + pos = writePrimary(primaryEntry, buffer, pos); } // write a terminating null attribute for the the level 2 primaries return writeAttrNull(buffer, pos); @@ -1253,8 +1256,8 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getClassAndMethodNameWithParams()), primary.getClassAndMethodNameWithParams()); - pos = writeAttrStrp(primary.getClassAndMethodNameWithParams(), buffer, pos); + debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); + pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); pos = writeAttrAddress(primary.getLo(), buffer, pos); debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); @@ -1278,6 +1281,8 @@ public int writeAttrString(String value, byte[] buffer, int pos) { return putAsciiStringBytes(value, buffer, pos); } } + + @Override protected void debug(String format, Object... args) { if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); @@ -1315,6 +1320,7 @@ public String getSectionName() { return DW_ARANGES_SECTION_NAME; } + @Override public void createContent() { int pos = 0; // we need an entry for each compilation unit @@ -1365,6 +1371,7 @@ public byte[] getOrDecideContent(Map alreadyDecided, return super.getOrDecideContent(alreadyDecided, contentHint); } + @Override public void writeContent() { byte[] buffer = getContent(); int size = buffer.length; @@ -1377,9 +1384,9 @@ public void writeContent() { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = classEntry.getCUIndex(); - LinkedList primaryEntries = classEntry.getPrimaryEntries(); + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); // add room for each entry into length count - length += primaryEntries.size() * 2 * 8; + length += classPrimaryEntries.size() * 2 * 8; length += 2 * 8; debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); @@ -1393,9 +1400,9 @@ public void writeContent() { pos = putByte((byte) 0, buffer, pos); } debug(" [0x%08x] Address Length Name\n", pos); - for (PrimaryEntry primaryEntry : primaryEntries) { - Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getClassAndMethodName()); + for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { + Range primary = classPrimaryEntry.getPrimary(); + debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); } @@ -1406,6 +1413,7 @@ public void writeContent() { assert pos == size; } + @Override protected void debug(String format, Object... args) { super.debug(format, args); } @@ -1468,6 +1476,7 @@ public String getSectionName() { return DW_LINE_SECTION_NAME; } + @Override public void createContent() { // we need to create a header, dir table, file table and line // number table encoding for each CU @@ -1571,6 +1580,7 @@ public byte[] getOrDecideContent(Map alreadyDecided, return super.getOrDecideContent(alreadyDecided, contentHint); } + @Override public void writeContent() { byte[] buffer = getContent(); @@ -1728,7 +1738,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getClassAndMethodName(), subLine); + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); if (subLine < 0) { // no line info so stay at previous file:line subLine = line; @@ -1841,6 +1851,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { return pos; } + @Override protected void debug(String format, Object... args) { if (((int) args[0] - debugBase) < 0x100000) { super.debug(format, args); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index e068ded3b845..9e72991dcc88 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -58,41 +58,13 @@ public class Range { this.methodName = stringTable.uniqueString(methodName); this.paramNames = stringTable.uniqueString(paramNames); this.returnTypeName = stringTable.uniqueString(returnTypeName); - this.fullMethodName = stringTable.uniqueDebugString(getClassAndMethodNameWithParams()); + this.fullMethodName = stringTable.uniqueDebugString(constructClassAndMethodNameWithParams()); this.lo = lo; this.hi = hi; this.line = line; this.primary = primary; } - - public boolean sameClassName(Range other) { - return className.equals(other.className); - } - - public boolean sameMethodName(Range other) { - return methodName.equals(other.methodName); - } - - public boolean sameParamNames(Range other) { - return paramNames.equals(other.paramNames); - } - - public boolean sameReturnTypeName(Range other) { - return returnTypeName.equals(other.returnTypeName); - } - - public boolean sameFileName(Range other) { - return fileName.equals(other.fileName); - } - - public boolean sameMethod(Range other) { - return sameClassName(other) && - sameMethodName(other) && - sameParamNames(other) && - sameReturnTypeName(other); - } - public boolean contains(Range other) { return (lo <= other.lo && hi >= other.hi); } @@ -114,12 +86,6 @@ public String getClassName() { public String getMethodName() { return methodName; } - public String getParamNames() { - return paramNames; - } - public String getReturnTypeName() { - return returnTypeName; - } public int getHi() { return hi; } @@ -129,17 +95,10 @@ public int getLo() { public int getLine() { return line; } - public String getClassAndMethodName() { - return getExtendedMethodName(false, false); - } - public String getClassAndMethodNameWithParams() { - return getExtendedMethodName(true, false); - } - public String getFullMethodName() { - return getExtendedMethodName(true, true); + return fullMethodName; } - + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); if (includeReturnType && returnTypeName.length() > 0) { @@ -158,4 +117,8 @@ public String getExtendedMethodName(boolean includeParams, boolean includeReturn } return builder.toString(); } + + private String constructClassAndMethodNameWithParams() { + return getExtendedMethodName(true, false); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index 09710793cba7..dd311ed1807a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -57,6 +57,7 @@ public boolean isAddToStrSection() { public void setAddToStrSection() { this.addToStrSection = true; } + @Override public boolean equals(Object object) { if (object == null || !(object instanceof StringEntry)) { return false; @@ -65,9 +66,11 @@ public boolean equals(Object object) { return this == other || string.equals(other.string); } } + @Override public int hashCode() { return string.hashCode() + 37; } + @Override public String toString() { return string; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index faa2b8ef3b61..9ebc74a69bfd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -37,7 +37,7 @@ public class StringTable implements Iterable { private final HashMap table; public StringTable() { - this.table = new HashMap(); + this.table = new HashMap<>(); } public String uniqueString(String string) { @@ -68,6 +68,7 @@ public int debugStringIndex(String string) { } return stringEntry.getOffset(); } + @Override public Iterator iterator() { return table.values().iterator(); } From bb6a891e7d009ce16d1cd3490560ed4963ce5d87 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 15:10:17 +0000 Subject: [PATCH 061/130] fixed eclipseformat style issues --- .../src/com/oracle/objectfile/ObjectFile.java | 2 +- .../debuginfo/DebugInfoProvider.java | 27 +- .../oracle/objectfile/elf/ELFObjectFile.java | 18 +- .../objectfile/elf/dwarf/ClassEntry.java | 22 +- .../oracle/objectfile/elf/dwarf/DirEntry.java | 1 - .../objectfile/elf/dwarf/DwarfSections.java | 316 ++++++++++-------- .../objectfile/elf/dwarf/FileEntry.java | 2 + .../objectfile/elf/dwarf/PrimaryEntry.java | 17 + .../oracle/objectfile/elf/dwarf/Range.java | 8 +- .../objectfile/elf/dwarf/StringEntry.java | 9 + .../objectfile/elf/dwarf/StringTable.java | 1 + .../svm/hosted/image/NativeBootImage.java | 45 ++- 12 files changed, 317 insertions(+), 151 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 0ad1476936a2..7bc6be01f48d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1089,7 +1089,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // support for consuming debug info - public void installDebugInfo( @SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { + public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default } 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 7c4d3757e227..cf6daf5ec247 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 @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.debuginfo; + import java.util.List; // class defining interfaces used to allow a native image @@ -39,15 +40,25 @@ interface DebugTypeInfo { // access details of a specific compiled method interface DebugCodeInfo { String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); + DebugLineInfoProvider lineInfoProvider(); + String paramNames(); + String returnTypeName(); + int getFrameSize(); + List getFrameSizeChanges(); } @@ -58,16 +69,26 @@ interface DebugDataInfo { // access details of a specific outer or inlined method at a given line number interface DebugLineInfo { String fileName(); + String className(); + String methodName(); + int addressLo(); + int addressHi(); + int line(); } interface DebugFrameSizeChange { - enum Type {EXTEND, CONTRACT} + enum Type { + EXTEND, + CONTRACT + } + int getOffset(); + DebugFrameSizeChange.Type getType(); } @@ -80,7 +101,7 @@ interface DebugCodeInfoProvider extends Iterable { } // convenience interface defining iterator type - interface DebugLineInfoProvider extends Iterable{ + interface DebugLineInfoProvider extends Iterable { } // convenience interface defining iterator type @@ -88,6 +109,8 @@ interface DebugDataInfoProvider extends Iterable { } DebugTypeInfoProvider typeInfoProvider(); + DebugCodeInfoProvider codeInfoProvider(); + DebugDataInfoProvider dataInfoProvider(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 7d1ca73a467e..f3149f30125e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1170,12 +1170,18 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - @SuppressWarnings("unused") ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - @SuppressWarnings("unused") ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - @SuppressWarnings("unused") ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - @SuppressWarnings("unused") ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - @SuppressWarnings("unused") ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - @SuppressWarnings("unused") ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + @SuppressWarnings("unused") + ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + @SuppressWarnings("unused") + ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + @SuppressWarnings("unused") + ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + @SuppressWarnings("unused") + ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + @SuppressWarnings("unused") + ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + @SuppressWarnings("unused") + ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 4421181710e7..8522cdff9ca6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.elf.dwarf; + import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import java.util.HashMap; @@ -32,12 +33,12 @@ import java.util.List; import java.util.Map; -public class ClassEntry { +public class ClassEntry { // the name of the associated class private String className; // the associated file FileEntry fileEntry; - // a list recording details of all primary ranges included in + // a list recording details of all primary ranges included in // this class sorted by ascending address range private LinkedList primaryEntries; // an index identifying primary ranges which have already been encountered @@ -60,7 +61,7 @@ public class ClassEntry { private int totalSize; public ClassEntry(String className, FileEntry fileEntry) { - this.className = className; + this.className = className; this.fileEntry = fileEntry; this.primaryEntries = new LinkedList<>(); this.primaryIndex = new HashMap<>(); @@ -90,6 +91,7 @@ PrimaryEntry addPrimary(Range primary, List frameSizeInfos } return null; } + void addSubRange(Range subrange, FileEntry subFileEntry) { Range primary = subrange.getPrimary(); // the subrange should belong to a primary range @@ -109,6 +111,7 @@ void addSubRange(Range subrange, FileEntry subFileEntry) { localDirsIndex.put(dirEntry, localDirs.size()); } } + public int localDirsIdx(DirEntry dirEntry) { if (dirEntry != null) { return localDirsIndex.get(dirEntry); @@ -135,44 +138,57 @@ void setCUIndex(int cuIndex) { assert this.cuIndex == -1; this.cuIndex = cuIndex; } + int getCUIndex() { // should have been set before being read assert cuIndex >= 0; return cuIndex; } + int getLineIndex() { return lineIndex; } + void setLineIndex(int lineIndex) { this.lineIndex = lineIndex; } + public void setLinePrologueSize(int linePrologueSize) { this.linePrologueSize = linePrologueSize; } + public int getLinePrologueSize() { return linePrologueSize; } + public int getTotalSize() { return totalSize; } + public void setTotalSize(int totalSize) { this.totalSize = totalSize; } + public FileEntry getFileEntry() { return fileEntry; } + public String getClassName() { return className; } + public LinkedList getPrimaryEntries() { return primaryEntries; } + public Object primaryIndexFor(Range primaryRange) { return primaryIndex.get(primaryRange); } + public LinkedList getLocalDirs() { return localDirs; } + public LinkedList getLocalFiles() { return localFiles; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 1ce68980f93a..89d0b81bb8f0 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -49,4 +49,3 @@ public String getPath() { return path; } } - diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 19008f6ba50d..d01a90b24688 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.elf.dwarf; + import com.oracle.objectfile.BasicProgbitsSectionImpl; import com.oracle.objectfile.BuildDependency; import com.oracle.objectfile.LayoutDecision; @@ -108,9 +109,8 @@ public class DwarfSections { // private static final byte DW_ACCESS_protected = 2; // private static final byte DW_ACCESS_private = 3; - // not yet needed - // private static final int DW_AT_type = 0; // only present for non-void functions + // private static final int DW_AT_type = 0; // only present for non-void functions // private static final int DW_AT_accessibility = 0; // CIE and FDE entries @@ -156,8 +156,8 @@ public DwarfSections(ELFMachine elfMachine) { dwarfARangesSection = new DwarfARangesSectionImpl(); dwarfLineSection = new DwarfLineSectionImpl(); dwarfFameSection = (elfMachine == ELFMachine.AArch64 - ? new DwarfFrameSectionImplAArch64() - : new DwarfFrameSectionImplX86_64()); + ? new DwarfFrameSectionImplAArch64() + : new DwarfFrameSectionImplX86_64()); } public DwarfStrSectionImpl getStrSectionImpl() { @@ -205,7 +205,7 @@ public ELFMachine getElfMachine() { // 2) by inlined method (sub range) within top level method ordered by ascending address // this ensures that all debug records are generated in increasing address order - // a list recording details of all primary ranges included in + // a list recording details of all primary ranges included in // this file sorted by ascending address range private LinkedList primaryEntries = new LinkedList<>(); @@ -271,7 +271,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, returnTypeName, className, methodName, paramNames, fileName); + // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, + // returnTypeName, className, methodName, paramNames, fileName); // create an infoSection entry for the method addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { @@ -280,8 +281,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { String methodNameAtLine = debugLineInfo.methodName(); int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); - int line = debugLineInfo.line(); - // record all subranges even if they have no line or file so we at least get a symbol for them + int line = debugLineInfo.line(); + // record all subranges even if they have no line or file so we at least get a + // symbol for them Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); } @@ -299,7 +301,7 @@ public ClassEntry ensureClassEntry(Range range) { ClassEntry classEntry = primaryClassesIndex.get(className); if (classEntry == null) { // create and index the entry associating it with the right file - FileEntry fileEntry = ensureFileEntry(range); + FileEntry fileEntry = ensureFileEntry(range); classEntry = new ClassEntry(className, fileEntry); primaryClasses.add(classEntry); primaryClassesIndex.put(className, classEntry); @@ -316,8 +318,8 @@ public FileEntry ensureFileEntry(Range range) { DirEntry dirEntry = ensureDirEntry(fileName); String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), - stringTable.uniqueString(baseName), - dirEntry); + stringTable.uniqueString(baseName), + dirEntry); files.add(fileEntry); filesIndex.put(fileName, fileEntry); // if this is a primary entry then add it to the primary list @@ -381,12 +383,14 @@ public DwarfSectionImpl() { } public abstract void createContent(); + public abstract void writeContent(); + public void checkDebug(int pos) { // if the env var relevant to this element // type is set then switch on debugging String name = getSectionName(); - String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); + String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { debug = true; debugBase = pos; @@ -394,7 +398,7 @@ public void checkDebug(int pos) { } } - protected void debug(String format, Object ... args) { + protected void debug(String format, Object... args) { if (debug) { System.out.format(format, args); } @@ -405,11 +409,13 @@ public int putByte(byte b, byte[] buffer, int pos) { buffer[pos++] = b; return pos; } + public int putShort(short s, byte[] buffer, int pos) { buffer[pos++] = (byte) (s & 0xff); buffer[pos++] = (byte) ((s >> 8) & 0xff); return pos; } + public int putInt(int i, byte[] buffer, int pos) { buffer[pos++] = (byte) (i & 0xff); buffer[pos++] = (byte) ((i >> 8) & 0xff); @@ -417,6 +423,7 @@ public int putInt(int i, byte[] buffer, int pos) { buffer[pos++] = (byte) ((i >> 24) & 0xff); return pos; } + public int putLong(long l, byte[] buffer, int pos) { buffer[pos++] = (byte) (l & 0xff); buffer[pos++] = (byte) ((l >> 8) & 0xff); @@ -428,12 +435,14 @@ public int putLong(long l, byte[] buffer, int pos) { buffer[pos++] = (byte) ((l >> 56) & 0xff); return pos; } + public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { // mark address so it is relocated relative to the start of the text segment markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); pos = putLong(0, buffer, pos); return pos; } + public int putULEB(long l, byte[] buffer, int pos) { for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); @@ -449,6 +458,7 @@ public int putULEB(long l, byte[] buffer, int pos) { } return pos; } + public int putSLEB(long l, byte[] buffer, int pos) { boolean negative = l < 0; for (int i = 0; i < 9; i++) { @@ -466,9 +476,11 @@ public int putSLEB(long l, byte[] buffer, int pos) { } return pos; } + public int putAsciiStringBytes(String s, byte[] buffer, int pos) { return putAsciiStringBytes(s, 0, buffer, pos); } + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); @@ -505,6 +517,7 @@ public int writeTag(long code, byte[] buffer, int pos) { return putSLEB(code, buffer, pos); } } + public int writeFlag(byte flag, byte[] buffer, int pos) { if (buffer == null) { return pos + putByte(flag, scratch, 0); @@ -554,16 +567,11 @@ public int writeAttrNull(byte[] buffer, int pos) { } public abstract String targetSectionName(); + public abstract LayoutDecision.Kind[] targetSectionKinds(); public abstract String getSectionName(); - /* - @Override - public int getOrDecideSize(Map alreadyDecided, int sizeHint) { - return super.getOrDecideSize(alreadyDecided, sizeHint); - } - */ @Override public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { // ensure content byte[] has been created before calling super method @@ -580,12 +588,12 @@ public Set getDependencies(Map deci Set deps = super.getDependencies(decisions); String targetName = targetSectionName(); ELFSection targetSection = (ELFSection) getElement().getOwner().elementForName(targetName); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); LayoutDecision.Kind[] targetKinds = targetSectionKinds(); // make our content depend on the size and content of the target for (LayoutDecision.Kind targetKind : targetKinds) { - LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); } // make our size depend on our content @@ -608,7 +616,7 @@ public String getSectionName() { @Override public void createContent() { int pos = 0; - for (StringEntry stringEntry : stringTable) { + for (StringEntry stringEntry : stringTable) { if (stringEntry.isAddToStrSection()) { stringEntry.setOffset(pos); String string = stringEntry.getString(); @@ -627,7 +635,7 @@ public void writeContent() { checkDebug(pos); - for (StringEntry stringEntry : stringTable) { + for (StringEntry stringEntry : stringTable) { if (stringEntry.isAddToStrSection()) { assert stringEntry.getOffset() == pos; String string = stringEntry.getString(); @@ -644,14 +652,17 @@ protected void debug(String format, Object... args) { // .debug_str section content depends on text section content and offset public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; @@ -679,18 +690,18 @@ public void createContent() { // terminated by a null entry // // a null entry has consists of just a 0 abbrev code - // LEB128 abbrev_code; // == 0 + // LEB128 abbrev_code; ...... == 0 // // non-null entries have the following format - // LEB128 abbrev_code; // unique noncode for this layout != 0 - // 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 DIE - // * // zero or more attributes - // // terminator + // LEB128 abbrev_code; ...... unique noncode for this layout != 0 + // 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 DIE + // * ........ zero or more attributes + // .... terminator // // An attribute_spec consists of an attribute name and form - // LEB128 attr_name; // 0 for the null attribute name - // LEB128 attr_form; // 0 for the null attribute form + // LEB128 attr_name; ........ 0 for the null attribute name + // LEB128 attr_form; ........ 0 for the null attribute form // // For the moment we only use one abbrev table for all CUs. // It contains two DIEs, the first to describe the compilation @@ -700,17 +711,17 @@ public void createContent() { // The DIE layouts are as follows: // // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - // DW_AT_language : DW_FORM_data1 - // DW_AT_name : DW_FORM_strp - // DW_AT_low_pc : DW_FORM_address - // DW_AT_hi_pc : DW_FORM_address - // DW_AT_stmt_list : DW_FORM_data4 + // DW_AT_language : ... DW_FORM_data1 + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_address + // DW_AT_hi_pc : ...... DW_FORM_address + // DW_AT_stmt_list : .. DW_FORM_data4 // // abbrev_code == 2, tag == DW_TAG_subprogram, no_children - // DW_AT_name : DW_FORM_strp - // DW_AT_low_pc : DW_FORM_addr - // DW_AT_hi_pc : DW_FORM_addr - // DW_AT_external : DW_FORM_flag + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_addr + // DW_AT_hi_pc : ...... DW_FORM_addr + // DW_AT_external : ... DW_FORM_flag pos = writeAbbrev1(null, pos); pos = writeAbbrev2(null, pos); @@ -727,7 +738,7 @@ public void writeContent() { checkDebug(pos); - pos = writeAbbrev1(buffer, pos); + pos = writeAbbrev1(buffer, pos); pos = writeAbbrev2(buffer, pos); assert pos == size; } @@ -795,14 +806,17 @@ protected void debug(String format, Object... args) { // .debug_abbrev section content depends on .debug_frame section content and offset public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; @@ -856,14 +870,14 @@ public int writeCIE(byte[] buffer, int pos) { // because we have to have at least one // the layout is // - // uint32 : length // length of remaining fields in this CIE - // uint32 : CIE_id // unique id for CIE == 0xffffff - // uint8 : version // == 1 - // uint8[] : augmentation // == "" so always 1 byte - // ULEB : code_alignment_factor // 1 (could use 4 for Aarch64) - // ULEB : data_alignment_factor // -8 - // byte : ret_addr reg id // x86_64 => 16 AArch64 => 32 - // byte[] : initial_instructions // includes pad to 8-byte boundary + // uint32 : length ............... length of remaining fields in this CIE + // uint32 : CIE_id ................ unique id for CIE == 0xffffff + // uint8 : version ................ == 1 + // uint8[] : augmentation ......... == "" so always 1 byte + // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + // ULEB : data_alignment_factor ... == -8 + // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + // byte[] : initial_instructions .. includes pad to 8-byte boundary if (buffer == null) { pos += putInt(0, scratch, 0); // don't care about length pos += putInt(DW_CFA_CIE_id, scratch, 0); @@ -928,22 +942,22 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { // we only need a vanilla FDE header with default fields // the layout is // - // uint32 : length // length of remaining fields in this FDE - // uint32 : CIE_offset // alwasy 0 i.e. identifies our only CIE header - // uint64 : initial_location // i.e. method lo address - // uint64 : address_range // i.e. method hi - lo - // byte[] : instructions // includes pad to 8-byte boundary + // uint32 : length ........... length of remaining fields in this FDE + // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + // uint64 : initial_location .. i.e. method lo address + // uint64 : address_range ..... i.e. method hi - lo + // byte[] : instructions ...... includes pad to 8-byte boundary int lengthPos = pos; if (buffer == null) { pos += putInt(0, scratch, 0); // dummy length pos += putInt(0, scratch, 0); // CIE_offset - pos += putLong(lo, scratch, 0); // initial address + pos += putLong(lo, scratch, 0); // initial address return pos + putLong(hi - lo, scratch, 0); // address range } else { pos = putInt(0, buffer, pos); // dummy length pos = putInt(0, buffer, pos); // CIE_offset - pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address + pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address return putLong(hi - lo, buffer, pos); // address range } } @@ -971,6 +985,7 @@ public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { return putULEB(offset, buffer, pos); } } + public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { if (buffer == null) { pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); @@ -980,6 +995,7 @@ public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { return putULEB(offset, buffer, pos); } } + public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { if (offset <= 0x3f) { return writeAdvanceLoc0((byte) offset, buffer, pos); @@ -991,6 +1007,7 @@ public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { return writeAdvanceLoc4(offset, buffer, pos); } } + public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { byte op = advanceLoc0Op(offset); if (buffer == null) { @@ -999,6 +1016,7 @@ public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { return putByte(op, buffer, pos); } } + public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { byte op = DW_CFA_advance_loc1; if (buffer == null) { @@ -1009,6 +1027,7 @@ public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { return putByte(offset, buffer, pos); } } + public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { byte op = DW_CFA_advance_loc2; if (buffer == null) { @@ -1019,6 +1038,7 @@ public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { return putShort(offset, buffer, pos); } } + public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { byte op = DW_CFA_advance_loc4; if (buffer == null) { @@ -1029,6 +1049,7 @@ public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { return putInt(offset, buffer, pos); } } + public int writeOffset(int register, int offset, byte[] buffer, int pos) { byte op = offsetOp(register); if (buffer == null) { @@ -1039,6 +1060,7 @@ public int writeOffset(int register, int offset, byte[] buffer, int pos) { return putULEB(offset, buffer, pos); } } + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { if (buffer == null) { pos += putByte(DW_CFA_register, scratch, 0); @@ -1052,31 +1074,39 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { } public abstract int getPCIdx(); + public abstract int getSPIdx(); + public abstract int writeInitialInstructions(byte[] buffer, int pos); @Override protected void debug(String format, Object... args) { super.debug(format, args); } + // .debug_frame section content depends on .debug_line section content and offset public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } + private byte offsetOp(int register) { assert (register >> 6) == 0; return (byte) ((DW_CFA_offset << 6) | register); } + private byte advanceLoc0Op(int offset) { assert (offset >= 0 && offset <= 0x3f); return (byte) ((DW_CFA_advance_loc << 6) | offset); @@ -1090,21 +1120,25 @@ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public DwarfFrameSectionImplX86_64() { super(); } + @Override public int getPCIdx() { return DW_CFA_RIP_IDX; } + @Override public int getSPIdx() { return DW_CFA_RSP_IDX; } + @Override public int writeInitialInstructions(byte[] buffer, int pos) { // rsp points at the word containing the saved rip // so the frame base (cfa) is at rsp + 8 (why not - ???) // def_cfa r7 (sp) offset 8 pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); - // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa (why not -1 ???) + // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + // (why not -1 ???) // offset r16 (rip) cfa - 8 pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; @@ -1120,14 +1154,17 @@ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { public DwarfFrameSectionImplAArch64() { super(); } + @Override public int getPCIdx() { return DW_CFA_PC_IDX; } + @Override public int getSPIdx() { return DW_CFA_SP_IDX; } + @Override public int writeInitialInstructions(byte[] buffer, int pos) { // rsp has not been updated @@ -1156,12 +1193,12 @@ public void createContent() { // we need a single level 0 DIE for each compilation unit (CU) // Each CU's Level 0 DIE is preceded by a fixed header: // and terminated by a null DIE - // uint32 length // excluding this length field - // uint16 dwarf_version // always 2 ?? - // uint32 abbrev offset // always 0 ?? - // uint8 address_size // always 8 - // * // sequence of top-level and nested child entries - // // == 0 + // uint32 length ......... excluding this length field + // uint16 dwarf_version .. always 2 ?? + // uint32 abbrev offset .. always 0 ?? + // uint8 address_size .... always 8 + // * ................ sequence of top-level and nested child entries + // ............ == 0 // // a DIE is a recursively defined structure // it starts with a code for the associated @@ -1170,13 +1207,13 @@ public void createContent() { // a null value and followed by zero or more child // DIEs (zero iff has_children == no_children) // - // LEB128 abbrev_code != 0 // non-zero value indexes tag + attr layout of DIE - // * // value sequence as determined by abbrev entry - // * // sequence of child DIEs (if appropriate) - // // == 0 + // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + // * ....... value sequence as determined by abbrev entry + // * ................... sequence of child DIEs (if appropriate) + // ............. == 0 // // note that a null_DIE looks like - // LEB128 abbrev_code == 0 + // LEB128 abbrev_code ....... == 0 // i.e. it also looks like a null_value byte[] buffer = null; @@ -1231,6 +1268,7 @@ public int writeCUHeader(byte[] buffer, int pos) { return putByte((byte) 8, buffer, pos); // address size } } + public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); @@ -1252,7 +1290,8 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { return writeAttrNull(buffer, pos); } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { + + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); @@ -1266,6 +1305,7 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) debug(" [0x%08x] external true\n", pos); return writeFlag(DW_FLAG_true, buffer, pos); } + public int writeAttrStrp(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(0, scratch, 0); @@ -1274,6 +1314,7 @@ public int writeAttrStrp(String value, byte[] buffer, int pos) { return putInt(idx, buffer, pos); } } + public int writeAttrString(String value, byte[] buffer, int pos) { if (buffer == null) { return pos + value.length() + 1; @@ -1293,14 +1334,17 @@ protected void debug(String format, Object... args) { // .debug_info section content depends on abbrev section content and offset public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; @@ -1325,21 +1369,21 @@ public void createContent() { int pos = 0; // we need an entry for each compilation unit // - // uint32 length // in bytes (not counting these 4 bytes) - // uint16 dwarf_version // always 2 - // uint32 info_offset // offset of compilation unit on debug_info - // uint8 address_size // always 8 - // uint8 segment_desc_size // ??? + // uint32 length ............ in bytes (not counting these 4 bytes) + // uint16 dwarf_version ..... always 2 + // uint32 info_offset ....... offset of compilation unit on debug_info + // uint8 address_size ....... always 8 + // uint8 segment_desc_size .. ??? // // i.e. 12 bytes followed by padding // aligning up to 2 * address size // - // uint8 pad[4] + // uint8 pad[4] // // followed by N + 1 times // - // uint64 lo // lo address of range - // uint64 length // number of bytes in range + // uint64 lo ................ lo address of range + // uint64 length ............ number of bytes in range // // where N is the number of ranges belonging to the compilation unit // and the last range contains two zeroes @@ -1420,19 +1464,22 @@ protected void debug(String format, Object... args) { // .debug_aranges section content depends on .debug_info section content and offset public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } - } + } public class DwarfLineSectionImpl extends DwarfSectionImpl { // header section always contains fixed number of bytes @@ -1447,23 +1494,27 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * standard opcodes defined by Dwarf 2 */ - private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an invalid opcode - private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for extended opcodes - private static final byte DW_LNS_copy = 1; // append current state as matrix row 0 args + private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an + // invalid opcode + private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for + // extended opcodes + private static final byte DW_LNS_copy = 1; // append current state as matrix row + // 0 args private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row - private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode 255 0 args + private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode + // 255 0 args private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg /* * extended opcodes defined by Dwarf 2 */ private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 - private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses + private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 @@ -1489,7 +1540,7 @@ public void createContent() { int headerSize = headerSize(); int dirTableSize = computeDirTableSize(classEntry); int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; + int prologueSize = headerSize + dirTableSize + fileTableSize; classEntry.setLinePrologueSize(prologueSize); int lineNumberTableSize = computeLineNUmberTableSize(classEntry); int totalSize = prologueSize + lineNumberTableSize; @@ -1502,16 +1553,16 @@ public void createContent() { public int headerSize() { // header size is standard 31 bytes - // uint32 total_length - // uint16 version - // uint32 prologue_length - // uint8 min_insn_length - // uint8 default_is_stmt - // int8 line_base - // uint8 line_range - // uint8 opcode_base - // uint8 li_opcode_base - // uint8[opcode_base-1] standard_opcode_lengths + // uint32 total_length + // uint16 version + // uint32 prologue_length + // uint8 min_insn_length + // uint8 default_is_stmt + // int8 line_base + // uint8 line_range + // uint8 opcode_base + // uint8 li_opcode_base + // uint8[opcode_base-1] standard_opcode_lengths return DW_LN_HEADER_SIZE; } @@ -1681,7 +1732,6 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { public int debugLine = 1; public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // the primary file entry should always be first in the local files list assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; @@ -1713,7 +1763,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // boolean end_sequence = false; // set state for primary - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), + primaryRange.getLine()); // initialize and write a row for the start of the primary method pos = putSetFile(file, fileIdx, buffer, pos); @@ -1746,7 +1797,6 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { subFileIdx = fileIdx; debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); } - /* // there is a temptation to append end sequence at here // when the hiAddress lies strictly between the current // address and the start of the next subrange because, @@ -1757,27 +1807,28 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { // so the code below is not actually needed. it is left in // to clarify i) that this is a deliberate choice and ii) what // that deliberate choice is avoiding. - if (address < hiAddress && hiAddress < subAddressLo) { - long addressDelta = hiAddress - address; - // increment address to hi address, write an - // end sequence and update state to new range - pos = putAdvancePC(addressDelta, buffer, pos); - pos = putEndSequence(buffer, pos); - file = subfile; - fileIdx = subFileIdx; - pos = putSetFile(file, fileIdx, buffer, pos); - line = subLine; - // state machine value of line is currently 1 - // increment to desired line - if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); + if (false) { + if (address < hiAddress && hiAddress < subAddressLo) { + long addressDelta = hiAddress - address; + // increment address to hi address, write an + // end sequence and update state to new rang + pos = putAdvancePC(addressDelta, buffer, pos); + pos = putEndSequence(buffer, pos); + file = subfile; + fileIdx = subFileIdx; + pos = putSetFile(file, fileIdx, buffer, pos); + line = subLine; + // state machine value of line is currently 1 + // increment to desired line + if (line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putSetBasicBlock(buffer, pos); + // use a reloc to ensure address is relative to text base + address = hiAddress; + pos = putSetAddress(hiAddress, buffer, pos); } - pos = putSetBasicBlock(buffer, pos); - // use a reloc to ensure address is relative to text base - address = hiAddress; - pos = putSetAddress(hiAddress, buffer, pos); } - */ // if we have to update to a new file then do so if (subFileIdx != fileIdx) { // update the current file @@ -2055,7 +2106,7 @@ public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) { debugAddress += opcodeAddress(opcode); debugLine += opcodeLine(opcode); debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, pos); } } @@ -2102,15 +2153,18 @@ public boolean isFixedAdvancePC(long addressDiff) { // .debug_line section content depends on .debug_str section content and offset public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + @Override public String targetSectionName() { return TARGET_SECTION_NAME; } + public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address }; + @Override public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index 5a4ed796d8dc..3a8943cabdf6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -43,9 +43,11 @@ public FileEntry(String fileName, String baseName, DirEntry dirEntry) { public String getFileName() { return fileName; } + public String getBaseName() { return baseName; } + String getDirName() { return (dirEntry != null ? dirEntry.getPath() : ""); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index cdc84b9c4961..a26d060c8859 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; + public class PrimaryEntry { // the primary range detailed by this object Range primary; @@ -64,6 +65,7 @@ public PrimaryEntry(Range primary, List frameSizeInfos, in this.cuIndex = -1; this.lineIndex = -1; } + public void addSubRange(Range subrange, FileEntry subFileEntry) { // we should not see a subrange more than once assert !subranges.contains(subrange); @@ -73,58 +75,73 @@ public void addSubRange(Range subrange, FileEntry subFileEntry) { subranges.add(subrange); subrangeIndex.put(subrange, subFileEntry); } + public Range getPrimary() { return primary; } + public ClassEntry getClassEntry() { return classEntry; } + public FileEntry getFileEntry() { return classEntry.getFileEntry(); } + public List getSubranges() { return subranges; } + public FileEntry getSubrangeFileEntry(Range subrange) { return subrangeIndex.get(subrange); } + List getFrameSizeInfos() { return frameSizeInfos; } + int getFrameSize() { return frameSize; } + void setCUIndex(int cuIndex) { // should only get set once to a non-negative value assert cuIndex >= 0; assert this.cuIndex == -1; this.cuIndex = cuIndex; } + int getCUIndex() { // should have been set before being read assert cuIndex >= 0; return cuIndex; } + int getLineIndex() { // should have been set before being read assert lineIndex >= 0; return lineIndex; } + void setLineIndex(int lineIndex) { // should only get set once to a non-negative value assert lineIndex >= 0; assert this.lineIndex == -1; this.lineIndex = lineIndex; } + public int getLinePrologueSize() { return linePrologueSize; } + public void setLinePrologueSize(int linePrologueSize) { this.linePrologueSize = linePrologueSize; } + public int getTotalSize() { return totalSize; } + public void setTotalSize(int totalSize) { this.totalSize = totalSize; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 9e72991dcc88..6692d23b7df6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -80,25 +80,31 @@ public Range getPrimary() { public String getFileName() { return fileName; } + public String getClassName() { return className; } + public String getMethodName() { return methodName; } + public int getHi() { return hi; } + public int getLo() { return lo; } + public int getLine() { return line; } + public String getFullMethodName() { return fullMethodName; } - + public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); if (includeReturnType && returnTypeName.length() > 0) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index dd311ed1807a..a96e5eb19e6a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -38,25 +38,31 @@ public class StringEntry { this.string = string; this.offset = -1; } + public String getString() { return string; } + public int getOffset() { // offset must be set before this can be fetched assert offset >= 0; return offset; } + public void setOffset(int offset) { assert this.offset < 0; assert offset >= 0; this.offset = offset; } + public boolean isAddToStrSection() { return addToStrSection; } + public void setAddToStrSection() { this.addToStrSection = true; } + @Override public boolean equals(Object object) { if (object == null || !(object instanceof StringEntry)) { @@ -66,14 +72,17 @@ public boolean equals(Object object) { return this == other || string.equals(other.string); } } + @Override public int hashCode() { return string.hashCode() + 37; } + @Override public String toString() { return string; } + public boolean isEmpty() { return string.length() == 0; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 9ebc74a69bfd..74506877df94 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -68,6 +68,7 @@ public int debugStringIndex(String string) { } return stringEntry.getOffset(); } + @Override public Iterator iterator() { return table.values().iterator(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 4633280eebce..338ff37f22d6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -985,19 +985,22 @@ private class NativeImageDebugInfoProvider implements DebugInfoProvider { this.codeCacheIterator = codeCache.compilations.entrySet().iterator(); this.heapIterator = heap.objects.entrySet().iterator(); } + @Override - public DebugTypeInfoProvider typeInfoProvider() { + public DebugTypeInfoProvider typeInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { return false; } + @Override public DebugTypeInfo next() { return null; } }; } + @Override public DebugCodeInfoProvider codeInfoProvider() { return () -> new Iterator() { @@ -1005,6 +1008,7 @@ public DebugCodeInfoProvider codeInfoProvider() { public boolean hasNext() { return codeCacheIterator.hasNext(); } + @Override public DebugCodeInfo next() { Map.Entry entry = codeCacheIterator.next(); @@ -1012,13 +1016,15 @@ public DebugCodeInfo next() { } }; } + @Override - public DebugDataInfoProvider dataInfoProvider() { + public DebugDataInfoProvider dataInfoProvider() { return () -> new Iterator() { @Override public boolean hasNext() { return false; } + @Override public DebugDataInfo next() { return null; @@ -1030,13 +1036,15 @@ public DebugDataInfo next() { private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; + NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; this.compilation = compilation; } + @Override public String fileName() { - HostedType declaringClass = method.getDeclaringClass(); + HostedType declaringClass = method.getDeclaringClass(); String name = declaringClass.getSourceFileName(); if (name != null) { // the file name will not include any path @@ -1064,30 +1072,37 @@ public String fileName() { } return name; } + @Override public String className() { return method.format("%H"); } + @Override public String methodName() { return method.format("%n"); } + @Override public String paramNames() { return method.format("%P"); } + @Override public String returnTypeName() { return method.format("%R"); } + @Override public int addressLo() { return method.getCodeAddressOffset(); } + @Override public int addressHi() { return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); } + @Override public int line() { LineNumberTable lineNumberTable = method.getLineNumberTable(); @@ -1096,6 +1111,7 @@ public int line() { } return -1; } + @Override public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { if (fileName().length() == 0) { @@ -1104,6 +1120,7 @@ public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { public boolean hasNext() { return false; } + @Override public DebugLineInfo next() { return null; @@ -1112,19 +1129,23 @@ public DebugLineInfo next() { } return () -> new Iterator() { final Iterator sourceIterator = compilation.getSourceMappings().iterator(); + @Override public boolean hasNext() { return sourceIterator.hasNext(); } + @Override public DebugLineInfo next() { return new NativeImageDebugLineInfo(sourceIterator.next()); } }; } + public int getFrameSize() { return compilation.getTotalFrameSize(); } + public List getFrameSizeChanges() { List frameSizeChanges = new LinkedList<>(); for (Mark mark : compilation.getMarks()) { @@ -1132,24 +1153,26 @@ public List getFrameSizeChanges() { if (mark.id.equals("PROLOGUE_DECD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); frameSizeChanges.add(sizeChange); - // } else if (mark.id.equals("PROLOGUE_END")) { + // } else if (mark.id.equals("PROLOGUE_END")) { // can ignore these - // } else if (mark.id.equals("EPILOGUE_START")) { + // } else if (mark.id.equals("EPILOGUE_START")) { // can ignore these } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); frameSizeChanges.add(sizeChange); - // } else if(mark.id.equals("EPILOGUE_END")) { + // } else if(mark.id.equals("EPILOGUE_END")) { } } return frameSizeChanges; } } + private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; private final ResolvedJavaMethod method; private final int lo; private final int hi; + NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); int bci = position.getBCI(); @@ -1158,6 +1181,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { this.lo = sourceMapping.getStartOffset(); this.hi = sourceMapping.getEndOffset(); } + @Override public String fileName() { String name = className(); @@ -1172,22 +1196,27 @@ public String fileName() { } return name.replace('.', '/') + ".java"; } + @Override public String className() { return method.format("%H"); } + @Override public String methodName() { return method.format("%n"); } + @Override public int addressLo() { return lo; } + @Override public int addressHi() { return hi; } + @Override public int line() { LineNumberTable lineNumberTable = method.getLineNumberTable(); @@ -1197,17 +1226,21 @@ public int line() { return -1; } } + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; private Type type; + NativeImageDebugFrameSizeChange(int offset, Type type) { this.offset = offset; this.type = type; } + @Override public int getOffset() { return offset; } + @Override public Type getType() { return type; From ec060681712571740bd6674a3f1df23882d0ab90 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 15:59:37 +0000 Subject: [PATCH 062/130] more style whackamole --- .../objectfile/elf/dwarf/DwarfSections.java | 183 +++++++++++------- 1 file changed, 114 insertions(+), 69 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index d01a90b24688..5cb930219ea7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -65,7 +65,7 @@ public class DwarfSections { private static final short DW_VERSION_2 = 2; // define all the abbrev section codes we need for our DIEs - private static final int DW_ABBREV_CODE_null = 0; + // private static final int DW_ABBREV_CODE_null = 0; private static final int DW_ABBREV_CODE_compile_unit = 1; private static final int DW_ABBREV_CODE_subprogram = 2; @@ -75,7 +75,7 @@ public class DwarfSections { // define all the Dwarf attributes we need for our DIEs private static final int DW_AT_null = 0x0; private static final int DW_AT_name = 0x3; - private static final int DW_AT_comp_dir = 0x1b; + // private static final int DW_AT_comp_dir = 0x1b; private static final int DW_AT_stmt_list = 0x10; private static final int DW_AT_low_pc = 0x11; private static final int DW_AT_hi_pc = 0x12; @@ -85,13 +85,13 @@ public class DwarfSections { private static final int DW_AT_frame_base = 0x40; // define all the Dwarf attribute forms we need for our DIEs private static final int DW_FORM_null = 0x0; - private static final int DW_FORM_string = 0x8; + // private static final int DW_FORM_string = 0x8; private static final int DW_FORM_strp = 0xe; // not currently used private static final int DW_FORM_addr = 0x1; private static final int DW_FORM_data1 = 0x0b; // use flag instead private static final int DW_FORM_data4 = 0x6; - private static final int DW_FORM_data8 = 0x7; - private static final int DW_FORM_block1 = 0x0a; + // private static final int DW_FORM_data8 = 0x7; + // private static final int DW_FORM_block1 = 0x0a; private static final int DW_FORM_flag = 0xc; // define specific attribute values for given attribute or form types @@ -115,30 +115,30 @@ public class DwarfSections { // CIE and FDE entries - public static final int DW_CFA_CIE_id = -1; - public static final int DW_CFA_FDE_id = 0; + private static final int DW_CFA_CIE_id = -1; + // private static final int DW_CFA_FDE_id = 0; - public static final byte DW_CFA_CIE_version = 1; + private static final byte DW_CFA_CIE_version = 1; // values for high 2 bits - public static final byte DW_CFA_advance_loc = 0x1; - public static final byte DW_CFA_offset = 0x2; - public static final byte DW_CFA_restore = 0x3; + private static final byte DW_CFA_advance_loc = 0x1; + private static final byte DW_CFA_offset = 0x2; + // private static final byte DW_CFA_restore = 0x3; // values for low 6 bits - public static final byte DW_CFA_nop = 0x0; - public static final byte DW_CFA_set_loc1 = 0x1; - public static final byte DW_CFA_advance_loc1 = 0x2; - public static final byte DW_CFA_advance_loc2 = 0x3; - public static final byte DW_CFA_advance_loc4 = 0x4; - public static final byte DW_CFA_offset_extended = 0x5; - public static final byte DW_CFA_restore_extended = 0x6; - public static final byte DW_CFA_undefined = 0x7; - public static final byte DW_CFA_same_value = 0x8; - public static final byte DW_CFA_register = 0x9; - public static final byte DW_CFA_def_cfa = 0xc; - public static final byte DW_CFA_def_cfa_register = 0xd; - public static final byte DW_CFA_def_cfa_offset = 0xe; + private static final byte DW_CFA_nop = 0x0; + // private static final byte DW_CFA_set_loc1 = 0x1; + private static final byte DW_CFA_advance_loc1 = 0x2; + private static final byte DW_CFA_advance_loc2 = 0x3; + private static final byte DW_CFA_advance_loc4 = 0x4; + // private static final byte DW_CFA_offset_extended = 0x5; + // private static final byte DW_CFA_restore_extended = 0x6; + // private static final byte DW_CFA_undefined = 0x7; + // private static final byte DW_CFA_same_value = 0x8; + private static final byte DW_CFA_register = 0x9; + private static final byte DW_CFA_def_cfa = 0xc; + // private static final byte DW_CFA_def_cfa_register = 0xd; + private static final byte DW_CFA_def_cfa_offset = 0xe; private ELFMachine elfMachine; private DwarfStrSectionImpl dwarfStrSection; @@ -405,18 +405,21 @@ protected void debug(String format, Object... args) { } // base level put methods that assume a non-null buffer - public int putByte(byte b, byte[] buffer, int pos) { + public int putByte(byte b, byte[] buffer, int p) { + int pos = p; buffer[pos++] = b; return pos; } - public int putShort(short s, byte[] buffer, int pos) { + public int putShort(short s, byte[] buffer, int p) { + int pos = p; buffer[pos++] = (byte) (s & 0xff); buffer[pos++] = (byte) ((s >> 8) & 0xff); return pos; } - public int putInt(int i, byte[] buffer, int pos) { + public int putInt(int i, byte[] buffer, int p) { + int pos = p; buffer[pos++] = (byte) (i & 0xff); buffer[pos++] = (byte) ((i >> 8) & 0xff); buffer[pos++] = (byte) ((i >> 16) & 0xff); @@ -424,7 +427,8 @@ public int putInt(int i, byte[] buffer, int pos) { return pos; } - public int putLong(long l, byte[] buffer, int pos) { + public int putLong(long l, byte[] buffer, int p) { + int pos = p; buffer[pos++] = (byte) (l & 0xff); buffer[pos++] = (byte) ((l >> 8) & 0xff); buffer[pos++] = (byte) ((l >> 16) & 0xff); @@ -443,7 +447,9 @@ public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { return pos; } - public int putULEB(long l, byte[] buffer, int pos) { + public int putULEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); l = l >>> 7; @@ -459,7 +465,9 @@ public int putULEB(long l, byte[] buffer, int pos) { return pos; } - public int putSLEB(long l, byte[] buffer, int pos) { + public int putSLEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; boolean negative = l < 0; for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); @@ -481,7 +489,8 @@ public int putAsciiStringBytes(String s, byte[] buffer, int pos) { return putAsciiStringBytes(s, 0, buffer, pos); } - public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int pos) { + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { + int pos = p; for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); if (c > 127) { @@ -759,7 +768,8 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { } } - public int writeAbbrev1(byte[] buffer, int pos) { + public int writeAbbrev1(byte[] buffer, int p) { + int pos = p; // abbrev 1 compile unit pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); pos = writeTag(DW_TAG_compile_unit, buffer, pos); @@ -780,7 +790,8 @@ public int writeAbbrev1(byte[] buffer, int pos) { return pos; } - public int writeAbbrev2(byte[] buffer, int pos) { + public int writeAbbrev2(byte[] buffer, int p) { + int pos = p; // abbrev 2 compile unit pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); pos = writeTag(DW_TAG_subprogram, buffer, pos); @@ -865,7 +876,7 @@ public void writeContent() { assert pos == size; } - public int writeCIE(byte[] buffer, int pos) { + public int writeCIE(byte[] buffer, int p) { // we only need a vanilla CIE with default fields // because we have to have at least one // the layout is @@ -878,6 +889,7 @@ public int writeCIE(byte[] buffer, int pos) { // ULEB : data_alignment_factor ... == -8 // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 // byte[] : initial_instructions .. includes pad to 8-byte boundary + int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // don't care about length pos += putInt(DW_CFA_CIE_id, scratch, 0); @@ -910,7 +922,8 @@ public int writeCIE(byte[] buffer, int pos) { } } - public int writeMethodFrames(byte[] buffer, int pos) { + public int writeMethodFrames(byte[] buffer, int p) { + int pos = p; for (ClassEntry classEntry : primaryClasses) { for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { long lo = primaryEntry.getPrimary().getLo(); @@ -938,7 +951,7 @@ public int writeMethodFrames(byte[] buffer, int pos) { return pos; } - public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { + public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { // we only need a vanilla FDE header with default fields // the layout is // @@ -948,7 +961,7 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { // uint64 : address_range ..... i.e. method hi - lo // byte[] : instructions ...... includes pad to 8-byte boundary - int lengthPos = pos; + int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // dummy length pos += putInt(0, scratch, 0); // CIE_offset @@ -962,7 +975,8 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int pos) { } } - public int writePaddingNops(int alignment, byte[] buffer, int pos) { + public int writePaddingNops(int alignment, byte[] buffer, int p) { + int pos = p; assert (alignment & (alignment - 1)) == 0; while ((pos & (alignment - 1)) != 0) { if (buffer == null) { @@ -974,7 +988,8 @@ public int writePaddingNops(int alignment, byte[] buffer, int pos) { return pos; } - public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { + public int writeDefCFA(int register, int offset, byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putByte(DW_CFA_def_cfa, scratch, 0); pos += putSLEB(register, scratch, 0); @@ -986,7 +1001,8 @@ public int writeDefCFA(int register, int offset, byte[] buffer, int pos) { } } - public int writeDefCFAOffset(int offset, byte[] buffer, int pos) { + public int writeDefCFAOffset(int offset, byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); return pos + putULEB(offset, scratch, 0); @@ -1017,7 +1033,8 @@ public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { + public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { + int pos = p; byte op = DW_CFA_advance_loc1; if (buffer == null) { pos += putByte(op, scratch, 0); @@ -1028,8 +1045,9 @@ public int writeAdvanceLoc1(byte offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { + public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { byte op = DW_CFA_advance_loc2; + int pos = p; if (buffer == null) { pos += putByte(op, scratch, 0); return pos + putShort(offset, scratch, 0); @@ -1039,8 +1057,9 @@ public int writeAdvanceLoc2(short offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { + public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { byte op = DW_CFA_advance_loc4; + int pos = p; if (buffer == null) { pos += putByte(op, scratch, 0); return pos + putInt(offset, scratch, 0); @@ -1050,8 +1069,9 @@ public int writeAdvanceLoc4(int offset, byte[] buffer, int pos) { } } - public int writeOffset(int register, int offset, byte[] buffer, int pos) { + public int writeOffset(int register, int offset, byte[] buffer, int p) { byte op = offsetOp(register); + int pos = p; if (buffer == null) { pos += putByte(op, scratch, 0); return pos + putULEB(offset, scratch, 0); @@ -1061,7 +1081,8 @@ public int writeOffset(int register, int offset, byte[] buffer, int pos) { } } - public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int pos) { + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putByte(DW_CFA_register, scratch, 0); pos += putULEB(savedReg, scratch, 0); @@ -1132,7 +1153,8 @@ public int getSPIdx() { } @Override - public int writeInitialInstructions(byte[] buffer, int pos) { + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; // rsp points at the word containing the saved rip // so the frame base (cfa) is at rsp + 8 (why not - ???) // def_cfa r7 (sp) offset 8 @@ -1166,7 +1188,8 @@ public int getSPIdx() { } @Override - public int writeInitialInstructions(byte[] buffer, int pos) { + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; // rsp has not been updated // caller pc is in lr // register r32 (rpc), r30 (lr) @@ -1255,7 +1278,8 @@ public void writeContent() { assert pos == size; } - public int writeCUHeader(byte[] buffer, int pos) { + public int writeCUHeader(byte[] buffer, int p) { + int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // CU length pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version @@ -1269,7 +1293,8 @@ public int writeCUHeader(byte[] buffer, int pos) { } } - public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); @@ -1291,7 +1316,8 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int pos) { } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { + int pos = p; Range primary = primaryEntry.getPrimary(); debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); @@ -1306,7 +1332,8 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int pos) { return writeFlag(DW_FLAG_true, buffer, pos); } - public int writeAttrStrp(String value, byte[] buffer, int pos) { + public int writeAttrStrp(String value, byte[] buffer, int p) { + int pos = p; if (buffer == null) { return pos + putInt(0, scratch, 0); } else { @@ -1315,7 +1342,8 @@ public int writeAttrStrp(String value, byte[] buffer, int pos) { } } - public int writeAttrString(String value, byte[] buffer, int pos) { + public int writeAttrString(String value, byte[] buffer, int p) { + int pos = p; if (buffer == null) { return pos + value.length() + 1; } else { @@ -1659,7 +1687,8 @@ public void writeContent() { assert pos == buffer.length; } - public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; // 4 ubyte length field pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); // 2 ubyte version is always 2 @@ -1694,7 +1723,8 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int pos) { return pos; } - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; debug(" [0x%08x] Dir Name\n", pos); // write out the list of dirs referenced form this file entry int dirIdx = 1; @@ -1709,7 +1739,8 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int pos) { return pos; } - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; int fileIdx = 1; debug(" [0x%08x] Entry Dir Name\n", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { @@ -1732,7 +1763,8 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int pos) { public int debugLine = 1; public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int pos) { + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; // the primary file entry should always be first in the local files list assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; String primaryClassName = classEntry.getClassName(); @@ -1911,8 +1943,9 @@ protected void debug(String format, Object... args) { } } - public int putCopy(byte[] buffer, int pos) { + public int putCopy(byte[] buffer, int p) { byte opcode = DW_LNS_copy; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -1922,8 +1955,9 @@ public int putCopy(byte[] buffer, int pos) { } } - public int putAdvancePC(long uleb, byte[] buffer, int pos) { + public int putAdvancePC(long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_pc; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); @@ -1935,8 +1969,9 @@ public int putAdvancePC(long uleb, byte[] buffer, int pos) { } } - public int putAdvanceLine(long sleb, byte[] buffer, int pos) { + public int putAdvanceLine(long sleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_line; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putSLEB(sleb, scratch, 0); @@ -1948,8 +1983,9 @@ public int putAdvanceLine(long sleb, byte[] buffer, int pos) { } } - public int putSetFile(String file, long uleb, byte[] buffer, int pos) { + public int putSetFile(String file, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_file; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); @@ -1960,8 +1996,9 @@ public int putSetFile(String file, long uleb, byte[] buffer, int pos) { } } - public int putSetColumn(long uleb, byte[] buffer, int pos) { + public int putSetColumn(long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); @@ -1971,8 +2008,9 @@ public int putSetColumn(long uleb, byte[] buffer, int pos) { } } - public int putNegateStmt(byte[] buffer, int pos) { + public int putNegateStmt(byte[] buffer, int p) { byte opcode = DW_LNS_negate_stmt; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -1980,8 +2018,9 @@ public int putNegateStmt(byte[] buffer, int pos) { } } - public int putSetBasicBlock(byte[] buffer, int pos) { + public int putSetBasicBlock(byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -1990,8 +2029,9 @@ public int putSetBasicBlock(byte[] buffer, int pos) { } } - public int putConstAddPC(byte[] buffer, int pos) { + public int putConstAddPC(byte[] buffer, int p) { byte opcode = DW_LNS_const_add_pc; + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { @@ -2002,8 +2042,9 @@ public int putConstAddPC(byte[] buffer, int pos) { } } - public int putFixedAdvancePC(short arg, byte[] buffer, int pos) { + public int putFixedAdvancePC(short arg, byte[] buffer, int p) { byte opcode = DW_LNS_fixed_advance_pc; + int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putShort(arg, scratch, 0); @@ -2015,8 +2056,9 @@ public int putFixedAdvancePC(short arg, byte[] buffer, int pos) { } } - public int putEndSequence(byte[] buffer, int pos) { + public int putEndSequence(byte[] buffer, int p) { byte opcode = DW_LNE_end_sequence; + int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB @@ -2034,8 +2076,9 @@ public int putEndSequence(byte[] buffer, int pos) { } } - public int putSetAddress(long arg, byte[] buffer, int pos) { + public int putSetAddress(long arg, byte[] buffer, int p) { byte opcode = DW_LNE_set_address; + int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); // insert extended insn byte count as ULEB @@ -2053,8 +2096,9 @@ public int putSetAddress(long arg, byte[] buffer, int pos) { } } - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int pos) { + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; + int pos = p; // calculate bytes needed for opcode + args int fileBytes = file.length() + 1; long insnBytes = 1; @@ -2096,7 +2140,8 @@ public int opcodeLine(byte opcode) { return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int putSpecialOpcode(byte opcode, byte[] buffer, int pos) { + public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { + int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { From 44ad637e843e40d803e2ac5674690f19eb0212b7 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 16:46:56 +0000 Subject: [PATCH 063/130] death to style dragons --- .../oracle/objectfile/elf/dwarf/DwarfSections.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 5cb930219ea7..433650f6b657 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -82,7 +82,7 @@ public class DwarfSections { private static final int DW_AT_language = 0x13; private static final int DW_AT_external = 0x3f; // private static final int DW_AT_return_addr = 0x2a; - private static final int DW_AT_frame_base = 0x40; + // private static final int DW_AT_frame_base = 0x40; // define all the Dwarf attribute forms we need for our DIEs private static final int DW_FORM_null = 0x0; // private static final int DW_FORM_string = 0x8; @@ -99,7 +99,7 @@ public class DwarfSections { private static final byte DW_CHILDREN_no = 0; private static final byte DW_CHILDREN_yes = 1; // DW_FORM_flag attribute values - private static final byte DW_FLAG_false = 0; + // private static final byte DW_FLAG_false = 0; private static final byte DW_FLAG_true = 1; // value for DW_AT_language attribute with form DATA1 private static final byte DW_LANG_Java = 0xb; @@ -440,7 +440,8 @@ public int putLong(long l, byte[] buffer, int p) { return pos; } - public int putRelocatableCodeOffset(long l, byte[] buffer, int pos) { + public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { + int pos = p; // mark address so it is relocated relative to the start of the text segment markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); pos = putLong(0, buffer, pos); @@ -1541,7 +1542,7 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * extended opcodes defined by Dwarf 2 */ - private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 + // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 @@ -1864,7 +1865,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { // if we have to update to a new file then do so if (subFileIdx != fileIdx) { // update the current file - pos = putSetFile(subfile, (long) subFileIdx, buffer, pos); + pos = putSetFile(subfile, subFileIdx, buffer, pos); file = subfile; fileIdx = subFileIdx; } From b8ba2300ff0b37f1e4c25adf459bdf1f44b43f05 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 22 Jan 2020 17:33:02 +0000 Subject: [PATCH 064/130] sigh ... still more style issues --- .../objectfile/elf/dwarf/DwarfSections.java | 44 ++++--------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 433650f6b657..1c5505780164 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -252,9 +252,9 @@ private int debugStringIndex(String string) { public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); - for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { - // install types - } + // for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { + // install types + // } // ensure we have a null string in the string section uniqueDebugString(""); @@ -289,10 +289,10 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { } } DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - for (DebugDataInfo debugDataInfo : dataInfoProvider) { - // install details of heap elements - String name = debugDataInfo.toString(); - } + // for (DebugDataInfo debugDataInfo : dataInfoProvider) { + // install details of heap elements + // String name = debugDataInfo.toString(); + // } } public ClassEntry ensureClassEntry(Range range) { @@ -390,7 +390,7 @@ public void checkDebug(int pos) { // if the env var relevant to this element // type is set then switch on debugging String name = getSectionName(); - String envVarName = "DWARF_" + getSectionName().substring(1).toUpperCase(); + String envVarName = "DWARF_" + name.substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { debug = true; debugBase = pos; @@ -469,7 +469,6 @@ public int putULEB(long val, byte[] buffer, int p) { public int putSLEB(long val, byte[] buffer, int p) { long l = val; int pos = p; - boolean negative = l < 0; for (int i = 0; i < 9; i++) { byte b = (byte) (l & 0x7f); l = l >> 7; @@ -1837,31 +1836,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { // the current subrange and the start of the next one. // however, debug works better if we treat all the insns up // to the next range start as belonging to the current line - // so the code below is not actually needed. it is left in - // to clarify i) that this is a deliberate choice and ii) what - // that deliberate choice is avoiding. - if (false) { - if (address < hiAddress && hiAddress < subAddressLo) { - long addressDelta = hiAddress - address; - // increment address to hi address, write an - // end sequence and update state to new rang - pos = putAdvancePC(addressDelta, buffer, pos); - pos = putEndSequence(buffer, pos); - file = subfile; - fileIdx = subFileIdx; - pos = putSetFile(file, fileIdx, buffer, pos); - line = subLine; - // state machine value of line is currently 1 - // increment to desired line - if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); - } - pos = putSetBasicBlock(buffer, pos); - // use a reloc to ensure address is relative to text base - address = hiAddress; - pos = putSetAddress(hiAddress, buffer, pos); - } - } + // // if we have to update to a new file then do so if (subFileIdx != fileIdx) { // update the current file @@ -1920,7 +1895,6 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { // move line and address range on line += lineDelta; address += addressDelta; - hiAddress = subAddressHi; } // append a final end sequence just below the next primary range if (address < primaryRange.getHi()) { From 8deb6a1a2084c62d5fe186d72623a5ddb2e1e2a8 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 09:41:12 +0000 Subject: [PATCH 065/130] another style domino topples --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 1c5505780164..dace87a7a6c0 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -34,11 +34,9 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.elf.ELFMachine; From 638656e913eff2d983166110c14d556a5621700b Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 11:40:04 +0000 Subject: [PATCH 066/130] converted lots of comments to javadcoc, added new ones and edited content of comments --- .../src/com/oracle/objectfile/ObjectFile.java | 8 +- .../debuginfo/DebugInfoProvider.java | 42 ++-- .../objectfile/elf/dwarf/ClassEntry.java | 61 ++++-- .../oracle/objectfile/elf/dwarf/DirEntry.java | 16 +- .../objectfile/elf/dwarf/DwarfSections.java | 204 +++++++++++++++--- .../objectfile/elf/dwarf/FileEntry.java | 3 + .../objectfile/elf/dwarf/PrimaryEntry.java | 44 +++- .../oracle/objectfile/elf/dwarf/Range.java | 10 +- .../objectfile/elf/dwarf/StringEntry.java | 9 +- .../objectfile/elf/dwarf/StringTable.java | 34 ++- .../svm/hosted/image/NativeBootImage.java | 20 ++ 11 files changed, 365 insertions(+), 86 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 7bc6be01f48d..7855dee0fe27 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1087,8 +1087,12 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int // flag compatibility } - // support for consuming debug info - + /** + * API method provided to allow a native image generator to provide details of + * types, code and heap data inserted into a native image + * @param debugInfoProvider an implementation of the provider interface that + * communicates details of the relevant types, code and heap data. + */ public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default } 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 cf6daf5ec247..5caf0caab959 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 @@ -28,16 +28,22 @@ import java.util.List; -// class defining interfaces used to allow a native image -// to communicate details of types, code and data to -// the underlying object file so that the object file -// can insert appropriate debug info +/** + * interfaces used to allow a native image to communicate + * details of types, code and data to the underlying + * object file so that the latter can insert appropriate + * debug info + */ public interface DebugInfoProvider { - // access details of a specific type + /** + * access details of a specific type + */ interface DebugTypeInfo { } - // access details of a specific compiled method + /** + * access details of a specific compiled method + */ interface DebugCodeInfo { String fileName(); @@ -62,11 +68,15 @@ interface DebugCodeInfo { List getFrameSizeChanges(); } - // access details of a specific heap object + /** + * access details of a specific heap object + */ interface DebugDataInfo { } - // access details of a specific outer or inlined method at a given line number + /** + * access details of a specific outer or inlined method at a given line number + */ interface DebugLineInfo { String fileName(); @@ -92,19 +102,27 @@ enum Type { DebugFrameSizeChange.Type getType(); } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugTypeInfoProvider extends Iterable { } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugCodeInfoProvider extends Iterable { } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugLineInfoProvider extends Iterable { } - // convenience interface defining iterator type + /** + * convenience interface defining iterator type + */ interface DebugDataInfoProvider extends Iterable { } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 8522cdff9ca6..cfdf6c091e11 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -33,31 +33,66 @@ import java.util.List; import java.util.Map; +/** + * track debug info associated with a Java class + */ public class ClassEntry { - // the name of the associated class + /** + * the name of the associated class + */ private String className; - // the associated file + /** + * details of the associated file + */ FileEntry fileEntry; - // a list recording details of all primary ranges included in - // this class sorted by ascending address range + /** + * a list recording details of all primary + * ranges included in this class sorted by + * ascending address range + */ private LinkedList primaryEntries; - // an index identifying primary ranges which have already been encountered + /** + * an index identifying primary ranges which + * have already been encountered + */ private Map primaryIndex; - // an index of all primary and secondary files referenced from this class's CU + /** + * an index of all primary and secondary files + * referenced from this class's compilation unit + */ private Map localFilesIndex; - // a list of the same files + /** + * a list of the same files + */ private LinkedList localFiles; - // an index of all primary and secondary dirs referenced from this class's CU + /** + * an index of all primary and secondary dirs + * referenced from this class's compilation unit + */ private HashMap localDirsIndex; - // a list of the same dirs + /** + * a list of the same dirs + */ private LinkedList localDirs; - // index of debug_info section compilation unit for this class + /** + * index of debug_info section compilation unit + * for this class + */ private int cuIndex; - // index into debug_line section for associated CU + /** + * index into debug_line section for associated + * compilation unit + */ private int lineIndex; - // size of line number info prologue region for associated CU + /** + * size of line number info prologue region for + * associated compilation unit + */ private int linePrologueSize; - // total size of line number info region for associated CU + /** + * total size of line number info region for + * associated compilation unit + */ private int totalSize; public ClassEntry(String className, FileEntry fileEntry) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 89d0b81bb8f0..5f46a82b0665 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -26,21 +26,13 @@ package com.oracle.objectfile.elf.dwarf; -// files may be located in a source directory associated -// with a well known substratevm or compiler root package -// in that case the the file's directory path will be something -// like "foo.bar.baz/src/foo/bar/baz/mumble/grumble/bletch" -// i.e. the root package and "src" will be inserted as a prefix -// before the dirs derived from the actual package -// files whose package does not match a well-known root package -// will be listed using the dirs derived from the package -// i.e. simply "foo/bar/baz/mumble/grumble/bletch" - +/** + * track the directory associated with one or + * more source files + */ public class DirEntry { private String path; - // create an entry for a root package path - // or a user path not under a root package public DirEntry(String path) { this.path = path; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index dace87a7a6c0..425d06220c56 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -48,8 +48,16 @@ import java.util.Map; import java.util.Set; +/** + * an outer class that models the debug info in an + * organization that facilitates generation of the + * required DWARF sections. It groups common data and + * behaviours for use by the various subclasses of + * inner class DwarfSectionImpl that take responsibility + * for generating content for a specific section type. + */ public class DwarfSections { - // names of the different sections we create or reference + // names of the different ELF sections we create or reference // in reverse dependency order public static final String TEXT_SECTION_NAME = ".text"; public static final String DW_STR_SECTION_NAME = ".debug_str"; @@ -59,7 +67,9 @@ public class DwarfSections { public static final String DW_INFO_SECTION_NAME = ".debug_info"; public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; - // dwarf version 2 is all we need for debug info + /** + * currently generated debug info relies on DWARF spec vesion 2 + */ private static final short DW_VERSION_2 = 2; // define all the abbrev section codes we need for our DIEs @@ -186,25 +196,39 @@ public ELFMachine getElfMachine() { return elfMachine; } - // a scratch buffer used during computation of a section's size + /** + * a scratch buffer used during computation of a section's size + */ protected static final byte[] scratch = new byte[10]; - // table listing all known strings + /** + * a table listing all known strings, some of + * which may be marked for insertion into the + * .debug_str section + */ private StringTable stringTable = new StringTable(); - // list detailing all dirs in which files are found to reside - // either as part of substrate/compiler or user code + /** + * list detailing all dirs in which files are found to reside + * either as part of substrate/compiler or user code + */ private LinkedList dirs = new LinkedList<>(); - // index of already seen dirs + /** + * index of already seen dirs + */ private Map dirsIndex = new HashMap<>(); - // The obvious traversal structure for debug records is + // The obvious traversal structure for debug records is: + // // 1) by top level compiled method (primary Range) ordered by ascending address // 2) by inlined method (sub range) within top level method ordered by ascending address + // // this ensures that all debug records are generated in increasing address order - // a list recording details of all primary ranges included in - // this file sorted by ascending address range + /** + * a list recording details of all primary ranges included in + * this file sorted by ascending address range + */ private LinkedList primaryEntries = new LinkedList<>(); // An alternative traversal option is @@ -224,32 +248,67 @@ public ELFMachine getElfMachine() { // time would allow more sharing e.g. enabling all classes in a file to share a single copy // of the file and dir tables. - // list of class entries detailing class info for primary ranges + /** + * list of class entries detailing class info for primary ranges + */ private LinkedList primaryClasses = new LinkedList<>(); - // index of already seen classes + /** + * index of already seen classes + */ private Map primaryClassesIndex = new HashMap<>(); - // List of files which contain primary ranges + /** + * list of files which contain primary ranges + */ private LinkedList primaryFiles = new LinkedList<>(); - // List of files which contain primary or secondary ranges + /** + * List of files which contain primary or secondary ranges + */ private LinkedList files = new LinkedList<>(); - // index of already seen files + /** + * index of already seen files + */ private Map filesIndex = new HashMap<>(); + /** + * indirects this call to the string table + * @param string the string to be inserted + * @return a unique equivalent String + */ public String uniqueString(String string) { return stringTable.uniqueString(string); } + /** + * indirects this call to the string table, ensuring + * the table entry is marked for inclusion in the + * .debug_str section + * @param string the string to be inserted and + * marked for inclusion in the .debug_str section + * @return a unique equivalent String + */ public String uniqueDebugString(String string) { return stringTable.uniqueDebugString(string); } + /** + * indirects this call to the string table + * @param string the string whose index is required + * @return the offset of the string in the .debug_str + * section + */ private int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } + /** + * entry point allowing ELFObjectFile to pass on information + * about types, code and heap data + * @param debugInfoProvider provider instance passed by + * ObjectFile client + */ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); + // DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); // for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { // install types // } @@ -286,7 +345,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { addSubRange(primaryRange, subRange); } } - DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + // DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); // for (DebugDataInfo debugDataInfo : dataInfoProvider) { // install details of heap elements // String name = debugDataInfo.toString(); @@ -370,6 +429,10 @@ private DirEntry ensureDirEntry(String file) { return dirEntry; } + /** + * class from which all DWARF debug section + * inherit providing common behaviours + */ // shared implementation methods to manage content creation public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { public boolean debug = false; @@ -380,8 +443,28 @@ public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { public DwarfSectionImpl() { } + /** + * creates the target byte[] array used to define the section + * contents + * + * the main task of this method is to precompute the + * size of the debug section. given the complexity of the + * data layouts that invariably requires performing a dummy + * write of the contents, inserting bytes into a small, + * scratch buffer only when absolutely necessary. subclasses + * may also cache some information for use when writing the + * contents. + */ public abstract void createContent(); + /** + * populates the byte[] array used to contain the section + * contents + * + * in most cases this task reruns the operations performed + * under createContent but this time actually writing data + * to the target byte[]. + */ public abstract void writeContent(); public void checkDebug(int pos) { @@ -403,6 +486,7 @@ protected void debug(String format, Object... args) { } // base level put methods that assume a non-null buffer + public int putByte(byte b, byte[] buffer, int p) { int pos = p; buffer[pos++] = b; @@ -573,10 +657,25 @@ public int writeAttrNull(byte[] buffer, int pos) { } } + /** + * identify the section after which this debug section + * needs to be ordered when sizing and creating content + * @return the name of the preceding section + */ public abstract String targetSectionName(); + /** + * identify the layout properties of the target section + * which need to have been decided before the contents + * of this section can be created. + * @return an array of the relevant decision kinds + */ public abstract LayoutDecision.Kind[] targetSectionKinds(); + /** + * identify this debug section by name + * @return the name of the debug section + */ public abstract String getSectionName(); @Override @@ -610,6 +709,9 @@ public Set getDependencies(Map deci } } + /** + * generator for .debug_str section + */ public class DwarfStrSectionImpl extends DwarfSectionImpl { public DwarfStrSectionImpl() { super(); @@ -657,7 +759,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_str section content depends on text section content and offset + /** + * .debug_str section content depends on text section content and offset + */ public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @Override @@ -665,6 +769,9 @@ public String targetSectionName() { return TARGET_SECTION_NAME; } + /** + * .debug_str section content depends on text section content and offset + */ public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET @@ -676,6 +783,9 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generator for .debug_abbrev section + */ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { public DwarfAbbrevSectionImpl() { @@ -813,7 +923,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_abbrev section content depends on .debug_frame section content and offset + /** + * .debug_abbrev section content depends on .debug_frame section content and offset + */ public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @Override @@ -832,6 +944,9 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generic generator for .debug_frame section + */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { public DwarfFrameSectionImpl() { @@ -1103,7 +1218,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_frame section content depends on .debug_line section content and offset + /** + * .debug_frame section content depends on .debug_line section content and offset + */ public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @Override @@ -1132,6 +1249,10 @@ private byte advanceLoc0Op(int offset) { } } + /** + * x86_64-specific generator for .debug_frame section + * that knows details of x86_64 registers and frame layout + */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public static final int DW_CFA_RSP_IDX = 7; public static final int DW_CFA_RIP_IDX = 16; @@ -1165,6 +1286,10 @@ public int writeInitialInstructions(byte[] buffer, int p) { } } + /** + * AArch64-specific generator for .debug_frame section + * that knows details of AArch64 registers and frame layout + */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { public static final int DW_CFA_FP_IDX = 29; public static final int DW_CFA_LR_IDX = 30; @@ -1196,8 +1321,13 @@ public int writeInitialInstructions(byte[] buffer, int p) { } } + /** + * generator for .debug_info section + */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { - // header section always contains fixed number of bytes + /** + * an info header section always contains a fixed number of bytes + */ private static final int DW_DIE_HEADER_SIZE = 11; public DwarfInfoSectionImpl() { @@ -1358,7 +1488,9 @@ protected void debug(String format, Object... args) { } } - // .debug_info section content depends on abbrev section content and offset + /** + * .debug_info section content depends on abbrev section content and offset + */ public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @Override @@ -1377,6 +1509,9 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generator for .debug_aranges section + */ public class DwarfARangesSectionImpl extends DwarfSectionImpl { private static final int DW_AR_HEADER_SIZE = 12; private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size @@ -1507,14 +1642,27 @@ public LayoutDecision.Kind[] targetSectionKinds() { } } + /** + * generator for .debug_line section + */ public class DwarfLineSectionImpl extends DwarfSectionImpl { - // header section always contains fixed number of bytes + /** + * line header section always contains fixed number of bytes + */ private static final int DW_LN_HEADER_SIZE = 27; - // line base is -5 + /** + * current generator follows C++ with line base -5 + */ private static final int DW_LN_LINE_BASE = -5; - // opcode line range is 14 giving full range -5 to 8 + /** + * current generator follows C++ with line range 14 + * giving full range -5 to 8 + */ private static final int DW_LN_LINE_RANGE = 14; - // opcode base should equal DW_LNS_define_file + 1 + /** + * current generator uses opcode base of 13 + * which equal DW_LNS_define_file + 1 + */ private static final int DW_LN_OPCODE_BASE = 13; /* @@ -2169,7 +2317,9 @@ public boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } - // .debug_line section content depends on .debug_str section content and offset + /** + * .debug_line section content depends on .debug_str section content and offset + */ public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index 3a8943cabdf6..cd530c68de04 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -26,6 +26,9 @@ package com.oracle.objectfile.elf.dwarf; +/** + * track debug info associated with a Java source file. + */ public class FileEntry { // the name of the associated file including path private String fileName; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index a26d060c8859..2727b03c7e12 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -32,26 +32,50 @@ import java.util.LinkedList; import java.util.List; +/** + * track debug info associated with a primary method + * i.e. a top level compiled method + */ public class PrimaryEntry { - // the primary range detailed by this object + /** + * the primary range detailed by this object + */ Range primary; - // details of the class owning this range + /** + * details of the class owning this range + */ ClassEntry classEntry; - // a list of subranges associated with the primary range + /** + * a list of subranges associated with the primary range + */ List subranges; - // a mapping from subranges to their associated file entry + /** + * a mapping from subranges to their associated file entry + */ HashMap subrangeIndex; - // details of of compiled method frame size changes + /** + * details of of compiled method frame size changes + */ private List frameSizeInfos; - // size of compiled method frame + /** + * size of compiled method frame + */ private int frameSize; - // index of debug_info section compilation unit for this file + /** + * index of debug_info section compilation unit for this file + */ private int cuIndex; - // index into debug_line section for associated compilation unit + /** + * index into debug_line section for associated compilation unit + */ private int lineIndex; - // size of line number info prologue region for associated compilation unit + /** + * size of line number info prologue region for associated compilation unit + */ private int linePrologueSize; - // total size of line number info region for associated compilation unit + /** + * total size of line number info region for associated compilation unit + */ private int totalSize; public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 6692d23b7df6..758825272a7e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -26,10 +26,12 @@ package com.oracle.objectfile.elf.dwarf; -// details of a specific address range in a compiled method -// either a primary range identifying a whole method -// or a sub-range identifying a sequence of -// instructions that belong to an inlined method +/** + * details of a specific address range in a compiled method + * either a primary range identifying a whole method + * or a sub-range identifying a sequence of + * instructions that belong to an inlined method + */ public class Range { private String fileName; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index a96e5eb19e6a..d9a40dc2b3ed 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -26,9 +26,12 @@ package com.oracle.objectfile.elf.dwarf; -// class used to ensure we keep only one copy of a String -// amd track it's locations in the string section should -// it need to be entered +/** + * class used to retain a unique (up to equals) copy of + * a String and also to flag whether the String needs to be + * located in the .debug_string section and track the offset + * where it gets written. + */ public class StringEntry { private String string; private int offset; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 74506877df94..1ec68deb7e70 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -29,9 +29,12 @@ import java.util.HashMap; import java.util.Iterator; -// class which reduces incoming strings to unique -// instances and also marks strings which need -// to be written to the debug_str section +/** + * a class which allows incoming strings to be reduced + * to unique (up to equaals) instances and allows marking + * of strings which need to be written to the debug_str + * section and retrieval of the lcoation offset after writing. + */ public class StringTable implements Iterable { private final HashMap table; @@ -40,10 +43,28 @@ public StringTable() { this.table = new HashMap<>(); } + /** + * ensures a unique instance of a string exists in the + * table, inserting the supplied String if no equivalent + * String is already present. this should only be called + * before the string section has been written. + * @param string the string to be included in the table + * @return the unique instance of the String + */ public String uniqueString(String string) { return ensureString(string, false); } + /** + * ensures a unique instance of a string exists in the + * table and is marked for inclusion in the debug_str + * section, inserting the supplied String if no equivalent + * String is already present. this should only be called + * before the string section has been written. + * @param string the string to be included in the table + * and marked for inclusion in the debug_str section + * @return the unique instance of the String + */ public String uniqueDebugString(String string) { return ensureString(string, true); } @@ -60,6 +81,13 @@ private String ensureString(String string, boolean addToStrSection) { return stringEntry.getString(); } + /** + * retrieves the offset at which a given string was written + * into the debug_str section. this should only be called + * after the string section has been written. + * @param string + * @return + */ public int debugStringIndex(String string) { StringEntry stringEntry = table.get(string); assert stringEntry != null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 338ff37f22d6..989457847076 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -972,6 +972,11 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final NativeImageCodeCache codeCache; } + /** + * implementation of the DebugInfoProvider API interface + * that allows type, code and heap data info to be passed to + * an ObjectFile when generation of debug info is enabled + */ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; private final NativeImageHeap heap; @@ -1033,6 +1038,11 @@ public DebugDataInfo next() { } } + /** + * implementation of the DebugCodeInfo API interface + * that allows code info to be passed to an ObjectFile + * when generation of debug info is enabled + */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; @@ -1167,6 +1177,11 @@ public List getFrameSizeChanges() { } } + /** + * implementation of the DebugLineInfo API interface + * that allows line number info to be passed to an + * ObjectFile when generation of debug info is enabled + */ private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; private final ResolvedJavaMethod method; @@ -1227,6 +1242,11 @@ public int line() { } } + /** + * implementation of the DebugFrameSizeChange API interface + * that allows stack frame size change info to be passed to + * an ObjectFile when generation of debug info is enabled + */ private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; private Type type; From ff76233af2f8f5ca866d7793128468e5a681f7d0 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 13:22:23 +0000 Subject: [PATCH 067/130] fix missing javadoc return and remove unused imports --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 4 ++-- .../src/com/oracle/objectfile/elf/dwarf/StringTable.java | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 425d06220c56..3004762524f7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -34,10 +34,10 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; +// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; +// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.elf.ELFMachine; import com.oracle.objectfile.elf.ELFObjectFile.ELFSection; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 1ec68deb7e70..87b0af1eb437 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -86,7 +86,9 @@ private String ensureString(String string, boolean addToStrSection) { * into the debug_str section. this should only be called * after the string section has been written. * @param string - * @return + * @return the offset or -1 if the string does not + * define an entry or the entry has nto been written + * to the debug_str section */ public int debugStringIndex(String string) { StringEntry stringEntry = table.get(string); From 84060e0a42b0698713bda4f67677cadfb569b40d Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 23 Jan 2020 14:52:33 +0000 Subject: [PATCH 068/130] fix punctuation issues and remove redudant declaration --- .../src/com/oracle/objectfile/ObjectFile.java | 2 +- .../debuginfo/DebugInfoProvider.java | 18 ++-- .../objectfile/elf/dwarf/ClassEntry.java | 26 +++--- .../oracle/objectfile/elf/dwarf/DirEntry.java | 2 +- .../objectfile/elf/dwarf/DwarfSections.java | 92 +++++++++---------- .../objectfile/elf/dwarf/PrimaryEntry.java | 22 ++--- .../svm/hosted/image/NativeBootImage.java | 8 +- 7 files changed, 82 insertions(+), 88 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 7855dee0fe27..518b171882d4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1089,7 +1089,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int /** * API method provided to allow a native image generator to provide details of - * types, code and heap data inserted into a native image + * types, code and heap data inserted into a native image. * @param debugInfoProvider an implementation of the provider interface that * communicates details of the relevant types, code and heap data. */ 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 5caf0caab959..13e8cb73dab3 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 @@ -32,17 +32,17 @@ * interfaces used to allow a native image to communicate * details of types, code and data to the underlying * object file so that the latter can insert appropriate - * debug info + * debug info. */ public interface DebugInfoProvider { /** - * access details of a specific type + * access details of a specific type. */ interface DebugTypeInfo { } /** - * access details of a specific compiled method + * access details of a specific compiled method. */ interface DebugCodeInfo { String fileName(); @@ -69,13 +69,13 @@ interface DebugCodeInfo { } /** - * access details of a specific heap object + * access details of a specific heap object. */ interface DebugDataInfo { } /** - * access details of a specific outer or inlined method at a given line number + * access details of a specific outer or inlined method at a given line number. */ interface DebugLineInfo { String fileName(); @@ -103,25 +103,25 @@ enum Type { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugTypeInfoProvider extends Iterable { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugCodeInfoProvider extends Iterable { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugLineInfoProvider extends Iterable { } /** - * convenience interface defining iterator type + * convenience interface defining iterator type. */ interface DebugDataInfoProvider extends Iterable { } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index cfdf6c091e11..9e429a565e49 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -34,64 +34,64 @@ import java.util.Map; /** - * track debug info associated with a Java class + * track debug info associated with a Java class. */ public class ClassEntry { /** - * the name of the associated class + * the name of the associated class. */ private String className; /** - * details of the associated file + * details of the associated file. */ FileEntry fileEntry; /** * a list recording details of all primary * ranges included in this class sorted by - * ascending address range + * ascending address range. */ private LinkedList primaryEntries; /** * an index identifying primary ranges which - * have already been encountered + * have already been encountered. */ private Map primaryIndex; /** * an index of all primary and secondary files - * referenced from this class's compilation unit + * referenced from this class's compilation unit. */ private Map localFilesIndex; /** - * a list of the same files + * a list of the same files. */ private LinkedList localFiles; /** * an index of all primary and secondary dirs - * referenced from this class's compilation unit + * referenced from this class's compilation unit. */ private HashMap localDirsIndex; /** - * a list of the same dirs + * a list of the same dirs. */ private LinkedList localDirs; /** * index of debug_info section compilation unit - * for this class + * for this class. */ private int cuIndex; /** * index into debug_line section for associated - * compilation unit + * compilation unit. */ private int lineIndex; /** * size of line number info prologue region for - * associated compilation unit + * associated compilation unit. */ private int linePrologueSize; /** * total size of line number info region for - * associated compilation unit + * associated compilation unit. */ private int totalSize; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 5f46a82b0665..5caac5a20997 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -28,7 +28,7 @@ /** * track the directory associated with one or - * more source files + * more source files. */ public class DirEntry { private String path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 3004762524f7..78217b99bd0c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -68,7 +68,7 @@ public class DwarfSections { public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; /** - * currently generated debug info relies on DWARF spec vesion 2 + * currently generated debug info relies on DWARF spec vesion 2. */ private static final short DW_VERSION_2 = 2; @@ -197,24 +197,24 @@ public ELFMachine getElfMachine() { } /** - * a scratch buffer used during computation of a section's size + * a scratch buffer used during computation of a section's size. */ protected static final byte[] scratch = new byte[10]; /** * a table listing all known strings, some of * which may be marked for insertion into the - * .debug_str section + * debug_str section. */ private StringTable stringTable = new StringTable(); /** * list detailing all dirs in which files are found to reside - * either as part of substrate/compiler or user code + * either as part of substrate/compiler or user code. */ private LinkedList dirs = new LinkedList<>(); /** - * index of already seen dirs + * index of already seen dirs. */ private Map dirsIndex = new HashMap<>(); @@ -227,7 +227,7 @@ public ELFMachine getElfMachine() { /** * a list recording details of all primary ranges included in - * this file sorted by ascending address range + * this file sorted by ascending address range. */ private LinkedList primaryEntries = new LinkedList<>(); @@ -249,29 +249,29 @@ public ELFMachine getElfMachine() { // of the file and dir tables. /** - * list of class entries detailing class info for primary ranges + * list of class entries detailing class info for primary ranges. */ private LinkedList primaryClasses = new LinkedList<>(); /** - * index of already seen classes + * index of already seen classes. */ private Map primaryClassesIndex = new HashMap<>(); /** - * list of files which contain primary ranges + * list of files which contain primary ranges. */ private LinkedList primaryFiles = new LinkedList<>(); /** - * List of files which contain primary or secondary ranges + * List of files which contain primary or secondary ranges. */ private LinkedList files = new LinkedList<>(); /** - * index of already seen files + * index of already seen files. */ private Map filesIndex = new HashMap<>(); /** - * indirects this call to the string table + * indirects this call to the string table. * @param string the string to be inserted * @return a unique equivalent String */ @@ -282,9 +282,9 @@ public String uniqueString(String string) { /** * indirects this call to the string table, ensuring * the table entry is marked for inclusion in the - * .debug_str section + * debug_str section. * @param string the string to be inserted and - * marked for inclusion in the .debug_str section + * marked for inclusion in the debug_str section * @return a unique equivalent String */ public String uniqueDebugString(String string) { @@ -292,7 +292,7 @@ public String uniqueDebugString(String string) { } /** - * indirects this call to the string table + * indirects this call to the string table. * @param string the string whose index is required * @return the offset of the string in the .debug_str * section @@ -303,7 +303,7 @@ private int debugStringIndex(String string) { /** * entry point allowing ELFObjectFile to pass on information - * about types, code and heap data + * about types, code and heap data. * @param debugInfoProvider provider instance passed by * ObjectFile client */ @@ -431,7 +431,7 @@ private DirEntry ensureDirEntry(String file) { /** * class from which all DWARF debug section - * inherit providing common behaviours + * inherit providing common behaviours. */ // shared implementation methods to manage content creation public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { @@ -445,7 +445,7 @@ public DwarfSectionImpl() { /** * creates the target byte[] array used to define the section - * contents + * contents. * * the main task of this method is to precompute the * size of the debug section. given the complexity of the @@ -459,7 +459,7 @@ public DwarfSectionImpl() { /** * populates the byte[] array used to contain the section - * contents + * contents. * * in most cases this task reruns the operations performed * under createContent but this time actually writing data @@ -659,7 +659,7 @@ public int writeAttrNull(byte[] buffer, int pos) { /** * identify the section after which this debug section - * needs to be ordered when sizing and creating content + * needs to be ordered when sizing and creating content. * @return the name of the preceding section */ public abstract String targetSectionName(); @@ -673,7 +673,7 @@ public int writeAttrNull(byte[] buffer, int pos) { public abstract LayoutDecision.Kind[] targetSectionKinds(); /** - * identify this debug section by name + * identify this debug section by name. * @return the name of the debug section */ public abstract String getSectionName(); @@ -710,7 +710,7 @@ public Set getDependencies(Map deci } /** - * generator for .debug_str section + * generator for debug_str section. */ public class DwarfStrSectionImpl extends DwarfSectionImpl { public DwarfStrSectionImpl() { @@ -760,7 +760,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_str section content depends on text section content and offset + * debug_str section content depends on text section content and offset. */ public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @@ -770,7 +770,7 @@ public String targetSectionName() { } /** - * .debug_str section content depends on text section content and offset + * debug_str section content depends on text section content and offset. */ public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, @@ -784,7 +784,7 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generator for .debug_abbrev section + * generator for debug_abbrev section. */ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { @@ -924,7 +924,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_abbrev section content depends on .debug_frame section content and offset + * debug_abbrev section content depends on debug_frame section content and offset. */ public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @@ -945,7 +945,7 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generic generator for .debug_frame section + * generic generator for debug_frame section. */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { @@ -1219,7 +1219,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_frame section content depends on .debug_line section content and offset + * debug_frame section content depends on debug_line section content and offset. */ public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @@ -1250,8 +1250,8 @@ private byte advanceLoc0Op(int offset) { } /** - * x86_64-specific generator for .debug_frame section - * that knows details of x86_64 registers and frame layout + * x86_64-specific generator for debug_frame section + * that knows details of x86_64 registers and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public static final int DW_CFA_RSP_IDX = 7; @@ -1287,8 +1287,8 @@ public int writeInitialInstructions(byte[] buffer, int p) { } /** - * AArch64-specific generator for .debug_frame section - * that knows details of AArch64 registers and frame layout + * AArch64-specific generator for debug_frame section + * that knows details of AArch64 registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { public static final int DW_CFA_FP_IDX = 29; @@ -1322,11 +1322,11 @@ public int writeInitialInstructions(byte[] buffer, int p) { } /** - * generator for .debug_info section + * generator for debug_info section. */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { /** - * an info header section always contains a fixed number of bytes + * an info header section always contains a fixed number of bytes. */ private static final int DW_DIE_HEADER_SIZE = 11; @@ -1489,7 +1489,7 @@ protected void debug(String format, Object... args) { } /** - * .debug_info section content depends on abbrev section content and offset + * debug_info section content depends on abbrev section content and offset. */ public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @@ -1510,7 +1510,7 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generator for .debug_aranges section + * generator for debug_aranges section. */ public class DwarfARangesSectionImpl extends DwarfSectionImpl { private static final int DW_AR_HEADER_SIZE = 12; @@ -1643,25 +1643,25 @@ public LayoutDecision.Kind[] targetSectionKinds() { } /** - * generator for .debug_line section + * generator for debug_line section. */ public class DwarfLineSectionImpl extends DwarfSectionImpl { /** - * line header section always contains fixed number of bytes + * line header section always contains fixed number of bytes. */ private static final int DW_LN_HEADER_SIZE = 27; /** - * current generator follows C++ with line base -5 + * current generator follows C++ with line base -5. */ private static final int DW_LN_LINE_BASE = -5; /** * current generator follows C++ with line range 14 - * giving full range -5 to 8 + * giving full range -5 to 8. */ private static final int DW_LN_LINE_RANGE = 14; /** * current generator uses opcode base of 13 - * which equal DW_LNS_define_file + 1 + * which must equal DW_LNS_define_file + 1. */ private static final int DW_LN_OPCODE_BASE = 13; @@ -1934,13 +1934,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { line = 0; } long address = primaryRange.getLo(); - long hiAddress = address; - // int column = 0; - // boolean is_stmt = true; - // boolean is_basic_block = false; - // boolean end_sequence = false; - // set state for primary + // set state for primary debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); @@ -1957,7 +1952,6 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putCopy(buffer, pos); // now write a row for each subrange lo and hi - for (Range subrange : primaryEntry.getSubranges()) { assert subrange.getLo() >= primaryRange.getLo(); assert subrange.getHi() <= primaryRange.getHi(); @@ -2318,7 +2312,7 @@ public boolean isFixedAdvancePC(long addressDiff) { } /** - * .debug_line section content depends on .debug_str section content and offset + * debug_line section content depends on debug_str section content and offset. */ public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index 2727b03c7e12..6720703cf921 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -33,48 +33,48 @@ import java.util.List; /** - * track debug info associated with a primary method + * track debug info associated with a primary method. * i.e. a top level compiled method */ public class PrimaryEntry { /** - * the primary range detailed by this object + * the primary range detailed by this object. */ Range primary; /** - * details of the class owning this range + * details of the class owning this range. */ ClassEntry classEntry; /** - * a list of subranges associated with the primary range + * a list of subranges associated with the primary range. */ List subranges; /** - * a mapping from subranges to their associated file entry + * a mapping from subranges to their associated file entry. */ HashMap subrangeIndex; /** - * details of of compiled method frame size changes + * details of of compiled method frame size changes. */ private List frameSizeInfos; /** - * size of compiled method frame + * size of compiled method frame. */ private int frameSize; /** - * index of debug_info section compilation unit for this file + * index of debug_info section compilation unit for this file. */ private int cuIndex; /** - * index into debug_line section for associated compilation unit + * index into debug_line section for associated compilation unit. */ private int lineIndex; /** - * size of line number info prologue region for associated compilation unit + * size of line number info prologue region for associated compilation unit. */ private int linePrologueSize; /** - * total size of line number info region for associated compilation unit + * total size of line number info region for associated compilation unit. */ private int totalSize; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 989457847076..3eea965e1c5b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -975,7 +975,7 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile /** * implementation of the DebugInfoProvider API interface * that allows type, code and heap data info to be passed to - * an ObjectFile when generation of debug info is enabled + * an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; @@ -1041,7 +1041,7 @@ public DebugDataInfo next() { /** * implementation of the DebugCodeInfo API interface * that allows code info to be passed to an ObjectFile - * when generation of debug info is enabled + * when generation of debug info is enabled. */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; @@ -1180,7 +1180,7 @@ public List getFrameSizeChanges() { /** * implementation of the DebugLineInfo API interface * that allows line number info to be passed to an - * ObjectFile when generation of debug info is enabled + * ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; @@ -1245,7 +1245,7 @@ public int line() { /** * implementation of the DebugFrameSizeChange API interface * that allows stack frame size change info to be passed to - * an ObjectFile when generation of debug info is enabled + * an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; From 0d974dc87b9386f3bc1e0c347a3a2e2608defaad Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 24 Jan 2020 14:51:23 +0000 Subject: [PATCH 069/130] remove debug trace --- substratevm/write_gdbsourcepath | 6 ------ 1 file changed, 6 deletions(-) diff --git a/substratevm/write_gdbsourcepath b/substratevm/write_gdbsourcepath index 2cf9c728e1a4..b211b305a543 100644 --- a/substratevm/write_gdbsourcepath +++ b/substratevm/write_gdbsourcepath @@ -100,7 +100,6 @@ function add_sources() typeset -i ignore ignore=0 verbose "considering $dir" - set -x if [ ! -d ${dir}/src ]; then ignore=1 else @@ -114,24 +113,19 @@ function add_sources() # check for a specific jdk release if [ "${tail#jdk.}" != "$tail" ]; then # jdk. as part of a package name is ok - echo '+++' if ["${tail#jdk.}" != "$tail" ]; then echo allow $dir fi - echo /// ignore=0 elif [ "${tail#*jdk}" != "${JAVA_VERSION}" ]; then # jdk must match JAVA_VERSION - echo '+++' if [ "${dir#jdk.}" != "$dir" ]; then echo disallow $dir fi - echo /// ignore=1 fi fi fi - set +x if [ $ignore -eq 1 ] ; then verbose "ignoring $dir" else From 9151adfd53e2e39291513a0dc92b0a55db88ed9d Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 24 Jan 2020 15:55:39 +0000 Subject: [PATCH 070/130] fix reloc code to ensure content of elf section depends on content of reloc section --- .../oracle/objectfile/elf/ELFRelocationSection.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java index 1209c6662099..7826a6a786ba 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java @@ -236,6 +236,16 @@ public Iterable getDependencies(Map // decisions.get(syms).getDecision(LayoutProperty.Kind.CONTENT); // deps.add(BuildDependency.createOrGet(ourContent, symtabContent)); /* If we're dynamic, it also depends on the vaddr of all referenced sections. */ + + // our content depends on the content of the section being relocated + // (because entries only get registered during generation) + if (relocated != null) { + LayoutDecision relocatedSectionContent = + decisions.get(relocated).getDecision(LayoutDecision.Kind.CONTENT); + deps.add(BuildDependency.createOrGet(ourContent, + relocatedSectionContent)); + } + if (isDynamic()) { Set referenced = new HashSet<>(); for (Entry ent : entries.keySet()) { From 614c3e98a96e96550fda8ecef30962cd16ef22de Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 24 Jan 2020 15:56:23 +0000 Subject: [PATCH 071/130] add correct VADDR dependency so that debug sections can use vaddr of text section for debug --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 78217b99bd0c..d971e21a1d6a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -774,7 +774,8 @@ public String targetSectionName() { */ public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address }; @Override @@ -2324,7 +2325,6 @@ public String targetSectionName() { public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address }; @Override From d95c771240736088a92b120f9951c4bdb996e918 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 28 Jan 2020 17:45:49 +0000 Subject: [PATCH 072/130] fix some bugs turned up by enabling asserts --- .../oracle/objectfile/elf/dwarf/DwarfSections.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index d971e21a1d6a..286871c7227b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -467,6 +467,12 @@ public DwarfSectionImpl() { */ public abstract void writeContent(); + @Override + public boolean isLoadable() { + // even though we're a progbits section impl we're not actually loadable + return false; + } + public void checkDebug(int pos) { // if the env var relevant to this element // type is set then switch on debugging @@ -987,6 +993,9 @@ public void writeContent() { pos = writeCIE(buffer, pos); pos = writeMethodFrames(buffer, pos); + if (pos != size) { + System.out.format("pos = 0x%x size = 0x%x", pos, size); + } assert pos == size; } @@ -1010,7 +1019,7 @@ public int writeCIE(byte[] buffer, int p) { pos += putByte(DW_CFA_CIE_version, scratch, 0); pos += putAsciiStringBytes("", scratch, 0); pos += putULEB(1, scratch, 0); - pos += putULEB(-8, scratch, 0); + pos += putSLEB(-8, scratch, 0); pos += putByte((byte) getPCIdx(), scratch, 0); // write insns to set up empty frame pos = writeInitialInstructions(buffer, pos); From 624e4cae1e58c4a6b8a26e9b9e5f730493ce984f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 11:46:45 +0000 Subject: [PATCH 073/130] remove redudant local declarations --- .../oracle/objectfile/elf/ELFObjectFile.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index f3149f30125e..be10b81edd80 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1170,18 +1170,12 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content - @SuppressWarnings("unused") - ELFSection strSection = (ELFSection) newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); - @SuppressWarnings("unused") - ELFSection abbrevSection = (ELFSection) newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); - @SuppressWarnings("unused") - ELFSection locSection = (ELFSection) newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); - @SuppressWarnings("unused") - ELFSection infoSection = (ELFSection) newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); - @SuppressWarnings("unused") - ELFSection aRangesSection = (ELFSection) newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - @SuppressWarnings("unused") - ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); + newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); + newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); + newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); + newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); + newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the From 26ff905235a384935ae9aedfdc6035332987fb2a Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 12:01:52 +0000 Subject: [PATCH 074/130] removed redundant list of primary entries since iteration always happens via primaries within each class entry --- .../objectfile/elf/dwarf/DwarfSections.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 286871c7227b..474e74d20735 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -223,15 +223,10 @@ public ELFMachine getElfMachine() { // 1) by top level compiled method (primary Range) ordered by ascending address // 2) by inlined method (sub range) within top level method ordered by ascending address // - // this ensures that all debug records are generated in increasing address order - - /** - * a list recording details of all primary ranges included in - * this file sorted by ascending address range. - */ - private LinkedList primaryEntries = new LinkedList<>(); - + // these can be used to ensure that all debug records are generated in increasing address order + // // An alternative traversal option is + // // 1) by top level class (String id) // 2) by top level compiled method (primary Range) within a class ordered by ascending address // 3) by inlined method (sub range) within top level method ordered by ascending address @@ -241,6 +236,7 @@ public ELFMachine getElfMachine() { // or data values. this means we can treat each class as a compilation unit, allowing // data common to all methods of the class to be shared. // + // A third option appears to be to traverse via files, then top level class within file etc. // Unfortunately, files cannot be treated as the compilation unit. A file F may contain // multiple classes, say C1 and C2. There is no guarantee that methods for some other // class C' in file F' will not be compiled into the address space interleaved between @@ -395,10 +391,6 @@ public void addRange(Range primaryRange, List frameSizeInf assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); - if (entry != null) { - // track the entry for this range in address order - primaryEntries.add(entry); - } } public void addSubRange(Range primaryRange, Range subrange) { From 1d129cd7e002744d592a1883902b527d2d029479 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 14:29:32 +0000 Subject: [PATCH 075/130] relocate dwarf section implementations to separate files as outer classes --- .../oracle/objectfile/elf/ELFObjectFile.java | 21 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 171 ++ .../elf/dwarf/DwarfAbbrevSectionImpl.java | 212 ++ .../elf/dwarf/DwarfFrameSectionImpl.java | 350 +++ .../dwarf/DwarfFrameSectionImplAArch64.java | 63 + .../dwarf/DwarfFrameSectionImplX86_64.java | 64 + .../elf/dwarf/DwarfInfoSectionImpl.java | 227 ++ .../elf/dwarf/DwarfLineSectionImpl.java | 726 ++++++ .../elf/dwarf/DwarfSectionImpl.java | 339 +++ .../objectfile/elf/dwarf/DwarfSections.java | 2063 +---------------- .../elf/dwarf/DwarfStrSectionImpl.java | 106 + .../com/oracle/objectfile/elf/dwarf/impl.java | 3 + 12 files changed, 2346 insertions(+), 1999 deletions(-) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index be10b81edd80..ec8c3f3dfecd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -43,7 +43,13 @@ import com.oracle.objectfile.StringTable; import com.oracle.objectfile.SymbolTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.objectfile.elf.dwarf.DwarfARangesSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfAbbrevSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfFrameSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfInfoSectionImpl; +import com.oracle.objectfile.elf.dwarf.DwarfLineSectionImpl; import com.oracle.objectfile.elf.dwarf.DwarfSections; +import com.oracle.objectfile.elf.dwarf.DwarfStrSectionImpl; import com.oracle.objectfile.io.AssemblyBuffer; import com.oracle.objectfile.io.OutputAssembler; @@ -1163,19 +1169,20 @@ protected int getMinimumFileSize() { public void installDebugInfo(DebugInfoProvider debugInfoProvider) { DwarfSections dwarfSections = new DwarfSections(getMachine()); // we need an implementation for each section - DwarfSections.DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); - DwarfSections.DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); - DwarfSections.DwarfFrameSectionImpl frameSectionImpl = dwarfSections.getFrameSectionImpl(); - DwarfSections.DwarfInfoSectionImpl elfInfoSectionImpl = dwarfSections.getInfoSectionImpl(); - DwarfSections.DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); - DwarfSections.DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); + DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); + DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); + DwarfFrameSectionImpl frameSectionImpl = dwarfSections.getFrameSectionImpl(); + DwarfInfoSectionImpl elfInfoSectionImpl = dwarfSections.getInfoSectionImpl(); + DwarfARangesSectionImpl elfARangesSectionImpl = dwarfSections.getARangesSectionImpl(); + DwarfLineSectionImpl elfLineSectionImpl = dwarfSections.getLineSectionImpl(); // now we can create the section elements with empty content newUserDefinedSection(elfStrSectionImpl.getSectionName(), elfStrSectionImpl); newUserDefinedSection(elfAbbrevSectionImpl.getSectionName(), elfAbbrevSectionImpl); newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + @SuppressWarnings("unused") + ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java new file mode 100644 index 000000000000..43615669b10f --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; + +import java.util.LinkedList; +import java.util.Map; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ARANGES_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; +/** + * generator for debug_aranges section. + */ +public class DwarfARangesSectionImpl extends DwarfSectionImpl { + private static final int DW_AR_HEADER_SIZE = 12; + private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size + + public DwarfARangesSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_ARANGES_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + // we need an entry for each compilation unit + // + // uint32 length ............ in bytes (not counting these 4 bytes) + // uint16 dwarf_version ..... always 2 + // uint32 info_offset ....... offset of compilation unit on debug_info + // uint8 address_size ....... always 8 + // uint8 segment_desc_size .. ??? + // + // i.e. 12 bytes followed by padding + // aligning up to 2 * address size + // + // uint8 pad[4] + // + // followed by N + 1 times + // + // uint64 lo ................ lo address of range + // uint64 length ............ number of bytes in range + // + // where N is the number of ranges belonging to the compilation unit + // and the last range contains two zeroes + + for (ClassEntry classEntry : getPrimaryClasses()) { + pos += DW_AR_HEADER_SIZE; + // align to 2 * address size + pos += DW_AR_HEADER_PAD_SIZE; + pos += classEntry.getPrimaryEntries().size() * 2 * 8; + pos += 2 * 8; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + ObjectFile.Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debugTextBase = ((Number) valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_ARANGES\n", pos); + for (ClassEntry classEntry : getPrimaryClasses()) { + int lastpos = pos; + int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; + int cuIndex = classEntry.getCUIndex(); + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + // add room for each entry into length count + length += classPrimaryEntries.size() * 2 * 8; + length += 2 * 8; + debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); + pos = putInt(length, buffer, pos); + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 + pos = putInt(cuIndex, buffer, pos); + pos = putByte((byte) 8, buffer, pos); // address size is always 8 + pos = putByte((byte) 0, buffer, pos); // segment size is always 0 + assert (pos - lastpos) == DW_AR_HEADER_SIZE; + // align to 2 * address size + for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { + pos = putByte((byte) 0, buffer, pos); + } + debug(" [0x%08x] Address Length Name\n", pos); + for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { + Range primary = classPrimaryEntry.getPrimary(); + debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); + pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); + pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); + } + pos = putLong(0, buffer, pos); + pos = putLong(0, buffer, pos); + } + + assert pos == size; + } + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + // .debug_aranges section content depends on .debug_info section content and offset + public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} + 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 new file mode 100644 index 000000000000..2336e27608a4 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfAbbrevSectionImpl.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_compile_unit; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_subprogram; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_external; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_hi_pc; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_language; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_low_pc; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_name; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_null; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_AT_stmt_list; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CHILDREN_no; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CHILDREN_yes; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_addr; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_data1; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_data4; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_flag; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_null; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FORM_strp; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_TAG_compile_unit; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_TAG_subprogram; + +/** + * generator for debug_abbrev section. + */ +public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { + + public DwarfAbbrevSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_ABBREV_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + // an abbrev table contains abbrev entries for one or + // more CUs. the table includes a sequence of abbrev + // entries each of which defines a specific DIE layout + // employed to describe some DIE in a CU. a table is + // terminated by a null entry + // + // a null entry has consists of just a 0 abbrev code + // LEB128 abbrev_code; ...... == 0 + // + // non-null entries have the following format + // LEB128 abbrev_code; ...... unique noncode for this layout != 0 + // 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 DIE + // * ........ zero or more attributes + // .... terminator + // + // An attribute_spec consists of an attribute name and form + // LEB128 attr_name; ........ 0 for the null attribute name + // LEB128 attr_form; ........ 0 for the null attribute form + // + // For the moment we only use one abbrev table for all CUs. + // It contains two DIEs, the first to describe the compilation + // unit itself and the second to describe each method within + // that compilation unit. + // + // The DIE layouts are as follows: + // + // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + // DW_AT_language : ... DW_FORM_data1 + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_address + // DW_AT_hi_pc : ...... DW_FORM_address + // DW_AT_stmt_list : .. DW_FORM_data4 + // + // abbrev_code == 2, tag == DW_TAG_subprogram, no_children + // DW_AT_name : ....... DW_FORM_strp + // DW_AT_low_pc : ..... DW_FORM_addr + // DW_AT_hi_pc : ...... DW_FORM_addr + // DW_AT_external : ... DW_FORM_flag + + pos = writeAbbrev1(null, pos); + pos = writeAbbrev2(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + pos = writeAbbrev1(buffer, pos); + pos = writeAbbrev2(buffer, pos); + assert pos == size; + } + + public int writeAttrType(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAttrForm(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeAbbrev1(byte[] buffer, int p) { + int pos = p; + // abbrev 1 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + pos = writeTag(DW_TAG_compile_unit, buffer, pos); + pos = writeFlag(DW_CHILDREN_yes, buffer, pos); + pos = writeAttrType(DW_AT_language, buffer, pos); + pos = writeAttrForm(DW_FORM_data1, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_stmt_list, buffer, pos); + pos = writeAttrForm(DW_FORM_data4, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + public int writeAbbrev2(byte[] buffer, int p) { + int pos = p; + // abbrev 2 compile unit + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + pos = writeTag(DW_TAG_subprogram, buffer, pos); + pos = writeFlag(DW_CHILDREN_no, buffer, pos); + pos = writeAttrType(DW_AT_name, buffer, pos); + pos = writeAttrForm(DW_FORM_strp, buffer, pos); + pos = writeAttrType(DW_AT_low_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_hi_pc, buffer, pos); + pos = writeAttrForm(DW_FORM_addr, buffer, pos); + pos = writeAttrType(DW_AT_external, buffer, pos); + pos = writeAttrForm(DW_FORM_flag, buffer, pos); + // now terminate + pos = writeAttrType(DW_AT_null, buffer, pos); + pos = writeAttrForm(DW_FORM_null, buffer, pos); + return pos; + } + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + /** + * debug_abbrev section content depends on debug_frame section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java new file mode 100644 index 000000000000..93719731dcd8 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_id; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_version; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc1; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc2; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_advance_loc4; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_def_cfa; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_def_cfa_offset; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_nop; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_offset; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_register; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; +/** + * generic generator for debug_frame section. + */ +public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { + + public DwarfFrameSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_FRAME_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + + // the frame section contains one CIE at offset 0 + // followed by an FIE for each method + pos = writeCIE(null, pos); + pos = writeMethodFrames(null, pos); + + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + // there are entries for the prologue region where the + // stack is being built, the method body region(s) where + // the code executes with a fixed size frame and the + // epilogue region(s) where the stack is torn down + pos = writeCIE(buffer, pos); + pos = writeMethodFrames(buffer, pos); + + if (pos != size) { + System.out.format("pos = 0x%x size = 0x%x", pos, size); + } + assert pos == size; + } + + public int writeCIE(byte[] buffer, int p) { + // we only need a vanilla CIE with default fields + // because we have to have at least one + // the layout is + // + // uint32 : length ............... length of remaining fields in this CIE + // uint32 : CIE_id ................ unique id for CIE == 0xffffff + // uint8 : version ................ == 1 + // uint8[] : augmentation ......... == "" so always 1 byte + // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + // ULEB : data_alignment_factor ... == -8 + // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + // byte[] : initial_instructions .. includes pad to 8-byte boundary + int pos = p; + if (buffer == null) { + pos += putInt(0, scratch, 0); // don't care about length + pos += putInt(DW_CFA_CIE_id, scratch, 0); + pos += putByte(DW_CFA_CIE_version, scratch, 0); + pos += putAsciiStringBytes("", scratch, 0); + pos += putULEB(1, scratch, 0); + pos += putSLEB(-8, scratch, 0); + pos += putByte((byte) getPCIdx(), scratch, 0); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + // no need to write length + return pos; + } else { + int lengthPos = pos; + pos = putInt(0, buffer, pos); + pos = putInt(DW_CFA_CIE_id, buffer, pos); + pos = putByte(DW_CFA_CIE_version, buffer, pos); + pos = putAsciiStringBytes("", buffer, pos); + pos = putULEB(1, buffer, pos); + pos = putSLEB(-8, buffer, pos); + pos = putByte((byte) getPCIdx(), buffer, pos); + // write insns to set up empty frame + pos = writeInitialInstructions(buffer, pos); + // pad to word alignment + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + return pos; + } + } + + public int writeMethodFrames(byte[] buffer, int p) { + int pos = p; + for (ClassEntry classEntry : getPrimaryClasses()) { + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + long lo = primaryEntry.getPrimary().getLo(); + long hi = primaryEntry.getPrimary().getHi(); + int frameSize = primaryEntry.getFrameSize(); + int currentOffset = 0; + int lengthPos = pos; + pos = writeFDEHeader((int) lo, (int) hi, buffer, pos); + for (DebugInfoProvider.DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { + int advance = debugFrameSizeInfo.getOffset() - currentOffset; + currentOffset += advance; + pos = writeAdvanceLoc(advance, buffer, pos); + if (debugFrameSizeInfo.getType() == DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND) { + // SP has been extended so rebase CFA using full frame + pos = writeDefCFAOffset(frameSize, buffer, pos); + } else { + // SP has been contracted so rebase CFA using empty frame + pos = writeDefCFAOffset(8, buffer, pos); + } + } + pos = writePaddingNops(8, buffer, pos); + patchLength(lengthPos, buffer, pos); + } + } + return pos; + } + + public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { + // we only need a vanilla FDE header with default fields + // the layout is + // + // uint32 : length ........... length of remaining fields in this FDE + // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + // uint64 : initial_location .. i.e. method lo address + // uint64 : address_range ..... i.e. method hi - lo + // byte[] : instructions ...... includes pad to 8-byte boundary + + int pos = p; + if (buffer == null) { + pos += putInt(0, scratch, 0); // dummy length + pos += putInt(0, scratch, 0); // CIE_offset + pos += putLong(lo, scratch, 0); // initial address + return pos + putLong(hi - lo, scratch, 0); // address range + } else { + pos = putInt(0, buffer, pos); // dummy length + pos = putInt(0, buffer, pos); // CIE_offset + pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address + return putLong(hi - lo, buffer, pos); // address range + } + } + + public int writePaddingNops(int alignment, byte[] buffer, int p) { + int pos = p; + assert (alignment & (alignment - 1)) == 0; + while ((pos & (alignment - 1)) != 0) { + if (buffer == null) { + pos++; + } else { + pos = putByte(DW_CFA_nop, buffer, pos); + } + } + return pos; + } + + public int writeDefCFA(int register, int offset, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa, scratch, 0); + pos += putSLEB(register, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa, buffer, pos); + pos = putULEB(register, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + + public int writeDefCFAOffset(int offset, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(DW_CFA_def_cfa_offset, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + + public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { + if (offset <= 0x3f) { + return writeAdvanceLoc0((byte) offset, buffer, pos); + } else if (offset <= 0xff) { + return writeAdvanceLoc1((byte) offset, buffer, pos); + } else if (offset <= 0xffff) { + return writeAdvanceLoc2((short) offset, buffer, pos); + } else { + return writeAdvanceLoc4(offset, buffer, pos); + } + } + + public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { + byte op = advanceLoc0Op(offset); + if (buffer == null) { + return pos + putByte(op, scratch, 0); + } else { + return putByte(op, buffer, pos); + } + } + + public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { + int pos = p; + byte op = DW_CFA_advance_loc1; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putByte(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putByte(offset, buffer, pos); + } + } + + public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { + byte op = DW_CFA_advance_loc2; + int pos = p; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putShort(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putShort(offset, buffer, pos); + } + } + + public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { + byte op = DW_CFA_advance_loc4; + int pos = p; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putInt(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putInt(offset, buffer, pos); + } + } + + public int writeOffset(int register, int offset, byte[] buffer, int p) { + byte op = offsetOp(register); + int pos = p; + if (buffer == null) { + pos += putByte(op, scratch, 0); + return pos + putULEB(offset, scratch, 0); + } else { + pos = putByte(op, buffer, pos); + return putULEB(offset, buffer, pos); + } + } + + public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putByte(DW_CFA_register, scratch, 0); + pos += putULEB(savedReg, scratch, 0); + return pos + putULEB(savedToReg, scratch, 0); + } else { + pos = putByte(DW_CFA_register, buffer, pos); + pos = putULEB(savedReg, buffer, pos); + return putULEB(savedToReg, buffer, pos); + } + } + + public abstract int getPCIdx(); + + public abstract int getSPIdx(); + + public abstract int writeInitialInstructions(byte[] buffer, int pos); + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + /** + * debug_frame section content depends on debug_line section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } + + private byte offsetOp(int register) { + assert (register >> 6) == 0; + return (byte) ((DW_CFA_offset << 6) | register); + } + + private byte advanceLoc0Op(int offset) { + assert (offset >= 0 && offset <= 0x3f); + return (byte) ((DW_CFA_advance_loc << 6) | offset); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java new file mode 100644 index 000000000000..58d490853e5b --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; + +/** + * AArch64-specific generator for debug_frame section + * that knows details of AArch64 registers and frame layout. + */ +public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_FP_IDX = 29; + public static final int DW_CFA_LR_IDX = 30; + public static final int DW_CFA_SP_IDX = 31; + public static final int DW_CFA_PC_IDX = 32; + + public DwarfFrameSectionImplAArch64(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public int getPCIdx() { + return DW_CFA_PC_IDX; + } + + @Override + public int getSPIdx() { + return DW_CFA_SP_IDX; + } + + @Override + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; + // rsp has not been updated + // caller pc is in lr + // register r32 (rpc), r30 (lr) + pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); + return pos; + } +} + diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java new file mode 100644 index 000000000000..b4b638305b5f --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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; + +/** + * x86_64-specific generator for debug_frame section + * that knows details of x86_64 registers and frame layout. + */ +public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { + public static final int DW_CFA_RSP_IDX = 7; + public static final int DW_CFA_RIP_IDX = 16; + + public DwarfFrameSectionImplX86_64(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public int getPCIdx() { + return DW_CFA_RIP_IDX; + } + + @Override + public int getSPIdx() { + return DW_CFA_RSP_IDX; + } + + @Override + public int writeInitialInstructions(byte[] buffer, int p) { + int pos = p; + // rsp points at the word containing the saved rip + // so the frame base (cfa) is at rsp + 8 (why not - ???) + // def_cfa r7 (sp) offset 8 + pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); + // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + // (why not -1 ???) + // offset r16 (rip) cfa - 8 + pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); + return pos; + } +} 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 new file mode 100644 index 000000000000..033a09273a68 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfInfoSectionImpl.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; + +import java.util.LinkedList; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_compile_unit; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_subprogram; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FLAG_true; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LANG_Java; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; +/** + * generator for debug_info section. + */ +public class DwarfInfoSectionImpl extends DwarfSectionImpl { + /** + * an info header section always contains a fixed number of bytes. + */ + private static final int DW_DIE_HEADER_SIZE = 11; + + public DwarfInfoSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_INFO_SECTION_NAME; + } + + @Override + public void createContent() { + // we need a single level 0 DIE for each compilation unit (CU) + // Each CU's Level 0 DIE is preceded by a fixed header: + // and terminated by a null DIE + // uint32 length ......... excluding this length field + // uint16 dwarf_version .. always 2 ?? + // uint32 abbrev offset .. always 0 ?? + // uint8 address_size .... always 8 + // * ................ sequence of top-level and nested child entries + // ............ == 0 + // + // a DIE is a recursively defined structure + // it starts with a code for the associated + // abbrev entry followed by a series of attribute + // values as determined by the entry terminated by + // a null value and followed by zero or more child + // DIEs (zero iff has_children == no_children) + // + // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + // * ....... value sequence as determined by abbrev entry + // * ................... sequence of child DIEs (if appropriate) + // ............. == 0 + // + // note that a null_DIE looks like + // LEB128 abbrev_code ....... == 0 + // i.e. it also looks like a null_value + + byte[] buffer = null; + int pos = 0; + + for (ClassEntry classEntry : getPrimaryClasses()) { + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // no need to backpatch length at lengthPos + } + buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + debug(" [0x%08x] DEBUG_INFO\n", pos); + debug(" [0x%08x] size = 0x%08x\n", pos, size); + for (ClassEntry classEntry : getPrimaryClasses()) { + // save the offset of this file's CU so it can + // be used when writing the aranges section + classEntry.setCUIndex(pos); + int lengthPos = pos; + pos = writeCUHeader(buffer, pos); + debug(" [0x%08x] Compilation Unit\n", pos, size); + assert pos == lengthPos + DW_DIE_HEADER_SIZE; + pos = writeCU(classEntry, buffer, pos); + // backpatch length at lengthPos (excluding length field) + patchLength(lengthPos, buffer, pos); + } + assert pos == size; + } + + public int writeCUHeader(byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + pos += putInt(0, scratch, 0); // CU length + pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version + pos += putInt(0, scratch, 0); // abbrev offset + return pos + putByte((byte) 8, scratch, 0); // address size + } else { + pos = putInt(0, buffer, pos); // CU length + pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version + pos = putInt(0, buffer, pos); // abbrev offset + return putByte((byte) 8, buffer, pos); // address size + } + } + + public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); + debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); + pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); + debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); + pos = writeAttrData1(DW_LANG_Java, buffer, pos); + debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); + pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); + pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); + debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); + pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); + debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); + pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); + for (PrimaryEntry primaryEntry : classPrimaryEntries) { + pos = writePrimary(primaryEntry, buffer, pos); + } + // write a terminating null attribute for the the level 2 primaries + return writeAttrNull(buffer, pos); + + } + + public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { + int pos = p; + Range primary = primaryEntry.getPrimary(); + debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); + pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); + debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); + pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); + debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); + pos = writeAttrAddress(primary.getLo(), buffer, pos); + debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); + pos = writeAttrAddress(primary.getHi(), buffer, pos); + // need to pass true only if method is public + debug(" [0x%08x] external true\n", pos); + return writeFlag(DW_FLAG_true, buffer, pos); + } + + public int writeAttrStrp(String value, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + return pos + putInt(0, scratch, 0); + } else { + int idx = debugStringIndex(value); + return putInt(idx, buffer, pos); + } + } + + public int writeAttrString(String value, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + return pos + value.length() + 1; + } else { + return putAsciiStringBytes(value, buffer, pos); + } + } + + @Override + protected void debug(String format, Object... args) { + if (((int) args[0] - debugBase) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + /** + * debug_info section content depends on abbrev section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} + diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java new file mode 100644 index 000000000000..7ae876f3e05f --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -0,0 +1,726 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; + +import java.util.Map; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; +/** + * generator for debug_line section. + */ +public class DwarfLineSectionImpl extends DwarfSectionImpl { + /** + * line header section always contains fixed number of bytes. + */ + private static final int DW_LN_HEADER_SIZE = 27; + /** + * current generator follows C++ with line base -5. + */ + private static final int DW_LN_LINE_BASE = -5; + /** + * current generator follows C++ with line range 14 + * giving full range -5 to 8. + */ + private static final int DW_LN_LINE_RANGE = 14; + /** + * current generator uses opcode base of 13 + * which must equal DW_LNS_define_file + 1. + */ + private static final int DW_LN_OPCODE_BASE = 13; + + /* + * standard opcodes defined by Dwarf 2 + */ + private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an + // invalid opcode + private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for + // extended opcodes + private static final byte DW_LNS_copy = 1; // append current state as matrix row + // 0 args + private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg + private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg + private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg + private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg + private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args + private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row + private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode + // 255 0 args + private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg + + /* + * extended opcodes defined by Dwarf 2 + */ + // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 + private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses + private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 + private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 + + DwarfLineSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_LINE_SECTION_NAME; + } + + @Override + public void createContent() { + // we need to create a header, dir table, file table and line + // number table encoding for each CU + + // write entries for each file listed in the primary list + int pos = 0; + for (ClassEntry classEntry : getPrimaryClasses()) { + int startPos = pos; + classEntry.setLineIndex(startPos); + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(classEntry); + int fileTableSize = computeFileTableSize(classEntry); + int prologueSize = headerSize + dirTableSize + fileTableSize; + classEntry.setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(classEntry); + int totalSize = prologueSize + lineNumberTableSize; + classEntry.setTotalSize(totalSize); + pos += totalSize; + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + public int headerSize() { + // header size is standard 31 bytes + // uint32 total_length + // uint16 version + // uint32 prologue_length + // uint8 min_insn_length + // uint8 default_is_stmt + // int8 line_base + // uint8 line_range + // uint8 opcode_base + // uint8 li_opcode_base + // uint8[opcode_base-1] standard_opcode_lengths + + return DW_LN_HEADER_SIZE; + } + + public int computeDirTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int dirSize = 0; + for (DirEntry dir : classEntry.getLocalDirs()) { + dirSize += dir.getPath().length() + 1; + } + // allow for separator nul + dirSize++; + return dirSize; + } + + public int computeFileTableSize(ClassEntry classEntry) { + // table contains a sequence of 'nul'-terminated + // dir name bytes followed by an extra 'nul' + // and then a sequence of 'nul'-terminated + // file name bytes followed by an extra 'nul' + + // for now we assume dir and file names are ASCII + // byte strings + int fileSize = 0; + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we want the file base name excluding path + String baseName = localEntry.getBaseName(); + int length = baseName.length(); + fileSize += length + 1; + DirEntry dirEntry = localEntry.dirEntry; + int idx = classEntry.localDirsIdx(dirEntry); + fileSize += putULEB(idx, scratch, 0); + // the two zero timestamps require 1 byte each + fileSize += 2; + } + // allow for terminator nul + fileSize++; + return fileSize; + } + + public int computeLineNUmberTableSize(ClassEntry classEntry) { + // sigh -- we have to do this by generating the + // content even though we cannot write it into a byte[] + return writeLineNumberTable(classEntry, null, 0); + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + ObjectFile.Element textElement = getElement().getOwner().elementForName(".text"); + LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); + if (decisionMap != null) { + Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); + if (valueObj != null && valueObj instanceof Number) { + // this may not be the final vaddr for the text segment + // but it will be close enough to make debug easier + // i.e. to within a 4k page or two + debugTextBase = ((Number) valueObj).longValue(); + } + } + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + + int pos = 0; + checkDebug(pos); + debug(" [0x%08x] DEBUG_LINE\n", pos); + + for (ClassEntry classEntry : getPrimaryClasses()) { + int startPos = pos; + assert classEntry.getLineIndex() == startPos; + debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + pos = writeHeader(classEntry, buffer, pos); + debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + int dirTablePos = pos; + pos = writeDirTable(classEntry, buffer, pos); + debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(classEntry, buffer, pos); + debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(classEntry, buffer, pos); + debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); + debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + } + assert pos == buffer.length; + } + + public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + // 4 ubyte length field + pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); + // 2 ubyte version is always 2 + pos = putShort(DW_VERSION_2, buffer, pos); + // 4 ubyte prologue length includes rest of header and + // dir + file table section + int prologueSize = classEntry.getLinePrologueSize() - 6; + pos = putInt(prologueSize, buffer, pos); + // 1 ubyte min instruction length is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte default is_stmt is always 1 + pos = putByte((byte) 1, buffer, pos); + // 1 byte line base is always -5 + pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); + // 1 ubyte line range is always 14 giving range -5 to 8 + pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); + // 1 ubyte opcode base is always 13 + pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); + // specify opcode arg sizes for the standard opcodes + putByte((byte) 0, buffer, pos); // DW_LNS_copy + putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc + putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line + putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file + putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column + putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt + putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block + putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc + putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc + putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence + putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address + pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file + return pos; + } + + public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + debug(" [0x%08x] Dir Name\n", pos); + // write out the list of dirs referenced form this file entry + int dirIdx = 1; + for (DirEntry dir : classEntry.getLocalDirs()) { + // write nul terminated string text. + debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); + pos = putAsciiStringBytes(dir.getPath(), buffer, pos); + dirIdx++; + } + // separate dirs from files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + int fileIdx = 1; + debug(" [0x%08x] Entry Dir Name\n", pos); + for (FileEntry localEntry : classEntry.getLocalFiles()) { + // we need the file name minus path, the associated dir index, and 0 for time stamps + String baseName = localEntry.getBaseName(); + DirEntry dirEntry = localEntry.dirEntry; + int dirIdx = classEntry.localDirsIdx(dirEntry); + debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); + pos = putAsciiStringBytes(baseName, buffer, pos); + pos = putULEB(dirIdx, buffer, pos); + pos = putULEB(0, buffer, pos); + pos = putULEB(0, buffer, pos); + fileIdx++; + } + // terminate files with a nul + pos = putByte((byte) 0, buffer, pos); + return pos; + } + + public int debugLine = 1; + public int debugCopyCount = 0; + + public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { + int pos = p; + // the primary file entry should always be first in the local files list + assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; + String primaryClassName = classEntry.getClassName(); + String primaryFileName = classEntry.getFileName(); + String file = primaryFileName; + int fileIdx = 1; + debug(" [0x%08x] primary class %s\n", pos, primaryClassName); + debug(" [0x%08x] primary file %s\n", pos, primaryFileName); + for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { + Range primaryRange = primaryEntry.getPrimary(); + assert primaryRange.getFileName().equals(primaryFileName); + // each primary represents a method i.e. a contiguous + // sequence of subranges. we assume the default state + // at the start of each sequence because we always post an + // end_sequence when we finish all the subranges in the method + long line = primaryRange.getLine(); + if (line < 0 && primaryEntry.getSubranges().size() > 0) { + line = primaryEntry.getSubranges().get(0).getLine(); + } + if (line < 0) { + line = 0; + } + long address = primaryRange.getLo(); + + // set state for primary + debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), + primaryRange.getLine()); + + // initialize and write a row for the start of the primary method + pos = putSetFile(file, fileIdx, buffer, pos); + pos = putSetBasicBlock(buffer, pos); + // address is currently 0 + pos = putSetAddress(address, buffer, pos); + // state machine value of line is currently 1 + // increment to desired line + if (line != 1) { + pos = putAdvanceLine(line - 1, buffer, pos); + } + pos = putCopy(buffer, pos); + + // now write a row for each subrange lo and hi + for (Range subrange : primaryEntry.getSubranges()) { + assert subrange.getLo() >= primaryRange.getLo(); + assert subrange.getHi() <= primaryRange.getHi(); + FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); + String subfile = subFileEntry.getFileName(); + int subFileIdx = classEntry.localFilesIdx(subFileEntry); + long subLine = subrange.getLine(); + long subAddressLo = subrange.getLo(); + long subAddressHi = subrange.getHi(); + debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); + if (subLine < 0) { + // no line info so stay at previous file:line + subLine = line; + subfile = file; + subFileIdx = fileIdx; + debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); + } + // there is a temptation to append end sequence at here + // when the hiAddress lies strictly between the current + // address and the start of the next subrange because, + // ostensibly, we have void space between the end of + // the current subrange and the start of the next one. + // however, debug works better if we treat all the insns up + // to the next range start as belonging to the current line + // + // if we have to update to a new file then do so + if (subFileIdx != fileIdx) { + // update the current file + pos = putSetFile(subfile, subFileIdx, buffer, pos); + file = subfile; + fileIdx = subFileIdx; + } + // check if we can advance line and/or address in + // one byte with a special opcode + long lineDelta = subLine - line; + long addressDelta = subAddressLo - address; + byte opcode = isSpecialOpcode(addressDelta, lineDelta); + if (opcode != DW_LNS_undefined) { + // ignore pointless write when addressDelta == lineDelta == 0 + if (addressDelta != 0 || lineDelta != 0) { + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // does it help to divide and conquer using + // a fixed address increment + int remainder = isConstAddPC(addressDelta); + if (remainder > 0) { + pos = putConstAddPC(buffer, pos); + // the remaining address can be handled with a + // special opcode but what about the line delta + opcode = isSpecialOpcode(remainder, lineDelta); + if (opcode != DW_LNS_undefined) { + // address remainder and line now fit + pos = putSpecialOpcode(opcode, buffer, pos); + } else { + // ok, bump the line separately then use a + // special opcode for the address remainder + opcode = isSpecialOpcode(remainder, 0); + assert opcode != DW_LNS_undefined; + pos = putAdvanceLine(lineDelta, buffer, pos); + pos = putSpecialOpcode(opcode, buffer, pos); + } + } else { + // increment line and pc separately + if (lineDelta != 0) { + pos = putAdvanceLine(lineDelta, buffer, pos); + } + // n.b. we might just have had an out of range line increment + // with a zero address increment + if (addressDelta > 0) { + // see if we can use a ushort for the increment + if (isFixedAdvancePC(addressDelta)) { + pos = putFixedAdvancePC((short) addressDelta, buffer, pos); + } else { + pos = putAdvancePC(addressDelta, buffer, pos); + } + } + pos = putCopy(buffer, pos); + } + } + // move line and address range on + line += lineDelta; + address += addressDelta; + } + // append a final end sequence just below the next primary range + if (address < primaryRange.getHi()) { + long addressDelta = primaryRange.getHi() - address; + // increment address before we write the end sequence + pos = putAdvancePC(addressDelta, buffer, pos); + } + pos = putEndSequence(buffer, pos); + } + debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); + + return pos; + } + + @Override + protected void debug(String format, Object... args) { + if (((int) args[0] - debugBase) < 0x100000) { + super.debug(format, args); + } else if (format.startsWith(" [0x%08x] primary file")) { + super.debug(format, args); + } + } + + public int putCopy(byte[] buffer, int p) { + byte opcode = DW_LNS_copy; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debugCopyCount++; + debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); + return putByte(opcode, buffer, pos); + } + } + + public int putAdvancePC(long uleb, byte[] buffer, int p) { + byte opcode = DW_LNS_advance_pc; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debugAddress += uleb; + debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putAdvanceLine(long sleb, byte[] buffer, int p) { + byte opcode = DW_LNS_advance_line; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putSLEB(sleb, scratch, 0); + } else { + debugLine += sleb; + debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); + pos = putByte(opcode, buffer, pos); + return putSLEB(sleb, buffer, pos); + } + } + + public int putSetFile(String file, long uleb, byte[] buffer, int p) { + byte opcode = DW_LNS_set_file; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putSetColumn(long uleb, byte[] buffer, int p) { + byte opcode = DW_LNS_set_column; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putULEB(uleb, scratch, 0); + } else { + pos = putByte(opcode, buffer, pos); + return putULEB(uleb, buffer, pos); + } + } + + public int putNegateStmt(byte[] buffer, int p) { + byte opcode = DW_LNS_negate_stmt; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + return putByte(opcode, buffer, pos); + } + } + + public int putSetBasicBlock(byte[] buffer, int p) { + byte opcode = DW_LNS_set_basic_block; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Set basic block\n", pos); + return putByte(opcode, buffer, pos); + } + } + + public int putConstAddPC(byte[] buffer, int p) { + byte opcode = DW_LNS_const_add_pc; + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + int advance = opcodeAddress((byte) 255); + debugAddress += advance; + debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); + return putByte(opcode, buffer, pos); + } + } + + public int putFixedAdvancePC(short arg, byte[] buffer, int p) { + byte opcode = DW_LNS_fixed_advance_pc; + int pos = p; + if (buffer == null) { + pos = pos + putByte(opcode, scratch, 0); + return pos + putShort(arg, scratch, 0); + } else { + debugAddress += arg; + debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); + pos = putByte(opcode, buffer, pos); + return putShort(arg, buffer, pos); + } + } + + public int putEndSequence(byte[] buffer, int p) { + byte opcode = DW_LNE_end_sequence; + int pos = p; + if (buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(1, scratch, 0); + return pos + putByte(opcode, scratch, 0); + } else { + debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); + debugAddress = debugTextBase; + debugLine = 1; + debugCopyCount = 0; + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(1, buffer, pos); + return putByte(opcode, buffer, pos); + } + } + + public int putSetAddress(long arg, byte[] buffer, int p) { + byte opcode = DW_LNE_set_address; + int pos = p; + if (buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // insert extended insn byte count as ULEB + pos = pos + putULEB(9, scratch, 0); + pos = pos + putByte(opcode, scratch, 0); + return pos + putLong(arg, scratch, 0); + } else { + debugAddress = debugTextBase + (int) arg; + debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert extended insn byte count as ULEB + pos = putULEB(9, buffer, pos); + pos = putByte(opcode, buffer, pos); + return putRelocatableCodeOffset(arg, buffer, pos); + } + } + + public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { + byte opcode = DW_LNE_define_file; + int pos = p; + // calculate bytes needed for opcode + args + int fileBytes = file.length() + 1; + long insnBytes = 1; + insnBytes += fileBytes; + insnBytes += putULEB(uleb1, scratch, 0); + insnBytes += putULEB(uleb2, scratch, 0); + insnBytes += putULEB(uleb3, scratch, 0); + if (buffer == null) { + pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); + // write insnBytes as a ULEB + pos += putULEB(insnBytes, scratch, 0); + return pos + (int) insnBytes; + } else { + debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); + pos = putByte(DW_LNS_extended_prefix, buffer, pos); + // insert insn length as uleb + pos = putULEB(insnBytes, buffer, pos); + // insert opcode and args + pos = putByte(opcode, buffer, pos); + pos = putAsciiStringBytes(file, buffer, pos); + pos = putULEB(uleb1, buffer, pos); + pos = putULEB(uleb2, buffer, pos); + return putULEB(uleb3, buffer, pos); + } + } + + public int opcodeId(byte opcode) { + int iopcode = opcode & 0xff; + return iopcode - DW_LN_OPCODE_BASE; + } + + public int opcodeAddress(byte opcode) { + int iopcode = opcode & 0xff; + return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + } + + public int opcodeLine(byte opcode) { + int iopcode = opcode & 0xff; + return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; + } + + public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { + int pos = p; + if (buffer == null) { + return pos + putByte(opcode, scratch, 0); + } else { + if (debug && opcode == 0) { + debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); + } + debugAddress += opcodeAddress(opcode); + debugLine += opcodeLine(opcode); + debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + return putByte(opcode, buffer, pos); + } + } + + private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; + private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); + + public byte isSpecialOpcode(long addressDelta, long lineDelta) { + if (addressDelta < 0) { + return DW_LNS_undefined; + } + if (lineDelta >= DW_LN_LINE_BASE) { + long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; + if (offsetLineDelta < DW_LN_LINE_RANGE) { + // line_delta can be encoded + // check if address is ok + if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { + long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; + if (opcode <= 255) { + return (byte) opcode; + } + } + } + } + + // return invalid opcode + return DW_LNS_undefined; + } + + public int isConstAddPC(long addressDelta) { + if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { + return 0; + } + if (addressDelta <= MAX_ADDPC_DELTA) { + return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); + } else { + return 0; + } + } + + public boolean isFixedAdvancePC(long addressDiff) { + return addressDiff >= 0 && addressDiff < 0xffff; + } + + /** + * debug_line section content depends on debug_str section content and offset. + */ + public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} 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 new file mode 100644 index 000000000000..b3a270fe5682 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.elf.ELFObjectFile; + +import java.util.Map; +import java.util.Set; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; + +/** + * class from which all DWARF debug sections + * inherit providing common behaviours. + */ +public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { + protected DwarfSections dwarfSections; + public boolean debug = false; + public long debugTextBase = 0; + public long debugAddress = 0; + public int debugBase = 0; + + public DwarfSectionImpl(DwarfSections dwarfSections) { + this.dwarfSections = dwarfSections; + } + + /** + * creates the target byte[] array used to define the section + * contents. + * + * the main task of this method is to precompute the + * size of the debug section. given the complexity of the + * data layouts that invariably requires performing a dummy + * write of the contents, inserting bytes into a small, + * scratch buffer only when absolutely necessary. subclasses + * may also cache some information for use when writing the + * contents. + */ + public abstract void createContent(); + + /** + * populates the byte[] array used to contain the section + * contents. + * + * in most cases this task reruns the operations performed + * under createContent but this time actually writing data + * to the target byte[]. + */ + public abstract void writeContent(); + + @Override + public boolean isLoadable() { + // even though we're a progbits section impl we're not actually loadable + return false; + } + + public void checkDebug(int pos) { + // if the env var relevant to this element + // type is set then switch on debugging + String name = getSectionName(); + String envVarName = "DWARF_" + name.substring(1).toUpperCase(); + if (System.getenv(envVarName) != null) { + debug = true; + debugBase = pos; + debugAddress = debugTextBase; + } + } + + protected void debug(String format, Object... args) { + if (debug) { + System.out.format(format, args); + } + } + + // base level put methods that assume a non-null buffer + + public int putByte(byte b, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = b; + return pos; + } + + public int putShort(short s, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + return pos; + } + + public int putInt(int i, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + return pos; + } + + public int putLong(long l, byte[] buffer, int p) { + int pos = p; + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + return pos; + } + + public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { + int pos = p; + // mark address so it is relocated relative to the start of the text segment + markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); + pos = putLong(0, buffer, pos); + return pos; + } + + public int putULEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >>> 7; + boolean done = (l == 0); + if (!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if (done) { + break; + } + } + return pos; + } + + public int putSLEB(long val, byte[] buffer, int p) { + long l = val; + int pos = p; + for (int i = 0; i < 9; i++) { + byte b = (byte) (l & 0x7f); + l = l >> 7; + boolean bIsSigned = (b & 0x40) != 0; + boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); + if (!done) { + b = (byte) (b | 0x80); + } + pos = putByte(b, buffer, pos); + if (done) { + break; + } + } + return pos; + } + + public int putAsciiStringBytes(String s, byte[] buffer, int pos) { + return putAsciiStringBytes(s, 0, buffer, pos); + } + + public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { + int pos = p; + for (int l = startChar; l < s.length(); l++) { + char c = s.charAt(l); + if (c > 127) { + throw new RuntimeException("oops : expected ASCII string! " + s); + } + buffer[pos++] = (byte) c; + } + buffer[pos++] = '\0'; + return pos; + } + + // common write methods that check for a null buffer + + public void patchLength(int lengthPos, byte[] buffer, int pos) { + if (buffer != null) { + int length = pos - (lengthPos + 4); + putInt(length, buffer, lengthPos); + } + } + + public int writeAbbrevCode(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeTag(long code, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(code, scratch, 0); + } else { + return putSLEB(code, buffer, pos); + } + } + + public int writeFlag(byte flag, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(flag, scratch, 0); + } else { + return putByte(flag, buffer, pos); + } + } + + public int writeAttrAddress(long address, byte[] buffer, int pos) { + if (buffer == null) { + return pos + 8; + } else { + return putRelocatableCodeOffset(address, buffer, pos); + } + } + + public int writeAttrData8(long value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putLong(value, scratch, 0); + } else { + return putLong(value, buffer, pos); + } + } + + public int writeAttrData4(int value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putInt(value, scratch, 0); + } else { + return putInt(value, buffer, pos); + } + } + + public int writeAttrData1(byte value, byte[] buffer, int pos) { + if (buffer == null) { + return pos + putByte(value, scratch, 0); + } else { + return putByte(value, buffer, pos); + } + } + + public int writeAttrNull(byte[] buffer, int pos) { + if (buffer == null) { + return pos + putSLEB(0, scratch, 0); + } else { + return putSLEB(0, buffer, pos); + } + } + + /** + * identify the section after which this debug section + * needs to be ordered when sizing and creating content. + * @return the name of the preceding section + */ + public abstract String targetSectionName(); + + /** + * identify the layout properties of the target section + * which need to have been decided before the contents + * of this section can be created. + * @return an array of the relevant decision kinds + */ + public abstract LayoutDecision.Kind[] targetSectionKinds(); + + /** + * identify this debug section by name. + * @return the name of the debug section + */ + public abstract String getSectionName(); + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + // ensure content byte[] has been created before calling super method + createContent(); + + // ensure content byte[] has been written before calling super method + writeContent(); + + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public Set getDependencies(Map decisions) { + Set deps = super.getDependencies(decisions); + String targetName = targetSectionName(); + ELFObjectFile.ELFSection targetSection = (ELFObjectFile.ELFSection) getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + // make our content depend on the size and content of the target + for (LayoutDecision.Kind targetKind : targetKinds) { + LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + } + // make our size depend on our content + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + + return deps; + } + + /** + * a scratch buffer used during computation of a section's size. + */ + protected static final byte[] scratch = new byte[10]; + + protected Iterable getPrimaryClasses() { + return dwarfSections.getPrimaryClasses(); + } + + protected int debugStringIndex(String str) { + return dwarfSections.debugStringIndex(str); + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 474e74d20735..817ad2f868a7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -26,11 +26,7 @@ package com.oracle.objectfile.elf.dwarf; -import com.oracle.objectfile.BasicProgbitsSectionImpl; -import com.oracle.objectfile.BuildDependency; import com.oracle.objectfile.LayoutDecision; -import com.oracle.objectfile.LayoutDecisionMap; -import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; @@ -38,22 +34,19 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; // import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; -import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.elf.ELFMachine; -import com.oracle.objectfile.elf.ELFObjectFile.ELFSection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Set; /** - * an outer class that models the debug info in an + * A class that models the debug info in an * organization that facilitates generation of the * required DWARF sections. It groups common data and * behaviours for use by the various subclasses of - * inner class DwarfSectionImpl that take responsibility + * class DwarfSectionImpl that take responsibility * for generating content for a specific section type. */ public class DwarfSections { @@ -70,83 +63,83 @@ public class DwarfSections { /** * currently generated debug info relies on DWARF spec vesion 2. */ - private static final short DW_VERSION_2 = 2; + public static final short DW_VERSION_2 = 2; // define all the abbrev section codes we need for our DIEs - // private static final int DW_ABBREV_CODE_null = 0; - private static final int DW_ABBREV_CODE_compile_unit = 1; - private static final int DW_ABBREV_CODE_subprogram = 2; + // public static final int DW_ABBREV_CODE_null = 0; + public static final int DW_ABBREV_CODE_compile_unit = 1; + public static final int DW_ABBREV_CODE_subprogram = 2; // define all the Dwarf tags we need for our DIEs - private static final int DW_TAG_compile_unit = 0x11; - private static final int DW_TAG_subprogram = 0x2e; + public static final int DW_TAG_compile_unit = 0x11; + public static final int DW_TAG_subprogram = 0x2e; // define all the Dwarf attributes we need for our DIEs - private static final int DW_AT_null = 0x0; - private static final int DW_AT_name = 0x3; - // private static final int DW_AT_comp_dir = 0x1b; - private static final int DW_AT_stmt_list = 0x10; - private static final int DW_AT_low_pc = 0x11; - private static final int DW_AT_hi_pc = 0x12; - private static final int DW_AT_language = 0x13; - private static final int DW_AT_external = 0x3f; - // private static final int DW_AT_return_addr = 0x2a; - // private static final int DW_AT_frame_base = 0x40; + public static final int DW_AT_null = 0x0; + public static final int DW_AT_name = 0x3; + // public static final int DW_AT_comp_dir = 0x1b; + public static final int DW_AT_stmt_list = 0x10; + public static final int DW_AT_low_pc = 0x11; + public static final int DW_AT_hi_pc = 0x12; + public static final int DW_AT_language = 0x13; + public static final int DW_AT_external = 0x3f; + // public static final int DW_AT_return_addr = 0x2a; + // public static final int DW_AT_frame_base = 0x40; // define all the Dwarf attribute forms we need for our DIEs - private static final int DW_FORM_null = 0x0; + public static final int DW_FORM_null = 0x0; // private static final int DW_FORM_string = 0x8; - private static final int DW_FORM_strp = 0xe; // not currently used - private static final int DW_FORM_addr = 0x1; - private static final int DW_FORM_data1 = 0x0b; // use flag instead - private static final int DW_FORM_data4 = 0x6; - // private static final int DW_FORM_data8 = 0x7; - // private static final int DW_FORM_block1 = 0x0a; - private static final int DW_FORM_flag = 0xc; + public static final int DW_FORM_strp = 0xe; // not currently used + public static final int DW_FORM_addr = 0x1; + public static final int DW_FORM_data1 = 0x0b; // use flag instead + public static final int DW_FORM_data4 = 0x6; + // public static final int DW_FORM_data8 = 0x7; + // public static final int DW_FORM_block1 = 0x0a; + public static final int DW_FORM_flag = 0xc; // define specific attribute values for given attribute or form types // DIE header has_children attribute values - private static final byte DW_CHILDREN_no = 0; - private static final byte DW_CHILDREN_yes = 1; + public static final byte DW_CHILDREN_no = 0; + public static final byte DW_CHILDREN_yes = 1; // DW_FORM_flag attribute values - // private static final byte DW_FLAG_false = 0; - private static final byte DW_FLAG_true = 1; + // public static final byte DW_FLAG_false = 0; + public static final byte DW_FLAG_true = 1; // value for DW_AT_language attribute with form DATA1 - private static final byte DW_LANG_Java = 0xb; + public static final byte DW_LANG_Java = 0xb; // access not needed until we make functions members // DW_AT_Accessibility attribute values - // private static final byte DW_ACCESS_public = 1; - // private static final byte DW_ACCESS_protected = 2; - // private static final byte DW_ACCESS_private = 3; + // public static final byte DW_ACCESS_public = 1; + // public static final byte DW_ACCESS_protected = 2; + // public static final byte DW_ACCESS_private = 3; // not yet needed - // private static final int DW_AT_type = 0; // only present for non-void functions - // private static final int DW_AT_accessibility = 0; + // public static final int DW_AT_type = 0; // only present for non-void functions + // public static final int DW_AT_accessibility = 0; // CIE and FDE entries - private static final int DW_CFA_CIE_id = -1; - // private static final int DW_CFA_FDE_id = 0; + public static final int DW_CFA_CIE_id = -1; + // public static final int DW_CFA_FDE_id = 0; - private static final byte DW_CFA_CIE_version = 1; + public static final byte DW_CFA_CIE_version = 1; // values for high 2 bits - private static final byte DW_CFA_advance_loc = 0x1; - private static final byte DW_CFA_offset = 0x2; - // private static final byte DW_CFA_restore = 0x3; + public static final byte DW_CFA_advance_loc = 0x1; + public static final byte DW_CFA_offset = 0x2; + // public static final byte DW_CFA_restore = 0x3; // values for low 6 bits - private static final byte DW_CFA_nop = 0x0; - // private static final byte DW_CFA_set_loc1 = 0x1; - private static final byte DW_CFA_advance_loc1 = 0x2; - private static final byte DW_CFA_advance_loc2 = 0x3; - private static final byte DW_CFA_advance_loc4 = 0x4; - // private static final byte DW_CFA_offset_extended = 0x5; - // private static final byte DW_CFA_restore_extended = 0x6; - // private static final byte DW_CFA_undefined = 0x7; - // private static final byte DW_CFA_same_value = 0x8; - private static final byte DW_CFA_register = 0x9; - private static final byte DW_CFA_def_cfa = 0xc; - // private static final byte DW_CFA_def_cfa_register = 0xd; - private static final byte DW_CFA_def_cfa_offset = 0xe; + public static final byte DW_CFA_nop = 0x0; + // public static final byte DW_CFA_set_loc1 = 0x1; + public static final byte DW_CFA_advance_loc1 = 0x2; + public static final byte DW_CFA_advance_loc2 = 0x3; + public static final byte DW_CFA_advance_loc4 = 0x4; + // public static final byte DW_CFA_offset_extended = 0x5; + // public static final byte DW_CFA_restore_extended = 0x6; + // public static final byte DW_CFA_undefined = 0x7; + // public static final byte DW_CFA_same_value = 0x8; + public static final byte DW_CFA_register = 0x9; + public static final byte DW_CFA_def_cfa = 0xc; + // public static final byte DW_CFA_def_cfa_register = 0xd; + public static final byte DW_CFA_def_cfa_offset = 0xe; private ELFMachine elfMachine; private DwarfStrSectionImpl dwarfStrSection; @@ -158,14 +151,16 @@ public class DwarfSections { public DwarfSections(ELFMachine elfMachine) { this.elfMachine = elfMachine; - dwarfStrSection = new DwarfStrSectionImpl(); - dwarfAbbrevSection = new DwarfAbbrevSectionImpl(); - dwarfInfoSection = new DwarfInfoSectionImpl(); - dwarfARangesSection = new DwarfARangesSectionImpl(); - dwarfLineSection = new DwarfLineSectionImpl(); - dwarfFameSection = (elfMachine == ELFMachine.AArch64 - ? new DwarfFrameSectionImplAArch64() - : new DwarfFrameSectionImplX86_64()); + dwarfStrSection = new DwarfStrSectionImpl(this); + dwarfAbbrevSection = new DwarfAbbrevSectionImpl(this); + dwarfInfoSection = new DwarfInfoSectionImpl(this); + dwarfARangesSection = new DwarfARangesSectionImpl(this); + dwarfLineSection = new DwarfLineSectionImpl(this); + if (elfMachine == ELFMachine.AArch64) { + dwarfFameSection = new DwarfFrameSectionImplAArch64(this); + } else { + dwarfFameSection = new DwarfFrameSectionImplX86_64(this); + } } public DwarfStrSectionImpl getStrSectionImpl() { @@ -192,15 +187,6 @@ public DwarfLineSectionImpl getLineSectionImpl() { return dwarfLineSection; } - public ELFMachine getElfMachine() { - return elfMachine; - } - - /** - * a scratch buffer used during computation of a section's size. - */ - protected static final byte[] scratch = new byte[10]; - /** * a table listing all known strings, some of * which may be marked for insertion into the @@ -293,7 +279,7 @@ public String uniqueDebugString(String string) { * @return the offset of the string in the .debug_str * section */ - private int debugStringIndex(String string) { + public int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } @@ -405,7 +391,7 @@ public void addSubRange(Range primaryRange, Range subrange) { classEntry.addSubRange(subrange, subrangeEntry); } - private DirEntry ensureDirEntry(String file) { + public DirEntry ensureDirEntry(String file) { int pathLength = file.lastIndexOf('/'); if (pathLength < 0) { // no path/package means use dir entry 0 @@ -420,1917 +406,10 @@ private DirEntry ensureDirEntry(String file) { } return dirEntry; } - - /** - * class from which all DWARF debug section - * inherit providing common behaviours. - */ - // shared implementation methods to manage content creation - public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { - public boolean debug = false; - public long debugTextBase = 0; - public long debugAddress = 0; - public int debugBase = 0; - - public DwarfSectionImpl() { - } - - /** - * creates the target byte[] array used to define the section - * contents. - * - * the main task of this method is to precompute the - * size of the debug section. given the complexity of the - * data layouts that invariably requires performing a dummy - * write of the contents, inserting bytes into a small, - * scratch buffer only when absolutely necessary. subclasses - * may also cache some information for use when writing the - * contents. - */ - public abstract void createContent(); - - /** - * populates the byte[] array used to contain the section - * contents. - * - * in most cases this task reruns the operations performed - * under createContent but this time actually writing data - * to the target byte[]. - */ - public abstract void writeContent(); - - @Override - public boolean isLoadable() { - // even though we're a progbits section impl we're not actually loadable - return false; - } - - public void checkDebug(int pos) { - // if the env var relevant to this element - // type is set then switch on debugging - String name = getSectionName(); - String envVarName = "DWARF_" + name.substring(1).toUpperCase(); - if (System.getenv(envVarName) != null) { - debug = true; - debugBase = pos; - debugAddress = debugTextBase; - } - } - - protected void debug(String format, Object... args) { - if (debug) { - System.out.format(format, args); - } - } - - // base level put methods that assume a non-null buffer - - public int putByte(byte b, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = b; - return pos; - } - - public int putShort(short s, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = (byte) (s & 0xff); - buffer[pos++] = (byte) ((s >> 8) & 0xff); - return pos; - } - - public int putInt(int i, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = (byte) (i & 0xff); - buffer[pos++] = (byte) ((i >> 8) & 0xff); - buffer[pos++] = (byte) ((i >> 16) & 0xff); - buffer[pos++] = (byte) ((i >> 24) & 0xff); - return pos; - } - - public int putLong(long l, byte[] buffer, int p) { - int pos = p; - buffer[pos++] = (byte) (l & 0xff); - buffer[pos++] = (byte) ((l >> 8) & 0xff); - buffer[pos++] = (byte) ((l >> 16) & 0xff); - buffer[pos++] = (byte) ((l >> 24) & 0xff); - buffer[pos++] = (byte) ((l >> 32) & 0xff); - buffer[pos++] = (byte) ((l >> 40) & 0xff); - buffer[pos++] = (byte) ((l >> 48) & 0xff); - buffer[pos++] = (byte) ((l >> 56) & 0xff); - return pos; - } - - public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { - int pos = p; - // mark address so it is relocated relative to the start of the text segment - markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); - pos = putLong(0, buffer, pos); - return pos; - } - - public int putULEB(long val, byte[] buffer, int p) { - long l = val; - int pos = p; - for (int i = 0; i < 9; i++) { - byte b = (byte) (l & 0x7f); - l = l >>> 7; - boolean done = (l == 0); - if (!done) { - b = (byte) (b | 0x80); - } - pos = putByte(b, buffer, pos); - if (done) { - break; - } - } - return pos; - } - - public int putSLEB(long val, byte[] buffer, int p) { - long l = val; - int pos = p; - for (int i = 0; i < 9; i++) { - byte b = (byte) (l & 0x7f); - l = l >> 7; - boolean bIsSigned = (b & 0x40) != 0; - boolean done = ((bIsSigned && l == -1) || (!bIsSigned && l == 0)); - if (!done) { - b = (byte) (b | 0x80); - } - pos = putByte(b, buffer, pos); - if (done) { - break; - } - } - return pos; - } - - public int putAsciiStringBytes(String s, byte[] buffer, int pos) { - return putAsciiStringBytes(s, 0, buffer, pos); - } - - public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { - int pos = p; - for (int l = startChar; l < s.length(); l++) { - char c = s.charAt(l); - if (c > 127) { - throw new RuntimeException("oops : expected ASCII string! " + s); - } - buffer[pos++] = (byte) c; - } - buffer[pos++] = '\0'; - return pos; - } - - // common write methods that check for a null buffer - - public void patchLength(int lengthPos, byte[] buffer, int pos) { - if (buffer != null) { - int length = pos - (lengthPos + 4); - putInt(length, buffer, lengthPos); - } - } - - public int writeAbbrevCode(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeTag(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeFlag(byte flag, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putByte(flag, scratch, 0); - } else { - return putByte(flag, buffer, pos); - } - } - - public int writeAttrAddress(long address, byte[] buffer, int pos) { - if (buffer == null) { - return pos + 8; - } else { - return putRelocatableCodeOffset(address, buffer, pos); - } - } - - public int writeAttrData8(long value, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putLong(value, scratch, 0); - } else { - return putLong(value, buffer, pos); - } - } - - public int writeAttrData4(int value, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putInt(value, scratch, 0); - } else { - return putInt(value, buffer, pos); - } - } - - public int writeAttrData1(byte value, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putByte(value, scratch, 0); - } else { - return putByte(value, buffer, pos); - } - } - - public int writeAttrNull(byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(0, scratch, 0); - } else { - return putSLEB(0, buffer, pos); - } - } - - /** - * identify the section after which this debug section - * needs to be ordered when sizing and creating content. - * @return the name of the preceding section - */ - public abstract String targetSectionName(); - - /** - * identify the layout properties of the target section - * which need to have been decided before the contents - * of this section can be created. - * @return an array of the relevant decision kinds - */ - public abstract LayoutDecision.Kind[] targetSectionKinds(); - - /** - * identify this debug section by name. - * @return the name of the debug section - */ - public abstract String getSectionName(); - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - // ensure content byte[] has been created before calling super method - createContent(); - - // ensure content byte[] has been written before calling super method - writeContent(); - - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public Set getDependencies(Map decisions) { - Set deps = super.getDependencies(decisions); - String targetName = targetSectionName(); - ELFSection targetSection = (ELFSection) getElement().getOwner().elementForName(targetName); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); - LayoutDecision.Kind[] targetKinds = targetSectionKinds(); - // make our content depend on the size and content of the target - for (LayoutDecision.Kind targetKind : targetKinds) { - LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); - deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); - } - // make our size depend on our content - deps.add(BuildDependency.createOrGet(ourSize, ourContent)); - - return deps; - } - } - - /** - * generator for debug_str section. - */ - public class DwarfStrSectionImpl extends DwarfSectionImpl { - public DwarfStrSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_STR_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()) { - stringEntry.setOffset(pos); - String string = stringEntry.getString(); - pos += string.length() + 1; - } - } - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - for (StringEntry stringEntry : stringTable) { - if (stringEntry.isAddToStrSection()) { - assert stringEntry.getOffset() == pos; - String string = stringEntry.getString(); - pos = putAsciiStringBytes(string, buffer, pos); - } - } - assert pos == size; - } - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - /** - * debug_str section content depends on text section content and offset. - */ - public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - /** - * debug_str section content depends on text section content and offset. - */ - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } + public StringTable getStringTable() { + return stringTable; } - - /** - * generator for debug_abbrev section. - */ - public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { - - public DwarfAbbrevSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_ABBREV_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - // an abbrev table contains abbrev entries for one or - // more CUs. the table includes a sequence of abbrev - // entries each of which defines a specific DIE layout - // employed to describe some DIE in a CU. a table is - // terminated by a null entry - // - // a null entry has consists of just a 0 abbrev code - // LEB128 abbrev_code; ...... == 0 - // - // non-null entries have the following format - // LEB128 abbrev_code; ...... unique noncode for this layout != 0 - // 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 DIE - // * ........ zero or more attributes - // .... terminator - // - // An attribute_spec consists of an attribute name and form - // LEB128 attr_name; ........ 0 for the null attribute name - // LEB128 attr_form; ........ 0 for the null attribute form - // - // For the moment we only use one abbrev table for all CUs. - // It contains two DIEs, the first to describe the compilation - // unit itself and the second to describe each method within - // that compilation unit. - // - // The DIE layouts are as follows: - // - // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - // DW_AT_language : ... DW_FORM_data1 - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_address - // DW_AT_hi_pc : ...... DW_FORM_address - // DW_AT_stmt_list : .. DW_FORM_data4 - // - // abbrev_code == 2, tag == DW_TAG_subprogram, no_children - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_addr - // DW_AT_hi_pc : ...... DW_FORM_addr - // DW_AT_external : ... DW_FORM_flag - - pos = writeAbbrev1(null, pos); - pos = writeAbbrev2(null, pos); - - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - pos = writeAbbrev1(buffer, pos); - pos = writeAbbrev2(buffer, pos); - assert pos == size; - } - - public int writeAttrType(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeAttrForm(long code, byte[] buffer, int pos) { - if (buffer == null) { - return pos + putSLEB(code, scratch, 0); - } else { - return putSLEB(code, buffer, pos); - } - } - - public int writeAbbrev1(byte[] buffer, int p) { - int pos = p; - // abbrev 1 compile unit - pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); - pos = writeTag(DW_TAG_compile_unit, buffer, pos); - pos = writeFlag(DW_CHILDREN_yes, buffer, pos); - pos = writeAttrType(DW_AT_language, buffer, pos); - pos = writeAttrForm(DW_FORM_data1, buffer, pos); - pos = writeAttrType(DW_AT_name, buffer, pos); - pos = writeAttrForm(DW_FORM_strp, buffer, pos); - pos = writeAttrType(DW_AT_low_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_hi_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_stmt_list, buffer, pos); - pos = writeAttrForm(DW_FORM_data4, buffer, pos); - // now terminate - pos = writeAttrType(DW_AT_null, buffer, pos); - pos = writeAttrForm(DW_FORM_null, buffer, pos); - return pos; - } - - public int writeAbbrev2(byte[] buffer, int p) { - int pos = p; - // abbrev 2 compile unit - pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - pos = writeTag(DW_TAG_subprogram, buffer, pos); - pos = writeFlag(DW_CHILDREN_no, buffer, pos); - pos = writeAttrType(DW_AT_name, buffer, pos); - pos = writeAttrForm(DW_FORM_strp, buffer, pos); - pos = writeAttrType(DW_AT_low_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_hi_pc, buffer, pos); - pos = writeAttrForm(DW_FORM_addr, buffer, pos); - pos = writeAttrType(DW_AT_external, buffer, pos); - pos = writeAttrForm(DW_FORM_flag, buffer, pos); - // now terminate - pos = writeAttrType(DW_AT_null, buffer, pos); - pos = writeAttrForm(DW_FORM_null, buffer, pos); - return pos; - } - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - /** - * debug_abbrev section content depends on debug_frame section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - } - - /** - * generic generator for debug_frame section. - */ - public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { - - public DwarfFrameSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_FRAME_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - - // the frame section contains one CIE at offset 0 - // followed by an FIE for each method - pos = writeCIE(null, pos); - pos = writeMethodFrames(null, pos); - - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - // there are entries for the prologue region where the - // stack is being built, the method body region(s) where - // the code executes with a fixed size frame and the - // epilogue region(s) where the stack is torn down - pos = writeCIE(buffer, pos); - pos = writeMethodFrames(buffer, pos); - - if (pos != size) { - System.out.format("pos = 0x%x size = 0x%x", pos, size); - } - assert pos == size; - } - - public int writeCIE(byte[] buffer, int p) { - // we only need a vanilla CIE with default fields - // because we have to have at least one - // the layout is - // - // uint32 : length ............... length of remaining fields in this CIE - // uint32 : CIE_id ................ unique id for CIE == 0xffffff - // uint8 : version ................ == 1 - // uint8[] : augmentation ......... == "" so always 1 byte - // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) - // ULEB : data_alignment_factor ... == -8 - // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 - // byte[] : initial_instructions .. includes pad to 8-byte boundary - int pos = p; - if (buffer == null) { - pos += putInt(0, scratch, 0); // don't care about length - pos += putInt(DW_CFA_CIE_id, scratch, 0); - pos += putByte(DW_CFA_CIE_version, scratch, 0); - pos += putAsciiStringBytes("", scratch, 0); - pos += putULEB(1, scratch, 0); - pos += putSLEB(-8, scratch, 0); - pos += putByte((byte) getPCIdx(), scratch, 0); - // write insns to set up empty frame - pos = writeInitialInstructions(buffer, pos); - // pad to word alignment - pos = writePaddingNops(8, buffer, pos); - // no need to write length - return pos; - } else { - int lengthPos = pos; - pos = putInt(0, buffer, pos); - pos = putInt(DW_CFA_CIE_id, buffer, pos); - pos = putByte(DW_CFA_CIE_version, buffer, pos); - pos = putAsciiStringBytes("", buffer, pos); - pos = putULEB(1, buffer, pos); - pos = putSLEB(-8, buffer, pos); - pos = putByte((byte) getPCIdx(), buffer, pos); - // write insns to set up empty frame - pos = writeInitialInstructions(buffer, pos); - // pad to word alignment - pos = writePaddingNops(8, buffer, pos); - patchLength(lengthPos, buffer, pos); - return pos; - } - } - - public int writeMethodFrames(byte[] buffer, int p) { - int pos = p; - for (ClassEntry classEntry : primaryClasses) { - for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { - long lo = primaryEntry.getPrimary().getLo(); - long hi = primaryEntry.getPrimary().getHi(); - int frameSize = primaryEntry.getFrameSize(); - int currentOffset = 0; - int lengthPos = pos; - pos = writeFDEHeader((int) lo, (int) hi, buffer, pos); - for (DebugFrameSizeChange debugFrameSizeInfo : primaryEntry.getFrameSizeInfos()) { - int advance = debugFrameSizeInfo.getOffset() - currentOffset; - currentOffset += advance; - pos = writeAdvanceLoc(advance, buffer, pos); - if (debugFrameSizeInfo.getType() == DebugFrameSizeChange.Type.EXTEND) { - // SP has been extended so rebase CFA using full frame - pos = writeDefCFAOffset(frameSize, buffer, pos); - } else { - // SP has been contracted so rebase CFA using empty frame - pos = writeDefCFAOffset(8, buffer, pos); - } - } - pos = writePaddingNops(8, buffer, pos); - patchLength(lengthPos, buffer, pos); - } - } - return pos; - } - - public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { - // we only need a vanilla FDE header with default fields - // the layout is - // - // uint32 : length ........... length of remaining fields in this FDE - // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header - // uint64 : initial_location .. i.e. method lo address - // uint64 : address_range ..... i.e. method hi - lo - // byte[] : instructions ...... includes pad to 8-byte boundary - - int pos = p; - if (buffer == null) { - pos += putInt(0, scratch, 0); // dummy length - pos += putInt(0, scratch, 0); // CIE_offset - pos += putLong(lo, scratch, 0); // initial address - return pos + putLong(hi - lo, scratch, 0); // address range - } else { - pos = putInt(0, buffer, pos); // dummy length - pos = putInt(0, buffer, pos); // CIE_offset - pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address - return putLong(hi - lo, buffer, pos); // address range - } - } - - public int writePaddingNops(int alignment, byte[] buffer, int p) { - int pos = p; - assert (alignment & (alignment - 1)) == 0; - while ((pos & (alignment - 1)) != 0) { - if (buffer == null) { - pos++; - } else { - pos = putByte(DW_CFA_nop, buffer, pos); - } - } - return pos; - } - - public int writeDefCFA(int register, int offset, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putByte(DW_CFA_def_cfa, scratch, 0); - pos += putSLEB(register, scratch, 0); - return pos + putULEB(offset, scratch, 0); - } else { - pos = putByte(DW_CFA_def_cfa, buffer, pos); - pos = putULEB(register, buffer, pos); - return putULEB(offset, buffer, pos); - } - } - - public int writeDefCFAOffset(int offset, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); - return pos + putULEB(offset, scratch, 0); - } else { - pos = putByte(DW_CFA_def_cfa_offset, buffer, pos); - return putULEB(offset, buffer, pos); - } - } - - public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { - if (offset <= 0x3f) { - return writeAdvanceLoc0((byte) offset, buffer, pos); - } else if (offset <= 0xff) { - return writeAdvanceLoc1((byte) offset, buffer, pos); - } else if (offset <= 0xffff) { - return writeAdvanceLoc2((short) offset, buffer, pos); - } else { - return writeAdvanceLoc4(offset, buffer, pos); - } - } - - public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { - byte op = advanceLoc0Op(offset); - if (buffer == null) { - return pos + putByte(op, scratch, 0); - } else { - return putByte(op, buffer, pos); - } - } - - public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { - int pos = p; - byte op = DW_CFA_advance_loc1; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putByte(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putByte(offset, buffer, pos); - } - } - - public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { - byte op = DW_CFA_advance_loc2; - int pos = p; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putShort(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putShort(offset, buffer, pos); - } - } - - public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { - byte op = DW_CFA_advance_loc4; - int pos = p; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putInt(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putInt(offset, buffer, pos); - } - } - - public int writeOffset(int register, int offset, byte[] buffer, int p) { - byte op = offsetOp(register); - int pos = p; - if (buffer == null) { - pos += putByte(op, scratch, 0); - return pos + putULEB(offset, scratch, 0); - } else { - pos = putByte(op, buffer, pos); - return putULEB(offset, buffer, pos); - } - } - - public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putByte(DW_CFA_register, scratch, 0); - pos += putULEB(savedReg, scratch, 0); - return pos + putULEB(savedToReg, scratch, 0); - } else { - pos = putByte(DW_CFA_register, buffer, pos); - pos = putULEB(savedReg, buffer, pos); - return putULEB(savedToReg, buffer, pos); - } - } - - public abstract int getPCIdx(); - - public abstract int getSPIdx(); - - public abstract int writeInitialInstructions(byte[] buffer, int pos); - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - /** - * debug_frame section content depends on debug_line section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - - private byte offsetOp(int register) { - assert (register >> 6) == 0; - return (byte) ((DW_CFA_offset << 6) | register); - } - - private byte advanceLoc0Op(int offset) { - assert (offset >= 0 && offset <= 0x3f); - return (byte) ((DW_CFA_advance_loc << 6) | offset); - } - } - - /** - * x86_64-specific generator for debug_frame section - * that knows details of x86_64 registers and frame layout. - */ - public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_RSP_IDX = 7; - public static final int DW_CFA_RIP_IDX = 16; - - public DwarfFrameSectionImplX86_64() { - super(); - } - - @Override - public int getPCIdx() { - return DW_CFA_RIP_IDX; - } - - @Override - public int getSPIdx() { - return DW_CFA_RSP_IDX; - } - - @Override - public int writeInitialInstructions(byte[] buffer, int p) { - int pos = p; - // rsp points at the word containing the saved rip - // so the frame base (cfa) is at rsp + 8 (why not - ???) - // def_cfa r7 (sp) offset 8 - pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); - // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa - // (why not -1 ???) - // offset r16 (rip) cfa - 8 - pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); - return pos; - } - } - - /** - * AArch64-specific generator for debug_frame section - * that knows details of AArch64 registers and frame layout. - */ - public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_FP_IDX = 29; - public static final int DW_CFA_LR_IDX = 30; - public static final int DW_CFA_SP_IDX = 31; - public static final int DW_CFA_PC_IDX = 32; - - public DwarfFrameSectionImplAArch64() { - super(); - } - - @Override - public int getPCIdx() { - return DW_CFA_PC_IDX; - } - - @Override - public int getSPIdx() { - return DW_CFA_SP_IDX; - } - - @Override - public int writeInitialInstructions(byte[] buffer, int p) { - int pos = p; - // rsp has not been updated - // caller pc is in lr - // register r32 (rpc), r30 (lr) - pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); - return pos; - } - } - - /** - * generator for debug_info section. - */ - public class DwarfInfoSectionImpl extends DwarfSectionImpl { - /** - * an info header section always contains a fixed number of bytes. - */ - private static final int DW_DIE_HEADER_SIZE = 11; - - public DwarfInfoSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_INFO_SECTION_NAME; - } - - @Override - public void createContent() { - // we need a single level 0 DIE for each compilation unit (CU) - // Each CU's Level 0 DIE is preceded by a fixed header: - // and terminated by a null DIE - // uint32 length ......... excluding this length field - // uint16 dwarf_version .. always 2 ?? - // uint32 abbrev offset .. always 0 ?? - // uint8 address_size .... always 8 - // * ................ sequence of top-level and nested child entries - // ............ == 0 - // - // a DIE is a recursively defined structure - // it starts with a code for the associated - // abbrev entry followed by a series of attribute - // values as determined by the entry terminated by - // a null value and followed by zero or more child - // DIEs (zero iff has_children == no_children) - // - // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE - // * ....... value sequence as determined by abbrev entry - // * ................... sequence of child DIEs (if appropriate) - // ............. == 0 - // - // note that a null_DIE looks like - // LEB128 abbrev_code ....... == 0 - // i.e. it also looks like a null_value - - byte[] buffer = null; - int pos = 0; - - for (ClassEntry classEntry : primaryClasses) { - int lengthPos = pos; - pos = writeCUHeader(buffer, pos); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); - // no need to backpatch length at lengthPos - } - buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - debug(" [0x%08x] DEBUG_INFO\n", pos); - debug(" [0x%08x] size = 0x%08x\n", pos, size); - for (ClassEntry classEntry : primaryClasses) { - // save the offset of this file's CU so it can - // be used when writing the aranges section - classEntry.setCUIndex(pos); - int lengthPos = pos; - pos = writeCUHeader(buffer, pos); - debug(" [0x%08x] Compilation Unit\n", pos, size); - assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); - // backpatch length at lengthPos (excluding length field) - patchLength(lengthPos, buffer, pos); - } - assert pos == size; - } - - public int writeCUHeader(byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - pos += putInt(0, scratch, 0); // CU length - pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version - pos += putInt(0, scratch, 0); // abbrev offset - return pos + putByte((byte) 8, scratch, 0); // address size - } else { - pos = putInt(0, buffer, pos); // CU length - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version - pos = putInt(0, buffer, pos); // abbrev offset - return putByte((byte) 8, buffer, pos); // address size - } - } - - public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); - pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); - debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); - pos = writeAttrData1(DW_LANG_Java, buffer, pos); - debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); - pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); - pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); - debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); - pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); - debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); - pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); - for (PrimaryEntry primaryEntry : classPrimaryEntries) { - pos = writePrimary(primaryEntry, buffer, pos); - } - // write a terminating null attribute for the the level 2 primaries - return writeAttrNull(buffer, pos); - - } - - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { - int pos = p; - Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); - pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); - pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); - pos = writeAttrAddress(primary.getLo(), buffer, pos); - debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); - pos = writeAttrAddress(primary.getHi(), buffer, pos); - // need to pass true only if method is public - debug(" [0x%08x] external true\n", pos); - return writeFlag(DW_FLAG_true, buffer, pos); - } - - public int writeAttrStrp(String value, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - return pos + putInt(0, scratch, 0); - } else { - int idx = debugStringIndex(value); - return putInt(idx, buffer, pos); - } - } - - public int writeAttrString(String value, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - return pos + value.length() + 1; - } else { - return putAsciiStringBytes(value, buffer, pos); - } - } - - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - - /** - * debug_info section content depends on abbrev section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - } - - /** - * generator for debug_aranges section. - */ - public class DwarfARangesSectionImpl extends DwarfSectionImpl { - private static final int DW_AR_HEADER_SIZE = 12; - private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size - - public DwarfARangesSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_ARANGES_SECTION_NAME; - } - - @Override - public void createContent() { - int pos = 0; - // we need an entry for each compilation unit - // - // uint32 length ............ in bytes (not counting these 4 bytes) - // uint16 dwarf_version ..... always 2 - // uint32 info_offset ....... offset of compilation unit on debug_info - // uint8 address_size ....... always 8 - // uint8 segment_desc_size .. ??? - // - // i.e. 12 bytes followed by padding - // aligning up to 2 * address size - // - // uint8 pad[4] - // - // followed by N + 1 times - // - // uint64 lo ................ lo address of range - // uint64 length ............ number of bytes in range - // - // where N is the number of ranges belonging to the compilation unit - // and the last range contains two zeroes - - for (ClassEntry classEntry : primaryClasses) { - pos += DW_AR_HEADER_SIZE; - // align to 2 * address size - pos += DW_AR_HEADER_PAD_SIZE; - pos += classEntry.getPrimaryEntries().size() * 2 * 8; - pos += 2 * 8; - } - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - Element textElement = getElement().getOwner().elementForName(".text"); - LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); - if (decisionMap != null) { - Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); - if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two - debugTextBase = ((Number) valueObj).longValue(); - } - } - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - int size = buffer.length; - int pos = 0; - - checkDebug(pos); - - debug(" [0x%08x] DEBUG_ARANGES\n", pos); - for (ClassEntry classEntry : primaryClasses) { - int lastpos = pos; - int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; - int cuIndex = classEntry.getCUIndex(); - LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - // add room for each entry into length count - length += classPrimaryEntries.size() * 2 * 8; - length += 2 * 8; - debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); - pos = putInt(length, buffer, pos); - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 - pos = putInt(cuIndex, buffer, pos); - pos = putByte((byte) 8, buffer, pos); // address size is always 8 - pos = putByte((byte) 0, buffer, pos); // segment size is always 0 - assert (pos - lastpos) == DW_AR_HEADER_SIZE; - // align to 2 * address size - for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { - pos = putByte((byte) 0, buffer, pos); - } - debug(" [0x%08x] Address Length Name\n", pos); - for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { - Range primary = classPrimaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); - pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); - pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); - } - pos = putLong(0, buffer, pos); - pos = putLong(0, buffer, pos); - } - - assert pos == size; - } - - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - - // .debug_aranges section content depends on .debug_info section content and offset - public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } - } - - /** - * generator for debug_line section. - */ - public class DwarfLineSectionImpl extends DwarfSectionImpl { - /** - * line header section always contains fixed number of bytes. - */ - private static final int DW_LN_HEADER_SIZE = 27; - /** - * current generator follows C++ with line base -5. - */ - private static final int DW_LN_LINE_BASE = -5; - /** - * current generator follows C++ with line range 14 - * giving full range -5 to 8. - */ - private static final int DW_LN_LINE_RANGE = 14; - /** - * current generator uses opcode base of 13 - * which must equal DW_LNS_define_file + 1. - */ - private static final int DW_LN_OPCODE_BASE = 13; - - /* - * standard opcodes defined by Dwarf 2 - */ - private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an - // invalid opcode - private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for - // extended opcodes - private static final byte DW_LNS_copy = 1; // append current state as matrix row - // 0 args - private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg - private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg - private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg - private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg - private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args - private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row - private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode - // 255 0 args - private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg - - /* - * extended opcodes defined by Dwarf 2 - */ - // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 - private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses - private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 - private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 - - DwarfLineSectionImpl() { - super(); - } - - @Override - public String getSectionName() { - return DW_LINE_SECTION_NAME; - } - - @Override - public void createContent() { - // we need to create a header, dir table, file table and line - // number table encoding for each CU - - // write entries for each file listed in the primary list - int pos = 0; - for (ClassEntry classEntry : primaryClasses) { - int startPos = pos; - classEntry.setLineIndex(startPos); - int headerSize = headerSize(); - int dirTableSize = computeDirTableSize(classEntry); - int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; - classEntry.setLinePrologueSize(prologueSize); - int lineNumberTableSize = computeLineNUmberTableSize(classEntry); - int totalSize = prologueSize + lineNumberTableSize; - classEntry.setTotalSize(totalSize); - pos += totalSize; - } - byte[] buffer = new byte[pos]; - super.setContent(buffer); - } - - public int headerSize() { - // header size is standard 31 bytes - // uint32 total_length - // uint16 version - // uint32 prologue_length - // uint8 min_insn_length - // uint8 default_is_stmt - // int8 line_base - // uint8 line_range - // uint8 opcode_base - // uint8 li_opcode_base - // uint8[opcode_base-1] standard_opcode_lengths - - return DW_LN_HEADER_SIZE; - } - - public int computeDirTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings - int dirSize = 0; - for (DirEntry dir : classEntry.getLocalDirs()) { - dirSize += dir.getPath().length() + 1; - } - // allow for separator nul - dirSize++; - return dirSize; - } - - public int computeFileTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings - int fileSize = 0; - for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we want the file base name excluding path - String baseName = localEntry.getBaseName(); - int length = baseName.length(); - fileSize += length + 1; - DirEntry dirEntry = localEntry.dirEntry; - int idx = classEntry.localDirsIdx(dirEntry); - fileSize += putULEB(idx, scratch, 0); - // the two zero timestamps require 1 byte each - fileSize += 2; - } - // allow for terminator nul - fileSize++; - return fileSize; - } - - public int computeLineNUmberTableSize(ClassEntry classEntry) { - // sigh -- we have to do this by generating the - // content even though we cannot write it into a byte[] - return writeLineNumberTable(classEntry, null, 0); - } - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - Element textElement = getElement().getOwner().elementForName(".text"); - LayoutDecisionMap decisionMap = alreadyDecided.get(textElement); - if (decisionMap != null) { - Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); - if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two - debugTextBase = ((Number) valueObj).longValue(); - } - } - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public void writeContent() { - byte[] buffer = getContent(); - - int pos = 0; - checkDebug(pos); - debug(" [0x%08x] DEBUG_LINE\n", pos); - - for (ClassEntry classEntry : primaryClasses) { - int startPos = pos; - assert classEntry.getLineIndex() == startPos; - debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); - pos = writeHeader(classEntry, buffer, pos); - debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); - int dirTablePos = pos; - pos = writeDirTable(classEntry, buffer, pos); - debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); - int fileTablePos = pos; - pos = writeFileTable(classEntry, buffer, pos); - debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); - int lineNumberTablePos = pos; - pos = writeLineNumberTable(classEntry, buffer, pos); - debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); - debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); - } - assert pos == buffer.length; - } - - public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - // 4 ubyte length field - pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); - // 2 ubyte version is always 2 - pos = putShort(DW_VERSION_2, buffer, pos); - // 4 ubyte prologue length includes rest of header and - // dir + file table section - int prologueSize = classEntry.getLinePrologueSize() - 6; - pos = putInt(prologueSize, buffer, pos); - // 1 ubyte min instruction length is always 1 - pos = putByte((byte) 1, buffer, pos); - // 1 byte default is_stmt is always 1 - pos = putByte((byte) 1, buffer, pos); - // 1 byte line base is always -5 - pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); - // 1 ubyte line range is always 14 giving range -5 to 8 - pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); - // 1 ubyte opcode base is always 13 - pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); - // specify opcode arg sizes for the standard opcodes - putByte((byte) 0, buffer, pos); // DW_LNS_copy - putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc - putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line - putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file - putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column - putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt - putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block - putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc - putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc - putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence - putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address - pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file - return pos; - } - - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - debug(" [0x%08x] Dir Name\n", pos); - // write out the list of dirs referenced form this file entry - int dirIdx = 1; - for (DirEntry dir : classEntry.getLocalDirs()) { - // write nul terminated string text. - debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); - pos = putAsciiStringBytes(dir.getPath(), buffer, pos); - dirIdx++; - } - // separate dirs from files with a nul - pos = putByte((byte) 0, buffer, pos); - return pos; - } - - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - int fileIdx = 1; - debug(" [0x%08x] Entry Dir Name\n", pos); - for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we need the file name minus path, the associated dir index, and 0 for time stamps - String baseName = localEntry.getBaseName(); - DirEntry dirEntry = localEntry.dirEntry; - int dirIdx = classEntry.localDirsIdx(dirEntry); - debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); - pos = putAsciiStringBytes(baseName, buffer, pos); - pos = putULEB(dirIdx, buffer, pos); - pos = putULEB(0, buffer, pos); - pos = putULEB(0, buffer, pos); - fileIdx++; - } - // terminate files with a nul - pos = putByte((byte) 0, buffer, pos); - return pos; - } - - public int debugLine = 1; - public int debugCopyCount = 0; - - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { - int pos = p; - // the primary file entry should always be first in the local files list - assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; - String primaryClassName = classEntry.getClassName(); - String primaryFileName = classEntry.getFileName(); - String file = primaryFileName; - int fileIdx = 1; - debug(" [0x%08x] primary class %s\n", pos, primaryClassName); - debug(" [0x%08x] primary file %s\n", pos, primaryFileName); - for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { - Range primaryRange = primaryEntry.getPrimary(); - assert primaryRange.getFileName().equals(primaryFileName); - // each primary represents a method i.e. a contiguous - // sequence of subranges. we assume the default state - // at the start of each sequence because we always post an - // end_sequence when we finish all the subranges in the method - long line = primaryRange.getLine(); - if (line < 0 && primaryEntry.getSubranges().size() > 0) { - line = primaryEntry.getSubranges().get(0).getLine(); - } - if (line < 0) { - line = 0; - } - long address = primaryRange.getLo(); - - // set state for primary - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), - primaryRange.getLine()); - - // initialize and write a row for the start of the primary method - pos = putSetFile(file, fileIdx, buffer, pos); - pos = putSetBasicBlock(buffer, pos); - // address is currently 0 - pos = putSetAddress(address, buffer, pos); - // state machine value of line is currently 1 - // increment to desired line - if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); - } - pos = putCopy(buffer, pos); - - // now write a row for each subrange lo and hi - for (Range subrange : primaryEntry.getSubranges()) { - assert subrange.getLo() >= primaryRange.getLo(); - assert subrange.getHi() <= primaryRange.getHi(); - FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); - String subfile = subFileEntry.getFileName(); - int subFileIdx = classEntry.localFilesIdx(subFileEntry); - long subLine = subrange.getLine(); - long subAddressLo = subrange.getLo(); - long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); - if (subLine < 0) { - // no line info so stay at previous file:line - subLine = line; - subfile = file; - subFileIdx = fileIdx; - debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); - } - // there is a temptation to append end sequence at here - // when the hiAddress lies strictly between the current - // address and the start of the next subrange because, - // ostensibly, we have void space between the end of - // the current subrange and the start of the next one. - // however, debug works better if we treat all the insns up - // to the next range start as belonging to the current line - // - // if we have to update to a new file then do so - if (subFileIdx != fileIdx) { - // update the current file - pos = putSetFile(subfile, subFileIdx, buffer, pos); - file = subfile; - fileIdx = subFileIdx; - } - // check if we can advance line and/or address in - // one byte with a special opcode - long lineDelta = subLine - line; - long addressDelta = subAddressLo - address; - byte opcode = isSpecialOpcode(addressDelta, lineDelta); - if (opcode != DW_LNS_undefined) { - // ignore pointless write when addressDelta == lineDelta == 0 - if (addressDelta != 0 || lineDelta != 0) { - pos = putSpecialOpcode(opcode, buffer, pos); - } - } else { - // does it help to divide and conquer using - // a fixed address increment - int remainder = isConstAddPC(addressDelta); - if (remainder > 0) { - pos = putConstAddPC(buffer, pos); - // the remaining address can be handled with a - // special opcode but what about the line delta - opcode = isSpecialOpcode(remainder, lineDelta); - if (opcode != DW_LNS_undefined) { - // address remainder and line now fit - pos = putSpecialOpcode(opcode, buffer, pos); - } else { - // ok, bump the line separately then use a - // special opcode for the address remainder - opcode = isSpecialOpcode(remainder, 0); - assert opcode != DW_LNS_undefined; - pos = putAdvanceLine(lineDelta, buffer, pos); - pos = putSpecialOpcode(opcode, buffer, pos); - } - } else { - // increment line and pc separately - if (lineDelta != 0) { - pos = putAdvanceLine(lineDelta, buffer, pos); - } - // n.b. we might just have had an out of range line increment - // with a zero address increment - if (addressDelta > 0) { - // see if we can use a ushort for the increment - if (isFixedAdvancePC(addressDelta)) { - pos = putFixedAdvancePC((short) addressDelta, buffer, pos); - } else { - pos = putAdvancePC(addressDelta, buffer, pos); - } - } - pos = putCopy(buffer, pos); - } - } - // move line and address range on - line += lineDelta; - address += addressDelta; - } - // append a final end sequence just below the next primary range - if (address < primaryRange.getHi()) { - long addressDelta = primaryRange.getHi() - address; - // increment address before we write the end sequence - pos = putAdvancePC(addressDelta, buffer, pos); - } - pos = putEndSequence(buffer, pos); - } - debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); - - return pos; - } - - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - - public int putCopy(byte[] buffer, int p) { - byte opcode = DW_LNS_copy; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - debugCopyCount++; - debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); - return putByte(opcode, buffer, pos); - } - } - - public int putAdvancePC(long uleb, byte[] buffer, int p) { - byte opcode = DW_LNS_advance_pc; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putULEB(uleb, scratch, 0); - } else { - debugAddress += uleb; - debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); - pos = putByte(opcode, buffer, pos); - return putULEB(uleb, buffer, pos); - } - } - - public int putAdvanceLine(long sleb, byte[] buffer, int p) { - byte opcode = DW_LNS_advance_line; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putSLEB(sleb, scratch, 0); - } else { - debugLine += sleb; - debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); - pos = putByte(opcode, buffer, pos); - return putSLEB(sleb, buffer, pos); - } - } - - public int putSetFile(String file, long uleb, byte[] buffer, int p) { - byte opcode = DW_LNS_set_file; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putULEB(uleb, scratch, 0); - } else { - debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); - pos = putByte(opcode, buffer, pos); - return putULEB(uleb, buffer, pos); - } - } - - public int putSetColumn(long uleb, byte[] buffer, int p) { - byte opcode = DW_LNS_set_column; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putULEB(uleb, scratch, 0); - } else { - pos = putByte(opcode, buffer, pos); - return putULEB(uleb, buffer, pos); - } - } - - public int putNegateStmt(byte[] buffer, int p) { - byte opcode = DW_LNS_negate_stmt; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - return putByte(opcode, buffer, pos); - } - } - - public int putSetBasicBlock(byte[] buffer, int p) { - byte opcode = DW_LNS_set_basic_block; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - debug(" [0x%08x] Set basic block\n", pos); - return putByte(opcode, buffer, pos); - } - } - - public int putConstAddPC(byte[] buffer, int p) { - byte opcode = DW_LNS_const_add_pc; - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - int advance = opcodeAddress((byte) 255); - debugAddress += advance; - debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); - return putByte(opcode, buffer, pos); - } - } - - public int putFixedAdvancePC(short arg, byte[] buffer, int p) { - byte opcode = DW_LNS_fixed_advance_pc; - int pos = p; - if (buffer == null) { - pos = pos + putByte(opcode, scratch, 0); - return pos + putShort(arg, scratch, 0); - } else { - debugAddress += arg; - debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); - pos = putByte(opcode, buffer, pos); - return putShort(arg, buffer, pos); - } - } - - public int putEndSequence(byte[] buffer, int p) { - byte opcode = DW_LNE_end_sequence; - int pos = p; - if (buffer == null) { - pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB - pos = pos + putULEB(1, scratch, 0); - return pos + putByte(opcode, scratch, 0); - } else { - debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); - debugAddress = debugTextBase; - debugLine = 1; - debugCopyCount = 0; - pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB - pos = putULEB(1, buffer, pos); - return putByte(opcode, buffer, pos); - } - } - - public int putSetAddress(long arg, byte[] buffer, int p) { - byte opcode = DW_LNE_set_address; - int pos = p; - if (buffer == null) { - pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB - pos = pos + putULEB(9, scratch, 0); - pos = pos + putByte(opcode, scratch, 0); - return pos + putLong(arg, scratch, 0); - } else { - debugAddress = debugTextBase + (int) arg; - debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); - pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB - pos = putULEB(9, buffer, pos); - pos = putByte(opcode, buffer, pos); - return putRelocatableCodeOffset(arg, buffer, pos); - } - } - - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { - byte opcode = DW_LNE_define_file; - int pos = p; - // calculate bytes needed for opcode + args - int fileBytes = file.length() + 1; - long insnBytes = 1; - insnBytes += fileBytes; - insnBytes += putULEB(uleb1, scratch, 0); - insnBytes += putULEB(uleb2, scratch, 0); - insnBytes += putULEB(uleb3, scratch, 0); - if (buffer == null) { - pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // write insnBytes as a ULEB - pos += putULEB(insnBytes, scratch, 0); - return pos + (int) insnBytes; - } else { - debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); - pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert insn length as uleb - pos = putULEB(insnBytes, buffer, pos); - // insert opcode and args - pos = putByte(opcode, buffer, pos); - pos = putAsciiStringBytes(file, buffer, pos); - pos = putULEB(uleb1, buffer, pos); - pos = putULEB(uleb2, buffer, pos); - return putULEB(uleb3, buffer, pos); - } - } - - public int opcodeId(byte opcode) { - int iopcode = opcode & 0xff; - return iopcode - DW_LN_OPCODE_BASE; - } - - public int opcodeAddress(byte opcode) { - int iopcode = opcode & 0xff; - return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; - } - - public int opcodeLine(byte opcode) { - int iopcode = opcode & 0xff; - return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; - } - - public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { - int pos = p; - if (buffer == null) { - return pos + putByte(opcode, scratch, 0); - } else { - if (debug && opcode == 0) { - debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); - } - debugAddress += opcodeAddress(opcode); - debugLine += opcodeLine(opcode); - debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); - return putByte(opcode, buffer, pos); - } - } - - private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; - private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - - public byte isSpecialOpcode(long addressDelta, long lineDelta) { - if (addressDelta < 0) { - return DW_LNS_undefined; - } - if (lineDelta >= DW_LN_LINE_BASE) { - long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; - if (offsetLineDelta < DW_LN_LINE_RANGE) { - // line_delta can be encoded - // check if address is ok - if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { - long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; - if (opcode <= 255) { - return (byte) opcode; - } - } - } - } - - // return invalid opcode - return DW_LNS_undefined; - } - - public int isConstAddPC(long addressDelta) { - if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { - return 0; - } - if (addressDelta <= MAX_ADDPC_DELTA) { - return (int) (addressDelta - MAX_ADDRESS_ONLY_DELTA); - } else { - return 0; - } - } - - public boolean isFixedAdvancePC(long addressDiff) { - return addressDiff >= 0 && addressDiff < 0xffff; - } - - /** - * debug_line section content depends on debug_str section content and offset. - */ - public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; - - @Override - public String targetSectionName() { - return TARGET_SECTION_NAME; - } - - public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - }; - - @Override - public LayoutDecision.Kind[] targetSectionKinds() { - return targetSectionKinds; - } + public LinkedList getPrimaryClasses() { + return primaryClasses; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java new file mode 100644 index 000000000000..855bca3c749d --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 com.oracle.objectfile.LayoutDecision; + +import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; +import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; +/** + * generator for debug_str section. + */ +public class DwarfStrSectionImpl extends DwarfSectionImpl { + public DwarfStrSectionImpl(DwarfSections dwarfSections) { + super(dwarfSections); + } + + @Override + public String getSectionName() { + return DW_STR_SECTION_NAME; + } + + @Override + public void createContent() { + int pos = 0; + for (StringEntry stringEntry : dwarfSections.getStringTable()) { + if (stringEntry.isAddToStrSection()) { + stringEntry.setOffset(pos); + String string = stringEntry.getString(); + pos += string.length() + 1; + } + } + byte[] buffer = new byte[pos]; + super.setContent(buffer); + } + + @Override + public void writeContent() { + byte[] buffer = getContent(); + int size = buffer.length; + int pos = 0; + + checkDebug(pos); + + for (StringEntry stringEntry : dwarfSections.getStringTable()) { + if (stringEntry.isAddToStrSection()) { + assert stringEntry.getOffset() == pos; + String string = stringEntry.getString(); + pos = putAsciiStringBytes(string, buffer, pos); + } + } + assert pos == size; + } + + @Override + protected void debug(String format, Object... args) { + super.debug(format, args); + } + + /** + * debug_str section content depends on text section content and offset. + */ + public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + + @Override + public String targetSectionName() { + return TARGET_SECTION_NAME; + } + + /** + * debug_str section content depends on text section content and offset. + */ + public final LayoutDecision.Kind[] targetSectionKinds = { + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.VADDR, // add this so we can use the base address + }; + + @Override + public LayoutDecision.Kind[] targetSectionKinds() { + return targetSectionKinds; + } +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java new file mode 100644 index 000000000000..51c785b0a98d --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java @@ -0,0 +1,3 @@ +package com.oracle.objectfile.elf.dwarf; +public class impl { +} From 46a42db4d547d6768af72b37f93c8f31aa9b2b5f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 17:53:01 +0000 Subject: [PATCH 076/130] added option GenertaeDebugInfo= and made it force TrackNodeSourcePosition=true --- .../oracle/objectfile/elf/dwarf/DwarfSections.java | 1 + .../src/com/oracle/svm/core/SubstrateOptions.java | 13 +++++++++++++ .../oracle/svm/hosted/image/NativeBootImage.java | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 817ad2f868a7..2d7fd87a2586 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -50,6 +50,7 @@ * for generating content for a specific section type. */ public class DwarfSections { + // names of the different ELF sections we create or reference // in reverse dependency order public static final String TEXT_SECTION_NAME = ".text"; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 90520da8749f..1706a8f4ea56 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -53,6 +53,8 @@ import com.oracle.svm.core.option.RuntimeOptionKey; import com.oracle.svm.core.option.XOptions; +import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; + public class SubstrateOptions { @Option(help = "Class containing the default entry point method. Optional if --shared is used.", type = OptionType.User)// @@ -437,4 +439,15 @@ public static Predicate makeFilter(String[] definedFilters) { public static int codeAlignment() { return GraalOptions.LoopHeaderAlignment.getValue(HostedOptionValues.singleton()); } + @Option(help = "Insert debug info into the generated native image or library")// + public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey(0) { + @Override + protected void onValueUpdate(EconomicMap, Object> values, Integer oldValue, Integer newValue) { + // force update of TrackNodeSourcePosition + if (newValue > 0 && !Boolean.TRUE.equals(values.get(TrackNodeSourcePosition))) { + TrackNodeSourcePosition.update(values, true); + } + } + }; + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 3eea965e1c5b..30c2d5f23ca3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -473,7 +473,7 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { // if we have constructed any debug info then // give the object file a chance to install it - if (GraalOptions.TrackNodeSourcePosition.getValue(HostedOptionValues.singleton())) { + if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); objectFile.installDebugInfo(provider); } From 05eb983c590fd8da10d67baea6c2d738d4faedcc Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 6 Feb 2020 17:54:06 +0000 Subject: [PATCH 077/130] deleted another remaining redundant local var --- .../src/com/oracle/objectfile/elf/ELFObjectFile.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index ec8c3f3dfecd..8f3121fbdd63 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1181,8 +1181,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { newUserDefinedSection(frameSectionImpl.getSectionName(), frameSectionImpl); newUserDefinedSection(elfInfoSectionImpl.getSectionName(), elfInfoSectionImpl); newUserDefinedSection(elfARangesSectionImpl.getSectionName(), elfARangesSectionImpl); - @SuppressWarnings("unused") - ELFSection debugSection = (ELFSection) newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); + newUserDefinedSection(elfLineSectionImpl.getSectionName(), elfLineSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all // dependent sections are filled in and then sized according to the From a13a3f52c9c9d0eee6fc13ae9092a74c5200d520 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 7 Feb 2020 16:53:06 +0000 Subject: [PATCH 078/130] fixed style issues and made code aware of target byte order --- .../oracle/objectfile/elf/ELFObjectFile.java | 2 +- .../objectfile/elf/dwarf/ClassEntry.java | 8 +- .../oracle/objectfile/elf/dwarf/DirEntry.java | 9 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 78 +-- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 98 ++-- .../elf/dwarf/DwarfFrameSectionImpl.java | 118 +++-- .../dwarf/DwarfFrameSectionImplAArch64.java | 10 +- .../dwarf/DwarfFrameSectionImplX86_64.java | 18 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 100 ++-- .../elf/dwarf/DwarfLineSectionImpl.java | 455 ++++++++++++------ .../elf/dwarf/DwarfSectionImpl.java | 94 +++- .../objectfile/elf/dwarf/DwarfSections.java | 200 +++++--- .../elf/dwarf/DwarfStrSectionImpl.java | 3 +- .../objectfile/elf/dwarf/FileEntry.java | 14 +- .../objectfile/elf/dwarf/PrimaryEntry.java | 86 +--- .../oracle/objectfile/elf/dwarf/Range.java | 22 +- .../objectfile/elf/dwarf/StringEntry.java | 12 +- .../objectfile/elf/dwarf/StringTable.java | 20 +- .../com/oracle/objectfile/elf/dwarf/impl.java | 3 - 19 files changed, 835 insertions(+), 515 deletions(-) delete mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java index 8f3121fbdd63..68b33d97287d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFObjectFile.java @@ -1167,7 +1167,7 @@ protected int getMinimumFileSize() { @Override public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - DwarfSections dwarfSections = new DwarfSections(getMachine()); + DwarfSections dwarfSections = new DwarfSections(getMachine(), getByteOrder()); // we need an implementation for each section DwarfStrSectionImpl elfStrSectionImpl = dwarfSections.getStrSectionImpl(); DwarfAbbrevSectionImpl elfAbbrevSectionImpl = dwarfSections.getAbbrevSectionImpl(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 9e429a565e49..0ff7290cb43f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -129,10 +129,14 @@ PrimaryEntry addPrimary(Range primary, List frameSizeInfos void addSubRange(Range subrange, FileEntry subFileEntry) { Range primary = subrange.getPrimary(); - // the subrange should belong to a primary range + /* + * the subrange should belong to a primary range + */ assert primary != null; PrimaryEntry primaryEntry = primaryIndex.get(primary); - // we should already have seen the primary range + /* + * we should already have seen the primary range + */ assert primaryEntry != null; assert primaryEntry.getClassEntry() == this; primaryEntry.addSubRange(subrange, subFileEntry); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index 5caac5a20997..dde46b4b8828 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -27,8 +27,15 @@ package com.oracle.objectfile.elf.dwarf; /** - * track the directory associated with one or + * Tracks the directory associated with one or * more source files. + * + * This is identified separately from each FileEntry + * idenityfing files that reside in the directory. + * That is necessary because the line info generator + * needs to collect and write out directory names + * into directory tables once only rather than once + * per file. */ public class DirEntry { private String path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 43615669b10f..8ae11c436937 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -37,7 +37,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; /** - * generator for debug_aranges section. + * Section generator for debug_aranges section. */ public class DwarfARangesSectionImpl extends DwarfSectionImpl { private static final int DW_AR_HEADER_SIZE = 12; @@ -55,30 +55,34 @@ public String getSectionName() { @Override public void createContent() { int pos = 0; - // we need an entry for each compilation unit - // - // uint32 length ............ in bytes (not counting these 4 bytes) - // uint16 dwarf_version ..... always 2 - // uint32 info_offset ....... offset of compilation unit on debug_info - // uint8 address_size ....... always 8 - // uint8 segment_desc_size .. ??? - // - // i.e. 12 bytes followed by padding - // aligning up to 2 * address size - // - // uint8 pad[4] - // - // followed by N + 1 times - // - // uint64 lo ................ lo address of range - // uint64 length ............ number of bytes in range - // - // where N is the number of ranges belonging to the compilation unit - // and the last range contains two zeroes + /* + * we need an entry for each compilation unit + * + * uint32 length ............ in bytes (not counting these 4 bytes) + * uint16 dwarf_version ..... always 2 + * uint32 info_offset ....... offset of compilation unit on debug_info + * uint8 address_size ....... always 8 + * uint8 segment_desc_size .. ??? + * + * i.e. 12 bytes followed by padding + * aligning up to 2 * address size + * + * uint8 pad[4] + * + * followed by N + 1 times + * + * uint64 lo ................ lo address of range + * uint64 length ............ number of bytes in range + * + * where N is the number of ranges belonging to the compilation unit + * and the last range contains two zeroes + */ for (ClassEntry classEntry : getPrimaryClasses()) { pos += DW_AR_HEADER_SIZE; - // align to 2 * address size + /* + * align to 2 * address size + */ pos += DW_AR_HEADER_PAD_SIZE; pos += classEntry.getPrimaryEntries().size() * 2 * 8; pos += 2 * 8; @@ -94,9 +98,11 @@ public byte[] getOrDecideContent(Map alre if (decisionMap != null) { Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two + /* + * this may not be the final vaddr for the text segment + * but it will be close enough to make debug easier + * i.e. to within a 4k page or two + */ debugTextBase = ((Number) valueObj).longValue(); } } @@ -117,17 +123,24 @@ public void writeContent() { int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; int cuIndex = classEntry.getCUIndex(); LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - // add room for each entry into length count + /* + * add room for each entry into length count + */ length += classPrimaryEntries.size() * 2 * 8; length += 2 * 8; debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version is always 2 + /* dwarf version is always 2 */ + pos = putShort(DW_VERSION_2, buffer, pos); pos = putInt(cuIndex, buffer, pos); - pos = putByte((byte) 8, buffer, pos); // address size is always 8 - pos = putByte((byte) 0, buffer, pos); // segment size is always 0 + /* address size is always 8 */ + pos = putByte((byte) 8, buffer, pos); + /* segment size is always 0 */ + pos = putByte((byte) 0, buffer, pos); assert (pos - lastpos) == DW_AR_HEADER_SIZE; - // align to 2 * address size + /* + * align to 2 * address size + */ for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { pos = putByte((byte) 0, buffer, pos); } @@ -150,7 +163,9 @@ protected void debug(String format, Object... args) { super.debug(format, args); } - // .debug_aranges section content depends on .debug_info section content and offset + /* + * debug_aranges section content depends on debug_info section content and offset + */ public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; @Override @@ -168,4 +183,3 @@ public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } } - 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 2336e27608a4..c8f97729dd95 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 @@ -51,7 +51,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_TAG_subprogram; /** - * generator for debug_abbrev section. + * Section generator for debug_abbrev section. */ public class DwarfAbbrevSectionImpl extends DwarfSectionImpl { @@ -67,45 +67,47 @@ public String getSectionName() { @Override public void createContent() { int pos = 0; - // an abbrev table contains abbrev entries for one or - // more CUs. the table includes a sequence of abbrev - // entries each of which defines a specific DIE layout - // employed to describe some DIE in a CU. a table is - // terminated by a null entry - // - // a null entry has consists of just a 0 abbrev code - // LEB128 abbrev_code; ...... == 0 - // - // non-null entries have the following format - // LEB128 abbrev_code; ...... unique noncode for this layout != 0 - // 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 DIE - // * ........ zero or more attributes - // .... terminator - // - // An attribute_spec consists of an attribute name and form - // LEB128 attr_name; ........ 0 for the null attribute name - // LEB128 attr_form; ........ 0 for the null attribute form - // - // For the moment we only use one abbrev table for all CUs. - // It contains two DIEs, the first to describe the compilation - // unit itself and the second to describe each method within - // that compilation unit. - // - // The DIE layouts are as follows: - // - // abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - // DW_AT_language : ... DW_FORM_data1 - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_address - // DW_AT_hi_pc : ...... DW_FORM_address - // DW_AT_stmt_list : .. DW_FORM_data4 - // - // abbrev_code == 2, tag == DW_TAG_subprogram, no_children - // DW_AT_name : ....... DW_FORM_strp - // DW_AT_low_pc : ..... DW_FORM_addr - // DW_AT_hi_pc : ...... DW_FORM_addr - // DW_AT_external : ... DW_FORM_flag + /* + * an abbrev table contains abbrev entries for one or + * more CUs. the table includes a sequence of abbrev + * entries each of which defines a specific DIE layout + * employed to describe some DIE in a CU. a table is + * terminated by a null entry + * + * a null entry has consists of just a 0 abbrev code + * LEB128 abbrev_code; ...... == 0 + * + * non-null entries have the following format + * LEB128 abbrev_code; ...... unique noncode for this layout != 0 + * 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 DIE + * * ........ zero or more attributes + * .... terminator + * + * An attribute_spec consists of an attribute name and form + * LEB128 attr_name; ........ 0 for the null attribute name + * LEB128 attr_form; ........ 0 for the null attribute form + * + * For the moment we only use one abbrev table for all CUs. + * It contains two DIEs, the first to describe the compilation + * unit itself and the second to describe each method within + * that compilation unit. + * + * The DIE layouts are as follows: + * + * abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + * DW_AT_language : ... DW_FORM_data1 + * DW_AT_name : ....... DW_FORM_strp + * DW_AT_low_pc : ..... DW_FORM_address + * DW_AT_hi_pc : ...... DW_FORM_address + * DW_AT_stmt_list : .. DW_FORM_data4 + * + * abbrev_code == 2, tag == DW_TAG_subprogram, no_children + * DW_AT_name : ....... DW_FORM_strp + * DW_AT_low_pc : ..... DW_FORM_addr + * DW_AT_hi_pc : ...... DW_FORM_addr + * DW_AT_external : ... DW_FORM_flag + */ pos = writeAbbrev1(null, pos); pos = writeAbbrev2(null, pos); @@ -145,7 +147,9 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { public int writeAbbrev1(byte[] buffer, int p) { int pos = p; - // abbrev 1 compile unit + /* + * abbrev 1 compile unit + */ pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); pos = writeTag(DW_TAG_compile_unit, buffer, pos); pos = writeFlag(DW_CHILDREN_yes, buffer, pos); @@ -159,7 +163,9 @@ public int writeAbbrev1(byte[] buffer, int p) { pos = writeAttrForm(DW_FORM_addr, buffer, pos); pos = writeAttrType(DW_AT_stmt_list, buffer, pos); pos = writeAttrForm(DW_FORM_data4, buffer, pos); - // now terminate + /* + * now terminate + */ pos = writeAttrType(DW_AT_null, buffer, pos); pos = writeAttrForm(DW_FORM_null, buffer, pos); return pos; @@ -167,7 +173,9 @@ public int writeAbbrev1(byte[] buffer, int p) { public int writeAbbrev2(byte[] buffer, int p) { int pos = p; - // abbrev 2 compile unit + /* + * abbrev 2 compile unit + */ pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); pos = writeTag(DW_TAG_subprogram, buffer, pos); pos = writeFlag(DW_CHILDREN_no, buffer, pos); @@ -179,7 +187,9 @@ public int writeAbbrev2(byte[] buffer, int p) { pos = writeAttrForm(DW_FORM_addr, buffer, pos); pos = writeAttrType(DW_AT_external, buffer, pos); pos = writeAttrForm(DW_FORM_flag, buffer, pos); - // now terminate + /* + * now terminate + */ pos = writeAttrType(DW_AT_null, buffer, pos); pos = writeAttrForm(DW_FORM_null, buffer, pos); return pos; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 93719731dcd8..3923045bacd4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -42,7 +42,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; /** - * generic generator for debug_frame section. + * Section generic generator for debug_frame section. */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { @@ -59,8 +59,10 @@ public String getSectionName() { public void createContent() { int pos = 0; - // the frame section contains one CIE at offset 0 - // followed by an FIE for each method + /* + * the frame section contains one CIE at offset 0 + * followed by an FIE for each method + */ pos = writeCIE(null, pos); pos = writeMethodFrames(null, pos); @@ -76,10 +78,12 @@ public void writeContent() { checkDebug(pos); - // there are entries for the prologue region where the - // stack is being built, the method body region(s) where - // the code executes with a fixed size frame and the - // epilogue region(s) where the stack is torn down + /* + * there are entries for the prologue region where the + * stack is being built, the method body region(s) where + * the code executes with a fixed size frame and the + * epilogue region(s) where the stack is torn down + */ pos = writeCIE(buffer, pos); pos = writeMethodFrames(buffer, pos); @@ -90,18 +94,20 @@ public void writeContent() { } public int writeCIE(byte[] buffer, int p) { - // we only need a vanilla CIE with default fields - // because we have to have at least one - // the layout is - // - // uint32 : length ............... length of remaining fields in this CIE - // uint32 : CIE_id ................ unique id for CIE == 0xffffff - // uint8 : version ................ == 1 - // uint8[] : augmentation ......... == "" so always 1 byte - // ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) - // ULEB : data_alignment_factor ... == -8 - // byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 - // byte[] : initial_instructions .. includes pad to 8-byte boundary + /* + * we only need a vanilla CIE with default fields + * because we have to have at least one + * the layout is + * + * uint32 : length ............... length of remaining fields in this CIE + * uint32 : CIE_id ................ unique id for CIE == 0xffffff + * uint8 : version ................ == 1 + * uint8[] : augmentation ......... == "" so always 1 byte + * ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + * ULEB : data_alignment_factor ... == -8 + * byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + * byte[] : initial_instructions .. includes pad to 8-byte boundary + */ int pos = p; if (buffer == null) { pos += putInt(0, scratch, 0); // don't care about length @@ -111,11 +117,17 @@ public int writeCIE(byte[] buffer, int p) { pos += putULEB(1, scratch, 0); pos += putSLEB(-8, scratch, 0); pos += putByte((byte) getPCIdx(), scratch, 0); - // write insns to set up empty frame + /* + * write insns to set up empty frame + */ pos = writeInitialInstructions(buffer, pos); - // pad to word alignment + /* + * pad to word alignment + */ pos = writePaddingNops(8, buffer, pos); - // no need to write length + /* + * no need to write length + */ return pos; } else { int lengthPos = pos; @@ -126,9 +138,13 @@ public int writeCIE(byte[] buffer, int p) { pos = putULEB(1, buffer, pos); pos = putSLEB(-8, buffer, pos); pos = putByte((byte) getPCIdx(), buffer, pos); - // write insns to set up empty frame + /* + * write insns to set up empty frame + */ pos = writeInitialInstructions(buffer, pos); - // pad to word alignment + /* + * pad to word alignment + */ pos = writePaddingNops(8, buffer, pos); patchLength(lengthPos, buffer, pos); return pos; @@ -150,10 +166,14 @@ public int writeMethodFrames(byte[] buffer, int p) { currentOffset += advance; pos = writeAdvanceLoc(advance, buffer, pos); if (debugFrameSizeInfo.getType() == DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND) { - // SP has been extended so rebase CFA using full frame + /* + * SP has been extended so rebase CFA using full frame + */ pos = writeDefCFAOffset(frameSize, buffer, pos); } else { - // SP has been contracted so rebase CFA using empty frame + /* + * SP has been contracted so rebase CFA using empty frame + */ pos = writeDefCFAOffset(8, buffer, pos); } } @@ -165,26 +185,36 @@ public int writeMethodFrames(byte[] buffer, int p) { } public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { - // we only need a vanilla FDE header with default fields - // the layout is - // - // uint32 : length ........... length of remaining fields in this FDE - // uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header - // uint64 : initial_location .. i.e. method lo address - // uint64 : address_range ..... i.e. method hi - lo - // byte[] : instructions ...... includes pad to 8-byte boundary + /* + * we only need a vanilla FDE header with default fields + * the layout is + * + * uint32 : length ........... length of remaining fields in this FDE + * uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + * uint64 : initial_location .. i.e. method lo address + * uint64 : address_range ..... i.e. method hi - lo + * byte[] : instructions ...... includes pad to 8-byte boundary + */ int pos = p; if (buffer == null) { - pos += putInt(0, scratch, 0); // dummy length - pos += putInt(0, scratch, 0); // CIE_offset - pos += putLong(lo, scratch, 0); // initial address - return pos + putLong(hi - lo, scratch, 0); // address range + /* dummy length */ + pos += putInt(0, scratch, 0); + /* CIE_offset */ + pos += putInt(0, scratch, 0); + /* initial address */ + pos += putLong(lo, scratch, 0); + /* address range */ + return pos + putLong(hi - lo, scratch, 0); } else { - pos = putInt(0, buffer, pos); // dummy length - pos = putInt(0, buffer, pos); // CIE_offset - pos = putRelocatableCodeOffset(lo, buffer, pos); // initial address - return putLong(hi - lo, buffer, pos); // address range + /* dummy length */ + pos = putInt(0, buffer, pos); + /* CIE_offset */ + pos = putInt(0, buffer, pos); + /* initial address */ + pos = putRelocatableCodeOffset(lo, buffer, pos); + /* address range */ + return putLong(hi - lo, buffer, pos); } } @@ -338,12 +368,12 @@ public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } - private byte offsetOp(int register) { + private static byte offsetOp(int register) { assert (register >> 6) == 0; return (byte) ((DW_CFA_offset << 6) | register); } - private byte advanceLoc0Op(int offset) { + private static byte advanceLoc0Op(int offset) { assert (offset >= 0 && offset <= 0x3f); return (byte) ((DW_CFA_advance_loc << 6) | offset); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index 58d490853e5b..8f4ab1818ec4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -27,7 +27,7 @@ package com.oracle.objectfile.elf.dwarf; /** - * AArch64-specific generator for debug_frame section + * AArch64-specific section generator for debug_frame section * that knows details of AArch64 registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { @@ -53,9 +53,11 @@ public int getSPIdx() { @Override public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; - // rsp has not been updated - // caller pc is in lr - // register r32 (rpc), r30 (lr) + /* + * rsp has not been updated + * caller pc is in lr + * register r32 (rpc), r30 (lr) + */ pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); return pos; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java index b4b638305b5f..7fabf34ad449 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -27,7 +27,7 @@ package com.oracle.objectfile.elf.dwarf; /** - * x86_64-specific generator for debug_frame section + * x86_64-specific section generator for debug_frame section * that knows details of x86_64 registers and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { @@ -51,13 +51,17 @@ public int getSPIdx() { @Override public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; - // rsp points at the word containing the saved rip - // so the frame base (cfa) is at rsp + 8 (why not - ???) - // def_cfa r7 (sp) offset 8 + /* + * rsp points at the word containing the saved rip + * so the frame base (cfa) is at rsp + 8 (why not - ???) + * def_cfa r7 (sp) offset 8 + */ pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); - // and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa - // (why not -1 ???) - // offset r16 (rip) cfa - 8 + /* + * and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + * (why not -1 ???) + * offset r16 (rip) cfa - 8 + */ pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; } 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 033a09273a68..6a07284cb46a 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 @@ -38,7 +38,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LANG_Java; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; /** - * generator for debug_info section. + * Section generator for debug_info section. */ public class DwarfInfoSectionImpl extends DwarfSectionImpl { /** @@ -57,31 +57,33 @@ public String getSectionName() { @Override public void createContent() { - // we need a single level 0 DIE for each compilation unit (CU) - // Each CU's Level 0 DIE is preceded by a fixed header: - // and terminated by a null DIE - // uint32 length ......... excluding this length field - // uint16 dwarf_version .. always 2 ?? - // uint32 abbrev offset .. always 0 ?? - // uint8 address_size .... always 8 - // * ................ sequence of top-level and nested child entries - // ............ == 0 - // - // a DIE is a recursively defined structure - // it starts with a code for the associated - // abbrev entry followed by a series of attribute - // values as determined by the entry terminated by - // a null value and followed by zero or more child - // DIEs (zero iff has_children == no_children) - // - // LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE - // * ....... value sequence as determined by abbrev entry - // * ................... sequence of child DIEs (if appropriate) - // ............. == 0 - // - // note that a null_DIE looks like - // LEB128 abbrev_code ....... == 0 - // i.e. it also looks like a null_value + /* + * we need a single level 0 DIE for each compilation unit (CU) + * Each CU's Level 0 DIE is preceded by a fixed header: + * and terminated by a null DIE + * uint32 length ......... excluding this length field + * uint16 dwarf_version .. always 2 ?? + * uint32 abbrev offset .. always 0 ?? + * uint8 address_size .... always 8 + * * ................ sequence of top-level and nested child entries + * ............ == 0 + * + * a DIE is a recursively defined structure + * it starts with a code for the associated + * abbrev entry followed by a series of attribute + * values as determined by the entry terminated by + * a null value and followed by zero or more child + * DIEs (zero iff has_children == no_children) + * + * LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + * * ....... value sequence as determined by abbrev entry + * * ................... sequence of child DIEs (if appropriate) + * ............. == 0 + * + * note that a null_DIE looks like + * LEB128 abbrev_code ....... == 0 + * i.e. it also looks like a null_value + */ byte[] buffer = null; int pos = 0; @@ -91,7 +93,9 @@ public void createContent() { pos = writeCUHeader(buffer, pos); assert pos == lengthPos + DW_DIE_HEADER_SIZE; pos = writeCU(classEntry, buffer, pos); - // no need to backpatch length at lengthPos + /* + * no need to backpatch length at lengthPos + */ } buffer = new byte[pos]; super.setContent(buffer); @@ -108,15 +112,19 @@ public void writeContent() { debug(" [0x%08x] DEBUG_INFO\n", pos); debug(" [0x%08x] size = 0x%08x\n", pos, size); for (ClassEntry classEntry : getPrimaryClasses()) { - // save the offset of this file's CU so it can - // be used when writing the aranges section + /* + * save the offset of this file's CU so it can + * be used when writing the aranges section + */ classEntry.setCUIndex(pos); int lengthPos = pos; pos = writeCUHeader(buffer, pos); debug(" [0x%08x] Compilation Unit\n", pos, size); assert pos == lengthPos + DW_DIE_HEADER_SIZE; pos = writeCU(classEntry, buffer, pos); - // backpatch length at lengthPos (excluding length field) + /* + * backpatch length at lengthPos (excluding length field) + */ patchLength(lengthPos, buffer, pos); } assert pos == size; @@ -125,15 +133,23 @@ public void writeContent() { public int writeCUHeader(byte[] buffer, int p) { int pos = p; if (buffer == null) { - pos += putInt(0, scratch, 0); // CU length - pos += putShort(DW_VERSION_2, scratch, 0); // dwarf version - pos += putInt(0, scratch, 0); // abbrev offset - return pos + putByte((byte) 8, scratch, 0); // address size + /* CU length */ + pos += putInt(0, scratch, 0); + /* dwarf version */ + pos += putShort(DW_VERSION_2, scratch, 0); + /* abbrev offset */ + pos += putInt(0, scratch, 0); + /* address size */ + return pos + putByte((byte) 8, scratch, 0); } else { - pos = putInt(0, buffer, pos); // CU length - pos = putShort(DW_VERSION_2, buffer, pos); // dwarf version - pos = putInt(0, buffer, pos); // abbrev offset - return putByte((byte) 8, buffer, pos); // address size + /* CU length */ + pos = putInt(0, buffer, pos); + /* dwarf version */ + pos = putShort(DW_VERSION_2, buffer, pos); + /* abbrev offset */ + pos = putInt(0, buffer, pos); + /* address size */ + return putByte((byte) 8, buffer, pos); } } @@ -155,7 +171,9 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { for (PrimaryEntry primaryEntry : classPrimaryEntries) { pos = writePrimary(primaryEntry, buffer, pos); } - // write a terminating null attribute for the the level 2 primaries + /* + * write a terminating null attribute for the the level 2 primaries + */ return writeAttrNull(buffer, pos); } @@ -171,7 +189,9 @@ public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { pos = writeAttrAddress(primary.getLo(), buffer, pos); debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); pos = writeAttrAddress(primary.getHi(), buffer, pos); - // need to pass true only if method is public + /* + * need to pass true only if method is public + */ debug(" [0x%08x] external true\n", pos); return writeFlag(DW_FLAG_true, buffer, pos); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 7ae876f3e05f..d19ce896362d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -36,7 +36,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; /** - * generator for debug_line section. + * Section generator for debug_line section. */ public class DwarfLineSectionImpl extends DwarfSectionImpl { /** @@ -59,31 +59,72 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { private static final int DW_LN_OPCODE_BASE = 13; /* - * standard opcodes defined by Dwarf 2 - */ - private static final byte DW_LNS_undefined = 0; // 0 can be returned to indicate an - // invalid opcode - private static final byte DW_LNS_extended_prefix = 0; // 0 can be inserted as a prefix for - // extended opcodes - private static final byte DW_LNS_copy = 1; // append current state as matrix row - // 0 args - private static final byte DW_LNS_advance_pc = 2; // increment address 1 uleb arg - private static final byte DW_LNS_advance_line = 3; // increment line 1 sleb arg - private static final byte DW_LNS_set_file = 4; // set file 1 uleb arg - private static final byte DW_LNS_set_column = 5; // set column 1 uleb arg - private static final byte DW_LNS_negate_stmt = 6; // flip is_stmt 0 args - private static final byte DW_LNS_set_basic_block = 7; // set end sequence and copy row - private static final byte DW_LNS_const_add_pc = 8; // increment address as per opcode - // 255 0 args - private static final byte DW_LNS_fixed_advance_pc = 9; // increment address 1 ushort arg + * standard opcodes defined by Dwarf 2 + */ + /* + * 0 can be returned to indicate an invalid opcode + */ + private static final byte DW_LNS_undefined = 0; + /* + * 0 can be inserted as a prefix for extended opcodes + */ + private static final byte DW_LNS_extended_prefix = 0; + /* + * append current state as matrix row 0 args + */ + private static final byte DW_LNS_copy = 1; + /* + * increment address 1 uleb arg + */ + private static final byte DW_LNS_advance_pc = 2; + /* + * increment line 1 sleb arg + */ + private static final byte DW_LNS_advance_line = 3; + /* + * set file 1 uleb arg + */ + private static final byte DW_LNS_set_file = 4; + /* + * set column 1 uleb arg + */ + private static final byte DW_LNS_set_column = 5; + /* + * flip is_stmt 0 args + */ + private static final byte DW_LNS_negate_stmt = 6; + /* + * set end sequence and copy row 0 args + */ + private static final byte DW_LNS_set_basic_block = 7; + /* + * increment address as per opcode 255 0 args + */ + private static final byte DW_LNS_const_add_pc = 8; + /* + * increment address 1 ushort arg + */ + private static final byte DW_LNS_fixed_advance_pc = 9; /* - * extended opcodes defined by Dwarf 2 - */ - // private static final byte DW_LNE_undefined = 0; // there is no extended opcode 0 - private static final byte DW_LNE_end_sequence = 1; // end sequence of addresses - private static final byte DW_LNE_set_address = 2; // there is no extended opcode 0 - private static final byte DW_LNE_define_file = 3; // there is no extended opcode 0 + * extended opcodes defined by Dwarf 2 + */ + /* + * there is no extended opcode 0 + */ + // private static final byte DW_LNE_undefined = 0; + /* + * end sequence of addresses + */ + private static final byte DW_LNE_end_sequence = 1; + /* + * set address as explicit long argument + */ + private static final byte DW_LNE_set_address = 2; + /* + * set file as explicit string argument + */ + private static final byte DW_LNE_define_file = 3; DwarfLineSectionImpl(DwarfSections dwarfSections) { super(dwarfSections); @@ -96,10 +137,14 @@ public String getSectionName() { @Override public void createContent() { - // we need to create a header, dir table, file table and line - // number table encoding for each CU + /* + * we need to create a header, dir table, file table and line + * number table encoding for each CU + */ - // write entries for each file listed in the primary list + /* + * write entries for each file listed in the primary list + */ int pos = 0; for (ClassEntry classEntry : getPrimaryClasses()) { int startPos = pos; @@ -119,66 +164,82 @@ public void createContent() { } public int headerSize() { - // header size is standard 31 bytes - // uint32 total_length - // uint16 version - // uint32 prologue_length - // uint8 min_insn_length - // uint8 default_is_stmt - // int8 line_base - // uint8 line_range - // uint8 opcode_base - // uint8 li_opcode_base - // uint8[opcode_base-1] standard_opcode_lengths + /* + * header size is standard 31 bytes + * uint32 total_length + * uint16 version + * uint32 prologue_length + * uint8 min_insn_length + * uint8 default_is_stmt + * int8 line_base + * uint8 line_range + * uint8 opcode_base + * uint8 li_opcode_base + * uint8[opcode_base-1] standard_opcode_lengths + */ return DW_LN_HEADER_SIZE; } public int computeDirTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings + /* + * table contains a sequence of 'nul'-terminated + * dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated + * file name bytes followed by an extra 'nul' + * + * for now we assume dir and file names are ASCII + * byte strings + */ int dirSize = 0; for (DirEntry dir : classEntry.getLocalDirs()) { dirSize += dir.getPath().length() + 1; } - // allow for separator nul + /* + * allow for separator nul + */ dirSize++; return dirSize; } public int computeFileTableSize(ClassEntry classEntry) { - // table contains a sequence of 'nul'-terminated - // dir name bytes followed by an extra 'nul' - // and then a sequence of 'nul'-terminated - // file name bytes followed by an extra 'nul' - - // for now we assume dir and file names are ASCII - // byte strings + /* + * table contains a sequence of 'nul'-terminated + * dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated + * file name bytes followed by an extra 'nul' + + * for now we assume dir and file names are ASCII + * byte strings + */ int fileSize = 0; for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we want the file base name excluding path + /* + * we want the file base name excluding path + */ String baseName = localEntry.getBaseName(); int length = baseName.length(); fileSize += length + 1; DirEntry dirEntry = localEntry.dirEntry; int idx = classEntry.localDirsIdx(dirEntry); fileSize += putULEB(idx, scratch, 0); - // the two zero timestamps require 1 byte each + /* + * the two zero timestamps require 1 byte each + */ fileSize += 2; } - // allow for terminator nul + /* + * allow for terminator nul + */ fileSize++; return fileSize; } public int computeLineNUmberTableSize(ClassEntry classEntry) { - // sigh -- we have to do this by generating the - // content even though we cannot write it into a byte[] + /* + * sigh -- we have to do this by generating the + * content even though we cannot write it into a byte[] + */ return writeLineNumberTable(classEntry, null, 0); } @@ -189,9 +250,11 @@ public byte[] getOrDecideContent(Map alre if (decisionMap != null) { Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { - // this may not be the final vaddr for the text segment - // but it will be close enough to make debug easier - // i.e. to within a 4k page or two + /* + * this may not be the final vaddr for the text segment + * but it will be close enough to make debug easier + * i.e. to within a 4k page or two + */ debugTextBase = ((Number) valueObj).longValue(); } } @@ -228,52 +291,88 @@ public void writeContent() { public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - // 4 ubyte length field + /* + * 4 ubyte length field + */ pos = putInt(classEntry.getTotalSize() - 4, buffer, pos); - // 2 ubyte version is always 2 + /* + * 2 ubyte version is always 2 + */ pos = putShort(DW_VERSION_2, buffer, pos); - // 4 ubyte prologue length includes rest of header and - // dir + file table section + /* + * 4 ubyte prologue length includes rest of header and + * dir + file table section + */ int prologueSize = classEntry.getLinePrologueSize() - 6; pos = putInt(prologueSize, buffer, pos); - // 1 ubyte min instruction length is always 1 + /* + * 1 ubyte min instruction length is always 1 + */ pos = putByte((byte) 1, buffer, pos); - // 1 byte default is_stmt is always 1 + /* + * 1 byte default is_stmt is always 1 + */ pos = putByte((byte) 1, buffer, pos); - // 1 byte line base is always -5 + /* + * 1 byte line base is always -5 + */ pos = putByte((byte) DW_LN_LINE_BASE, buffer, pos); - // 1 ubyte line range is always 14 giving range -5 to 8 + /* + * 1 ubyte line range is always 14 giving range -5 to 8 + */ pos = putByte((byte) DW_LN_LINE_RANGE, buffer, pos); - // 1 ubyte opcode base is always 13 + /* + * 1 ubyte opcode base is always 13 + */ pos = putByte((byte) DW_LN_OPCODE_BASE, buffer, pos); - // specify opcode arg sizes for the standard opcodes - putByte((byte) 0, buffer, pos); // DW_LNS_copy - putByte((byte) 1, buffer, pos + 1); // DW_LNS_advance_pc - putByte((byte) 1, buffer, pos + 2); // DW_LNS_advance_line - putByte((byte) 1, buffer, pos + 3); // DW_LNS_set_file - putByte((byte) 1, buffer, pos + 4); // DW_LNS_set_column - putByte((byte) 0, buffer, pos + 5); // DW_LNS_negate_stmt - putByte((byte) 0, buffer, pos + 6); // DW_LNS_set_basic_block - putByte((byte) 0, buffer, pos + 7); // DW_LNS_const_add_pc - putByte((byte) 1, buffer, pos + 8); // DW_LNS_fixed_advance_pc - putByte((byte) 0, buffer, pos + 9); // DW_LNS_end_sequence - putByte((byte) 0, buffer, pos + 10); // DW_LNS_set_address - pos = putByte((byte) 1, buffer, pos + 11); // DW_LNS_define_file + /* + * specify opcode arg sizes for the standard opcodes + */ + /* DW_LNS_copy */ + putByte((byte) 0, buffer, pos); + /* DW_LNS_advance_pc */ + putByte((byte) 1, buffer, pos + 1); + /* DW_LNS_advance_line */ + putByte((byte) 1, buffer, pos + 2); + /* DW_LNS_set_file */ + putByte((byte) 1, buffer, pos + 3); + /* DW_LNS_set_column */ + putByte((byte) 1, buffer, pos + 4); + /* DW_LNS_negate_stmt */ + putByte((byte) 0, buffer, pos + 5); + /* DW_LNS_set_basic_block */ + putByte((byte) 0, buffer, pos + 6); + /* DW_LNS_const_add_pc */ + putByte((byte) 0, buffer, pos + 7); + /* DW_LNS_fixed_advance_pc */ + putByte((byte) 1, buffer, pos + 8); + /* DW_LNS_end_sequence */ + putByte((byte) 0, buffer, pos + 9); + /* DW_LNS_set_address */ + putByte((byte) 0, buffer, pos + 10); + /* DW_LNS_define_file */ + pos = putByte((byte) 1, buffer, pos + 11); return pos; } public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; debug(" [0x%08x] Dir Name\n", pos); - // write out the list of dirs referenced form this file entry + /* + * write out the list of dirs referenced form this file entry + */ int dirIdx = 1; for (DirEntry dir : classEntry.getLocalDirs()) { - // write nul terminated string text. + /* + * write nul terminated string text. + */ debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); pos = putAsciiStringBytes(dir.getPath(), buffer, pos); dirIdx++; } - // separate dirs from files with a nul + /* + * separate dirs from files with a nul + */ pos = putByte((byte) 0, buffer, pos); return pos; } @@ -283,7 +382,9 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { int fileIdx = 1; debug(" [0x%08x] Entry Dir Name\n", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { - // we need the file name minus path, the associated dir index, and 0 for time stamps + /* + * we need the file name minus path, the associated dir index, and 0 for time stamps + */ String baseName = localEntry.getBaseName(); DirEntry dirEntry = localEntry.dirEntry; int dirIdx = classEntry.localDirsIdx(dirEntry); @@ -294,7 +395,9 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putULEB(0, buffer, pos); fileIdx++; } - // terminate files with a nul + /* + * terminate files with a nul + */ pos = putByte((byte) 0, buffer, pos); return pos; } @@ -304,7 +407,9 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - // the primary file entry should always be first in the local files list + /* + * the primary file entry should always be first in the local files list + */ assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; String primaryClassName = classEntry.getClassName(); String primaryFileName = classEntry.getFileName(); @@ -315,10 +420,12 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { Range primaryRange = primaryEntry.getPrimary(); assert primaryRange.getFileName().equals(primaryFileName); - // each primary represents a method i.e. a contiguous - // sequence of subranges. we assume the default state - // at the start of each sequence because we always post an - // end_sequence when we finish all the subranges in the method + /* + * each primary represents a method i.e. a contiguous + * sequence of subranges. we assume the default state + * at the start of each sequence because we always post an + * end_sequence when we finish all the subranges in the method + */ long line = primaryRange.getLine(); if (line < 0 && primaryEntry.getSubranges().size() > 0) { line = primaryEntry.getSubranges().get(0).getLine(); @@ -328,23 +435,33 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { } long address = primaryRange.getLo(); - // set state for primary + /* + * set state for primary + */ debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), primaryRange.getLine()); - // initialize and write a row for the start of the primary method + /* + * initialize and write a row for the start of the primary method + */ pos = putSetFile(file, fileIdx, buffer, pos); pos = putSetBasicBlock(buffer, pos); - // address is currently 0 + /* + * address is currently 0 + */ pos = putSetAddress(address, buffer, pos); - // state machine value of line is currently 1 - // increment to desired line + /* + * state machine value of line is currently 1 + * increment to desired line + */ if (line != 1) { pos = putAdvanceLine(line - 1, buffer, pos); } pos = putCopy(buffer, pos); - // now write a row for each subrange lo and hi + /* + * now write a row for each subrange lo and hi + */ for (Range subrange : primaryEntry.getSubranges()) { assert subrange.getLo() >= primaryRange.getLo(); assert subrange.getHi() <= primaryRange.getHi(); @@ -356,66 +473,90 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { long subAddressHi = subrange.getHi(); debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); if (subLine < 0) { - // no line info so stay at previous file:line + /* + * no line info so stay at previous file:line + */ subLine = line; subfile = file; subFileIdx = fileIdx; debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); } - // there is a temptation to append end sequence at here - // when the hiAddress lies strictly between the current - // address and the start of the next subrange because, - // ostensibly, we have void space between the end of - // the current subrange and the start of the next one. - // however, debug works better if we treat all the insns up - // to the next range start as belonging to the current line - // - // if we have to update to a new file then do so + /* + * there is a temptation to append end sequence at here + * when the hiAddress lies strictly between the current + * address and the start of the next subrange because, + * ostensibly, we have void space between the end of + * the current subrange and the start of the next one. + * however, debug works better if we treat all the insns up + * to the next range start as belonging to the current line + * + * if we have to update to a new file then do so + */ if (subFileIdx != fileIdx) { - // update the current file + /* + * update the current file + */ pos = putSetFile(subfile, subFileIdx, buffer, pos); file = subfile; fileIdx = subFileIdx; } - // check if we can advance line and/or address in - // one byte with a special opcode + /* + * check if we can advance line and/or address in + * one byte with a special opcode + */ long lineDelta = subLine - line; long addressDelta = subAddressLo - address; byte opcode = isSpecialOpcode(addressDelta, lineDelta); if (opcode != DW_LNS_undefined) { - // ignore pointless write when addressDelta == lineDelta == 0 + /* + * ignore pointless write when addressDelta == lineDelta == 0 + */ if (addressDelta != 0 || lineDelta != 0) { pos = putSpecialOpcode(opcode, buffer, pos); } } else { - // does it help to divide and conquer using - // a fixed address increment + /* + * does it help to divide and conquer using + * a fixed address increment + */ int remainder = isConstAddPC(addressDelta); if (remainder > 0) { pos = putConstAddPC(buffer, pos); - // the remaining address can be handled with a - // special opcode but what about the line delta + /* + * the remaining address can be handled with a + * special opcode but what about the line delta + */ opcode = isSpecialOpcode(remainder, lineDelta); if (opcode != DW_LNS_undefined) { - // address remainder and line now fit + /* + * address remainder and line now fit + */ pos = putSpecialOpcode(opcode, buffer, pos); } else { - // ok, bump the line separately then use a - // special opcode for the address remainder + /* + * ok, bump the line separately then use a + * special opcode for the address remainder + */ opcode = isSpecialOpcode(remainder, 0); assert opcode != DW_LNS_undefined; pos = putAdvanceLine(lineDelta, buffer, pos); pos = putSpecialOpcode(opcode, buffer, pos); } } else { - // increment line and pc separately + /* + * increment line and pc separately + */ if (lineDelta != 0) { pos = putAdvanceLine(lineDelta, buffer, pos); } - // n.b. we might just have had an out of range line increment - // with a zero address increment + /* + * n.b. we might just have had an out of range line increment + * with a zero address increment + */ if (addressDelta > 0) { - // see if we can use a ushort for the increment + /* + * see if we can use a ushort for the increment + */ if (isFixedAdvancePC(addressDelta)) { pos = putFixedAdvancePC((short) addressDelta, buffer, pos); } else { @@ -425,14 +566,20 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putCopy(buffer, pos); } } - // move line and address range on + /* + * move line and address range on + */ line += lineDelta; address += addressDelta; } - // append a final end sequence just below the next primary range + /* + * append a final end sequence just below the next primary range + */ if (address < primaryRange.getHi()) { long addressDelta = primaryRange.getHi() - address; - // increment address before we write the end sequence + /* + * increment address before we write the end sequence + */ pos = putAdvancePC(addressDelta, buffer, pos); } pos = putEndSequence(buffer, pos); @@ -569,7 +716,9 @@ public int putEndSequence(byte[] buffer, int p) { int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = pos + putULEB(1, scratch, 0); return pos + putByte(opcode, scratch, 0); } else { @@ -578,7 +727,9 @@ public int putEndSequence(byte[] buffer, int p) { debugLine = 1; debugCopyCount = 0; pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = putULEB(1, buffer, pos); return putByte(opcode, buffer, pos); } @@ -589,7 +740,9 @@ public int putSetAddress(long arg, byte[] buffer, int p) { int pos = p; if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = pos + putULEB(9, scratch, 0); pos = pos + putByte(opcode, scratch, 0); return pos + putLong(arg, scratch, 0); @@ -597,7 +750,9 @@ public int putSetAddress(long arg, byte[] buffer, int p) { debugAddress = debugTextBase + (int) arg; debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert extended insn byte count as ULEB + /* + * insert extended insn byte count as ULEB + */ pos = putULEB(9, buffer, pos); pos = putByte(opcode, buffer, pos); return putRelocatableCodeOffset(arg, buffer, pos); @@ -607,7 +762,9 @@ public int putSetAddress(long arg, byte[] buffer, int p) { public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; int pos = p; - // calculate bytes needed for opcode + args + /* + * calculate bytes needed for opcode + args + */ int fileBytes = file.length() + 1; long insnBytes = 1; insnBytes += fileBytes; @@ -616,15 +773,21 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] insnBytes += putULEB(uleb3, scratch, 0); if (buffer == null) { pos = pos + putByte(DW_LNS_extended_prefix, scratch, 0); - // write insnBytes as a ULEB + /* + * write insnBytes as a ULEB + */ pos += putULEB(insnBytes, scratch, 0); return pos + (int) insnBytes; } else { debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); pos = putByte(DW_LNS_extended_prefix, buffer, pos); - // insert insn length as uleb + /* + * insert insn length as uleb + */ pos = putULEB(insnBytes, buffer, pos); - // insert opcode and args + /* + * insert opcode and args + */ pos = putByte(opcode, buffer, pos); pos = putAsciiStringBytes(file, buffer, pos); pos = putULEB(uleb1, buffer, pos); @@ -633,17 +796,17 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] } } - public int opcodeId(byte opcode) { + public static int opcodeId(byte opcode) { int iopcode = opcode & 0xff; return iopcode - DW_LN_OPCODE_BASE; } - public int opcodeAddress(byte opcode) { + public static int opcodeAddress(byte opcode) { int iopcode = opcode & 0xff; return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; } - public int opcodeLine(byte opcode) { + public static int opcodeLine(byte opcode) { int iopcode = opcode & 0xff; return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } @@ -667,15 +830,17 @@ public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - public byte isSpecialOpcode(long addressDelta, long lineDelta) { + public static byte isSpecialOpcode(long addressDelta, long lineDelta) { if (addressDelta < 0) { return DW_LNS_undefined; } if (lineDelta >= DW_LN_LINE_BASE) { long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; if (offsetLineDelta < DW_LN_LINE_RANGE) { - // line_delta can be encoded - // check if address is ok + /* + * line_delta can be encoded + * check if address is ok + */ if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; if (opcode <= 255) { @@ -685,11 +850,13 @@ public byte isSpecialOpcode(long addressDelta, long lineDelta) { } } - // return invalid opcode + /* + * answer no by returning an invalid opcode + */ return DW_LNS_undefined; } - public int isConstAddPC(long addressDelta) { + public static int isConstAddPC(long addressDelta) { if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { return 0; } @@ -700,7 +867,7 @@ public int isConstAddPC(long addressDelta) { } } - public boolean isFixedAdvancePC(long addressDiff) { + public static boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } 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 b3a270fe5682..b508ef12f6a9 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 @@ -33,6 +33,7 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.elf.ELFObjectFile; +import java.nio.ByteOrder; import java.util.Map; import java.util.Set; @@ -79,13 +80,17 @@ public DwarfSectionImpl(DwarfSections dwarfSections) { @Override public boolean isLoadable() { - // even though we're a progbits section impl we're not actually loadable + /* + * even though we're a progbits section impl we're not actually loadable + */ return false; } public void checkDebug(int pos) { - // if the env var relevant to this element - // type is set then switch on debugging + /* + * if the env var relevant to this element + * type is set then switch on debugging + */ String name = getSectionName(); String envVarName = "DWARF_" + name.substring(1).toUpperCase(); if (System.getenv(envVarName) != null) { @@ -101,7 +106,13 @@ protected void debug(String format, Object... args) { } } - // base level put methods that assume a non-null buffer + protected boolean littleEndian() { + return dwarfSections.getByteOrder() == ByteOrder.LITTLE_ENDIAN; + } + + /* + * base level put methods that assume a non-null buffer + */ public int putByte(byte b, byte[] buffer, int p) { int pos = p; @@ -111,36 +122,61 @@ public int putByte(byte b, byte[] buffer, int p) { public int putShort(short s, byte[] buffer, int p) { int pos = p; - buffer[pos++] = (byte) (s & 0xff); - buffer[pos++] = (byte) ((s >> 8) & 0xff); + if (littleEndian()) { + buffer[pos++] = (byte) (s & 0xff); + buffer[pos++] = (byte) ((s >> 8) & 0xff); + } else { + buffer[pos++] = (byte) ((s >> 8) & 0xff); + buffer[pos++] = (byte) (s & 0xff); + } return pos; } public int putInt(int i, byte[] buffer, int p) { int pos = p; - buffer[pos++] = (byte) (i & 0xff); - buffer[pos++] = (byte) ((i >> 8) & 0xff); - buffer[pos++] = (byte) ((i >> 16) & 0xff); - buffer[pos++] = (byte) ((i >> 24) & 0xff); + if (littleEndian()) { + buffer[pos++] = (byte) (i & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 24) & 0xff); + } else { + buffer[pos++] = (byte) ((i >> 24) & 0xff); + buffer[pos++] = (byte) ((i >> 16) & 0xff); + buffer[pos++] = (byte) ((i >> 8) & 0xff); + buffer[pos++] = (byte) (i & 0xff); + } return pos; } public int putLong(long l, byte[] buffer, int p) { int pos = p; - buffer[pos++] = (byte) (l & 0xff); - buffer[pos++] = (byte) ((l >> 8) & 0xff); - buffer[pos++] = (byte) ((l >> 16) & 0xff); - buffer[pos++] = (byte) ((l >> 24) & 0xff); - buffer[pos++] = (byte) ((l >> 32) & 0xff); - buffer[pos++] = (byte) ((l >> 40) & 0xff); - buffer[pos++] = (byte) ((l >> 48) & 0xff); - buffer[pos++] = (byte) ((l >> 56) & 0xff); + if (littleEndian()) { + buffer[pos++] = (byte) (l & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 56) & 0xff); + } else { + buffer[pos++] = (byte) ((l >> 56) & 0xff); + buffer[pos++] = (byte) ((l >> 48) & 0xff); + buffer[pos++] = (byte) ((l >> 40) & 0xff); + buffer[pos++] = (byte) ((l >> 32) & 0xff); + buffer[pos++] = (byte) ((l >> 16) & 0xff); + buffer[pos++] = (byte) ((l >> 24) & 0xff); + buffer[pos++] = (byte) ((l >> 8) & 0xff); + buffer[pos++] = (byte) (l & 0xff); + } return pos; } public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { int pos = p; - // mark address so it is relocated relative to the start of the text segment + /* + * mark address so it is relocated relative to the start of the text segment + */ markRelocationSite(pos, 8, ObjectFile.RelocationKind.DIRECT, TEXT_SECTION_NAME, false, Long.valueOf(l)); pos = putLong(0, buffer, pos); return pos; @@ -200,7 +236,9 @@ public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { return pos; } - // common write methods that check for a null buffer + /* + * common write methods that check for a null buffer + */ public void patchLength(int lengthPos, byte[] buffer, int pos) { if (buffer != null) { @@ -296,10 +334,14 @@ public int writeAttrNull(byte[] buffer, int pos) { @Override public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - // ensure content byte[] has been created before calling super method + /* + * ensure content byte[] has been created before calling super method + */ createContent(); - // ensure content byte[] has been written before calling super method + /* + * ensure content byte[] has been written before calling super method + */ writeContent(); return super.getOrDecideContent(alreadyDecided, contentHint); @@ -313,12 +355,16 @@ public Set getDependencies(Map dirsIndex = new HashMap<>(); - // The obvious traversal structure for debug records is: - // - // 1) by top level compiled method (primary Range) ordered by ascending address - // 2) by inlined method (sub range) within top level method ordered by ascending address - // - // these can be used to ensure that all debug records are generated in increasing address order - // - // An alternative traversal option is - // - // 1) by top level class (String id) - // 2) by top level compiled method (primary Range) within a class ordered by ascending address - // 3) by inlined method (sub range) within top level method ordered by ascending address - // - // this relies on the (current) fact that methods of a given class always appear - // in a single continuous address range with no intervening code from other methods - // or data values. this means we can treat each class as a compilation unit, allowing - // data common to all methods of the class to be shared. - // - // A third option appears to be to traverse via files, then top level class within file etc. - // Unfortunately, files cannot be treated as the compilation unit. A file F may contain - // multiple classes, say C1 and C2. There is no guarantee that methods for some other - // class C' in file F' will not be compiled into the address space interleaved between - // methods of C1 and C2. That is a shame because generating debug info records one file at a - // time would allow more sharing e.g. enabling all classes in a file to share a single copy - // of the file and dir tables. + /* + * The obvious traversal structure for debug records is: + * + * 1) by top level compiled method (primary Range) ordered by ascending address + * 2) by inlined method (sub range) within top level method ordered by ascending address + * + * these can be used to ensure that all debug records are generated in increasing address order + * + * An alternative traversal option is + * + * 1) by top level class (String id) + * 2) by top level compiled method (primary Range) within a class ordered by ascending address + * 3) by inlined method (sub range) within top level method ordered by ascending address + * + * this relies on the (current) fact that methods of a given class always appear + * in a single continuous address range with no intervening code from other methods + * or data values. this means we can treat each class as a compilation unit, allowing + * data common to all methods of the class to be shared. + * + * A third option appears to be to traverse via files, then top level class within file etc. + * Unfortunately, files cannot be treated as the compilation unit. A file F may contain + * multiple classes, say C1 and C2. There is no guarantee that methods for some other + * class C' in file F' will not be compiled into the address space interleaved between + * methods of C1 and C2. That is a shame because generating debug info records one file at a + * time would allow more sharing e.g. enabling all classes in a file to share a single copy + * of the file and dir tables. + */ /** * list of class entries detailing class info for primary ranges. @@ -291,17 +324,23 @@ public int debugStringIndex(String string) { * ObjectFile client */ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - // DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); - // for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { - // install types - // } - - // ensure we have a null string in the string section + /* + * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); + * for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { + * install types + * } + */ + + /* + * ensure we have a null string in the string section + */ uniqueDebugString(""); DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { - // primary file name and full method name need to be written to the debug_str section + /* + * primary file name and full method name need to be written to the debug_str section + */ String fileName = debugCodeInfo.fileName(); String className = debugCodeInfo.className(); String methodName = debugCodeInfo.methodName(); @@ -311,9 +350,11 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - // System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, - // returnTypeName, className, methodName, paramNames, fileName); - // create an infoSection entry for the method + /* + * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, + * returnTypeName, className, methodName, paramNames, fileName); + * create an infoSection entry for the method + */ addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { String fileNameAtLine = debugLineInfo.fileName(); @@ -322,25 +363,33 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); int line = debugLineInfo.line(); - // record all subranges even if they have no line or file so we at least get a - // symbol for them + /* + * record all subranges even if they have no line or file so we at least get a + * symbol for them + */ Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); } } - // DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - // for (DebugDataInfo debugDataInfo : dataInfoProvider) { - // install details of heap elements - // String name = debugDataInfo.toString(); - // } + /* + * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); + * for (DebugDataInfo debugDataInfo : dataInfoProvider) { + * install details of heap elements + * String name = debugDataInfo.toString(); + * } + */ } public ClassEntry ensureClassEntry(Range range) { String className = range.getClassName(); - // see if we already have an entry + /* + * see if we already have an entry + */ ClassEntry classEntry = primaryClassesIndex.get(className); if (classEntry == null) { - // create and index the entry associating it with the right file + /* + * create and index the entry associating it with the right file + */ FileEntry fileEntry = ensureFileEntry(range); classEntry = new ClassEntry(className, fileEntry); primaryClasses.add(classEntry); @@ -352,7 +401,9 @@ public ClassEntry ensureClassEntry(Range range) { public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); - // ensure we have an entry + /* + * ensure we have an entry + */ FileEntry fileEntry = filesIndex.get(fileName); if (fileEntry == null) { DirEntry dirEntry = ensureDirEntry(fileName); @@ -362,7 +413,9 @@ public FileEntry ensureFileEntry(Range range) { dirEntry); files.add(fileEntry); filesIndex.put(fileName, fileEntry); - // if this is a primary entry then add it to the primary list + /* + * if this is a primary entry then add it to the primary list + */ if (range.isPrimary()) { primaryFiles.add(fileEntry); } else { @@ -386,8 +439,10 @@ public void addSubRange(Range primaryRange, Range subrange) { String className = primaryRange.getClassName(); ClassEntry classEntry = primaryClassesIndex.get(className); FileEntry subrangeEntry = ensureFileEntry(subrange); - // the primary range should already have been seen - // and associated with a primary class entry + /* + * the primary range should already have been seen + * and associated with a primary class entry + */ assert classEntry.primaryIndexFor(primaryRange) != null; classEntry.addSubRange(subrange, subrangeEntry); } @@ -395,7 +450,9 @@ public void addSubRange(Range primaryRange, Range subrange) { public DirEntry ensureDirEntry(String file) { int pathLength = file.lastIndexOf('/'); if (pathLength < 0) { - // no path/package means use dir entry 0 + /* + * no path/package means use dir entry 0 + */ return null; } String filePath = file.substring(0, pathLength); @@ -413,4 +470,7 @@ public StringTable getStringTable() { public LinkedList getPrimaryClasses() { return primaryClasses; } + public ByteOrder getByteOrder() { + return byteOrder; + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 855bca3c749d..0bcdbccb5992 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -96,7 +96,8 @@ public String targetSectionName() { public final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, - LayoutDecision.Kind.VADDR, // add this so we can use the base address + /* add this so we can use the text section base address for debug */ + LayoutDecision.Kind.VADDR, }; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index cd530c68de04..a597a4df17bc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -27,14 +27,20 @@ package com.oracle.objectfile.elf.dwarf; /** - * track debug info associated with a Java source file. + * Tracks debug info associated with a Java source file. */ public class FileEntry { - // the name of the associated file including path + /** + * The name of the associated file including path + */ private String fileName; - // the name of the associated file excluding path + /** + * The name of the associated file excluding path + */ private String baseName; - // the directory entry associated with this file entry + /** + * The directory entry associated with this file entry + */ DirEntry dirEntry; public FileEntry(String fileName, String baseName, DirEntry dirEntry) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java index 6720703cf921..cd356dd00535 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java @@ -33,51 +33,34 @@ import java.util.List; /** - * track debug info associated with a primary method. + * Tracks debug info associated with a primary method. * i.e. a top level compiled method */ public class PrimaryEntry { /** - * the primary range detailed by this object. + * The primary range detailed by this object. */ Range primary; /** - * details of the class owning this range. + * Details of the class owning this range. */ ClassEntry classEntry; /** - * a list of subranges associated with the primary range. + * A list of subranges associated with the primary range. */ List subranges; /** - * a mapping from subranges to their associated file entry. + * A mapping from subranges to their associated file entry. */ HashMap subrangeIndex; /** - * details of of compiled method frame size changes. + * Details of of compiled method frame size changes. */ private List frameSizeInfos; /** - * size of compiled method frame. + * Size of compiled method frame. */ private int frameSize; - /** - * index of debug_info section compilation unit for this file. - */ - private int cuIndex; - /** - * index into debug_line section for associated compilation unit. - */ - private int lineIndex; - /** - * size of line number info prologue region for associated compilation unit. - */ - private int linePrologueSize; - /** - * total size of line number info region for associated compilation unit. - */ - private int totalSize; - public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { this.primary = primary; this.classEntry = classEntry; @@ -85,17 +68,18 @@ public PrimaryEntry(Range primary, List frameSizeInfos, in this.subrangeIndex = new HashMap<>(); this.frameSizeInfos = frameSizeInfos; this.frameSize = frameSize; - // initialize indices into other sections to illegal values - this.cuIndex = -1; - this.lineIndex = -1; } public void addSubRange(Range subrange, FileEntry subFileEntry) { - // we should not see a subrange more than once + /* + * we should not see a subrange more than once + */ assert !subranges.contains(subrange); assert subrangeIndex.get(subrange) == null; - // we need to generate a file table entry - // for all ranges + /* + * we need to generate a file table entry + * for all ranges + */ subranges.add(subrange); subrangeIndex.put(subrange, subFileEntry); } @@ -127,46 +111,4 @@ List getFrameSizeInfos() { int getFrameSize() { return frameSize; } - - void setCUIndex(int cuIndex) { - // should only get set once to a non-negative value - assert cuIndex >= 0; - assert this.cuIndex == -1; - this.cuIndex = cuIndex; - } - - int getCUIndex() { - // should have been set before being read - assert cuIndex >= 0; - return cuIndex; - } - - int getLineIndex() { - // should have been set before being read - assert lineIndex >= 0; - return lineIndex; - } - - void setLineIndex(int lineIndex) { - // should only get set once to a non-negative value - assert lineIndex >= 0; - assert this.lineIndex == -1; - this.lineIndex = lineIndex; - } - - public int getLinePrologueSize() { - return linePrologueSize; - } - - public void setLinePrologueSize(int linePrologueSize) { - this.linePrologueSize = linePrologueSize; - } - - public int getTotalSize() { - return totalSize; - } - - public void setTotalSize(int totalSize) { - this.totalSize = totalSize; - } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 758825272a7e..41c78a176b2d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -27,10 +27,10 @@ package com.oracle.objectfile.elf.dwarf; /** - * details of a specific address range in a compiled method + * Details of a specific address range in a compiled method * either a primary range identifying a whole method * or a sub-range identifying a sequence of - * instructions that belong to an inlined method + * instructions that belong to an inlined method. */ public class Range { @@ -43,18 +43,26 @@ public class Range { private int lo; private int hi; private int line; - // this is null for a primary range + /* + * this is null for a primary range + */ private Range primary; - // create a primary range + /* + * create a primary range + */ Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { this(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); } - // create a primary or secondary range + /* + * create a primary or secondary range + */ Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { - // currently file name and full method name need to go into the debug_str section - // other strings just need to be deduplicated to save space + /* + * currently file name and full method name need to go into the debug_str section + * other strings just need to be deduplicated to save space + */ this.fileName = stringTable.uniqueDebugString(fileName); this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index d9a40dc2b3ed..b7963faf9661 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -27,10 +27,10 @@ package com.oracle.objectfile.elf.dwarf; /** - * class used to retain a unique (up to equals) copy of - * a String and also to flag whether the String needs to be - * located in the .debug_string section and track the offset - * where it gets written. + * Used to retain a unique (up to equals) copy of a + * String. Also flag swhether the String needs to be + * located in the debug_string section and, if so, + * tracks the offset at which it gets written. */ public class StringEntry { private String string; @@ -47,7 +47,9 @@ public String getString() { } public int getOffset() { - // offset must be set before this can be fetched + /* + * offset must be set before this can be fetched + */ assert offset >= 0; return offset; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 87b0af1eb437..1ba2def55f73 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -30,10 +30,10 @@ import java.util.Iterator; /** - * a class which allows incoming strings to be reduced - * to unique (up to equaals) instances and allows marking - * of strings which need to be written to the debug_str - * section and retrieval of the lcoation offset after writing. + * Allows incoming strings to be reduced to unique (up + * to equals) instances and supports marking of strings + * which need to be written to the debug_str section + * and retrieval of the location offset after writing. */ public class StringTable implements Iterable { @@ -44,9 +44,9 @@ public StringTable() { } /** - * ensures a unique instance of a string exists in the + * Wnsures a unique instance of a string exists in the * table, inserting the supplied String if no equivalent - * String is already present. this should only be called + * String is already present. This should only be called * before the string section has been written. * @param string the string to be included in the table * @return the unique instance of the String @@ -56,10 +56,10 @@ public String uniqueString(String string) { } /** - * ensures a unique instance of a string exists in the + * Ensures a unique instance of a string exists in the * table and is marked for inclusion in the debug_str * section, inserting the supplied String if no equivalent - * String is already present. this should only be called + * String is already present. This should only be called * before the string section has been written. * @param string the string to be included in the table * and marked for inclusion in the debug_str section @@ -82,8 +82,8 @@ private String ensureString(String string, boolean addToStrSection) { } /** - * retrieves the offset at which a given string was written - * into the debug_str section. this should only be called + * Retrieves the offset at which a given string was written + * into the debug_str section. This should only be called * after the string section has been written. * @param string * @return the offset or -1 if the string does not diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java deleted file mode 100644 index 51c785b0a98d..000000000000 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/impl.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.oracle.objectfile.elf.dwarf; -public class impl { -} From a6ca2e2222597ee30473385ff798f48a3a406d05 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 11 Feb 2020 16:59:32 +0000 Subject: [PATCH 079/130] start using Path expressions for directories and file names --- .../debuginfo/DebugInfoProvider.java | 96 +++++++++++++++---- .../objectfile/elf/dwarf/ClassEntry.java | 10 +- .../oracle/objectfile/elf/dwarf/DirEntry.java | 12 ++- .../elf/dwarf/DwarfLineSectionImpl.java | 68 ++++++------- .../objectfile/elf/dwarf/DwarfSections.java | 43 ++++----- .../objectfile/elf/dwarf/FileEntry.java | 32 +++---- .../oracle/objectfile/elf/dwarf/Range.java | 22 ++++- .../svm/hosted/image/NativeBootImage.java | 82 ++++++++++------ 8 files changed, 242 insertions(+), 123 deletions(-) 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 13e8cb73dab3..5aff1370bb33 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 @@ -26,6 +26,7 @@ package com.oracle.objectfile.debuginfo; +import java.nio.file.Path; import java.util.List; /** @@ -45,26 +46,63 @@ interface DebugTypeInfo { * access details of a specific compiled method. */ interface DebugCodeInfo { + /** + * @return the name of the file containing a compiled + * method excluding any path + */ String fileName(); - + /** + * @return a relative path to the file containing a compiled + * method derived from its package name or null if the method + * is in the empty package + */ + Path filePath(); + /** + * @return the fully qualified name of the class owning the + * compiled method + */ String className(); - + /** + * @return the name of the compiled method including + * signature + */ String methodName(); - + /** + * @return the lowest address containing code generated for + * the method represented as an offset into the code segment + */ int addressLo(); - + /** + * @return the first address above the code generated for + * the method represented as an offset into the code segment + */ int addressHi(); - + /** + * @return the starting line number for the method + */ int line(); - + /** + * @return a provider detailing line numbers + * addresses within the compiled method + */ DebugLineInfoProvider lineInfoProvider(); - + /** + * @return a string identifying the method parameters + */ String paramNames(); - + /** + * @return a string identifying the method return type + */ String returnTypeName(); - + /** + * @return the size of the method frame between prologue + * and epilogue + */ int getFrameSize(); - + /** + * @return a list of positions at which the stack is extended + * to a full frame or torn down to an empty frame + */ List getFrameSizeChanges(); } @@ -75,19 +113,45 @@ interface DebugDataInfo { } /** - * access details of a specific outer or inlined method at a given line number. + * access details of code generated for a specific outer + * or inlined method at a given line number. */ interface DebugLineInfo { + /** + * @return the name of the file containing the outer + * or inlined method excluding any path + */ String fileName(); - + /** + * @return a relative path to the file containing the outer + * or inlined method derived from its package name or null + * if the method is in the empty package + */ + Path filePath(); + /** + * @return the fully qualified name of the class owning the + * outer or inlined method + */ String className(); - + /** + * @return the name of the outer or inlined method including signature + */ String methodName(); - + /** + * @return the lowest address containing code generated for + * an outer or inlined code segment reported at this line + * represented as an offset into the code segment + */ int addressLo(); - + /** + * @return the first address above the code generated for + * an outer or inlined code segment reported at this line + * represented as an offset into the code segment + */ int addressHi(); - + /** + * @return the line number for the outer or inlined segment + */ int line(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java index 0ff7290cb43f..6d8714c5ae38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java @@ -106,7 +106,7 @@ public ClassEntry(String className, FileEntry fileEntry) { this.localDirsIndex = new HashMap<>(); localFiles.add(fileEntry); localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.dirEntry; + DirEntry dirEntry = fileEntry.getDirEntry(); if (dirEntry != null) { localDirs.add(dirEntry); localDirsIndex.put(dirEntry, localDirs.size()); @@ -144,7 +144,7 @@ void addSubRange(Range subrange, FileEntry subFileEntry) { localFiles.add(subFileEntry); localFilesIndex.put(subFileEntry, localFiles.size()); } - DirEntry dirEntry = subFileEntry.dirEntry; + DirEntry dirEntry = subFileEntry.getDirEntry(); if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { localDirs.add(dirEntry); localDirsIndex.put(dirEntry, localDirs.size()); @@ -167,8 +167,12 @@ String getFileName() { return fileEntry.getFileName(); } + String getFullFileName() { + return fileEntry.getFullName(); + } + String getDirName() { - return fileEntry.getDirName(); + return fileEntry.getPathName(); } void setCUIndex(int cuIndex) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java index dde46b4b8828..c033986b8be6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.elf.dwarf; +import java.nio.file.Path; + /** * Tracks the directory associated with one or * more source files. @@ -38,13 +40,17 @@ * per file. */ public class DirEntry { - private String path; + private Path path; - public DirEntry(String path) { + public DirEntry(Path path) { this.path = path; } - public String getPath() { + public Path getPath() { return path; } + + public String getPathString() { + return path.toString(); + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index d19ce896362d..10305904c0ea 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -147,17 +147,19 @@ public void createContent() { */ int pos = 0; for (ClassEntry classEntry : getPrimaryClasses()) { - int startPos = pos; - classEntry.setLineIndex(startPos); - int headerSize = headerSize(); - int dirTableSize = computeDirTableSize(classEntry); - int fileTableSize = computeFileTableSize(classEntry); - int prologueSize = headerSize + dirTableSize + fileTableSize; - classEntry.setLinePrologueSize(prologueSize); - int lineNumberTableSize = computeLineNUmberTableSize(classEntry); - int totalSize = prologueSize + lineNumberTableSize; - classEntry.setTotalSize(totalSize); - pos += totalSize; + if (classEntry.getFileName().length() != 0) { + int startPos = pos; + classEntry.setLineIndex(startPos); + int headerSize = headerSize(); + int dirTableSize = computeDirTableSize(classEntry); + int fileTableSize = computeFileTableSize(classEntry); + int prologueSize = headerSize + dirTableSize + fileTableSize; + classEntry.setLinePrologueSize(prologueSize); + int lineNumberTableSize = computeLineNUmberTableSize(classEntry); + int totalSize = prologueSize + lineNumberTableSize; + classEntry.setTotalSize(totalSize); + pos += totalSize; + } } byte[] buffer = new byte[pos]; super.setContent(buffer); @@ -193,7 +195,7 @@ public int computeDirTableSize(ClassEntry classEntry) { */ int dirSize = 0; for (DirEntry dir : classEntry.getLocalDirs()) { - dirSize += dir.getPath().length() + 1; + dirSize += dir.getPathString().length() + 1; } /* * allow for separator nul @@ -217,10 +219,10 @@ public int computeFileTableSize(ClassEntry classEntry) { /* * we want the file base name excluding path */ - String baseName = localEntry.getBaseName(); + String baseName = localEntry.getFileName(); int length = baseName.length(); fileSize += length + 1; - DirEntry dirEntry = localEntry.dirEntry; + DirEntry dirEntry = localEntry.getDirEntry(); int idx = classEntry.localDirsIdx(dirEntry); fileSize += putULEB(idx, scratch, 0); /* @@ -270,21 +272,23 @@ public void writeContent() { debug(" [0x%08x] DEBUG_LINE\n", pos); for (ClassEntry classEntry : getPrimaryClasses()) { - int startPos = pos; - assert classEntry.getLineIndex() == startPos; - debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); - pos = writeHeader(classEntry, buffer, pos); - debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); - int dirTablePos = pos; - pos = writeDirTable(classEntry, buffer, pos); - debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); - int fileTablePos = pos; - pos = writeFileTable(classEntry, buffer, pos); - debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); - int lineNumberTablePos = pos; - pos = writeLineNumberTable(classEntry, buffer, pos); - debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); - debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + if (classEntry.getFileName().length() != 0) { + int startPos = pos; + assert classEntry.getLineIndex() == startPos; + debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + pos = writeHeader(classEntry, buffer, pos); + debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + int dirTablePos = pos; + pos = writeDirTable(classEntry, buffer, pos); + debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + int fileTablePos = pos; + pos = writeFileTable(classEntry, buffer, pos); + debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + int lineNumberTablePos = pos; + pos = writeLineNumberTable(classEntry, buffer, pos); + debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); + debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + } } assert pos == buffer.length; } @@ -367,7 +371,7 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { * write nul terminated string text. */ debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); - pos = putAsciiStringBytes(dir.getPath(), buffer, pos); + pos = putAsciiStringBytes(dir.getPathString(), buffer, pos); dirIdx++; } /* @@ -385,8 +389,8 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { /* * we need the file name minus path, the associated dir index, and 0 for time stamps */ - String baseName = localEntry.getBaseName(); - DirEntry dirEntry = localEntry.dirEntry; + String baseName = localEntry.getFileName(); + DirEntry dirEntry = localEntry.getDirEntry(); int dirIdx = classEntry.localDirsIdx(dirEntry); debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); pos = putAsciiStringBytes(baseName, buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index afd996cda14d..42df6ae317cb 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -36,6 +36,7 @@ import com.oracle.objectfile.elf.ELFMachine; import java.nio.ByteOrder; +import java.nio.file.Path; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -234,7 +235,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { /** * index of already seen dirs. */ - private Map dirsIndex = new HashMap<>(); + private Map dirsIndex = new HashMap<>(); /* * The obvious traversal structure for debug records is: @@ -284,7 +285,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { /** * index of already seen files. */ - private Map filesIndex = new HashMap<>(); + private Map filesIndex = new HashMap<>(); /** * indirects this call to the string table. @@ -342,14 +343,16 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * primary file name and full method name need to be written to the debug_str section */ String fileName = debugCodeInfo.fileName(); - String className = debugCodeInfo.className(); + Path filePath = debugCodeInfo.filePath(); + // switch '$' in class names for '.' + String className = debugCodeInfo.className().replaceAll("\\$", "."); String methodName = debugCodeInfo.methodName(); String paramNames = debugCodeInfo.paramNames(); String returnTypeName = debugCodeInfo.returnTypeName(); int lo = debugCodeInfo.addressLo(); int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); - Range primaryRange = new Range(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); + Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); /* * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, * returnTypeName, className, methodName, paramNames, fileName); @@ -358,7 +361,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { String fileNameAtLine = debugLineInfo.fileName(); - String classNameAtLine = debugLineInfo.className(); + Path filePathAtLine = debugLineInfo.filePath(); + // switch '$' in class names for '.' + String classNameAtLine = debugLineInfo.className().replaceAll("\\$", "."); String methodNameAtLine = debugLineInfo.methodName(); int loAtLine = lo + debugLineInfo.addressLo(); int hiAtLine = lo + debugLineInfo.addressHi(); @@ -367,7 +372,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * record all subranges even if they have no line or file so we at least get a * symbol for them */ - Range subRange = new Range(fileNameAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); + Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); } } @@ -401,18 +406,17 @@ public ClassEntry ensureClassEntry(Range range) { public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); + Path filePath = range.getFilePath(); + Path fileAsPath = range.getFileAsPath(); /* * ensure we have an entry */ - FileEntry fileEntry = filesIndex.get(fileName); + FileEntry fileEntry = filesIndex.get(fileAsPath); if (fileEntry == null) { - DirEntry dirEntry = ensureDirEntry(fileName); - String baseName = (dirEntry == null ? fileName : fileName.substring(dirEntry.getPath().length() + 1)); - fileEntry = new FileEntry(stringTable.uniqueDebugString(fileName), - stringTable.uniqueString(baseName), - dirEntry); + DirEntry dirEntry = ensureDirEntry(filePath); + fileEntry = new FileEntry(fileName, dirEntry); files.add(fileEntry); - filesIndex.put(fileName, fileEntry); + filesIndex.put(fileAsPath, fileEntry); /* * if this is a primary entry then add it to the primary list */ @@ -420,7 +424,7 @@ public FileEntry ensureFileEntry(Range range) { primaryFiles.add(fileEntry); } else { Range primaryRange = range.getPrimary(); - FileEntry primaryEntry = filesIndex.get(primaryRange.getFileName()); + FileEntry primaryEntry = filesIndex.get(primaryRange.getFileAsPath()); assert primaryEntry != null; } } @@ -447,18 +451,13 @@ public void addSubRange(Range primaryRange, Range subrange) { classEntry.addSubRange(subrange, subrangeEntry); } - public DirEntry ensureDirEntry(String file) { - int pathLength = file.lastIndexOf('/'); - if (pathLength < 0) { - /* - * no path/package means use dir entry 0 - */ + public DirEntry ensureDirEntry(Path filePath) { + if (filePath == null) { return null; } - String filePath = file.substring(0, pathLength); DirEntry dirEntry = dirsIndex.get(filePath); if (dirEntry == null) { - dirEntry = new DirEntry(stringTable.uniqueString(filePath)); + dirEntry = new DirEntry(filePath); dirsIndex.put(filePath, dirEntry); dirs.add(dirEntry); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java index a597a4df17bc..bc53ec654e64 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java @@ -30,34 +30,32 @@ * Tracks debug info associated with a Java source file. */ public class FileEntry { - /** - * The name of the associated file including path - */ private String fileName; - /** - * The name of the associated file excluding path - */ - private String baseName; - /** - * The directory entry associated with this file entry - */ - DirEntry dirEntry; + private DirEntry dirEntry; - public FileEntry(String fileName, String baseName, DirEntry dirEntry) { + public FileEntry(String fileName, DirEntry dirEntry) { this.fileName = fileName; - this.baseName = baseName; this.dirEntry = dirEntry; } + /** + * The name of the associated file excluding path elements. + */ public String getFileName() { return fileName; } - public String getBaseName() { - return baseName; + public String getPathName() { + return getDirEntry().getPathString(); } - String getDirName() { - return (dirEntry != null ? dirEntry.getPath() : ""); + public String getFullName() { + return getDirEntry().getPath().resolve(getFileName()).toString(); + } + /** + * The directory entry associated with this file entry. + */ + public DirEntry getDirEntry() { + return dirEntry; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java index 41c78a176b2d..2608be71322b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.elf.dwarf; +import java.nio.file.Path; +import java.nio.file.Paths; /** * Details of a specific address range in a compiled method * either a primary range identifying a whole method @@ -35,6 +37,7 @@ public class Range { private String fileName; + private Path filePath; private String className; private String methodName; private String paramNames; @@ -51,19 +54,20 @@ public class Range { /* * create a primary range */ - Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { - this(fileName, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); + Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { + this(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); } /* * create a primary or secondary range */ - Range(String fileName, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { + Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { /* * currently file name and full method name need to go into the debug_str section * other strings just need to be deduplicated to save space */ this.fileName = stringTable.uniqueDebugString(fileName); + this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); this.paramNames = stringTable.uniqueString(paramNames); @@ -91,6 +95,18 @@ public String getFileName() { return fileName; } + public Path getFilePath() { + return filePath; + } + + public Path getFileAsPath() { + if (filePath != null) { + return filePath.resolve(fileName); + } else { + return Paths.get(fileName); + } + } + public String getClassName() { return className; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 30c2d5f23ca3..3cef29f16cdd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -39,6 +39,7 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Collection; @@ -62,7 +63,6 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; @@ -1055,32 +1055,41 @@ private class NativeImageDebugCodeInfo implements DebugCodeInfo { @Override public String fileName() { HostedType declaringClass = method.getDeclaringClass(); - String name = declaringClass.getSourceFileName(); - if (name != null) { - // the file name will not include any path - // use the package to create a path prefix - Package pkg = declaringClass.getJavaClass().getPackage(); - if (pkg != null) { - String prefix = pkg.getName(); - prefix = prefix.replace('.', '/'); - name = prefix + "/" + name; + String sourceFileName = declaringClass.getSourceFileName(); + + if (sourceFileName == null) { + String className = declaringClass.getJavaClass().getName(); + int idx = className.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + className = className.substring(idx + 1); } - } else { - // build file name from the class name which includes the package - name = className(); - // try to map inner classes back to their parent class's file - int idx = name.indexOf('$'); + idx = className.indexOf('$'); if (idx == 0) { // name is $XXX so cannot associate with a file - return ""; - } - if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - name = name.substring(0, idx); + // create a path with an empty name + sourceFileName = ""; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + className = className.substring(0, idx); + } + sourceFileName = className + ".java"; } - name = name.replace('.', '/') + ".java"; } - return name; + + return sourceFileName; + } + @Override + public Path filePath() { + HostedType declaringClass = method.getDeclaringClass(); + Package pkg = declaringClass.getJavaClass().getPackage(); + if (pkg != null) { + // use the package name as a path to the file + return Paths.get("", pkg.getName().split("\\.")); + } else { + return null; + } } @Override @@ -1124,7 +1133,7 @@ public int line() { @Override public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { - if (fileName().length() == 0) { + if (fileName().toString().length() == 0) { return () -> new Iterator() { @Override public boolean hasNext() { @@ -1200,16 +1209,35 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { String name = className(); - int idx = name.indexOf('$'); + int idx = name.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + name = name.substring(idx + 1); + } + idx = name.indexOf('$'); if (idx == 0) { // name is $XXX so cannot associate with a file - return ""; + name = ""; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + name = name.substring(0, idx); + } + name = name + ".java"; } + + return name; + } + + public Path filePath() { + String name = className(); + int idx = name.lastIndexOf('.'); if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name name = name.substring(0, idx); + return Paths.get("", name.split("\\.")); + } else { + return null; } - return name.replace('.', '/') + ".java"; } @Override From 40d10c03f4242e35cfad60144bae23c2589886e1 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Feb 2020 10:30:23 +0000 Subject: [PATCH 080/130] ensure dir path for module classes include module name at start --- .../svm/hosted/image/NativeBootImage.java | 86 +++++++++++++------ 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 3cef29f16cdd..d497f18a24f8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -55,8 +55,10 @@ import java.util.Set; import java.util.stream.Collectors; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; @@ -1083,10 +1085,18 @@ public String fileName() { @Override public Path filePath() { HostedType declaringClass = method.getDeclaringClass(); - Package pkg = declaringClass.getJavaClass().getPackage(); + Class javaClass = declaringClass.getJavaClass(); + Package pkg = javaClass.getPackage(); + String module = ModuleSupport.getModuleName(javaClass); if (pkg != null) { - // use the package name as a path to the file - return Paths.get("", pkg.getName().split("\\.")); + /* + * use the package name as a path to the file + * for jdk11 classes we assume that the path includes + * the module name then the package name components + * for jdk8 classes this will just collapse to + * the sequence of package name elements + */ + return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); } else { return null; } @@ -1208,35 +1218,63 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { - String name = className(); - int idx = name.lastIndexOf('.'); - if (idx > 0) { - // strip off package prefix - name = name.substring(idx + 1); - } - idx = name.indexOf('$'); - if (idx == 0) { - // name is $XXX so cannot associate with a file - name = ""; - } else { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + String sourceFileName = declaringClass.getSourceFileName(); + + if (sourceFileName == null) { + String className = declaringClass.getName(); + int idx = className.lastIndexOf('.'); if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - name = name.substring(0, idx); + // strip off package prefix + className = className.substring(idx + 1); + } + idx = className.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + // create a path with an empty name + sourceFileName = ""; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + className = className.substring(0, idx); + } + sourceFileName = className + ".java"; } - name = name + ".java"; } - return name; + return sourceFileName; } public Path filePath() { - String name = className(); - int idx = name.lastIndexOf('.'); - if (idx > 0) { - name = name.substring(0, idx); - return Paths.get("", name.split("\\.")); + ResolvedJavaType declaringClass = (method.getDeclaringClass()); + if (declaringClass instanceof OriginalClassProvider) { + Class javaClass = ((OriginalClassProvider) declaringClass).getJavaClass(); + Package pkg = javaClass.getPackage(); + String module = ModuleSupport.getModuleName(javaClass); + if (pkg != null) { + /* + * use the package name as a path to the file + * + * for jdk11 classes we assume that the path includes + * the module name then the package name components + * + * for jdk8 classes this will just collapse to + * the sequence of package name components + */ + return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); + } else { + return null; + } } else { - return null; + // use the class name to generate a path + String name = className(); + int idx = name.lastIndexOf('.'); + if (idx > 0) { + name = name.substring(0, idx); + return Paths.get("", name.split("\\.")); + } else { + return null; + } } } From 49b603c9d497e12d026d08c089cc67faa227600f Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Feb 2020 12:47:53 +0000 Subject: [PATCH 081/130] fix problem with non-null return for empty package on jdk11 --- .../src/com/oracle/svm/hosted/image/NativeBootImage.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index d497f18a24f8..471aad680435 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -1087,8 +1087,9 @@ public Path filePath() { HostedType declaringClass = method.getDeclaringClass(); Class javaClass = declaringClass.getJavaClass(); Package pkg = javaClass.getPackage(); + String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); - if (pkg != null) { + if (packageName.length() != 0) { /* * use the package name as a path to the file * for jdk11 classes we assume that the path includes @@ -1250,8 +1251,9 @@ public Path filePath() { if (declaringClass instanceof OriginalClassProvider) { Class javaClass = ((OriginalClassProvider) declaringClass).getJavaClass(); Package pkg = javaClass.getPackage(); + String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); - if (pkg != null) { + if (packageName.length() != 0) { /* * use the package name as a path to the file * From 0a184e1cbd952ae9daf231fb14f0de9d75a1274a Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 12 Feb 2020 17:17:54 +0000 Subject: [PATCH 082/130] avoid addition ofmodule prefix to file paths for Graal classes --- .../svm/hosted/image/NativeBootImage.java | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 471aad680435..02c2d32f5009 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -1040,6 +1040,43 @@ public DebugDataInfo next() { } } + private static final String[] GRAAL_SRC_PACKAGE_PREFIXES = { + "org.graalvm", + "com.oracle.graal", + "com.oracle.objectfile", + "com.oracle.svm", + "com.oracle.truffle", + }; + + + /** + * compute a prefix to be added to the front of the file path for + * a class in order to locate it under a GRaal or JDK-specific + * search root + * @param packageName the name of the package the class belongs to + * or possibly an empty string if it is in the default package. + * @param moduleName the name of the module the class belongs to + * or possibly null or an empty string if it is not located + * in a module + * @return any required prefix or the empty string if no prefix is required + */ + private String getPathPrefix(String packageName, String moduleName) { + /* + * if we have a module name it is used as a prefix except + * when the class belongs to Graal itself. + */ + if (moduleName == null || moduleName.length() == 0) { + return ""; + } else { + for (String prefix : GRAAL_SRC_PACKAGE_PREFIXES) { + if (packageName.startsWith(prefix)) { + return ""; + } + } + return moduleName; + } + } + /** * implementation of the DebugCodeInfo API interface * that allows code info to be passed to an ObjectFile @@ -1090,6 +1127,7 @@ public Path filePath() { String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); if (packageName.length() != 0) { + String prefix = getPathPrefix(packageName, module); /* * use the package name as a path to the file * for jdk11 classes we assume that the path includes @@ -1097,7 +1135,7 @@ public Path filePath() { * for jdk8 classes this will just collapse to * the sequence of package name elements */ - return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); + return Paths.get(prefix, pkg.getName().split("\\.")); } else { return null; } @@ -1254,6 +1292,7 @@ public Path filePath() { String packageName = (pkg != null ? pkg.getName() : ""); String module = ModuleSupport.getModuleName(javaClass); if (packageName.length() != 0) { + String prefix = getPathPrefix(packageName, module); /* * use the package name as a path to the file * @@ -1263,7 +1302,7 @@ public Path filePath() { * for jdk8 classes this will just collapse to * the sequence of package name components */ - return Paths.get((module == null ? "" : module), pkg.getName().split("\\.")); + return Paths.get(prefix, pkg.getName().split("\\.")); } else { return null; } From 0348fa769e13ba99cc27dede74479852160135ab Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 24 Feb 2020 17:55:22 +0000 Subject: [PATCH 083/130] lookup source files via classpath or local dir and cache copies in local sources dir --- .../svm/hosted/image/NativeBootImage.java | 160 ++------- .../image/sources/ApplicationSourceCache.java | 93 ++++++ .../image/sources/GraalVMSourceCache.java | 153 +++++++++ .../hosted/image/sources/JDKSourceCache.java | 71 ++++ .../svm/hosted/image/sources/SourceCache.java | 306 ++++++++++++++++++ .../hosted/image/sources/SourceCacheType.java | 33 ++ .../hosted/image/sources/SourceManager.java | 267 +++++++++++++++ substratevm/write_gdbsourcepath | 193 ----------- 8 files changed, 956 insertions(+), 320 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java delete mode 100644 substratevm/write_gdbsourcepath diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 02c2d32f5009..c0fb29eb1311 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -39,7 +39,6 @@ import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Collection; @@ -55,10 +54,9 @@ import java.util.Set; import java.util.stream.Collectors; -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.svm.core.option.HostedOptionValues; +import com.oracle.svm.hosted.image.sources.SourceManager; import com.oracle.svm.hosted.meta.HostedType; -import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.code.site.Mark; import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; @@ -476,6 +474,7 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { // if we have constructed any debug info then // give the object file a chance to install it if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { + ImageSingletons.add(SourceManager.class, new SourceManager()); DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); objectFile.installDebugInfo(provider); } @@ -1049,34 +1048,6 @@ public DebugDataInfo next() { }; - /** - * compute a prefix to be added to the front of the file path for - * a class in order to locate it under a GRaal or JDK-specific - * search root - * @param packageName the name of the package the class belongs to - * or possibly an empty string if it is in the default package. - * @param moduleName the name of the module the class belongs to - * or possibly null or an empty string if it is not located - * in a module - * @return any required prefix or the empty string if no prefix is required - */ - private String getPathPrefix(String packageName, String moduleName) { - /* - * if we have a module name it is used as a prefix except - * when the class belongs to Graal itself. - */ - if (moduleName == null || moduleName.length() == 0) { - return ""; - } else { - for (String prefix : GRAAL_SRC_PACKAGE_PREFIXES) { - if (packageName.startsWith(prefix)) { - return ""; - } - } - return moduleName; - } - } - /** * implementation of the DebugCodeInfo API interface * that allows code info to be passed to an ObjectFile @@ -1085,60 +1056,35 @@ private String getPathPrefix(String packageName, String moduleName) { private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; private final CompilationResult compilation; + private Path fullFilePath; NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; this.compilation = compilation; + this.fullFilePath = null; } @Override public String fileName() { - HostedType declaringClass = method.getDeclaringClass(); - String sourceFileName = declaringClass.getSourceFileName(); - - if (sourceFileName == null) { - String className = declaringClass.getJavaClass().getName(); - int idx = className.lastIndexOf('.'); - if (idx > 0) { - // strip off package prefix - className = className.substring(idx + 1); - } - idx = className.indexOf('$'); - if (idx == 0) { - // name is $XXX so cannot associate with a file - // create a path with an empty name - sourceFileName = ""; - } else { - if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - className = className.substring(0, idx); - } - sourceFileName = className + ".java"; - } + if (fullFilePath == null) { + HostedType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); } - - return sourceFileName; + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; } @Override public Path filePath() { - HostedType declaringClass = method.getDeclaringClass(); - Class javaClass = declaringClass.getJavaClass(); - Package pkg = javaClass.getPackage(); - String packageName = (pkg != null ? pkg.getName() : ""); - String module = ModuleSupport.getModuleName(javaClass); - if (packageName.length() != 0) { - String prefix = getPathPrefix(packageName, module); - /* - * use the package name as a path to the file - * for jdk11 classes we assume that the path includes - * the module name then the package name components - * for jdk8 classes this will just collapse to - * the sequence of package name elements - */ - return Paths.get(prefix, pkg.getName().split("\\.")); - } else { - return null; + if (fullFilePath == null) { + HostedType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getParent(); } + return null; } @Override @@ -1245,6 +1191,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { private final ResolvedJavaMethod method; private final int lo; private final int hi; + private Path fullFilePath = null; NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); @@ -1257,66 +1204,25 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - String sourceFileName = declaringClass.getSourceFileName(); - - if (sourceFileName == null) { - String className = declaringClass.getName(); - int idx = className.lastIndexOf('.'); - if (idx > 0) { - // strip off package prefix - className = className.substring(idx + 1); - } - idx = className.indexOf('$'); - if (idx == 0) { - // name is $XXX so cannot associate with a file - // create a path with an empty name - sourceFileName = ""; - } else { - if (idx > 0) { - // name is XXX$YYY so use outer class to derive file name - className = className.substring(0, idx); - } - sourceFileName = className + ".java"; - } + if (fullFilePath == null) { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); } - - return sourceFileName; + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; } public Path filePath() { - ResolvedJavaType declaringClass = (method.getDeclaringClass()); - if (declaringClass instanceof OriginalClassProvider) { - Class javaClass = ((OriginalClassProvider) declaringClass).getJavaClass(); - Package pkg = javaClass.getPackage(); - String packageName = (pkg != null ? pkg.getName() : ""); - String module = ModuleSupport.getModuleName(javaClass); - if (packageName.length() != 0) { - String prefix = getPathPrefix(packageName, module); - /* - * use the package name as a path to the file - * - * for jdk11 classes we assume that the path includes - * the module name then the package name components - * - * for jdk8 classes this will just collapse to - * the sequence of package name components - */ - return Paths.get(prefix, pkg.getName().split("\\.")); - } else { - return null; - } - } else { - // use the class name to generate a path - String name = className(); - int idx = name.lastIndexOf('.'); - if (idx > 0) { - name = name.substring(0, idx); - return Paths.get("", name.split("\\.")); - } else { - return null; - } + if (fullFilePath == null) { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); + } + if (fullFilePath != null) { + return fullFilePath.getParent(); } + return null; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java new file mode 100644 index 000000000000..1a9ebc2304fa --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class ApplicationSourceCache extends SourceCache { + /** + * create an application source cache + */ + protected ApplicationSourceCache() { + super(SourceCache.APPLICATION_CACHE_KEY); + initSrcRoots(); + } + + private void initSrcRoots() { + String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); + assert javaClassPath != null; + String[] classPathEntries = javaClassPath.split(File.pathSeparator); + /* add dirs or jars found in the classpath */ + for (String classPathEntry : classPathEntries) { + Path entryPath = Paths.get(classPathEntry); + String fileNameString = entryPath.getFileName().toString(); + if (fileNameString.endsWith(".jar")) { + // application jar /path/to/xxx.jar should have + // sources /path/to/xxx-sources.jar + int length = fileNameString.length(); + String srcFileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; + Path srcPath = entryPath.getParent().resolve(srcFileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(root); + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } else { + /* + * for dir entries ending in classes or target/classes + * look for a parallel src tree + */ + if (entryPath.endsWith("classes")) { + Path parent = entryPath.getParent(); + if (parent.endsWith("target")) { + parent = parent.getParent(); + } + Path srcPath = (parent.resolve("src")); + File file = srcPath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(srcPath); + } + } + } + } + /* add the current working directory as a path of last resort */ + srcRoots.add(Paths.get(".")); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java new file mode 100644 index 000000000000..181076bb364a --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedList; +import java.util.List; + +import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; +public class GraalVMSourceCache extends SourceCache { + /** + * create a GraalVM source cache + */ + protected GraalVMSourceCache() { + super(SourceCache.GRAALVM_CACHE_KEY); + initSrcRoots(); + } + + private static final String JAVA_CLASSPATH_PROP = "java.class.path"; + + private void initSrcRoots() { + String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); + assert javaClassPath != null; + String[] classPathEntries = javaClassPath.split(File.pathSeparator); + for (String classPathEntry : classPathEntries) { + Path entryPath = Paths.get(classPathEntry); + String fileNameString = entryPath.getFileName().toString(); + if (fileNameString.endsWith(".jar")) { + // GraalVM jar /path/to/xxx.jar should have + // sources /path/to/xxx.src.zip.jar + int length = fileNameString.length(); + String srcFileNameString = fileNameString.substring(0, length - 3) + "src.zip"; + Path srcPath = entryPath.getParent().resolve(srcFileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + if (filterSrcRoot(root)) { + srcRoots.add(root); + } + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } else { + /* graal classpath dir entries should have a src and/or src_gen subdirectory */ + Path srcPath = entryPath.resolve("src"); + if (filterSrcRoot(srcPath)) { + srcRoots.add(srcPath); + } + srcPath = entryPath.resolve("src_gen"); + if (filterSrcRoot(srcPath)) { + srcRoots.add(srcPath); + } + } + } + } + /** + * Ensure that the supplied root dir contains + * at least one subdirectory that matches one + * of the expected Graal package dir hierarchies. + * + * @param root A root path under which to locate + * the desired subdirectory + * @return true if a + */ + private boolean filterSrcRoot(Path root) { + // we are only interested in source roots + // that potentially contain GraalVM code + String separator = root.getFileSystem().getSeparator(); + + LinkedList toTest = new LinkedList<>(); + LinkedList toBeMatched = new LinkedList<>(); + /* build a list of GraalVM Paths to look for */ + for (String prefix : GRAALVM_SRC_PACKAGE_PREFIXES) { + String subDir = prefix.replaceAll("\\.", separator); + toBeMatched.add(root.resolve(subDir)); + } + /* start by checking immediate subdirs of root */ + try { + addSubDirs(root, toTest); + } catch (IOException e) { + // hmm, ignore this root then + return false; + } + + return searchDirectories(toTest, toBeMatched); + + } + private void addSubDirs(Path parent, LinkedList toSearch) throws IOException { + DirectoryStream directoryStream = Files.newDirectoryStream(parent); + for (Path dir : directoryStream) { + toSearch.addLast(dir); + } + } + private boolean searchDirectories(LinkedList toTest, LinkedList toBeMatched) { + try { + while (!toTest.isEmpty()) { + Path next = toTest.pop(); + for (Path p : toBeMatched) { + if (p.equals(next)) { + /* yes, the full monty! */ + return true; + } else if (p.startsWith(next)) { + /* this may lead where we want to go -- check subdirs */ + addSubDirs(next, toTest); + /* other matches are disjoint so we can break */ + break; + } + } + } + } catch (IOException e) { + /* ignore the exception and also skip the jar */ + } + /* nope, no useful dirs under this root */ + return false; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java new file mode 100644 index 000000000000..e10d5ce44226 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import java.io.IOException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class JDKSourceCache extends SourceCache { + /** + * create a JDK runtime class source cache. + */ + protected JDKSourceCache() { + super(SourceCache.JDK_CACHE_KEY); + initSrcRoots(); + } + + private void initSrcRoots() { + String javaHome = System.getProperty(JAVA_HOME_PROP); + assert javaHome != null; + Path javaHomePath = Paths.get("", javaHome); + Path srcZipPath = null; + String javaSpecversion = System.getProperty(JAVA_SPEC_VERSION_PROP); + if (javaSpecversion.equals("1.8")) { + srcZipPath = javaHomePath.resolve("src.zip"); + } else { + assert javaSpecversion.matches("[1-9][0-9]"); + srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); + } + if (srcZipPath.toFile().exists()) { + try { + FileSystem srcFileSystem = FileSystems.newFileSystem(srcZipPath, null); + for (Path root : srcFileSystem.getRootDirectories()) { + srcRoots.add(root); + } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ + } + } + } +} + diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java new file mode 100644 index 000000000000..64577d729ba2 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2020, 2020, 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.svm.hosted.image.sources; + +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.List; +/** + * An abstract cache manager for some subspace of the + * JDK, GraalVM or application source file space. This class + * implements core behaviours that manage a cache of source + * files in a specific subdirectory of the local sources + * directory. It allows source files to be located + * when present in the local cache or cached when not + * already present. Subclasses are responsible for providing + * behaviours that identify an original source for addition + * to the cache and for verifying that a cached file is not + * out of date with respect to its original. + */ + +public abstract class SourceCache { + + /* + * properties needed to locate relevant JDK and app source roots + */ + protected static final String JAVA_CLASSPATH_PROP = "java.class.path"; + protected static final String JAVA_HOME_PROP = "java.home"; + protected static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + /** + * A list of root directories which may contain source files + * from which this cache can be populated + */ + protected List srcRoots; + + /** + * Create a source cache with a specific base type. + * @param key a String identifying the subdir under + * which sources should be cached which should also + * match the type of content being cached + */ + protected SourceCache(String key) { + basePath = Paths.get(SOURCE_CACHE_ROOT_DIR, key); + srcRoots = new ArrayList<>(); + + } + + /** + * A local directory serving as the root for all + * source trees maintained by the different + * available source caches. + */ + private static final String SOURCE_CACHE_ROOT_DIR = "sources"; + /** + * The top level path relative to the root directory + * under which files belonging to this specific cache + * are located. + */ + private Path basePath; + /** + * JDK runtime code sources are cached using this key as a + * leading path prefix with a module name as a sub-path + * prefix when we have a modular JDK. + * + * For example, the full file path to a file under the cache + * root directory might be jdk/java/lang/Throwable.java on jdk8 or + * jdk/java.base/java/lang/Throwable.java on jdk11 + */ + protected static final String JDK_CACHE_KEY = "jdk"; + /** + * GraalVM code sources are cached using this key as a + * leading path prefix with an enclosing package name + * and the name src or src_gen forming a sub-path prefix. + * + * For example, the full file path to a file under the cache + * root directory might be + * graal/com/oracle/svm/core/Isolates.java + * or + * graal/org/graalvm/compiler/core/phases/LowTier_OptionDescriptors.java + */ + protected static final String GRAALVM_CACHE_KEY = "graal"; + /** + * Application code sources are cached using this key as + * a leading path prefix with a name or sequence of + * names derived from a classpath jar or dir entry + * employed as a sub-path prefix. + * + * For example, the full file path to a file under the cache + * root directory might be + * src/Hello.java + * or + * src/hello/impl/HelloImpl.java + * or + * src/hibernate-core-5.4.4.Final/org/hibernate/annotations/Entity.java + */ + protected static final String APPLICATION_CACHE_KEY = "src"; + /** + * Cache the source file identified by the supplied prototype + * path if a legitimate candidate for inclusion in this cache + * can be identified and is not yet included in the cache or + * alternatively identify and validate any existing candidate + * cache entry to ensure it is not out of date refreshing it + * if need be. + * + * @param filePath a prototype path for a file to be included + * in the cache derived from the name of some associated class. + * @return a path identifying the cached file or null + * if the candidate cannot be found. + */ + public Path resolve(Path filePath) { + File cachedFile = findCandidate(filePath); + if (cachedFile == null) { + return tryCacheFile(filePath); + } else { + return checkCacheFile(filePath); + } + } + + /** + * Given a prototype path for a file to be resolved + * return a File identifying a cached candidate for + * for that Path or null if no cached candidate exists. + * @param filePath a prototype path for a file to be included + * in the cache derived from the name of some associated class. + * @return a File identifying a cached candidate or null. + */ + public File findCandidate(Path filePath) { + /* + * JDK source candidates are stored in the src.zip file + * using the path we are being asked for. A cached version + * should exist under this cache's root using that same + * path. + */ + File file = cachedFile(filePath); + if (file.exists()) { + return file; + } + return null; + } + public Path tryCacheFile(Path filePath) { + for (Path root : srcRoots) { + Path targetPath = cachedPath(filePath); + Path sourcePath = extendPath(root, filePath); + try { + if (checkSourcePath(sourcePath)) { + ensureTargetDirs(targetPath.getParent()); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + // return the original filePath + // we don't want the sources/jdk prefix to go into the debuginfo + return filePath; + } + } catch (IOException e) { + } + } + return null; + } + public Path checkCacheFile(Path filePath) { + for (Path root : srcRoots) { + Path targetPath = cachedPath(filePath); + Path sourcePath = extendPath(root, filePath); + try { + if (checkSourcePath(sourcePath)) { + FileTime sourceTime = Files.getLastModifiedTime(sourcePath); + FileTime destTime = Files.getLastModifiedTime(targetPath); + if (destTime.compareTo(sourceTime) < 0) { + try { + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); + } catch (IOException e) { + return null; + } + } + return filePath; + } else { + /* delete the target file as it is out of date */ + targetPath.toFile().delete(); + } + } catch (IOException e) { + // hmm last modified time blew up? + return tryCacheFile(filePath); + } + } + return null; + } + /** + * Create and intialize the source cache used to locate and cache + * sources of a given type as determined by the supplied key. + * @param type an enum identifying both the type of Java sources + * cached by the returned cache and the subdir of the cached + * source subdirectory in which those sources are located. + * @return the desired source cache. + */ + public static SourceCache createSourceCache(SourceCacheType type) { + SourceCache sourceCache = null; + switch (type) { + case JDK: + sourceCache = new JDKSourceCache(); + break; + case GRAALVM: + sourceCache = new GraalVMSourceCache(); + break; + case APPLICATION: + sourceCache = new ApplicationSourceCache(); + break; + default: + assert false; + } + return sourceCache; + } + /** + * Extend a root path form one file system using a path potentially derived + * from another file system by converting he latter to a text string and + * replacing the file separator if necessary. + * @param root the path to be extended + * @param filePath the subpath to extend it with + * @return the extended path + */ + protected Path extendPath(Path root, Path filePath) { + String filePathString = filePath.toString(); + String fileSeparator = filePath.getFileSystem().getSeparator(); + String newSeparator = root.getFileSystem().getSeparator(); + if (!fileSeparator.equals(newSeparator)) { + filePathString = filePathString.replaceAll(fileSeparator, newSeparator); + } + return root.resolve(filePathString); + } + + /** + * convert a potential resolved candidate path to + * the corresponding local Path in this cache. + * @param candidate a resolved candidate path for + * some given resolution request + * @return the corresponding local Path + */ + protected Path cachedPath(Path candidate) { + return basePath.resolve(candidate); + } + /** + * convert a potential resolved candidate path to + * the corresponding local File in this cache. + * @param candidate a resolved candidate path for + * some given resolution request + * @return the corresponding local File + */ + protected File cachedFile(Path candidate) { + return cachedPath(candidate).toFile(); + } + /** + * indicate whether a source path identifies a fie in the associated file system + * @param sourcePath + * @return true if the path identifies a file or false if no such file can be found + * @throws IOException if there is some error in resolving the path + */ + private boolean checkSourcePath(Path sourcePath) throws IOException { + DirectoryStream stream = Files.newDirectoryStream(sourcePath.getParent()); + for (Path path : stream) { + if (path.equals(sourcePath)) { + return true; + } + } + return false; + } + /** + * ensure the directory hierarchy for a path exists + * creating any missing directories if needed + * @param targetDir a path to the desired directory + * @throws IOException if it is not possible to create + * one or more directories in the path + */ + private void ensureTargetDirs(Path targetDir) throws IOException { + if (targetDir != null) { + File targetFile = targetDir.toFile(); + if (!targetFile.exists()) { + targetDir.toFile().mkdirs(); + } + } + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java new file mode 100644 index 000000000000..10863a5e572c --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +public enum SourceCacheType { + JDK, + GRAALVM, + APPLICATION +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java new file mode 100644 index 000000000000..459acebe6a08 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.svm.hosted.image.sources; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.svm.util.ModuleSupport; +import jdk.vm.ci.meta.ResolvedJavaType; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; + +/** + * A singleton class responsible for locating source files + * for classes included in a native image and copying them + * into the local sources. + */ +public class SourceManager { + /** + * Find and cache a source file for a give Java class and + * return a Path to the file relative to the source. + * @param resolvedType the Java type whose source file + * should be located and cached + * @return a path identifying the location of a successfully + * cached file for inclusion in the generated debug info or + * null if a source file cannot be found or cached. + */ + public Path findAndCacheSource(ResolvedJavaType resolvedType) { + Path path = null; + String fileName = computeBaseName(resolvedType); + /* + * null for the name means this class + * will not have a source so we skip on that + */ + if (fileName != null) { + /* + * we can only provide sources + * for known classes and interfaces + */ + if (resolvedType.isInstanceClass() || resolvedType.isInterface()) { + /* + * if we have an OriginalClassProvider we + * can use the underlying Java class + * to provide the details we need to locate + * a source + */ + if (resolvedType instanceof OriginalClassProvider) { + Class javaClass = ((OriginalClassProvider) resolvedType).getJavaClass(); + String packageName = computePackageName(javaClass); + SourceCacheType type = sourceCacheType(packageName, javaClass); + path = locateSource(fileName, packageName, type, javaClass); + } + /* + * if we could not locate a source via the cache + * then the fallback is to generate a path to the + * file based on the class name and let the + * user configure a path to the sources + */ + if (path == null) { + String name = resolvedType.toJavaName(); + int idx = name.lastIndexOf('.'); + if (idx >= 0 && idx < name.length() - 1) { + name = name.substring(0, idx); + path = Paths.get("", name.split("\\.")); + path = path.resolve(fileName); + } + } + } + } + return path; + } + + /** + * Construct the base file name for a resolved + * Java class excluding path elements using either + * the source name embedded in the class file or + * the class name itself. + * @param resolvedType the resolved java type whose + * source file name is required + * @return the file name or null if it the class cannot + * be associated with a source file + */ + private String computeBaseName(ResolvedJavaType resolvedType) { + String fileName = resolvedType.getSourceFileName(); + if (fileName == null) { + /* ok, try to construct it from the class name */ + fileName = resolvedType.toJavaName(); + int idx = fileName.lastIndexOf('.'); + if (idx > 0) { + // strip off package prefix + fileName = fileName.substring(idx + 1); + } + idx = fileName.indexOf('$'); + if (idx == 0) { + // name is $XXX so cannot associate with a file + // + fileName = null; + } else { + if (idx > 0) { + // name is XXX$YYY so use outer class to derive file name + fileName = fileName.substring(0, idx); + } + fileName = fileName + ".java"; + } + } + return fileName; + } + /** + * Construct the package name for a Java class or + * the empty String if it has no package. + * @param javaClass the java class whose package + * name is required + * @return the package name or the empty String + * if it has no package + */ + private String computePackageName(Class javaClass) { + Package pkg = javaClass.getPackage(); + return (pkg == null ? "" : pkg.getName()); + } + /** + * Construct the prototype name for a Java source file + * which can be used to resolve and cache an actual source + * file. + * @param fileName the base file name for the source file + * @param packageName the name of the package for the associated Java class + * @param type the type of cache in which to lookup or cache this class's source file + * @param javaClass the java class whose prototype name is required + * @return a protoype name for the source file + */ + private Path computePrototypeName(String fileName, String packageName, SourceCacheType type, Class javaClass) { + String prefix = ""; + if (type == SourceCacheType.JDK) { + /* JDK paths may require the module name as prefix */ + String moduleName = ModuleSupport.getModuleName(javaClass); + if (moduleName != null) { + prefix = moduleName; + } + } + if (packageName.length() == 0) { + return Paths.get("", fileName); + } else { + return Paths.get(prefix, packageName.split("\\.")).resolve(fileName); + } + } + /** + * A whitelist of packages prefixes used to + * pre-filter JDK runtime class lookups. + */ + public static final String[] JDK_SRC_PACKAGE_PREFIXES = { + "java.", + "jdk.", + "javax.", + "sun.", + "com.sun.", + "org.ietf.", + "org.jcp.", + "org.omg.", + "org.w3c.", + "org.xml", + }; + /** + * A whitelist of packages prefixes used to + * pre-filter GraalVM class lookups. + */ + public static final String[] GRAALVM_SRC_PACKAGE_PREFIXES = { + "com.oracle.graal.", + "com.oracle.objectfile.", + "com.oracle.svm.", + "com.oracle.truffle.", + "org.graalvm.", + }; + + /** + * A whitelist of packages prefixes used to + * pre-filter app class lookups which + * includes just the empty string because + * any package will do. + */ + private static final String[] APP_SRC_PACKAGE_PREFIXES = { + "", + }; + + /** + * Check a package name against a whitelist of acceptable packages. + * @param packageName the package name of the class to be checked + * @param whitelist a list of prefixes one of which may form + * the initial prefix of the package name being checked + * @return true if the package name matches an entry in the + * whitelist otherwise false + */ + private boolean whiteListPackage(String packageName, String[] whitelist) { + for (String prefix : whitelist) { + if (packageName.startsWith(prefix)) { + return true; + } + } + return false; + } + + /** + * Identify which type of source cache should be used + * to locate a given class's source code. + */ + private SourceCacheType sourceCacheType(String packageName, Class javaClass) { + if (whiteListPackage(packageName, JDK_SRC_PACKAGE_PREFIXES)) { + return SourceCacheType.JDK; + } + if (whiteListPackage(packageName, GRAALVM_SRC_PACKAGE_PREFIXES)) { + return SourceCacheType.GRAALVM; + } + return SourceCacheType.APPLICATION; + } + /** + * A map from each of the top level root keys to a + * cache that knows how to handle lookup and caching + * of the associated type of source file. + */ + private static HashMap caches = new HashMap<>(); + + /** + * Retrieve the source cache used to locate and cache sources + * of a given type as determined by the supplied key, creating + * and initializing it if it does not already exist. + * @param type an enum identifying the type of Java sources + * cached by the returned cache. + * @return the desired source cache. + */ + private SourceCache getOrCreateCache(SourceCacheType type) { + SourceCache sourceCache = caches.get(type); + if (sourceCache == null) { + sourceCache = SourceCache.createSourceCache(type); + caches.put(type, sourceCache); + } + return sourceCache; + } + + private Path locateSource(String fileName, String packagename, SourceCacheType type, Class javaClass) { + SourceCache cache = getOrCreateCache(type); + Path prototypeName = computePrototypeName(fileName, packagename, type, javaClass); + return cache.resolve(prototypeName); + } +} + diff --git a/substratevm/write_gdbsourcepath b/substratevm/write_gdbsourcepath deleted file mode 100644 index b211b305a543..000000000000 --- a/substratevm/write_gdbsourcepath +++ /dev/null @@ -1,193 +0,0 @@ -#!/bin/bash - - -function usage() -{ - echo "write_gdbsourcepath [-h | -v]" - echo "writes command to set source path to .gdbsourcepath" - echo "set GRAAL_SRC_ROOT to graal git repo root" - echo " defaults to .. when . = sdk, compile, substratevm, truffle" - echo "set GRAAL_JDK_SRC_ROOT to unzipped src.zip root" - echo " defaults to JAVA_HOME/src" - exit $1 -} - -function check_args() -{ - while [ $# -ge 1 ]; do - if [ "$1" == "-v" ]; then - VERBOSE=1 - shift - elif [ "$1" == "-h" ]; then - usage 0 - else - usage 1 - fi - done -} - -typeset -i VERBOSE -VERBOSE=0 - -# debug -function verbose() -{ - if [ $VERBOSE -eq 1 ]; then - echo $* - fi -} - -# check which java we are using and set up JAVA_VERSION -function check_java_version() -{ - JAVA_VERSION_STRING=$(java -version |& grep version | cut -d' ' -f3) - if [ "${JAVA_VERSION_STRING#\"1.8.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=8 - elif [ "${JAVA_VERSION_STRING#\"9.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=9 - elif [ "${JAVA_VERSION_STRING#\"11.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=11 - elif [ "${JAVA_VERSION_STRING#\"14.}" != "${JAVA_VERSION_STRING}" ]; then - JAVA_VERSION=14 - else - echo "Unrecognized java version : $JAVA_VERSION_STRING" - exit 1 - fi -} - -# check for the required source trees and -# set up GRAAL_SRC_ROOT and GRAAL_JDK_SRC_ROOT -function check_source_dirs() -{ - if [ -z "$GRAAL_SRC_ROOT" ]; then - # see if we are in one of the Graal trees - if [ "${PWD#*/sdk}" != "$PWD" -o \ - "${PWD#*/compiler}" != "$PWD" -o \ - "${PWD#*/substratevm}" != "$PWD" -o \ - "${PWD#*/truffle}" != "$PWD" ]; then - GRAAL_SRC_ROOT=$(cd ..; pwd) - echo "defaulting GRAAL_SRC_ROOT to .. : $GRAAL_SRC_ROOT" - else - echo "Please set GRAAL_SRC_ROOT to git repo checkout dir" - exit 1 - fi - fi - - if [ -z "$GRAAL_JDK_SRC_ROOT" ]; then - if [ ! -z "$JAVA_HOME" ]; then - GRAAL_JDK_SRC_ROOT=$JAVA_HOME/src - echo "defaulting GRAAL_JDK_SRC_ROOT to JAVA_HOME : $GRAAL_JDK_SRC_ROOT" - else - JAVA_EXE=`which java` - GRAAL_JDK_SRC_ROOT=${JAVA_EXE%/bin/java}/src - fi - fi -} - -# add sources from a supplied graal source dir -function add_sources() -{ - # sanity check - if [ ! -d $1 ]; then - echo "hmm, was expecting a graal component directory, not this : $1" - fi - if [ ! -d $1/src ]; then - echo "hmm, was expecting to find a graal component source tree, not this : $1/src" - fi - root=$1 - for dir in $1/src/* - do - typeset -i ignore - ignore=0 - verbose "considering $dir" - if [ ! -d ${dir}/src ]; then - ignore=1 - else - # look for test or jdk in the trailing path - tail=${dir#$root} - if [ "${tail%*test}" != "$tail" -o \ - "${tail#*test}" != "$tail" ] ; then - # ignore test dirs - ignore=1 - elif [ "${tail#*jdk}" != "$tail" ]; then - # check for a specific jdk release - if [ "${tail#jdk.}" != "$tail" ]; then - # jdk. as part of a package name is ok - if ["${tail#jdk.}" != "$tail" ]; then - echo allow $dir - fi - ignore=0 - elif [ "${tail#*jdk}" != "${JAVA_VERSION}" ]; then - # jdk must match JAVA_VERSION - if [ "${dir#jdk.}" != "$dir" ]; then - echo disallow $dir - fi - ignore=1 - fi - fi - fi - if [ $ignore -eq 1 ] ; then - verbose "ignoring $dir" - else - verbose "including $dir" - SOURCEPATH=${SOURCEPATH}:$dir/src - fi - done -} - -# add sources from a supplied java source dir -function add_java_sources() -{ - # sanity check - if [ ! -d $1 ]; then - echo "hmm, was expecting to find a JDK source dir, not this : $1" - fi - SOURCEPATH=${SOURCEPATH}:$1 -} - -check_args $* - -check_java_version - -check_source_dirs - -GRAAL_SDK_SRC_ROOT=${GRAAL_SRC_ROOT}/sdk -GRAAL_COMPILER_SRC_ROOT=${GRAAL_SRC_ROOT}/compiler -GRAAL_SUBSTRATEVM_SRC_ROOT=${GRAAL_SRC_ROOT}/substratevm -GRAAL_TRUFFLE_SRC_ROOT=${GRAAL_SRC_ROOT}/truffle - -SOURCEPATH= - -if [ -d ${GRAAL_SDK_SRC_ROOT} ]; then - add_sources ${GRAAL_SDK_SRC_ROOT} -else - echo "Unable to find sdk sources in ${GRAAL_SDK_SRC_ROOT}" -fi -if [ -d ${GRAAL_COMPILER_SRC_ROOT} ]; then - add_sources ${GRAAL_COMPILER_SRC_ROOT} -else - echo "Unable to find compiler sources in ${GRAAL_COMPILER_SRC_ROOT}" -fi -if [ -d ${GRAAL_SUBSTRATEVM_SRC_ROOT} ]; then - add_sources ${GRAAL_SUBSTRATEVM_SRC_ROOT} -else - echo "Unable to find substratevm sources in ${GRAAL_SUBSTRATEVM_SRC_ROOT}" -fi -if [ -d ${GRAAL_TRUFFLE_SRC_ROOT} ]; then - add_sources ${GRAAL_TRUFFLE_SRC_ROOT} -else - echo "Unable to find truffle sources in ${GRAAL_TRUFFLE_SRC_ROOT}" -fi - -if [ -d ${GRAAL_JDK_SRC_ROOT} ]; then - add_java_sources ${GRAAL_JDK_SRC_ROOT} -else - echo "Unable to find JDK sources in ${GRAAL_JDK_SRC_ROOT}/src" - echo "unzip src.zip into \${GRAAL_JDK_SRC_ROOT}/src" -fi - -SOURCEPATH=${SOURCEPATH#:*} -echo "set directories $SOURCEPATH" > .gdbsourcepath -if [ $VERBOSE -gt 0 ]; then - cat .gdbsourcepath -fi From 9f04d5ebf88334ec0cda81cf8beb1bca9c8ee4ed Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 25 Feb 2020 10:43:54 +0000 Subject: [PATCH 084/130] correct use File and Path APIs --- .../image/sources/GraalVMSourceCache.java | 46 ++----------------- .../hosted/image/sources/JDKSourceCache.java | 8 ++-- .../svm/hosted/image/sources/SourceCache.java | 8 +--- 3 files changed, 9 insertions(+), 53 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 181076bb364a..2db78649e819 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -100,54 +100,16 @@ private void initSrcRoots() { * @return true if a */ private boolean filterSrcRoot(Path root) { - // we are only interested in source roots - // that potentially contain GraalVM code String separator = root.getFileSystem().getSeparator(); - LinkedList toTest = new LinkedList<>(); - LinkedList toBeMatched = new LinkedList<>(); - /* build a list of GraalVM Paths to look for */ + /* if any of the graal paths exist accept this root */ for (String prefix : GRAALVM_SRC_PACKAGE_PREFIXES) { String subDir = prefix.replaceAll("\\.", separator); - toBeMatched.add(root.resolve(subDir)); - } - /* start by checking immediate subdirs of root */ - try { - addSubDirs(root, toTest); - } catch (IOException e) { - // hmm, ignore this root then - return false; - } - - return searchDirectories(toTest, toBeMatched); - - } - private void addSubDirs(Path parent, LinkedList toSearch) throws IOException { - DirectoryStream directoryStream = Files.newDirectoryStream(parent); - for (Path dir : directoryStream) { - toSearch.addLast(dir); - } - } - private boolean searchDirectories(LinkedList toTest, LinkedList toBeMatched) { - try { - while (!toTest.isEmpty()) { - Path next = toTest.pop(); - for (Path p : toBeMatched) { - if (p.equals(next)) { - /* yes, the full monty! */ - return true; - } else if (p.startsWith(next)) { - /* this may lead where we want to go -- check subdirs */ - addSubDirs(next, toTest); - /* other matches are disjoint so we can break */ - break; - } - } + if (Files.isDirectory(root.resolve(subDir))) { + return true; } - } catch (IOException e) { - /* ignore the exception and also skip the jar */ } - /* nope, no useful dirs under this root */ + return false; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index e10d5ce44226..e53d75f75c9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -46,12 +46,12 @@ private void initSrcRoots() { String javaHome = System.getProperty(JAVA_HOME_PROP); assert javaHome != null; Path javaHomePath = Paths.get("", javaHome); - Path srcZipPath = null; - String javaSpecversion = System.getProperty(JAVA_SPEC_VERSION_PROP); - if (javaSpecversion.equals("1.8")) { + Path srcZipPath; + String javaSpecVersion = System.getProperty(JAVA_SPEC_VERSION_PROP); + if (javaSpecVersion.equals("1.8")) { srcZipPath = javaHomePath.resolve("src.zip"); } else { - assert javaSpecversion.matches("[1-9][0-9]"); + assert javaSpecVersion.matches("[1-9][0-9]"); srcZipPath = javaHomePath.resolve("lib").resolve("src.zip"); } if (srcZipPath.toFile().exists()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 64577d729ba2..dcf6b4f0961f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -280,13 +280,7 @@ protected File cachedFile(Path candidate) { * @throws IOException if there is some error in resolving the path */ private boolean checkSourcePath(Path sourcePath) throws IOException { - DirectoryStream stream = Files.newDirectoryStream(sourcePath.getParent()); - for (Path path : stream) { - if (path.equals(sourcePath)) { - return true; - } - } - return false; + return Files.isRegularFile(sourcePath); } /** * ensure the directory hierarchy for a path exists From b10ad74ace695687c1c8fdc135a0f0a2be1aa32b Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 25 Feb 2020 11:28:29 +0000 Subject: [PATCH 085/130] remove redundant imports --- .../oracle/svm/hosted/image/sources/GraalVMSourceCache.java | 3 --- .../src/com/oracle/svm/hosted/image/sources/SourceCache.java | 1 - 2 files changed, 4 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 2db78649e819..da8bfd6cde07 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -28,15 +28,12 @@ import java.io.File; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.LinkedList; -import java.util.List; import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; public class GraalVMSourceCache extends SourceCache { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index dcf6b4f0961f..91384cfcb553 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -27,7 +27,6 @@ import java.io.File; import java.io.IOException; -import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; From c73f835f139ea6abf5a79c693cab2fa3adf338af Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 25 Feb 2020 15:56:24 +0000 Subject: [PATCH 086/130] modified debug info API to use streams instead of iterators --- .../debuginfo/DebugInfoProvider.java | 13 ++-- .../objectfile/elf/dwarf/DwarfSections.java | 14 +--- .../svm/hosted/image/NativeBootImage.java | 77 +++---------------- 3 files changed, 21 insertions(+), 83 deletions(-) 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 5aff1370bb33..937e40c108f3 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 @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.util.List; +import java.util.stream.Stream; /** * interfaces used to allow a native image to communicate @@ -82,10 +83,10 @@ interface DebugCodeInfo { */ int line(); /** - * @return a provider detailing line numbers - * addresses within the compiled method + * @return a stream of records detailing line numbers + * and addresses within the compiled method */ - DebugLineInfoProvider lineInfoProvider(); + Stream lineInfoProvider(); /** * @return a string identifying the method parameters */ @@ -190,9 +191,9 @@ interface DebugLineInfoProvider extends Iterable { interface DebugDataInfoProvider extends Iterable { } - DebugTypeInfoProvider typeInfoProvider(); + Stream typeInfoProvider(); - DebugCodeInfoProvider codeInfoProvider(); + Stream codeInfoProvider(); - DebugDataInfoProvider dataInfoProvider(); + Stream dataInfoProvider(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 42df6ae317cb..0ba4bd7543ea 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -27,12 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfoProvider; -// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugDataInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; -// import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugTypeInfoProvider; import com.oracle.objectfile.elf.ELFMachine; import java.nio.ByteOrder; @@ -337,8 +332,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ uniqueDebugString(""); - DebugCodeInfoProvider codeInfoProvider = debugInfoProvider.codeInfoProvider(); - for (DebugCodeInfo debugCodeInfo : codeInfoProvider) { + debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> { /* * primary file name and full method name need to be written to the debug_str section */ @@ -359,7 +353,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { * create an infoSection entry for the method */ addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); - for (DebugLineInfo debugLineInfo : debugCodeInfo.lineInfoProvider()) { + debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); Path filePathAtLine = debugLineInfo.filePath(); // switch '$' in class names for '.' @@ -374,8 +368,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); - } - } + }); + }); /* * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); * for (DebugDataInfo debugDataInfo : dataInfoProvider) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index c0fb29eb1311..b5844d7b0a5d 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -46,13 +46,13 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.hosted.image.sources.SourceManager; @@ -981,61 +981,26 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; private final NativeImageHeap heap; - private final Iterator> codeCacheIterator; - private final Iterator> heapIterator; NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { super(); this.codeCache = codeCache; this.heap = heap; - this.codeCacheIterator = codeCache.compilations.entrySet().iterator(); - this.heapIterator = heap.objects.entrySet().iterator(); } @Override - public DebugTypeInfoProvider typeInfoProvider() { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public DebugTypeInfo next() { - return null; - } - }; + public Stream typeInfoProvider() { + return Stream.empty(); } @Override - public DebugCodeInfoProvider codeInfoProvider() { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return codeCacheIterator.hasNext(); - } - - @Override - public DebugCodeInfo next() { - Map.Entry entry = codeCacheIterator.next(); - return new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue()); - } - }; + public Stream codeInfoProvider() { + return codeCache.compilations.entrySet().stream().map(entry -> new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue())); } @Override - public DebugDataInfoProvider dataInfoProvider() { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public DebugDataInfo next() { - return null; - } - }; + public Stream dataInfoProvider() { + return Stream.empty(); } } @@ -1127,33 +1092,11 @@ public int line() { } @Override - public DebugInfoProvider.DebugLineInfoProvider lineInfoProvider() { + public Stream lineInfoProvider() { if (fileName().toString().length() == 0) { - return () -> new Iterator() { - @Override - public boolean hasNext() { - return false; - } - - @Override - public DebugLineInfo next() { - return null; - } - }; + return Stream.empty(); } - return () -> new Iterator() { - final Iterator sourceIterator = compilation.getSourceMappings().iterator(); - - @Override - public boolean hasNext() { - return sourceIterator.hasNext(); - } - - @Override - public DebugLineInfo next() { - return new NativeImageDebugLineInfo(sourceIterator.next()); - } - }; + return compilation.getSourceMappings().stream().map(sourceMapping -> new NativeImageDebugLineInfo(sourceMapping)); } public int getFrameSize() { From 09e006b83fee525eb8491fa429cb22148f98f12e Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 26 Feb 2020 11:13:45 +0000 Subject: [PATCH 087/130] updated DEBUGINFO readme to match latest version --- substratevm/DEBUGINFO.md | 152 +++++++++++++++++++++++++++++---------- 1 file changed, 116 insertions(+), 36 deletions(-) diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 5b859cd3cd7a..0536be0bf2a3 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -2,11 +2,22 @@ Using the ptototype debug info feature -------------------------------------- To add debug info to a generated native image add flag --H:+TrackNodeSourcePosition to the native image command line. +-H:+GenerateDebugInfo to the native image command line. - mx native-image -H:+TrackNodeSourcePosition Hello.java + $ javac Hello.java + $ mx native-image -H:+GenerateDebugInfo Hello + +The resulting image should contain code (method) debug records in a +format gdb understands (VS support is still under development). + +The flag also enables caching of sources for JDK runtime classes, +GraalVM classes and application classes which can be located during +native image generation. The cache is created under local subdirectory +sources and can be used to configure source file search path roots for +the debugger. Files in the cache are located in a directory hierarchy +that matches the file path information included in the native image +debug records -The resulting image should contain code (method) debug symbols. What is currently implemented ----------------------------- @@ -25,50 +36,119 @@ compiled method. Identifying the location of source code --------------------------------------- -In order for gdb to be able to locate the source files for your app -methods, Graal methods and JDK runtime methods you need to provide gdb -with a list of source root dirs a 'set directories' command: +One goal of the implementation is to make it simple to configure your +debugger so that it can identify the relevant source file when it +stops during program execution. The native image generator tries to +achieve this by accumulating the relevant sources in a suitably +structured file cache. + +The native image generator uses different strategies to locate source +files for JDK runtime classes, GraalVM classses and application source +classes for inclusion in the local sources cache. It identifies which +strategy to use based on the package name of the class. So, for +example, packages starting with java.* or jdk.* are JDK classes; +packages starting with org.graal.* or com.oracle.svm.* are GraalVM +classes; any other packages are regarded as application classes. + +Sources for JDK runtime classes are retrieved from the src.zip found +in the JDK release used to run the native image generation process. +Retrieved files are cached under subdirectory sources/jdk, using the +module name (for JDK11) and package name of the associated class to +define the directory hierarchy in which the source is located. + +So, for example, on Linux the source for class java.util.HashMap will +be cached in file sources/jdk/java.base/java/util/HashMap.java. Debug +info records for this class and its methods will identify this source +file using the relative directory path java.base/java/util and file +name HashMap.java. On Windows things will be the same modulo use of +'\' rather than '/' as the file separator. + +Sources for GraalVM classes are retrieved from zip files or source +directories derived from entries in the classpath. Retrieved files are +cached under subdirectory sources/graal, using the package name of the +associated class to define the directory hierarchy in which the source +is located (e.g. class com.oracle.svm.core.VM has its source file +cached at sources/graal/com/oracle/svm/core/VM.java). + +The lookup scheme for cached GraalVM sources varies depending upon +what is found in each classpath entry. Given a jar file entry like +/path/to/foo.jar, the corresponding file /path/to/foo.src.zip is +considered as a candidate zip file system from which source files may +be extracted. When the entry specifies a dir like /path/to/bar then +directories /path/to/bar/src and /path/to/bar/src_gen are considered +as candidates. Candidates are skipped when i) the zip file or source +directory does not exist or ii) it does not contain at least one +subdirectory hierarchy that matches one of the the expected GraalVM +package hierarchies. + +Sources for application classes are retrieved from source jar files or +source directories derived from entries in the classpath. Retrieved +files are cached under subdirectory sources/src, using the package +name of the associated class to define the directory hierarchy in +which the source is located (e.g. class org.my.foo.Foo has its +source file cached as sources/src/org/my/foo/Foo.java). + +The lookup scheme for cached pplication sources varies depending upon +what is found in each classpath entry. Given a jar file entry like +/path/to/foo.jar, the corresponding jar /path/to/foo-sources.jar is +considered as a candidate zip file system from which source files may +be extracted. When the entry specifies a dir like /path/to/bar/classes +or /path/to/bar/target/classes then directory /path/to/bar/src is +considered as a candidate. Finally, the current directory in whcih the +native image program is being run is also considered as a candidate. + +These lookup strategies are only provisional and may need extending in +future. Note however that it is possible to make missing sources +available by other means. One option is to unzip extra app source jars +or copying extra app source trees into the cache. Another is to +configure extra source search paths (see below). + +Configuring source paths in gdb +------------------------------- - (gdb) set directories /home/adinn/hello/src:/home/adinn/graal/sdk/src/org/graalvm.word/src:/home/adinn/graal/sdk/src/org.graalvm.options/src:... - -The argument is a comma separated list of source roots. It needs to -identify: +In order for gdb to be able to locate the source files for your app +classes, Graal classes and JDK runtime classes you need to provide gdb +with a list of source root dirs using the 'set directories' command: - - sources for your app - - sources under the Graal sdk, compiler, substratevm and truffle trees - - sources in the JDK src.zip file + (gdb) set directories /path/to/sources/jdk:/path/to/sources/graal:/path/to/sources/src -Needless to say the list for Graal is long and complex. Also, the JDK -sources are in a zip file and gdb does not understand zip sources. So -you need to extract the JDK sources as a preparatory step, +Directory .../sources/jdk should contain source files for all JDK runtime +classes referenced from debug records. -You can use shell script write_gdbsourcepath (added to Graal dir -substratevm) to auto-generate settings for the GRaal and JDK sources. +Directory .../sources/graal should contain source files for all GraalVM +classes referenced from debug records. Note that the current +implementation does not yet find some sources for the GraalVM JIT +compiler in the org.graalvm.compiler* package subspace. - $ bash write_gdbsourcepath +Directory .../sources/src should contain source files for all +application classes referenced from debug records, assuming they can +be located using the lookup strategy described above. -It creates a local file .gdbsourcepath which sets the relevant -directories. Before running it you can set two env vars to tell it -where to locate the source trees it needs to include: +You can supplement the files cached in sources/src by unzipping +application source jars or copying application source trees into the +cache. You need to ensure that any new subdirectory you add to +sources/src corresponds to the top level package for the classes whose +sources are being included. - - GRAAL_JAVA_SRC_ROOT should point to the dir into which you have - unzipped the src.zip from your Graal JDK release - - GRAAL_SRC_ROOT should point to the dir in which your Graal git - tree checkout is located +You can also add extra directories to the search path. Note that gdb +does not understand zip fomrat file systems so any extra entries you +add must identify a directory tree containing the relevant +sources. Once again. top leel entries in the directory added to the +search path must correspond to the top level package for the classes +whose sources are being included. -Note that the script ignores test source dirs and jdk dirs that do not -match the release level of the JDK (i.e. if you use jdk8 it will ony -include jdk8 src dirs). The script runs the java command available via -JAVA_HOME to idenitfy which JDK is in use). +Configuring source paths in VS +------------------------------ -If you run the script from the substratevm dir of your Graal git repo -checkout the script will default GRAAL_SRC_ROOT to the parent dir. +TO BE ADDED -If JAVA_HOME is set the script will default GRAAL_JAVA_SRC_ROOT to -$JAVA_HOME/src +Checking debug info on Linux +---------------------------- -Checking debug info -------------------- +n.b. this is only of interest to those who want to understand how the +debug info implemetation works or want to trouble shoot problems +encountered during debugging that might relate to the debug info +encoding. The objdump command can be used to display the dbeug info embedded into a native image. The following commands (which all assume the From 9a8b65fa3417c6b77c27e3ec1b8b38930158e283 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Wed, 26 Feb 2020 15:14:31 +0000 Subject: [PATCH 088/130] fixed typos and small format/wording errors and rmeoved smeredudant code removed some redundant code --- substratevm/DEBUGINFO.md | 8 +++---- .../debuginfo/DebugInfoProvider.java | 24 ------------------- .../objectfile/elf/dwarf/StringEntry.java | 2 +- .../objectfile/elf/dwarf/StringTable.java | 2 +- 4 files changed, 6 insertions(+), 30 deletions(-) diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 0536be0bf2a3..58e8bd48b63e 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -5,7 +5,7 @@ To add debug info to a generated native image add flag -H:+GenerateDebugInfo to the native image command line. $ javac Hello.java - $ mx native-image -H:+GenerateDebugInfo Hello + $ mx native-image -H:GenerateDebugInfo=1 Hello The resulting image should contain code (method) debug records in a format gdb understands (VS support is still under development). @@ -88,13 +88,13 @@ name of the associated class to define the directory hierarchy in which the source is located (e.g. class org.my.foo.Foo has its source file cached as sources/src/org/my/foo/Foo.java). -The lookup scheme for cached pplication sources varies depending upon +The lookup scheme for cached Application sources varies depending upon what is found in each classpath entry. Given a jar file entry like /path/to/foo.jar, the corresponding jar /path/to/foo-sources.jar is considered as a candidate zip file system from which source files may be extracted. When the entry specifies a dir like /path/to/bar/classes or /path/to/bar/target/classes then directory /path/to/bar/src is -considered as a candidate. Finally, the current directory in whcih the +considered as a candidate. Finally, the current directory in which the native image program is being run is also considered as a candidate. These lookup strategies are only provisional and may need extending in @@ -131,7 +131,7 @@ sources/src corresponds to the top level package for the classes whose sources are being included. You can also add extra directories to the search path. Note that gdb -does not understand zip fomrat file systems so any extra entries you +does not understand zip format file systems so any extra entries you add must identify a directory tree containing the relevant sources. Once again. top leel entries in the directory added to the search path must correspond to the top level package for the classes 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 937e40c108f3..444be49613ac 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 @@ -167,30 +167,6 @@ enum Type { DebugFrameSizeChange.Type getType(); } - /** - * convenience interface defining iterator type. - */ - interface DebugTypeInfoProvider extends Iterable { - } - - /** - * convenience interface defining iterator type. - */ - interface DebugCodeInfoProvider extends Iterable { - } - - /** - * convenience interface defining iterator type. - */ - interface DebugLineInfoProvider extends Iterable { - } - - /** - * convenience interface defining iterator type. - */ - interface DebugDataInfoProvider extends Iterable { - } - Stream typeInfoProvider(); Stream codeInfoProvider(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java index b7963faf9661..f08fa4da79c7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java @@ -48,7 +48,7 @@ public String getString() { public int getOffset() { /* - * offset must be set before this can be fetched + * Offset must be set before this can be fetched */ assert offset >= 0; return offset; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java index 1ba2def55f73..b2e0479e5e31 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java @@ -44,7 +44,7 @@ public StringTable() { } /** - * Wnsures a unique instance of a string exists in the + * Ensures a unique instance of a string exists in the * table, inserting the supplied String if no equivalent * String is already present. This should only be called * before the string section has been written. From 6774391f260ed2815521cbcd5b7ee76b789b2148 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 27 Feb 2020 13:32:43 +0000 Subject: [PATCH 089/130] added -H:DebugInfoSourceSearchPath option, tweaked SourceCacheType enum, cleaned up SourceCache init and memoized source cache checks --- .../com/oracle/svm/core/SubstrateOptions.java | 3 + .../image/sources/ApplicationSourceCache.java | 97 +++++++++++++------ .../image/sources/GraalVMSourceCache.java | 79 ++++++++++----- .../hosted/image/sources/JDKSourceCache.java | 10 +- .../svm/hosted/image/sources/SourceCache.java | 55 ++--------- .../hosted/image/sources/SourceCacheType.java | 20 +++- .../hosted/image/sources/SourceManager.java | 25 ++++- 7 files changed, 184 insertions(+), 105 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 1706a8f4ea56..9504c6710e02 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -450,4 +450,7 @@ protected void onValueUpdate(EconomicMap, Object> values, Integer o } }; + @Option(help = "Search path for source files for Application or GraalVM classes (list of comma-separated directories or jar files)")// + public static final HostedOptionKey DebugInfoSourceSearchPath = new HostedOptionKey(null) { + }; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 1a9ebc2304fa..26ee2f706db1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -26,6 +26,9 @@ package com.oracle.svm.hosted.image.sources; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.option.OptionUtils; + import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -34,60 +37,92 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static com.oracle.svm.hosted.image.sources.SourceCacheType.APPLICATION; + public class ApplicationSourceCache extends SourceCache { /** - * create an application source cache + * Create an application source cache. */ protected ApplicationSourceCache() { - super(SourceCache.APPLICATION_CACHE_KEY); initSrcRoots(); } + @Override + protected final SourceCacheType getType() { + return APPLICATION; + } + private void initSrcRoots() { String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); assert javaClassPath != null; String[] classPathEntries = javaClassPath.split(File.pathSeparator); - /* add dirs or jars found in the classpath */ + /* Add dirs or jars found in the classpath */ for (String classPathEntry : classPathEntries) { - Path entryPath = Paths.get(classPathEntry); - String fileNameString = entryPath.getFileName().toString(); - if (fileNameString.endsWith(".jar")) { - // application jar /path/to/xxx.jar should have - // sources /path/to/xxx-sources.jar + tryClassPathRoot(classPathEntry); + } + if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { + for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { + trySourceRoot(searchPathEntry); + } + } + /* add the current working directory as a path of last resort */ + srcRoots.add(Paths.get(".")); + } + private void tryClassPathRoot(String sourceRoot) { + trySourceRoot(sourceRoot, true); + } + private void trySourceRoot(String sourceRoot) { + trySourceRoot(sourceRoot, false); + } + private void trySourceRoot(String sourceRoot, boolean fromClassPath) { + Path sourcePath = Paths.get(sourceRoot); + String fileNameString = sourcePath.getFileName().toString(); + if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".zip")) { + if (fromClassPath && fileNameString.endsWith(".jar")) { + /* + * application jar /path/to/xxx.jar should have + * sources /path/to/xxx-sources.jar + */ int length = fileNameString.length(); - String srcFileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; - Path srcPath = entryPath.getParent().resolve(srcFileNameString); - if (srcPath.toFile().exists()) { - try { - FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); - for (Path root : fileSystem.getRootDirectories()) { - srcRoots.add(root); - } - } catch (IOException ioe) { - /* ignore this entry */ - } catch (FileSystemNotFoundException fnfe) { - /* ignore this entry */ + fileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; + } + sourcePath = sourcePath.getParent().resolve(fileNameString); + if (sourcePath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(sourcePath, null); + for (Path root : fileSystem.getRootDirectories()) { + srcRoots.add(root); } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ } - } else { + } + } else { + if (fromClassPath) { /* - * for dir entries ending in classes or target/classes - * look for a parallel src tree - */ - if (entryPath.endsWith("classes")) { - Path parent = entryPath.getParent(); + * for dir entries ending in classes or target/classes + * look for a parallel src tree + */ + if (sourcePath.endsWith("classes")) { + Path parent = sourcePath.getParent(); if (parent.endsWith("target")) { parent = parent.getParent(); } - Path srcPath = (parent.resolve("src")); - File file = srcPath.toFile(); + sourcePath = (parent.resolve("src")); + File file = sourcePath.toFile(); if (file.exists() && file.isDirectory()) { - srcRoots.add(srcPath); + srcRoots.add(sourcePath); } } + } else { + // try the path as provided + File file = sourcePath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(sourcePath); + } } } - /* add the current working directory as a path of last resort */ - srcRoots.add(Paths.get(".")); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index da8bfd6cde07..9ce7f603c848 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -26,6 +26,9 @@ package com.oracle.svm.hosted.image.sources; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.option.OptionUtils; + import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -35,16 +38,21 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static com.oracle.svm.hosted.image.sources.SourceCacheType.GRAALVM; import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; public class GraalVMSourceCache extends SourceCache { /** - * create a GraalVM source cache + * Create a GraalVM source cache. */ protected GraalVMSourceCache() { - super(SourceCache.GRAALVM_CACHE_KEY); initSrcRoots(); } + @Override + protected final SourceCacheType getType() { + return GRAALVM; + } + private static final String JAVA_CLASSPATH_PROP = "java.class.path"; private void initSrcRoots() { @@ -52,38 +60,63 @@ private void initSrcRoots() { assert javaClassPath != null; String[] classPathEntries = javaClassPath.split(File.pathSeparator); for (String classPathEntry : classPathEntries) { - Path entryPath = Paths.get(classPathEntry); - String fileNameString = entryPath.getFileName().toString(); - if (fileNameString.endsWith(".jar")) { - // GraalVM jar /path/to/xxx.jar should have - // sources /path/to/xxx.src.zip.jar + tryClassPathRoot(classPathEntry); + } + if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { + for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { + trySourceRoot(searchPathEntry); + } + } + } + private void tryClassPathRoot(String sourceRoot) { + trySourceRoot(sourceRoot, true); + } + private void trySourceRoot(String sourceRoot) { + trySourceRoot(sourceRoot, false); + } + private void trySourceRoot(String sourceRoot, boolean fromClassPath) { + Path sourcePath = Paths.get(sourceRoot); + String fileNameString = sourcePath.getFileName().toString(); + if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".src.zip")) { + if (fromClassPath && fileNameString.endsWith(".jar")) { + /* + * GraalVM jar /path/to/xxx.jar in classpath should + * have sources /path/to/xxx.src.zip + */ int length = fileNameString.length(); - String srcFileNameString = fileNameString.substring(0, length - 3) + "src.zip"; - Path srcPath = entryPath.getParent().resolve(srcFileNameString); - if (srcPath.toFile().exists()) { - try { - FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); - for (Path root : fileSystem.getRootDirectories()) { - if (filterSrcRoot(root)) { - srcRoots.add(root); - } + fileNameString = fileNameString.substring(0, length - 3) + "src.zip"; + } + Path srcPath = sourcePath.getParent().resolve(fileNameString); + if (srcPath.toFile().exists()) { + try { + FileSystem fileSystem = FileSystems.newFileSystem(srcPath, null); + for (Path root : fileSystem.getRootDirectories()) { + if (filterSrcRoot(root)) { + srcRoots.add(root); } - } catch (IOException ioe) { - /* ignore this entry */ - } catch (FileSystemNotFoundException fnfe) { - /* ignore this entry */ } + } catch (IOException ioe) { + /* ignore this entry */ + } catch (FileSystemNotFoundException fnfe) { + /* ignore this entry */ } - } else { + } + } else { + if (fromClassPath) { /* graal classpath dir entries should have a src and/or src_gen subdirectory */ - Path srcPath = entryPath.resolve("src"); + Path srcPath = sourcePath.resolve("src"); if (filterSrcRoot(srcPath)) { srcRoots.add(srcPath); } - srcPath = entryPath.resolve("src_gen"); + srcPath = sourcePath.resolve("src_gen"); if (filterSrcRoot(srcPath)) { srcRoots.add(srcPath); } + } else { + // try the path as provided + if (filterSrcRoot(sourcePath)) { + srcRoots.add(sourcePath); + } } } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index e53d75f75c9b..3268b70aea3f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -33,15 +33,21 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static com.oracle.svm.hosted.image.sources.SourceCacheType.JDK; + public class JDKSourceCache extends SourceCache { /** - * create a JDK runtime class source cache. + * Create a JDK runtime class source cache.. */ protected JDKSourceCache() { - super(SourceCache.JDK_CACHE_KEY); initSrcRoots(); } + @Override + protected final SourceCacheType getType() { + return JDK; + } + private void initSrcRoots() { String javaHome = System.getProperty(JAVA_HOME_PROP); assert javaHome != null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 91384cfcb553..9e55c9737489 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -62,17 +62,19 @@ public abstract class SourceCache { protected List srcRoots; /** - * Create a source cache with a specific base type. - * @param key a String identifying the subdir under - * which sources should be cached which should also - * match the type of content being cached + * Create some flavour of source cache. */ - protected SourceCache(String key) { - basePath = Paths.get(SOURCE_CACHE_ROOT_DIR, key); + protected SourceCache() { + basePath = Paths.get(SOURCE_CACHE_ROOT_DIR).resolve(getType().getSubdir()); srcRoots = new ArrayList<>(); - } + /** + * Idenitfy the specific type of this source cache + * @return + */ + protected abstract SourceCacheType getType(); + /** * A local directory serving as the root for all * source trees maintained by the different @@ -84,44 +86,7 @@ protected SourceCache(String key) { * under which files belonging to this specific cache * are located. */ - private Path basePath; - /** - * JDK runtime code sources are cached using this key as a - * leading path prefix with a module name as a sub-path - * prefix when we have a modular JDK. - * - * For example, the full file path to a file under the cache - * root directory might be jdk/java/lang/Throwable.java on jdk8 or - * jdk/java.base/java/lang/Throwable.java on jdk11 - */ - protected static final String JDK_CACHE_KEY = "jdk"; - /** - * GraalVM code sources are cached using this key as a - * leading path prefix with an enclosing package name - * and the name src or src_gen forming a sub-path prefix. - * - * For example, the full file path to a file under the cache - * root directory might be - * graal/com/oracle/svm/core/Isolates.java - * or - * graal/org/graalvm/compiler/core/phases/LowTier_OptionDescriptors.java - */ - protected static final String GRAALVM_CACHE_KEY = "graal"; - /** - * Application code sources are cached using this key as - * a leading path prefix with a name or sequence of - * names derived from a classpath jar or dir entry - * employed as a sub-path prefix. - * - * For example, the full file path to a file under the cache - * root directory might be - * src/Hello.java - * or - * src/hello/impl/HelloImpl.java - * or - * src/hibernate-core-5.4.4.Final/org/hibernate/annotations/Entity.java - */ - protected static final String APPLICATION_CACHE_KEY = "src"; + private final Path basePath; /** * Cache the source file identified by the supplied prototype * path if a legitimate candidate for inclusion in this cache diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java index 10863a5e572c..5e37d3883141 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCacheType.java @@ -26,8 +26,22 @@ package com.oracle.svm.hosted.image.sources; +import java.nio.file.Path; +import java.nio.file.Paths; + public enum SourceCacheType { - JDK, - GRAALVM, - APPLICATION + JDK("jdk"), + GRAALVM("graal"), + APPLICATION("src"); + + final Path subdir; + + SourceCacheType(String subdir) { + this.subdir = Paths.get(subdir); + } + + public Path getSubdir() { + return subdir; + } + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java index 459acebe6a08..d3d4252f6685 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -50,7 +50,12 @@ public class SourceManager { * null if a source file cannot be found or cached. */ public Path findAndCacheSource(ResolvedJavaType resolvedType) { - Path path = null; + /* short circuit if we have already seen this type */ + Path path = verifiedPaths.get(resolvedType); + if (path != null) { + return (path != INVALID_PATH ? path : null); + } + String fileName = computeBaseName(resolvedType); /* * null for the name means this class @@ -91,6 +96,9 @@ public Path findAndCacheSource(ResolvedJavaType resolvedType) { } } } + /* memoize the lookup */ + verifiedPaths.put(resolvedType, (path != null ? path : INVALID_PATH)); + return path; } @@ -241,6 +249,21 @@ private SourceCacheType sourceCacheType(String packageName, Class javaClass) */ private static HashMap caches = new HashMap<>(); + /** + * A map from a Java type to an associated source paths which + * is known to have an up to date entry in the relevant source + * file cache. This is used to memoize previous lookups. + */ + private static HashMap verifiedPaths = new HashMap<>(); + + /** + * An invalid path used as a marker to track failed lookups + * so we don't waste time looking up the source again. + * Note that all legitimate paths will end with a ".java" + * suffix. + */ + private static final Path INVALID_PATH = Paths.get("invalid"); + /** * Retrieve the source cache used to locate and cache sources * of a given type as determined by the supplied key, creating From 26af82e9b496945b8f860f8df7e46b5fccd7b5c7 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 27 Feb 2020 14:24:10 +0000 Subject: [PATCH 090/130] update readme to describe DebugInfoSourceSearchPath option --- substratevm/DEBUGINFO.md | 69 +++++++++++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/substratevm/DEBUGINFO.md b/substratevm/DEBUGINFO.md index 58e8bd48b63e..4ea2b3f640c3 100644 --- a/substratevm/DEBUGINFO.md +++ b/substratevm/DEBUGINFO.md @@ -2,22 +2,69 @@ Using the ptototype debug info feature -------------------------------------- To add debug info to a generated native image add flag --H:+GenerateDebugInfo to the native image command line. +-H:GenerateDebugInfo= to the native image command line (where N is +a positive integer value -- the default value 0 means generate no +debug info). For example, $ javac Hello.java $ mx native-image -H:GenerateDebugInfo=1 Hello The resulting image should contain code (method) debug records in a -format gdb understands (VS support is still under development). - -The flag also enables caching of sources for JDK runtime classes, -GraalVM classes and application classes which can be located during -native image generation. The cache is created under local subdirectory -sources and can be used to configure source file search path roots for -the debugger. Files in the cache are located in a directory hierarchy -that matches the file path information included in the native image -debug records - +format gdb understands (VS support is still under development). At +present it makes no difference which positive value is supplied as +argument to the GenerateDebugInfo option. + +The GenerateDebugInfo option also enables caching of sources for any +JDK runtime classes, GraalVM classes and application classes which can +be located during native image generation. The cache is created under +local subdirectory sources. It is used to configure source file search +path roots for the debugger. Files in the cache are located in a +directory hierarchy that matches the file path information included in +the native image debug records. The source cache should contain all +the files needed to debug the generated image and nothing more. This +local cache provides a convenient way of making just the necessary +sources available to the debugger/IDE when debugging a native image. + +The implementation tries to be smart about locating source files. It +uses the current JAVA_HOME to locate the JDK src.zip when searching +for JDK runtime sources. It also uses entries in the classpath to +suggest locations for GraalVM source files and application source +files (see below for precise details of the scheme used to identify +source locations). However, source layouts do vary and it may no tbe +possible to find all sources. Hence, users can specify the location of +source files explicitly on the command line using option +DebugInfoSourceSearchPath: + + $ javac --source-path apps/greeter/src \ + -d apps/greeter/classes org/my/greeter/*Greeter.java + $ javac -cp apps/greeter/classes \ + --source-path apps/hello/src \ + -d apps/hello/classes org/my/hello/Hello.java + $ mx native-image -H:GenerateDebugInfo=1 \ + -H:DebugInfoSourceSearchPath=apps/hello/src \ + -H:DebugInfoSourceSearchPath=apps/greeter/src \ + -cp apps/hello/classes:apps/greeter/classes org.my.hello.Hello + +Option DebugInfoSourceSearchPath can be repeated as many times as +required to notify all the target source locations. The value passed +to this option can be either an absolute or relative path. It can +identify either a directory, a source jar or a source zip file. It is +also possible to specify several source roots at once using a comma +separator: + + $ mx native-image -H:GenerateDebugInfo=1 \ + -H:DebugInfoSourceSearchPath=apps/hello/target/hello-sources.jar,apps/greeter/target/greeter-sources.jar \ + -cp apps/target/hello.jar:apps/target/greeter.jar \ + org.my.Hello + +Note that in both the examples above the DebugInfoSourceSearchPath +options are actually redundant. In the first case the classpath +entries for apps/hello/classes and apps/greeter/classes will be used +to derive the default search roots apps/hello/src and +apps/greeter/src. In the second case classpath entires +apps/target/hello.jar and apps/target/greeter.jar will be used to +derive the default search roots apps/target/hello-sources.jar and +apps/target/greeter-sources.jar. What is currently implemented ----------------------------- From 783d30ea5be5278be3b20f47a81a636786d65a64 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 27 Feb 2020 13:24:34 -0500 Subject: [PATCH 091/130] use string,replace() to avoid backslash error in regex on Windows --- .../src/com/oracle/svm/hosted/image/sources/SourceCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 9e55c9737489..b2ca02ee3985 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -212,7 +212,7 @@ protected Path extendPath(Path root, Path filePath) { String fileSeparator = filePath.getFileSystem().getSeparator(); String newSeparator = root.getFileSystem().getSeparator(); if (!fileSeparator.equals(newSeparator)) { - filePathString = filePathString.replaceAll(fileSeparator, newSeparator); + filePathString = filePathString.replace(fileSeparator, newSeparator); } return root.resolve(filePathString); } From 8dbf126ad9e2c7acbcfd4f70fdeb61f93c1b848d Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 28 Feb 2020 13:00:09 +0000 Subject: [PATCH 092/130] obtain classpath from image classloader, clean up source searches, ensure classpath dirs are used as is if no target/classes suffix --- .../image/sources/ApplicationSourceCache.java | 41 ++---- .../image/sources/GraalVMSourceCache.java | 17 +-- .../hosted/image/sources/JDKSourceCache.java | 6 + .../svm/hosted/image/sources/SourceCache.java | 118 +++++++++++++++--- 4 files changed, 124 insertions(+), 58 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 26ee2f706db1..50877485fd69 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -26,9 +26,6 @@ package com.oracle.svm.hosted.image.sources; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.option.OptionUtils; - import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -53,26 +50,19 @@ protected final SourceCacheType getType() { } private void initSrcRoots() { - String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); - assert javaClassPath != null; - String[] classPathEntries = javaClassPath.split(File.pathSeparator); /* Add dirs or jars found in the classpath */ for (String classPathEntry : classPathEntries) { tryClassPathRoot(classPathEntry); } - if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { - for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { - trySourceRoot(searchPathEntry); - } + for (String sourcePathEntry : sourcePathEntries) { + trySourceRoot(sourcePathEntry); } - /* add the current working directory as a path of last resort */ - srcRoots.add(Paths.get(".")); } - private void tryClassPathRoot(String sourceRoot) { - trySourceRoot(sourceRoot, true); + private void tryClassPathRoot(String classPathEntry) { + trySourceRoot(classPathEntry, true); } - private void trySourceRoot(String sourceRoot) { - trySourceRoot(sourceRoot, false); + private void trySourceRoot(String sourcePathEntry) { + trySourceRoot(sourcePathEntry, false); } private void trySourceRoot(String sourceRoot, boolean fromClassPath) { Path sourcePath = Paths.get(sourceRoot); @@ -103,7 +93,7 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { if (fromClassPath) { /* * for dir entries ending in classes or target/classes - * look for a parallel src tree + * translate to a parallel src tree */ if (sourcePath.endsWith("classes")) { Path parent = sourcePath.getParent(); @@ -111,18 +101,13 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { parent = parent.getParent(); } sourcePath = (parent.resolve("src")); - File file = sourcePath.toFile(); - if (file.exists() && file.isDirectory()) { - srcRoots.add(sourcePath); - } - } - } else { - // try the path as provided - File file = sourcePath.toFile(); - if (file.exists() && file.isDirectory()) { - srcRoots.add(sourcePath); } } + // try the path as provided + File file = sourcePath.toFile(); + if (file.exists() && file.isDirectory()) { + srcRoots.add(sourcePath); + } } } -} +} \ No newline at end of file diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 9ce7f603c848..d92c21ab05ee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -26,9 +26,6 @@ package com.oracle.svm.hosted.image.sources; -import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.option.OptionUtils; - import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; @@ -62,17 +59,15 @@ private void initSrcRoots() { for (String classPathEntry : classPathEntries) { tryClassPathRoot(classPathEntry); } - if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { - for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { - trySourceRoot(searchPathEntry); - } + for (String sourcePathEntry : sourcePathEntries) { + tryClassPathRoot(sourcePathEntry); } } - private void tryClassPathRoot(String sourceRoot) { - trySourceRoot(sourceRoot, true); + private void tryClassPathRoot(String classPathEntry) { + trySourceRoot(classPathEntry, true); } - private void trySourceRoot(String sourceRoot) { - trySourceRoot(sourceRoot, false); + private void trySourceRoot(String sourcePathEntry) { + trySourceRoot(sourcePathEntry, false); } private void trySourceRoot(String sourceRoot, boolean fromClassPath) { Path sourcePath = Paths.get(sourceRoot); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index 3268b70aea3f..ef6cb07baa71 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -48,6 +48,12 @@ protected final SourceCacheType getType() { return JDK; } + /* + * properties needed to locate relevant JDK and app source roots + */ + private static final String JAVA_HOME_PROP = "java.home"; + private static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + private void initSrcRoots() { String javaHome = System.getProperty(JAVA_HOME_PROP); assert javaHome != null; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index b2ca02ee3985..700cb123b7fd 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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 @@ -25,6 +26,13 @@ package com.oracle.svm.hosted.image.sources; +import com.oracle.svm.core.SubstrateOptions; +import com.oracle.svm.core.annotate.AutomaticFeature; +import com.oracle.svm.core.option.OptionUtils; +import com.oracle.svm.hosted.FeatureImpl; +import com.oracle.svm.hosted.ImageClassLoader; +import org.graalvm.nativeimage.hosted.Feature; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -34,6 +42,7 @@ import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.List; + /** * An abstract cache manager for some subspace of the * JDK, GraalVM or application source file space. This class @@ -49,12 +58,16 @@ public abstract class SourceCache { - /* - * properties needed to locate relevant JDK and app source roots + /** + * A list of all entries in the classpath used + * by the native image classloader */ - protected static final String JAVA_CLASSPATH_PROP = "java.class.path"; - protected static final String JAVA_HOME_PROP = "java.home"; - protected static final String JAVA_SPEC_VERSION_PROP = "java.specification.version"; + protected static final List classPathEntries = new ArrayList<>(); + /** + * A list of all entries in the classpath used + * by the native image classloader + */ + protected static final List sourcePathEntries = new ArrayList<>(); /** * A list of root directories which may contain source files * from which this cache can be populated @@ -70,8 +83,8 @@ protected SourceCache() { } /** - * Idenitfy the specific type of this source cache - * @return + * Identify the specific type of this source cache + * @return the source cache type */ protected abstract SourceCacheType getType(); @@ -130,6 +143,17 @@ public File findCandidate(Path filePath) { } return null; } + /** + * Attempt to copy a source file from one of this cache's + * source roots to the local sources directory storing + * it in the subdirectory that belongs to this cache. + * @param filePath a path appended to each of the cache's + * source roots in turn until an acceptable source file + * is found and copied to the local source directory. + * @return the supplied path if the file has been located + * and copied to the local sources directory or null if + * it was not found or the copy failed. + */ public Path tryCacheFile(Path filePath) { for (Path root : srcRoots) { Path targetPath = cachedPath(filePath); @@ -147,9 +171,21 @@ public Path tryCacheFile(Path filePath) { } return null; } + /** + * Check whether the copy of a given source file in the + * local source cache is up to date with respect to any + * original located in this cache's and if not copy the + * original to the subdirectory that belongs to this cache. + * @param filePath a path appended to each of the cache's + * source roots in turn until an matching original source + * is found for comparison against the local source directory. + * @return the supplied path if the file is up to date or if + * an updated version has been copied to the local sources + * directory or null if was not found or the copy failed. + */ public Path checkCacheFile(Path filePath) { + Path targetPath = cachedPath(filePath); for (Path root : srcRoots) { - Path targetPath = cachedPath(filePath); Path sourcePath = extendPath(root, filePath); try { if (checkSourcePath(sourcePath)) { @@ -159,19 +195,23 @@ public Path checkCacheFile(Path filePath) { try { Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); } catch (IOException e) { + /* delete the target file as it is invalid */ + targetPath.toFile().delete(); return null; } } return filePath; - } else { - /* delete the target file as it is out of date */ - targetPath.toFile().delete(); } } catch (IOException e) { - // hmm last modified time blew up? + /* delete the target file as it is invalid */ + targetPath.toFile().delete(); + /* have another go at caching it */ return tryCacheFile(filePath); } } + /* delete the target file as it is invalid */ + targetPath.toFile().delete(); + return null; } /** @@ -218,7 +258,7 @@ protected Path extendPath(Path root, Path filePath) { } /** - * convert a potential resolved candidate path to + * Convert a potential resolved candidate path to * the corresponding local Path in this cache. * @param candidate a resolved candidate path for * some given resolution request @@ -228,7 +268,7 @@ protected Path cachedPath(Path candidate) { return basePath.resolve(candidate); } /** - * convert a potential resolved candidate path to + * Convert a potential resolved candidate path to * the corresponding local File in this cache. * @param candidate a resolved candidate path for * some given resolution request @@ -238,17 +278,20 @@ protected File cachedFile(Path candidate) { return cachedPath(candidate).toFile(); } /** - * indicate whether a source path identifies a fie in the associated file system + * Indicate whether a source path identifies a + * file in the associated file system. * @param sourcePath - * @return true if the path identifies a file or false if no such file can be found - * @throws IOException if there is some error in resolving the path + * @return true if the path identifies a file or + * false if no such file can be found. + * @throws IOException if there is some error in + * resolving the path. */ private boolean checkSourcePath(Path sourcePath) throws IOException { return Files.isRegularFile(sourcePath); } /** - * ensure the directory hierarchy for a path exists - * creating any missing directories if needed + * Ensure the directory hierarchy for a path exists + * creating any missing directories if needed. * @param targetDir a path to the desired directory * @throws IOException if it is not possible to create * one or more directories in the path @@ -261,4 +304,41 @@ private void ensureTargetDirs(Path targetDir) throws IOException { } } } + /** + * Add a path to the list of classpath entries + * @param path The path to add. + */ + private static void addClassPathEntry(String path) { + classPathEntries.add(path); + } + + /** + * Add a path to the list of source path entries + * @param path The path to add. + */ + private static void addSourcePathEntry(String path) { + sourcePathEntries.add(path); + } + + /** + * An automatic feature class which acquires the image + * loader class path via the afterAnalysis callback. + */ + @AutomaticFeature + public static class SourceCacheFeature implements Feature { + @Override + public void afterAnalysis(AfterAnalysisAccess access) { + FeatureImpl.AfterAnalysisAccessImpl accessImpl = (FeatureImpl.AfterAnalysisAccessImpl) access; + ImageClassLoader loader = accessImpl.getImageClassLoader(); + for (String entry : loader.getClasspath()) { + addClassPathEntry(entry); + } + // also add any necessary source path entries + if (SubstrateOptions.DebugInfoSourceSearchPath.getValue() != null) { + for (String searchPathEntry : OptionUtils.flatten(",", SubstrateOptions.DebugInfoSourceSearchPath.getValue())) { + addSourcePathEntry(searchPathEntry); + } + } + } + } } From 7309dc65c3047bcefa6ce3827c02fabce449e1bd Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 3 Mar 2020 12:13:14 -0500 Subject: [PATCH 093/130] Move ClassEntry and siblings to package com.oracle.objectfile.debugentry --- .../{elf/dwarf => debugentry}/ClassEntry.java | 16 ++++++++-------- .../{elf/dwarf => debugentry}/DirEntry.java | 2 +- .../{elf/dwarf => debugentry}/FileEntry.java | 2 +- .../{elf/dwarf => debugentry}/PrimaryEntry.java | 6 +++--- .../{elf/dwarf => debugentry}/Range.java | 6 +++--- .../{elf/dwarf => debugentry}/StringEntry.java | 2 +- .../{elf/dwarf => debugentry}/StringTable.java | 2 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 3 +++ .../elf/dwarf/DwarfFrameSectionImpl.java | 2 ++ .../elf/dwarf/DwarfInfoSectionImpl.java | 3 +++ .../elf/dwarf/DwarfLineSectionImpl.java | 5 +++++ .../objectfile/elf/dwarf/DwarfSectionImpl.java | 1 + .../objectfile/elf/dwarf/DwarfSections.java | 6 ++++++ .../elf/dwarf/DwarfStrSectionImpl.java | 1 + 14 files changed, 39 insertions(+), 18 deletions(-) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/ClassEntry.java (94%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/DirEntry.java (97%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/FileEntry.java (97%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/PrimaryEntry.java (96%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/Range.java (91%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/StringEntry.java (98%) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/{elf/dwarf => debugentry}/StringTable.java (98%) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java similarity index 94% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java index 6d8714c5ae38..f5034a8254e7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/ClassEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/ClassEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -117,7 +117,7 @@ public ClassEntry(String className, FileEntry fileEntry) { this.totalSize = -1; } - PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { + public PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { if (primaryIndex.get(primary) == null) { PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); primaryEntries.add(primaryEntry); @@ -127,7 +127,7 @@ PrimaryEntry addPrimary(Range primary, List frameSizeInfos return null; } - void addSubRange(Range subrange, FileEntry subFileEntry) { + public void addSubRange(Range subrange, FileEntry subFileEntry) { Range primary = subrange.getPrimary(); /* * the subrange should belong to a primary range @@ -163,7 +163,7 @@ public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { return localFilesIndex.get(fileEntry); } - String getFileName() { + public String getFileName() { return fileEntry.getFileName(); } @@ -175,24 +175,24 @@ String getDirName() { return fileEntry.getPathName(); } - void setCUIndex(int cuIndex) { + public void setCUIndex(int cuIndex) { // should only get set once to a non-negative value assert cuIndex >= 0; assert this.cuIndex == -1; this.cuIndex = cuIndex; } - int getCUIndex() { + public int getCUIndex() { // should have been set before being read assert cuIndex >= 0; return cuIndex; } - int getLineIndex() { + public int getLineIndex() { return lineIndex; } - void setLineIndex(int lineIndex) { + public void setLineIndex(int lineIndex) { this.lineIndex = lineIndex; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java similarity index 97% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index c033986b8be6..c5f6fa045c67 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import java.nio.file.Path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java similarity index 97% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index bc53ec654e64..8c28e018100a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; /** * Tracks debug info associated with a Java source file. diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java similarity index 96% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index cd356dd00535..ebebdfec72b5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; @@ -104,11 +104,11 @@ public FileEntry getSubrangeFileEntry(Range subrange) { return subrangeIndex.get(subrange); } - List getFrameSizeInfos() { + public List getFrameSizeInfos() { return frameSizeInfos; } - int getFrameSize() { + public int getFrameSize() { return frameSize; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java similarity index 91% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 2608be71322b..a79e6f00219c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import java.nio.file.Path; import java.nio.file.Paths; @@ -54,14 +54,14 @@ public class Range { /* * create a primary range */ - Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { + public Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line) { this(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, line, null); } /* * create a primary or secondary range */ - Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { + public Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { /* * currently file name and full method name need to go into the debug_str section * other strings just need to be deduplicated to save space diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java similarity index 98% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java index f08fa4da79c7..d1ebb16be685 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; /** * Used to retain a unique (up to equals) copy of a diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java similarity index 98% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java index b2e0479e5e31..721c77940ee5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java @@ -24,7 +24,7 @@ * questions. */ -package com.oracle.objectfile.elf.dwarf; +package com.oracle.objectfile.debugentry; import java.util.HashMap; import java.util.Iterator; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 8ae11c436937..c20e9b27af0a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -29,6 +29,9 @@ 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.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import java.util.LinkedList; import java.util.Map; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 3923045bacd4..d8d7ad23af74 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_id; 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 6a07284cb46a..025450fca2de 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 @@ -27,6 +27,9 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import java.util.LinkedList; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 10305904c0ea..aff33ce4f828 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -29,6 +29,11 @@ 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.debugentry.DirEntry; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; import java.util.Map; 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 b508ef12f6a9..7b4a1d6fd8b1 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 @@ -31,6 +31,7 @@ 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.ELFObjectFile; import java.nio.ByteOrder; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 0ba4bd7543ea..faa546479b50 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -26,6 +26,12 @@ package com.oracle.objectfile.elf.dwarf; +import com.oracle.objectfile.debugentry.ClassEntry; +import com.oracle.objectfile.debugentry.DirEntry; +import com.oracle.objectfile.debugentry.FileEntry; +import com.oracle.objectfile.debugentry.PrimaryEntry; +import com.oracle.objectfile.debugentry.Range; +import com.oracle.objectfile.debugentry.StringTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.elf.ELFMachine; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 0bcdbccb5992..1ee212b112b5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -27,6 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.debugentry.StringEntry; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; From 4f21b65a57ee9dfbc46e3d62e056558a322839a0 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 6 Mar 2020 15:28:34 +0000 Subject: [PATCH 094/130] fixed problem with wrong path for graalvm sources and allowed for null source file path --- .../objectfile/debugentry/ClassEntry.java | 50 ++++++++---- .../objectfile/debugentry/PrimaryEntry.java | 4 - .../oracle/objectfile/debugentry/Range.java | 6 +- .../elf/dwarf/DwarfLineSectionImpl.java | 11 ++- .../objectfile/elf/dwarf/DwarfSections.java | 7 +- .../svm/hosted/image/NativeBootImage.java | 52 +++++++----- .../hosted/image/sources/SourceManager.java | 79 +++++++++---------- 7 files changed, 124 insertions(+), 85 deletions(-) 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 f5034a8254e7..b1a9cf22a1ee 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 @@ -104,12 +104,14 @@ public ClassEntry(String className, FileEntry fileEntry) { this.localFilesIndex = new HashMap<>(); this.localDirs = new LinkedList<>(); this.localDirsIndex = new HashMap<>(); - localFiles.add(fileEntry); - localFilesIndex.put(fileEntry, localFiles.size()); - DirEntry dirEntry = fileEntry.getDirEntry(); - if (dirEntry != null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); + if (fileEntry != null) { + localFiles.add(fileEntry); + localFilesIndex.put(fileEntry, localFiles.size()); + DirEntry dirEntry = fileEntry.getDirEntry(); + if (dirEntry != null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } } this.cuIndex = -1; this.lineIndex = -1; @@ -140,14 +142,16 @@ public void addSubRange(Range subrange, FileEntry subFileEntry) { assert primaryEntry != null; assert primaryEntry.getClassEntry() == this; primaryEntry.addSubRange(subrange, subFileEntry); - if (localFilesIndex.get(subFileEntry) == null) { - localFiles.add(subFileEntry); - localFilesIndex.put(subFileEntry, localFiles.size()); - } - DirEntry dirEntry = subFileEntry.getDirEntry(); - if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { - localDirs.add(dirEntry); - localDirsIndex.put(dirEntry, localDirs.size()); + if (subFileEntry != null) { + if (localFilesIndex.get(subFileEntry) == null) { + localFiles.add(subFileEntry); + localFilesIndex.put(subFileEntry, localFiles.size()); + } + DirEntry dirEntry = subFileEntry.getDirEntry(); + if (dirEntry != null && localDirsIndex.get(dirEntry) == null) { + localDirs.add(dirEntry); + localDirsIndex.put(dirEntry, localDirs.size()); + } } } @@ -164,15 +168,27 @@ public int localFilesIdx(@SuppressWarnings("hiding") FileEntry fileEntry) { } public String getFileName() { - return fileEntry.getFileName(); + if (fileEntry != null) { + return fileEntry.getFileName(); + } else { + return ""; + } } String getFullFileName() { - return fileEntry.getFullName(); + if (fileEntry != null) { + return fileEntry.getFullName(); + } else { + return null; + } } String getDirName() { - return fileEntry.getPathName(); + if (fileEntry != null) { + return fileEntry.getPathName(); + } else { + return ""; + } } public void setCUIndex(int cuIndex) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index ebebdfec72b5..93696d7f8889 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -92,10 +92,6 @@ public ClassEntry getClassEntry() { return classEntry; } - public FileEntry getFileEntry() { - return classEntry.getFileEntry(); - } - public List getSubranges() { return subranges; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index a79e6f00219c..e0904a962dbc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -66,7 +66,7 @@ public Range(String fileName, Path filePath, String className, String methodName * currently file name and full method name need to go into the debug_str section * other strings just need to be deduplicated to save space */ - this.fileName = stringTable.uniqueDebugString(fileName); + this.fileName = (fileName == null ? fileName : stringTable.uniqueDebugString(fileName)); this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); @@ -102,8 +102,10 @@ public Path getFilePath() { public Path getFileAsPath() { if (filePath != null) { return filePath.resolve(fileName); - } else { + } else if (fileName != null) { return Paths.get(fileName); + } else { + return null; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index aff33ce4f828..97818d1f280e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -226,6 +226,8 @@ public int computeFileTableSize(ClassEntry classEntry) { */ String baseName = localEntry.getFileName(); int length = baseName.length(); + /* we should never have a null or zero length entry in local files */ + assert length > 0; fileSize += length + 1; DirEntry dirEntry = localEntry.getDirEntry(); int idx = classEntry.localDirsIdx(dirEntry); @@ -416,10 +418,14 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; + FileEntry fileEntry = classEntry.getFileEntry(); + if (fileEntry == null) { + return pos; + } /* * the primary file entry should always be first in the local files list */ - assert classEntry.localFilesIdx(classEntry.getFileEntry()) == 1; + assert classEntry.localFilesIdx(fileEntry) == 1; String primaryClassName = classEntry.getClassName(); String primaryFileName = classEntry.getFileName(); String file = primaryFileName; @@ -475,6 +481,9 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { assert subrange.getLo() >= primaryRange.getLo(); assert subrange.getHi() <= primaryRange.getHi(); FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subrange); + if (subFileEntry == null) { + continue; + } String subfile = subFileEntry.getFileName(); int subFileIdx = classEntry.localFilesIdx(subFileEntry); long subLine = subrange.getLine(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index faa546479b50..6aa82609fa38 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -406,6 +406,9 @@ public ClassEntry ensureClassEntry(Range range) { public FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); + if (fileName == null) { + return null; + } Path filePath = range.getFilePath(); Path fileAsPath = range.getFileAsPath(); /* @@ -448,7 +451,9 @@ public void addSubRange(Range primaryRange, Range subrange) { * and associated with a primary class entry */ assert classEntry.primaryIndexFor(primaryRange) != null; - classEntry.addSubRange(subrange, subrangeEntry); + if (subrangeEntry != null) { + classEntry.addSubRange(subrange, subrangeEntry); + } } public DirEntry ensureDirEntry(Path filePath) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index b5844d7b0a5d..c2158c5c3268 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -54,6 +54,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.hosted.image.sources.SourceManager; import com.oracle.svm.hosted.meta.HostedType; @@ -1020,21 +1021,21 @@ public Stream dataInfoProvider() { */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; + private final ResolvedJavaType javaType; private final CompilationResult compilation; private Path fullFilePath; NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { this.method = method; + HostedType declaringClass = method.getDeclaringClass(); + Class clazz = declaringClass.getJavaClass(); + this.javaType = declaringClass.getWrapped(); this.compilation = compilation; - this.fullFilePath = null; + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(javaType, clazz); } @Override public String fileName() { - if (fullFilePath == null) { - HostedType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } if (fullFilePath != null) { return fullFilePath.getFileName().toString(); } @@ -1042,10 +1043,6 @@ public String fileName() { } @Override public Path filePath() { - if (fullFilePath == null) { - HostedType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } if (fullFilePath != null) { return fullFilePath.getParent(); } @@ -1054,7 +1051,7 @@ public Path filePath() { @Override public String className() { - return method.format("%H"); + return javaType.toClassName(); } @Override @@ -1134,7 +1131,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { private final ResolvedJavaMethod method; private final int lo; private final int hi; - private Path fullFilePath = null; + private Path fullFilePath; NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); @@ -1143,25 +1140,18 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { this.method = position.getMethod(); this.lo = sourceMapping.getStartOffset(); this.hi = sourceMapping.getEndOffset(); + computeFullFilePath(); } @Override public String fileName() { - if (fullFilePath == null) { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } - if (fullFilePath != null) { + if (fullFilePath != null) { return fullFilePath.getFileName().toString(); } return null; } public Path filePath() { - if (fullFilePath == null) { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass); - } if (fullFilePath != null) { return fullFilePath.getParent(); } @@ -1196,6 +1186,28 @@ public int line() { } return -1; } + + private void computeFullFilePath() { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + Class clazz = null; + if (declaringClass instanceof OriginalClassProvider) { + clazz = ((OriginalClassProvider) declaringClass).getJavaClass(); + } + /* + * HostedType and AnalysisType punt calls to + * getSourceFilename to the wrapped class so + * for consistency we need to do the path lookup + * relative to the wrapped class + */ + if (declaringClass instanceof HostedType) { + declaringClass = ((HostedType) declaringClass).getWrapped(); + } + if (declaringClass instanceof AnalysisType) { + declaringClass = ((AnalysisType) declaringClass).getWrapped(); + } + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass, clazz); + } + } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java index d3d4252f6685..c8f63224db6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -27,6 +27,7 @@ package com.oracle.svm.hosted.image.sources; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.meta.ResolvedJavaType; @@ -45,11 +46,12 @@ public class SourceManager { * return a Path to the file relative to the source. * @param resolvedType the Java type whose source file * should be located and cached + * @param clazz the Java class associated with the resolved type * @return a path identifying the location of a successfully * cached file for inclusion in the generated debug info or * null if a source file cannot be found or cached. */ - public Path findAndCacheSource(ResolvedJavaType resolvedType) { + public Path findAndCacheSource(ResolvedJavaType resolvedType, Class clazz) { /* short circuit if we have already seen this type */ Path path = verifiedPaths.get(resolvedType); if (path != null) { @@ -67,30 +69,13 @@ public Path findAndCacheSource(ResolvedJavaType resolvedType) { * for known classes and interfaces */ if (resolvedType.isInstanceClass() || resolvedType.isInterface()) { - /* - * if we have an OriginalClassProvider we - * can use the underlying Java class - * to provide the details we need to locate - * a source - */ - if (resolvedType instanceof OriginalClassProvider) { - Class javaClass = ((OriginalClassProvider) resolvedType).getJavaClass(); - String packageName = computePackageName(javaClass); - SourceCacheType type = sourceCacheType(packageName, javaClass); - path = locateSource(fileName, packageName, type, javaClass); - } - /* - * if we could not locate a source via the cache - * then the fallback is to generate a path to the - * file based on the class name and let the - * user configure a path to the sources - */ + String packageName = computePackageName(resolvedType); + SourceCacheType sourceCacheType = sourceCacheType(packageName); + path = locateSource(fileName, packageName, sourceCacheType, resolvedType, clazz); if (path == null) { - String name = resolvedType.toJavaName(); - int idx = name.lastIndexOf('.'); - if (idx >= 0 && idx < name.length() - 1) { - name = name.substring(0, idx); - path = Paths.get("", name.split("\\.")); + // as a last ditch effort derive path from the Java class name + if (packageName.length() > 0) { + path = Paths.get("", packageName.split("\\.")); path = path.resolve(fileName); } } @@ -138,16 +123,21 @@ private String computeBaseName(ResolvedJavaType resolvedType) { return fileName; } /** - * Construct the package name for a Java class or + * Construct the package name for a Java type or * the empty String if it has no package. - * @param javaClass the java class whose package + * @param javaType the Java type whose package * name is required * @return the package name or the empty String * if it has no package */ - private String computePackageName(Class javaClass) { - Package pkg = javaClass.getPackage(); - return (pkg == null ? "" : pkg.getName()); + private String computePackageName(ResolvedJavaType javaType) { + String name = javaType.toClassName(); + int idx = name.lastIndexOf('.'); + if (idx > 0) { + return name.substring(0, idx); + } else { + return ""; + } } /** * Construct the prototype name for a Java source file @@ -155,15 +145,17 @@ private String computePackageName(Class javaClass) { * file. * @param fileName the base file name for the source file * @param packageName the name of the package for the associated Java class - * @param type the type of cache in which to lookup or cache this class's source file - * @param javaClass the java class whose prototype name is required + * @param sourceCacheType the sourceCacheType of cache in which to lookup or cache this class's source file + * @param javaType the java sourceCacheType whose prototype name is required + * @param clazz the class associated with the sourceCacheType used to + * identify the module prefix for JDK classes * @return a protoype name for the source file */ - private Path computePrototypeName(String fileName, String packageName, SourceCacheType type, Class javaClass) { + private Path computePrototypeName(String fileName, String packageName, SourceCacheType sourceCacheType, ResolvedJavaType javaType, Class clazz) { String prefix = ""; - if (type == SourceCacheType.JDK) { - /* JDK paths may require the module name as prefix */ - String moduleName = ModuleSupport.getModuleName(javaClass); + if (sourceCacheType == SourceCacheType.JDK && clazz != null) { + /* JDK11+ paths will require the module name as prefix */ + String moduleName = ModuleSupport.getModuleName(clazz); if (moduleName != null) { prefix = moduleName; } @@ -231,9 +223,12 @@ private boolean whiteListPackage(String packageName, String[] whitelist) { /** * Identify which type of source cache should be used - * to locate a given class's source code. + * to locate a given class's source code as determined + * by it's package name. + * @param packageName the package name of the class. + * @return the corresponding source cache type */ - private SourceCacheType sourceCacheType(String packageName, Class javaClass) { + private SourceCacheType sourceCacheType(String packageName) { if (whiteListPackage(packageName, JDK_SRC_PACKAGE_PREFIXES)) { return SourceCacheType.JDK; } @@ -281,10 +276,14 @@ private SourceCache getOrCreateCache(SourceCacheType type) { return sourceCache; } - private Path locateSource(String fileName, String packagename, SourceCacheType type, Class javaClass) { + private Path locateSource(String fileName, String packagename, SourceCacheType type, ResolvedJavaType javaType, Class clazz) { SourceCache cache = getOrCreateCache(type); - Path prototypeName = computePrototypeName(fileName, packagename, type, javaClass); - return cache.resolve(prototypeName); + Path prototypeName = computePrototypeName(fileName, packagename, type, javaType, clazz); + if (prototypeName != null) { + return cache.resolve(prototypeName); + } else { + return null; + } } } From e8ade412fedb5bebd7e4e3f8d45beaacf194c63a Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 6 Mar 2020 17:56:31 +0000 Subject: [PATCH 095/130] remove unused field --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSections.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 6aa82609fa38..68e3e0250c96 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -173,7 +173,6 @@ public class DwarfSections { // public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; - private ELFMachine elfMachine; private ByteOrder byteOrder; private DwarfStrSectionImpl dwarfStrSection; private DwarfAbbrevSectionImpl dwarfAbbrevSection; @@ -183,7 +182,6 @@ public class DwarfSections { private DwarfFrameSectionImpl dwarfFameSection; public DwarfSections(ELFMachine elfMachine, ByteOrder byteOrder) { - this.elfMachine = elfMachine; this.byteOrder = byteOrder; dwarfStrSection = new DwarfStrSectionImpl(this); dwarfAbbrevSection = new DwarfAbbrevSectionImpl(this); From 1ae0ff11d7d3dba2d240a9894c33c28c4f6a8064 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 9 Mar 2020 08:56:05 +0000 Subject: [PATCH 096/130] code cleanups --- .../dwarf/DwarfFrameSectionImplAArch64.java | 2 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 3 ++ .../elf/dwarf/DwarfLineSectionImpl.java | 3 ++ .../elf/dwarf/DwarfSectionImpl.java | 3 ++ .../objectfile/elf/dwarf/DwarfSections.java | 40 ++++++------------- 5 files changed, 22 insertions(+), 29 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index 8f4ab1818ec4..1ebc8efde34b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -31,7 +31,7 @@ * that knows details of AArch64 registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_FP_IDX = 29; + // public static final int DW_CFA_FP_IDX = 29; public static final int DW_CFA_LR_IDX = 30; public static final int DW_CFA_SP_IDX = 31; public static final int DW_CFA_PC_IDX = 32; 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 025450fca2de..496518bc2391 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 @@ -209,6 +209,8 @@ public int writeAttrStrp(String value, byte[] buffer, int p) { } } + /* + * we may need this later public int writeAttrString(String value, byte[] buffer, int p) { int pos = p; if (buffer == null) { @@ -217,6 +219,7 @@ public int writeAttrString(String value, byte[] buffer, int p) { return putAsciiStringBytes(value, buffer, pos); } } + */ @Override protected void debug(String format, Object... args) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 97818d1f280e..7c5d9615740e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -669,6 +669,8 @@ public int putSetFile(String file, long uleb, byte[] buffer, int p) { } } + /* + * we may need these later public int putSetColumn(long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; int pos = p; @@ -690,6 +692,7 @@ public int putNegateStmt(byte[] buffer, int p) { return putByte(opcode, buffer, pos); } } + */ public int putSetBasicBlock(byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; 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 7b4a1d6fd8b1..2a9f9aba6651 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 @@ -280,6 +280,8 @@ public int writeAttrAddress(long address, byte[] buffer, int pos) { } } + /* + * we may need this later public int writeAttrData8(long value, byte[] buffer, int pos) { if (buffer == null) { return pos + putLong(value, scratch, 0); @@ -287,6 +289,7 @@ public int writeAttrData8(long value, byte[] buffer, int pos) { return putLong(value, buffer, pos); } } + */ public int writeAttrData4(int value, byte[] buffer, int pos) { if (buffer == null) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 68e3e0250c96..87830e17a547 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -29,7 +29,6 @@ import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.DirEntry; import com.oracle.objectfile.debugentry.FileEntry; -import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; import com.oracle.objectfile.debugentry.StringTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; @@ -227,13 +226,9 @@ public DwarfLineSectionImpl getLineSectionImpl() { private StringTable stringTable = new StringTable(); /** - * list detailing all dirs in which files are found to reside + * index of all dirs in which files are found to reside * either as part of substrate/compiler or user code. */ - private LinkedList dirs = new LinkedList<>(); - /** - * index of already seen dirs. - */ private Map dirsIndex = new HashMap<>(); /* @@ -274,15 +269,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { private Map primaryClassesIndex = new HashMap<>(); /** - * list of files which contain primary ranges. - */ - private LinkedList primaryFiles = new LinkedList<>(); - /** - * List of files which contain primary or secondary ranges. - */ - private LinkedList files = new LinkedList<>(); - /** - * index of already seen files. + * index of files which contain primary or secondary ranges. */ private Map filesIndex = new HashMap<>(); @@ -416,17 +403,15 @@ public FileEntry ensureFileEntry(Range range) { if (fileEntry == null) { DirEntry dirEntry = ensureDirEntry(filePath); fileEntry = new FileEntry(fileName, dirEntry); - files.add(fileEntry); - filesIndex.put(fileAsPath, fileEntry); /* - * if this is a primary entry then add it to the primary list + * index the file entry by file path */ - if (range.isPrimary()) { - primaryFiles.add(fileEntry); - } else { + filesIndex.put(fileAsPath, fileEntry); + if (!range.isPrimary()) { + /* check we have a file for the corresponding primary range */ Range primaryRange = range.getPrimary(); - FileEntry primaryEntry = filesIndex.get(primaryRange.getFileAsPath()); - assert primaryEntry != null; + FileEntry primaryFileEntry = filesIndex.get(primaryRange.getFileAsPath()); + assert primaryFileEntry != null; } } return fileEntry; @@ -435,7 +420,7 @@ public FileEntry ensureFileEntry(Range range) { public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); - PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); + classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); } public void addSubRange(Range primaryRange, Range subrange) { @@ -443,14 +428,14 @@ public void addSubRange(Range primaryRange, Range subrange) { assert !subrange.isPrimary(); String className = primaryRange.getClassName(); ClassEntry classEntry = primaryClassesIndex.get(className); - FileEntry subrangeEntry = ensureFileEntry(subrange); + FileEntry subrangeFileEntry = ensureFileEntry(subrange); /* * the primary range should already have been seen * and associated with a primary class entry */ assert classEntry.primaryIndexFor(primaryRange) != null; - if (subrangeEntry != null) { - classEntry.addSubRange(subrange, subrangeEntry); + if (subrangeFileEntry != null) { + classEntry.addSubRange(subrange, subrangeFileEntry); } } @@ -462,7 +447,6 @@ public DirEntry ensureDirEntry(Path filePath) { if (dirEntry == null) { dirEntry = new DirEntry(filePath); dirsIndex.put(filePath, dirEntry); - dirs.add(dirEntry); } return dirEntry; } From 5d0ab6b4a7feb7cec5e1027aec2ded60d85185cb Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 9 Mar 2020 11:31:06 +0000 Subject: [PATCH 097/130] comment out currently unused DWARF opcodes --- .../oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 7c5d9615740e..e0f81fb3f632 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -93,11 +93,17 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * set column 1 uleb arg */ + /* + * currently unused private static final byte DW_LNS_set_column = 5; + */ /* * flip is_stmt 0 args */ + /* + * currently unused private static final byte DW_LNS_negate_stmt = 6; + */ /* * set end sequence and copy row 0 args */ From 45e34168bae49d94f1d07ca8ac8b621eb0e460a5 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Mon, 9 Mar 2020 12:23:51 +0000 Subject: [PATCH 098/130] formatting --- .../src/com/oracle/objectfile/ObjectFile.java | 9 +- .../objectfile/debugentry/ClassEntry.java | 30 ++-- .../objectfile/debugentry/DirEntry.java | 12 +- .../objectfile/debugentry/FileEntry.java | 1 + .../objectfile/debugentry/PrimaryEntry.java | 7 +- .../oracle/objectfile/debugentry/Range.java | 14 +- .../objectfile/debugentry/StringEntry.java | 6 +- .../objectfile/debugentry/StringTable.java | 39 ++-- .../debuginfo/DebugInfoProvider.java | 81 +++++---- .../objectfile/elf/ELFRelocationSection.java | 5 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 22 ++- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 47 +++-- .../elf/dwarf/DwarfFrameSectionImpl.java | 30 ++-- .../dwarf/DwarfFrameSectionImplAArch64.java | 6 +- .../dwarf/DwarfFrameSectionImplX86_64.java | 10 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 43 ++--- .../elf/dwarf/DwarfLineSectionImpl.java | 36 ++-- .../elf/dwarf/DwarfSectionImpl.java | 4 +- .../objectfile/elf/dwarf/DwarfSections.java | 57 ++++-- .../elf/dwarf/DwarfStrSectionImpl.java | 9 +- .../com/oracle/svm/core/SubstrateOptions.java | 1 + .../svm/hosted/image/NativeBootImage.java | 40 ++--- .../image/sources/ApplicationSourceCache.java | 10 +- .../image/sources/GraalVMSourceCache.java | 19 +- .../hosted/image/sources/JDKSourceCache.java | 3 +- .../svm/hosted/image/sources/SourceCache.java | 166 +++++++++--------- .../hosted/image/sources/SourceManager.java | 150 +++++++--------- 27 files changed, 432 insertions(+), 425 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 518b171882d4..386978567ebf 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1088,10 +1088,11 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int } /** - * API method provided to allow a native image generator to provide details of - * types, code and heap data inserted into a native image. - * @param debugInfoProvider an implementation of the provider interface that - * communicates details of the relevant types, code and heap data. + * API method provided to allow a native image generator to provide details of types, code and + * heap data inserted into a native image. + * + * @param debugInfoProvider an implementation of the provider interface that communicates + * details of the relevant types, code and heap data. */ public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default 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 b1a9cf22a1ee..bb4917254b59 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 @@ -37,28 +37,25 @@ * track debug info associated with a Java class. */ public class ClassEntry { - /** + /** * the name of the associated class. - */ + */ private String className; /** * details of the associated file. */ FileEntry fileEntry; /** - * a list recording details of all primary - * ranges included in this class sorted by - * ascending address range. + * a list recording details of all primary ranges included in this class sorted by ascending + * address range. */ private LinkedList primaryEntries; /** - * an index identifying primary ranges which - * have already been encountered. + * an index identifying primary ranges which have already been encountered. */ private Map primaryIndex; /** - * an index of all primary and secondary files - * referenced from this class's compilation unit. + * an index of all primary and secondary files referenced from this class's compilation unit. */ private Map localFilesIndex; /** @@ -66,8 +63,7 @@ public class ClassEntry { */ private LinkedList localFiles; /** - * an index of all primary and secondary dirs - * referenced from this class's compilation unit. + * an index of all primary and secondary dirs referenced from this class's compilation unit. */ private HashMap localDirsIndex; /** @@ -75,23 +71,19 @@ public class ClassEntry { */ private LinkedList localDirs; /** - * index of debug_info section compilation unit - * for this class. + * index of debug_info section compilation unit for this class. */ private int cuIndex; /** - * index into debug_line section for associated - * compilation unit. + * index into debug_line section for associated compilation unit. */ private int lineIndex; /** - * size of line number info prologue region for - * associated compilation unit. + * size of line number info prologue region for associated compilation unit. */ private int linePrologueSize; /** - * total size of line number info region for - * associated compilation unit. + * total size of line number info region for associated compilation unit. */ private int totalSize; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index c5f6fa045c67..019611539160 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -29,15 +29,11 @@ import java.nio.file.Path; /** - * Tracks the directory associated with one or - * more source files. + * Tracks the directory associated with one or more source files. * - * This is identified separately from each FileEntry - * idenityfing files that reside in the directory. - * That is necessary because the line info generator - * needs to collect and write out directory names - * into directory tables once only rather than once - * per file. + * This is identified separately from each FileEntry idenityfing files that reside in the directory. + * That is necessary because the line info generator needs to collect and write out directory names + * into directory tables once only rather than once per file. */ public class DirEntry { private Path path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index 8c28e018100a..1aedf4dc879b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -52,6 +52,7 @@ public String getPathName() { public String getFullName() { return getDirEntry().getPath().resolve(getFileName()).toString(); } + /** * The directory entry associated with this file entry. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index 93696d7f8889..b0199d3c3f65 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -33,8 +33,7 @@ import java.util.List; /** - * Tracks debug info associated with a primary method. - * i.e. a top level compiled method + * Tracks debug info associated with a primary method. i.e. a top level compiled method */ public class PrimaryEntry { /** @@ -61,6 +60,7 @@ public class PrimaryEntry { * Size of compiled method frame. */ private int frameSize; + public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { this.primary = primary; this.classEntry = classEntry; @@ -77,8 +77,7 @@ public void addSubRange(Range subrange, FileEntry subFileEntry) { assert !subranges.contains(subrange); assert subrangeIndex.get(subrange) == null; /* - * we need to generate a file table entry - * for all ranges + * we need to generate a file table entry for all ranges */ subranges.add(subrange); subrangeIndex.put(subrange, subFileEntry); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index e0904a962dbc..191ec29b0532 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -28,11 +28,11 @@ import java.nio.file.Path; import java.nio.file.Paths; + /** - * Details of a specific address range in a compiled method - * either a primary range identifying a whole method - * or a sub-range identifying a sequence of - * instructions that belong to an inlined method. + * Details of a specific address range in a compiled method either a primary range identifying a + * whole method or a sub-range identifying a sequence of instructions that belong to an inlined + * method. */ public class Range { @@ -63,11 +63,11 @@ public Range(String fileName, Path filePath, String className, String methodName */ public Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { /* - * currently file name and full method name need to go into the debug_str section - * other strings just need to be deduplicated to save space + * currently file name and full method name need to go into the debug_str section other + * strings just need to be deduplicated to save space */ this.fileName = (fileName == null ? fileName : stringTable.uniqueDebugString(fileName)); - this.filePath = filePath; + this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); this.paramNames = stringTable.uniqueString(paramNames); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java index d1ebb16be685..f8fe7445d8d2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java @@ -27,10 +27,8 @@ package com.oracle.objectfile.debugentry; /** - * Used to retain a unique (up to equals) copy of a - * String. Also flag swhether the String needs to be - * located in the debug_string section and, if so, - * tracks the offset at which it gets written. + * Used to retain a unique (up to equals) copy of a String. Also flags whether the String needs to + * be located in the debug_string section and, if so, tracks the offset at which it gets written. */ public class StringEntry { private String string; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java index 721c77940ee5..9ea823ff00d4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java @@ -30,10 +30,9 @@ import java.util.Iterator; /** - * Allows incoming strings to be reduced to unique (up - * to equals) instances and supports marking of strings - * which need to be written to the debug_str section - * and retrieval of the location offset after writing. + * Allows incoming strings to be reduced to unique (up to equals) instances and supports marking of + * strings which need to be written to the debug_str section and retrieval of the location offset + * after writing. */ public class StringTable implements Iterable { @@ -44,10 +43,10 @@ public StringTable() { } /** - * Ensures a unique instance of a string exists in the - * table, inserting the supplied String if no equivalent - * String is already present. This should only be called - * before the string section has been written. + * Ensures a unique instance of a string exists in the table, inserting the supplied String if + * no equivalent String is already present. This should only be called before the string section + * has been written. + * * @param string the string to be included in the table * @return the unique instance of the String */ @@ -56,13 +55,12 @@ public String uniqueString(String string) { } /** - * Ensures a unique instance of a string exists in the - * table and is marked for inclusion in the debug_str - * section, inserting the supplied String if no equivalent - * String is already present. This should only be called - * before the string section has been written. - * @param string the string to be included in the table - * and marked for inclusion in the debug_str section + * Ensures a unique instance of a string exists in the table and is marked for inclusion in the + * debug_str section, inserting the supplied String if no equivalent String is already present. + * This should only be called before the string section has been written. + * + * @param string the string to be included in the table and marked for inclusion in the + * debug_str section * @return the unique instance of the String */ public String uniqueDebugString(String string) { @@ -82,13 +80,12 @@ private String ensureString(String string, boolean addToStrSection) { } /** - * Retrieves the offset at which a given string was written - * into the debug_str section. This should only be called - * after the string section has been written. + * Retrieves the offset at which a given string was written into the debug_str section. This + * should only be called after the string section has been written. + * * @param string - * @return the offset or -1 if the string does not - * define an entry or the entry has nto been written - * to the debug_str section + * @return the offset or -1 if the string does not define an entry or the entry has not been + * written to the debug_str section */ public int debugStringIndex(String string) { StringEntry stringEntry = table.get(string); 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 444be49613ac..185de9e86e85 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 @@ -31,10 +31,8 @@ import java.util.stream.Stream; /** - * interfaces used to allow a native image to communicate - * details of types, code and data to the underlying - * object file so that the latter can insert appropriate - * debug info. + * Interfaces used to allow a native image to communicate details of types, code and data to the + * underlying object file so that the latter can insert appropriate debug info. */ public interface DebugInfoProvider { /** @@ -48,61 +46,67 @@ interface DebugTypeInfo { */ interface DebugCodeInfo { /** - * @return the name of the file containing a compiled - * method excluding any path + * @return the name of the file containing a compiled method excluding any path */ String fileName(); + /** - * @return a relative path to the file containing a compiled - * method derived from its package name or null if the method - * is in the empty package + * @return a relative path to the file containing a compiled method derived from its package + * name or null if the method is in the empty package */ Path filePath(); + /** - * @return the fully qualified name of the class owning the - * compiled method + * @return the fully qualified name of the class owning the compiled method */ String className(); + /** - * @return the name of the compiled method including - * signature + * @return the name of the compiled method including signature */ String methodName(); + /** - * @return the lowest address containing code generated for - * the method represented as an offset into the code segment + * @return the lowest address containing code generated for the method represented as an + * offset into the code segment */ int addressLo(); + /** - * @return the first address above the code generated for - * the method represented as an offset into the code segment + * @return the first address above the code generated for the method represented as an + * offset into the code segment */ int addressHi(); + /** * @return the starting line number for the method */ int line(); + /** - * @return a stream of records detailing line numbers - * and addresses within the compiled method + * @return a stream of records detailing line numbers and addresses within the compiled + * method */ Stream lineInfoProvider(); + /** * @return a string identifying the method parameters */ String paramNames(); + /** * @return a string identifying the method return type */ String returnTypeName(); + /** - * @return the size of the method frame between prologue - * and epilogue + * @return the size of the method frame between prologue and epilogue */ int getFrameSize(); + /** - * @return a list of positions at which the stack is extended - * to a full frame or torn down to an empty frame + * @return a list of positions at which the stack is extended to a full frame or torn down + * to an empty frame */ List getFrameSizeChanges(); } @@ -114,42 +118,43 @@ interface DebugDataInfo { } /** - * access details of code generated for a specific outer - * or inlined method at a given line number. + * access details of code generated for a specific outer or inlined method at a given line + * number. */ interface DebugLineInfo { /** - * @return the name of the file containing the outer - * or inlined method excluding any path + * @return the name of the file containing the outer or inlined method excluding any path */ String fileName(); + /** - * @return a relative path to the file containing the outer - * or inlined method derived from its package name or null - * if the method is in the empty package + * @return a relative path to the file containing the outer or inlined method derived from + * its package name or null if the method is in the empty package */ Path filePath(); + /** - * @return the fully qualified name of the class owning the - * outer or inlined method + * @return the fully qualified name of the class owning the outer or inlined method */ String className(); + /** * @return the name of the outer or inlined method including signature */ String methodName(); + /** - * @return the lowest address containing code generated for - * an outer or inlined code segment reported at this line - * represented as an offset into the code segment + * @return the lowest address containing code generated for an outer or inlined code segment + * reported at this line represented as an offset into the code segment */ int addressLo(); + /** - * @return the first address above the code generated for - * an outer or inlined code segment reported at this line - * represented as an offset into the code segment + * @return the first address above the code generated for an outer or inlined code segment + * reported at this line represented as an offset into the code segment */ int addressHi(); + /** * @return the line number for the outer or inlined segment */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java index 7826a6a786ba..8aa18d5344f4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java @@ -240,10 +240,9 @@ public Iterable getDependencies(Map // our content depends on the content of the section being relocated // (because entries only get registered during generation) if (relocated != null) { - LayoutDecision relocatedSectionContent = - decisions.get(relocated).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision relocatedSectionContent = decisions.get(relocated).getDecision(LayoutDecision.Kind.CONTENT); deps.add(BuildDependency.createOrGet(ourContent, - relocatedSectionContent)); + relocatedSectionContent)); } if (isDynamic()) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index c20e9b27af0a..119798e3a21f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -61,21 +61,27 @@ public void createContent() { /* * we need an entry for each compilation unit * - * uint32 length ............ in bytes (not counting these 4 bytes) - * uint16 dwarf_version ..... always 2 - * uint32 info_offset ....... offset of compilation unit on debug_info - * uint8 address_size ....... always 8 - * uint8 segment_desc_size .. ??? + *
    + *
  • uint32 length ............ in bytes (not counting these 4 bytes) + *
  • uint16 dwarf_version ..... always 2 + *
  • uint32 info_offset ....... offset of compilation unit on debug_info + *
  • uint8 address_size ....... always 8 + *
  • uint8 segment_desc_size .. ??? + *
* * i.e. 12 bytes followed by padding * aligning up to 2 * address size * - * uint8 pad[4] + *
    + *
  • uint8 pad[4] + *
* * followed by N + 1 times * - * uint64 lo ................ lo address of range - * uint64 length ............ number of bytes in range + *
    + *
  • uint64 lo ................ lo address of range + *
  • uint64 length ............ number of bytes in range + *
* * where N is the number of ranges belonging to the compilation unit * and the last range contains two zeroes 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 c8f97729dd95..6e0709ccefef 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 @@ -75,18 +75,24 @@ public void createContent() { * terminated by a null entry * * a null entry has consists of just a 0 abbrev code - * LEB128 abbrev_code; ...... == 0 + *
    + *
  • LEB128 abbrev_code; ...... == 0 + *
* * non-null entries have the following format - * LEB128 abbrev_code; ...... unique noncode for this layout != 0 - * 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 DIE - * * ........ zero or more attributes - * .... terminator + *
    + *
  • LEB128 abbrev_code; ...... unique noncode for this layout != 0 + *
  • 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 DIE + *
  • attribute_spec* .......... zero or more attributes + *
  • null_attribute_spec ...... terminator + *
* * An attribute_spec consists of an attribute name and form - * LEB128 attr_name; ........ 0 for the null attribute name - * LEB128 attr_form; ........ 0 for the null attribute form + *
    + *
  • LEB128 attr_name; ........ 0 for the null attribute name + *
  • LEB128 attr_form; ........ 0 for the null attribute form + *
* * For the moment we only use one abbrev table for all CUs. * It contains two DIEs, the first to describe the compilation @@ -95,18 +101,21 @@ public void createContent() { * * The DIE layouts are as follows: * - * abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - * DW_AT_language : ... DW_FORM_data1 - * DW_AT_name : ....... DW_FORM_strp - * DW_AT_low_pc : ..... DW_FORM_address - * DW_AT_hi_pc : ...... DW_FORM_address - * DW_AT_stmt_list : .. DW_FORM_data4 + *
    + *
  • abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + *
  • DW_AT_language : ... DW_FORM_data1 + *
  • DW_AT_name : ....... DW_FORM_strp + *
  • DW_AT_low_pc : ..... DW_FORM_address + *
  • DW_AT_hi_pc : ...... DW_FORM_address + *
  • DW_AT_stmt_list : .. DW_FORM_data4 + *
* - * abbrev_code == 2, tag == DW_TAG_subprogram, no_children - * DW_AT_name : ....... DW_FORM_strp - * DW_AT_low_pc : ..... DW_FORM_addr - * DW_AT_hi_pc : ...... DW_FORM_addr - * DW_AT_external : ... DW_FORM_flag + *
    + *
  • abbrev_code == 2, tag == DW_TAG_subprogram, no_children + *
  • DW_AT_name : ....... DW_FORM_strp + *
  • DW_AT_hi_pc : ...... DW_FORM_addr + *
  • DW_AT_external : ... DW_FORM_flag + *
*/ pos = writeAbbrev1(null, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index d8d7ad23af74..3996fa7175b6 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -101,14 +101,16 @@ public int writeCIE(byte[] buffer, int p) { * because we have to have at least one * the layout is * - * uint32 : length ............... length of remaining fields in this CIE - * uint32 : CIE_id ................ unique id for CIE == 0xffffff - * uint8 : version ................ == 1 - * uint8[] : augmentation ......... == "" so always 1 byte - * ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) - * ULEB : data_alignment_factor ... == -8 - * byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 - * byte[] : initial_instructions .. includes pad to 8-byte boundary + *
    + *
  • uint32 : length ............... length of remaining fields in this CIE + *
  • uint32 : CIE_id ................ unique id for CIE == 0xffffff + *
  • uint8 : version ................ == 1 + *
  • uint8[] : augmentation ......... == "" so always 1 byte + *
  • ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + *
  • ULEB : data_alignment_factor ... == -8 + *
  • byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + *
  • byte[] : initial_instructions .. includes pad to 8-byte boundary + *
*/ int pos = p; if (buffer == null) { @@ -191,11 +193,13 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { * we only need a vanilla FDE header with default fields * the layout is * - * uint32 : length ........... length of remaining fields in this FDE - * uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header - * uint64 : initial_location .. i.e. method lo address - * uint64 : address_range ..... i.e. method hi - lo - * byte[] : instructions ...... includes pad to 8-byte boundary + *
    + *
  • uint32 : length ............ length of remaining fields in this FDE + *
  • uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + *
  • uint64 : initial_location .. i.e. method lo address + *
  • uint64 : address_range ..... i.e. method hi - lo + *
  • byte[] : instructions ...... includes pad to 8-byte boundary + *
*/ int pos = p; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index 1ebc8efde34b..ca570a8d3432 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -54,9 +54,11 @@ public int getSPIdx() { public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; /* - * rsp has not been updated + * rsp has not been updated and * caller pc is in lr - * register r32 (rpc), r30 (lr) + *
    + *
  • register r32 (rpc), r30 (lr) + *
*/ pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); return pos; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java index 7fabf34ad449..eec54f33b13a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -54,13 +54,17 @@ public int writeInitialInstructions(byte[] buffer, int p) { /* * rsp points at the word containing the saved rip * so the frame base (cfa) is at rsp + 8 (why not - ???) - * def_cfa r7 (sp) offset 8 + *
    + *
  • def_cfa r7 (sp) offset 8 + *
*/ pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); /* - * and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa + * rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa * (why not -1 ???) - * offset r16 (rip) cfa - 8 + *
    + *
  • offset r16 (rip) cfa - 8 + *
  • */ pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; 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 496518bc2391..25d5439802c2 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 @@ -61,30 +61,36 @@ public String getSectionName() { @Override public void createContent() { /* - * we need a single level 0 DIE for each compilation unit (CU) - * Each CU's Level 0 DIE is preceded by a fixed header: - * and terminated by a null DIE - * uint32 length ......... excluding this length field - * uint16 dwarf_version .. always 2 ?? - * uint32 abbrev offset .. always 0 ?? - * uint8 address_size .... always 8 - * * ................ sequence of top-level and nested child entries - * ............ == 0 + * we need a single level 0 DIE for each compilation unit (CU). + * Each CU's Level 0 DIE is preceded by a fixed header + * and terminated by a null DIE: + *
      + *
    • uint32 length ......... excluding this length field + *
    • uint16 dwarf_version .. always 2 ?? + *
    • uint32 abbrev offset .. always 0 ?? + *
    • uint8 address_size .... always 8 + *
    • DIE* .................. sequence of top-level and nested child entries + *
    • null_DIE .............. == 0 + *
    * - * a DIE is a recursively defined structure + * a DIE is a recursively defined structure. * it starts with a code for the associated * abbrev entry followed by a series of attribute - * values as determined by the entry terminated by + * values, as determined by the entry, terminated by * a null value and followed by zero or more child - * DIEs (zero iff has_children == no_children) + * DIEs (zero iff has_children == no_children). * - * LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE - * * ....... value sequence as determined by abbrev entry - * * ................... sequence of child DIEs (if appropriate) - * ............. == 0 + *
      + *
    • LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + *
    • attribute_value* ......... value sequence as determined by abbrev entry + *
    • DIE* ..................... sequence of child DIEs (if appropriate) + *
    • ............. == 0 + *
    * * note that a null_DIE looks like - * LEB128 abbrev_code ....... == 0 + *
      + *
    • LEB128 abbrev_code ....... == 0 + *
    * i.e. it also looks like a null_value */ @@ -209,8 +215,6 @@ public int writeAttrStrp(String value, byte[] buffer, int p) { } } - /* - * we may need this later public int writeAttrString(String value, byte[] buffer, int p) { int pos = p; if (buffer == null) { @@ -219,7 +223,6 @@ public int writeAttrString(String value, byte[] buffer, int p) { return putAsciiStringBytes(value, buffer, pos); } } - */ @Override protected void debug(String format, Object... args) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index e0f81fb3f632..d73f47b277b3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -93,17 +93,11 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * set column 1 uleb arg */ - /* - * currently unused private static final byte DW_LNS_set_column = 5; - */ /* * flip is_stmt 0 args */ - /* - * currently unused private static final byte DW_LNS_negate_stmt = 6; - */ /* * set end sequence and copy row 0 args */ @@ -123,7 +117,8 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * there is no extended opcode 0 */ - // private static final byte DW_LNE_undefined = 0; + @SuppressWarnings("unused") + private static final byte DW_LNE_undefined = 0; /* * end sequence of addresses */ @@ -179,16 +174,18 @@ public void createContent() { public int headerSize() { /* * header size is standard 31 bytes - * uint32 total_length - * uint16 version - * uint32 prologue_length - * uint8 min_insn_length - * uint8 default_is_stmt - * int8 line_base - * uint8 line_range - * uint8 opcode_base - * uint8 li_opcode_base - * uint8[opcode_base-1] standard_opcode_lengths + *
      + *
    • uint32 total_length + *
    • uint16 version + *
    • uint32 prologue_length + *
    • uint8 min_insn_length + *
    • uint8 default_is_stmt + *
    • int8 line_base + *
    • uint8 line_range + *
    • uint8 opcode_base + *
    • uint8 li_opcode_base + *
    • uint8[opcode_base-1] standard_opcode_lengths + *
    */ return DW_LN_HEADER_SIZE; @@ -675,8 +672,7 @@ public int putSetFile(String file, long uleb, byte[] buffer, int p) { } } - /* - * we may need these later + @SuppressWarnings("unused") public int putSetColumn(long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; int pos = p; @@ -689,6 +685,7 @@ public int putSetColumn(long uleb, byte[] buffer, int p) { } } + @SuppressWarnings("unused") public int putNegateStmt(byte[] buffer, int p) { byte opcode = DW_LNS_negate_stmt; int pos = p; @@ -698,7 +695,6 @@ public int putNegateStmt(byte[] buffer, int p) { return putByte(opcode, buffer, pos); } } - */ public int putSetBasicBlock(byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; 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 2a9f9aba6651..c83dce8c5dc6 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 @@ -280,8 +280,7 @@ public int writeAttrAddress(long address, byte[] buffer, int pos) { } } - /* - * we may need this later + @SuppressWarnings("unused") public int writeAttrData8(long value, byte[] buffer, int pos) { if (buffer == null) { return pos + putLong(value, scratch, 0); @@ -289,7 +288,6 @@ public int writeAttrData8(long value, byte[] buffer, int pos) { return putLong(value, buffer, pos); } } - */ public int writeAttrData4(int value, byte[] buffer, int pos) { if (buffer == null) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 87830e17a547..d3f8bc99fdda 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -94,19 +94,24 @@ public class DwarfSections { public static final int DW_AT_hi_pc = 0x12; public static final int DW_AT_language = 0x13; public static final int DW_AT_external = 0x3f; - // public static final int DW_AT_return_addr = 0x2a; - // public static final int DW_AT_frame_base = 0x40; + @SuppressWarnings("unused") + public static final int DW_AT_return_addr = 0x2a; + @SuppressWarnings("unused") + public static final int DW_AT_frame_base = 0x40; /* * define all the Dwarf attribute forms we need for our DIEs */ public static final int DW_FORM_null = 0x0; - // private static final int DW_FORM_string = 0x8; + @SuppressWarnings("unused") + private static final int DW_FORM_string = 0x8; public static final int DW_FORM_strp = 0xe; public static final int DW_FORM_addr = 0x1; public static final int DW_FORM_data1 = 0x0b; public static final int DW_FORM_data4 = 0x6; - // public static final int DW_FORM_data8 = 0x7; - // public static final int DW_FORM_block1 = 0x0a; + @SuppressWarnings("unused") + public static final int DW_FORM_data8 = 0x7; + @SuppressWarnings("unused") + public static final int DW_FORM_block1 = 0x0a; public static final int DW_FORM_flag = 0xc; /* @@ -120,7 +125,8 @@ public class DwarfSections { /* * DW_FORM_flag attribute values */ - // public static final byte DW_FLAG_false = 0; + @SuppressWarnings("unused") + public static final byte DW_FLAG_false = 0; public static final byte DW_FLAG_true = 1; /* * value for DW_AT_language attribute with form DATA1 @@ -132,15 +138,20 @@ public class DwarfSections { * * not needed until we make functions members */ - // public static final byte DW_ACCESS_public = 1; - // public static final byte DW_ACCESS_protected = 2; - // public static final byte DW_ACCESS_private = 3; + @SuppressWarnings("unused") + public static final byte DW_ACCESS_public = 1; + @SuppressWarnings("unused") + public static final byte DW_ACCESS_protected = 2; + @SuppressWarnings("unused") + public static final byte DW_ACCESS_private = 3; /* * others not yet needed */ - // public static final int DW_AT_type = 0; // only present for non-void functions - // public static final int DW_AT_accessibility = 0; + @SuppressWarnings("unused") + public static final int DW_AT_type = 0; // only present for non-void functions + @SuppressWarnings("unused") + public static final int DW_AT_accessibility = 0; /* * CIE and FDE entries @@ -148,28 +159,36 @@ public class DwarfSections { /* full byte/word values */ public static final int DW_CFA_CIE_id = -1; - // public static final int DW_CFA_FDE_id = 0; + @SuppressWarnings("unused") + public static final int DW_CFA_FDE_id = 0; public static final byte DW_CFA_CIE_version = 1; /* values encoded in high 2 bits */ public static final byte DW_CFA_advance_loc = 0x1; public static final byte DW_CFA_offset = 0x2; - // public static final byte DW_CFA_restore = 0x3; + @SuppressWarnings("unused") + public static final byte DW_CFA_restore = 0x3; /* values encoded in low 6 bits */ public static final byte DW_CFA_nop = 0x0; - // public static final byte DW_CFA_set_loc1 = 0x1; + @SuppressWarnings("unused") + public static final byte DW_CFA_set_loc1 = 0x1; public static final byte DW_CFA_advance_loc1 = 0x2; public static final byte DW_CFA_advance_loc2 = 0x3; public static final byte DW_CFA_advance_loc4 = 0x4; - // public static final byte DW_CFA_offset_extended = 0x5; - // public static final byte DW_CFA_restore_extended = 0x6; - // public static final byte DW_CFA_undefined = 0x7; - // public static final byte DW_CFA_same_value = 0x8; + @SuppressWarnings("unused") + public static final byte DW_CFA_offset_extended = 0x5; + @SuppressWarnings("unused") + public static final byte DW_CFA_restore_extended = 0x6; + @SuppressWarnings("unused") + public static final byte DW_CFA_undefined = 0x7; + @SuppressWarnings("unused") + public static final byte DW_CFA_same_value = 0x8; public static final byte DW_CFA_register = 0x9; public static final byte DW_CFA_def_cfa = 0xc; - // public static final byte DW_CFA_def_cfa_register = 0xd; + @SuppressWarnings("unused") + public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; private ByteOrder byteOrder; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 1ee212b112b5..845ab12ad8b2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -31,6 +31,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; + /** * generator for debug_str section. */ @@ -95,10 +96,10 @@ public String targetSectionName() { * debug_str section content depends on text section content and offset. */ public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - /* add this so we can use the text section base address for debug */ - LayoutDecision.Kind.VADDR, + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + /* add this so we can use the text section base address for debug */ + LayoutDecision.Kind.VADDR, }; @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index 9504c6710e02..696fdfad3fc1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -439,6 +439,7 @@ public static Predicate makeFilter(String[] definedFilters) { public static int codeAlignment() { return GraalOptions.LoopHeaderAlignment.getValue(HostedOptionValues.singleton()); } + @Option(help = "Insert debug info into the generated native image or library")// public static final HostedOptionKey GenerateDebugInfo = new HostedOptionKey(0) { @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index c2158c5c3268..1db5af2697a8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -975,9 +975,8 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile } /** - * implementation of the DebugInfoProvider API interface - * that allows type, code and heap data info to be passed to - * an ObjectFile when generation of debug info is enabled. + * implementation of the DebugInfoProvider API interface that allows type, code and heap data + * info to be passed to an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; @@ -1006,18 +1005,16 @@ public Stream dataInfoProvider() { } private static final String[] GRAAL_SRC_PACKAGE_PREFIXES = { - "org.graalvm", - "com.oracle.graal", - "com.oracle.objectfile", - "com.oracle.svm", - "com.oracle.truffle", + "org.graalvm", + "com.oracle.graal", + "com.oracle.objectfile", + "com.oracle.svm", + "com.oracle.truffle", }; - /** - * implementation of the DebugCodeInfo API interface - * that allows code info to be passed to an ObjectFile - * when generation of debug info is enabled. + * implementation of the DebugCodeInfo API interface that allows code info to be passed to an + * ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugCodeInfo implements DebugCodeInfo { private final HostedMethod method; @@ -1041,6 +1038,7 @@ public String fileName() { } return null; } + @Override public Path filePath() { if (fullFilePath != null) { @@ -1122,9 +1120,8 @@ public List getFrameSizeChanges() { } /** - * implementation of the DebugLineInfo API interface - * that allows line number info to be passed to an - * ObjectFile when generation of debug info is enabled. + * implementation of the DebugLineInfo API interface that allows line number info to be passed + * to an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugLineInfo implements DebugLineInfo { private final int bci; @@ -1145,7 +1142,7 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { @Override public String fileName() { - if (fullFilePath != null) { + if (fullFilePath != null) { return fullFilePath.getFileName().toString(); } return null; @@ -1194,10 +1191,8 @@ private void computeFullFilePath() { clazz = ((OriginalClassProvider) declaringClass).getJavaClass(); } /* - * HostedType and AnalysisType punt calls to - * getSourceFilename to the wrapped class so - * for consistency we need to do the path lookup - * relative to the wrapped class + * HostedType and AnalysisType punt calls to getSourceFilename to the wrapped class so + * for consistency we need to do the path lookup relative to the wrapped class */ if (declaringClass instanceof HostedType) { declaringClass = ((HostedType) declaringClass).getWrapped(); @@ -1211,9 +1206,8 @@ private void computeFullFilePath() { } /** - * implementation of the DebugFrameSizeChange API interface - * that allows stack frame size change info to be passed to - * an ObjectFile when generation of debug info is enabled. + * implementation of the DebugFrameSizeChange API interface that allows stack frame size change + * info to be passed to an ObjectFile when generation of debug info is enabled. */ private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { private int offset; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 50877485fd69..2f6dd613ba45 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -58,20 +58,22 @@ private void initSrcRoots() { trySourceRoot(sourcePathEntry); } } + private void tryClassPathRoot(String classPathEntry) { trySourceRoot(classPathEntry, true); } + private void trySourceRoot(String sourcePathEntry) { trySourceRoot(sourcePathEntry, false); } + private void trySourceRoot(String sourceRoot, boolean fromClassPath) { Path sourcePath = Paths.get(sourceRoot); String fileNameString = sourcePath.getFileName().toString(); if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".zip")) { if (fromClassPath && fileNameString.endsWith(".jar")) { /* - * application jar /path/to/xxx.jar should have - * sources /path/to/xxx-sources.jar + * application jar /path/to/xxx.jar should have sources /path/to/xxx-sources.jar */ int length = fileNameString.length(); fileNameString = fileNameString.substring(0, length - 4) + "-sources.zip"; @@ -92,8 +94,8 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { } else { if (fromClassPath) { /* - * for dir entries ending in classes or target/classes - * translate to a parallel src tree + * for dir entries ending in classes or target/classes translate to a parallel src + * tree */ if (sourcePath.endsWith("classes")) { Path parent = sourcePath.getParent(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index d92c21ab05ee..9fbf74483c3a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -37,6 +37,7 @@ import static com.oracle.svm.hosted.image.sources.SourceCacheType.GRAALVM; import static com.oracle.svm.hosted.image.sources.SourceManager.GRAALVM_SRC_PACKAGE_PREFIXES; + public class GraalVMSourceCache extends SourceCache { /** * Create a GraalVM source cache. @@ -63,20 +64,23 @@ private void initSrcRoots() { tryClassPathRoot(sourcePathEntry); } } + private void tryClassPathRoot(String classPathEntry) { trySourceRoot(classPathEntry, true); } + private void trySourceRoot(String sourcePathEntry) { trySourceRoot(sourcePathEntry, false); } + private void trySourceRoot(String sourceRoot, boolean fromClassPath) { Path sourcePath = Paths.get(sourceRoot); String fileNameString = sourcePath.getFileName().toString(); if (fileNameString.endsWith(".jar") || fileNameString.endsWith(".src.zip")) { if (fromClassPath && fileNameString.endsWith(".jar")) { /* - * GraalVM jar /path/to/xxx.jar in classpath should - * have sources /path/to/xxx.src.zip + * GraalVM jar /path/to/xxx.jar in classpath should have sources + * /path/to/xxx.src.zip */ int length = fileNameString.length(); fileNameString = fileNameString.substring(0, length - 3) + "src.zip"; @@ -96,7 +100,7 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { /* ignore this entry */ } } - } else { + } else { if (fromClassPath) { /* graal classpath dir entries should have a src and/or src_gen subdirectory */ Path srcPath = sourcePath.resolve("src"); @@ -115,13 +119,12 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { } } } + /** - * Ensure that the supplied root dir contains - * at least one subdirectory that matches one - * of the expected Graal package dir hierarchies. + * Ensure that the supplied root dir contains at least one subdirectory that matches one of the + * expected Graal package dir hierarchies. * - * @param root A root path under which to locate - * the desired subdirectory + * @param root A root path under which to locate the desired subdirectory * @return true if a */ private boolean filterSrcRoot(Path root) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java index ef6cb07baa71..fc93a0154994 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/JDKSourceCache.java @@ -59,7 +59,7 @@ private void initSrcRoots() { assert javaHome != null; Path javaHomePath = Paths.get("", javaHome); Path srcZipPath; - String javaSpecVersion = System.getProperty(JAVA_SPEC_VERSION_PROP); + String javaSpecVersion = System.getProperty(JAVA_SPEC_VERSION_PROP); if (javaSpecVersion.equals("1.8")) { srcZipPath = javaHomePath.resolve("src.zip"); } else { @@ -80,4 +80,3 @@ private void initSrcRoots() { } } } - diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 700cb123b7fd..ab453b4a816f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -44,33 +44,27 @@ import java.util.List; /** - * An abstract cache manager for some subspace of the - * JDK, GraalVM or application source file space. This class - * implements core behaviours that manage a cache of source - * files in a specific subdirectory of the local sources - * directory. It allows source files to be located - * when present in the local cache or cached when not - * already present. Subclasses are responsible for providing - * behaviours that identify an original source for addition - * to the cache and for verifying that a cached file is not - * out of date with respect to its original. + * An abstract cache manager for some subspace of the JDK, GraalVM or application source file space. + * This class implements core behaviours that manage a cache of source files in a specific + * subdirectory of the local sources directory. It allows source files to be located when present in + * the local cache or cached when not already present. Subclasses are responsible for providing + * behaviours that identify an original source for addition to the cache and for verifying that a + * cached file is not out of date with respect to its original. */ public abstract class SourceCache { /** - * A list of all entries in the classpath used - * by the native image classloader + * A list of all entries in the classpath used by the native image classloader */ protected static final List classPathEntries = new ArrayList<>(); /** - * A list of all entries in the classpath used - * by the native image classloader + * A list of all entries in the classpath used by the native image classloader */ protected static final List sourcePathEntries = new ArrayList<>(); /** - * A list of root directories which may contain source files - * from which this cache can be populated + * A list of root directories which may contain source files from which this cache can be + * populated */ protected List srcRoots; @@ -84,34 +78,31 @@ protected SourceCache() { /** * Identify the specific type of this source cache + * * @return the source cache type */ protected abstract SourceCacheType getType(); /** - * A local directory serving as the root for all - * source trees maintained by the different + * A local directory serving as the root for all source trees maintained by the different * available source caches. */ private static final String SOURCE_CACHE_ROOT_DIR = "sources"; /** - * The top level path relative to the root directory - * under which files belonging to this specific cache - * are located. + * The top level path relative to the root directory under which files belonging to this + * specific cache are located. */ private final Path basePath; + /** - * Cache the source file identified by the supplied prototype - * path if a legitimate candidate for inclusion in this cache - * can be identified and is not yet included in the cache or - * alternatively identify and validate any existing candidate - * cache entry to ensure it is not out of date refreshing it - * if need be. + * Cache the source file identified by the supplied prototype path if a legitimate candidate for + * inclusion in this cache can be identified and is not yet included in the cache or + * alternatively identify and validate any existing candidate cache entry to ensure it is not + * out of date refreshing it if need be. * - * @param filePath a prototype path for a file to be included - * in the cache derived from the name of some associated class. - * @return a path identifying the cached file or null - * if the candidate cannot be found. + * @param filePath a prototype path for a file to be included in the cache derived from the name + * of some associated class. + * @return a path identifying the cached file or null if the candidate cannot be found. */ public Path resolve(Path filePath) { File cachedFile = findCandidate(filePath); @@ -123,19 +114,17 @@ public Path resolve(Path filePath) { } /** - * Given a prototype path for a file to be resolved - * return a File identifying a cached candidate for - * for that Path or null if no cached candidate exists. - * @param filePath a prototype path for a file to be included - * in the cache derived from the name of some associated class. + * Given a prototype path for a file to be resolved return a File identifying a cached candidate + * for for that Path or null if no cached candidate exists. + * + * @param filePath a prototype path for a file to be included in the cache derived from the name + * of some associated class. * @return a File identifying a cached candidate or null. */ public File findCandidate(Path filePath) { /* - * JDK source candidates are stored in the src.zip file - * using the path we are being asked for. A cached version - * should exist under this cache's root using that same - * path. + * JDK source candidates are stored in the src.zip file using the path we are being asked + * for. A cached version should exist under this cache's root using that same path. */ File file = cachedFile(filePath); if (file.exists()) { @@ -143,16 +132,15 @@ public File findCandidate(Path filePath) { } return null; } + /** - * Attempt to copy a source file from one of this cache's - * source roots to the local sources directory storing - * it in the subdirectory that belongs to this cache. - * @param filePath a path appended to each of the cache's - * source roots in turn until an acceptable source file - * is found and copied to the local source directory. - * @return the supplied path if the file has been located - * and copied to the local sources directory or null if - * it was not found or the copy failed. + * Attempt to copy a source file from one of this cache's source roots to the local sources + * directory storing it in the subdirectory that belongs to this cache. + * + * @param filePath a path appended to each of the cache's source roots in turn until an + * acceptable source file is found and copied to the local source directory. + * @return the supplied path if the file has been located and copied to the local sources + * directory or null if it was not found or the copy failed. */ public Path tryCacheFile(Path filePath) { for (Path root : srcRoots) { @@ -171,17 +159,16 @@ public Path tryCacheFile(Path filePath) { } return null; } + /** - * Check whether the copy of a given source file in the - * local source cache is up to date with respect to any - * original located in this cache's and if not copy the - * original to the subdirectory that belongs to this cache. - * @param filePath a path appended to each of the cache's - * source roots in turn until an matching original source - * is found for comparison against the local source directory. - * @return the supplied path if the file is up to date or if - * an updated version has been copied to the local sources - * directory or null if was not found or the copy failed. + * Check whether the copy of a given source file in the local source cache is up to date with + * respect to any original located in this cache's and if not copy the original to the + * subdirectory that belongs to this cache. + * + * @param filePath a path appended to each of the cache's source roots in turn until an matching + * original source is found for comparison against the local source directory. + * @return the supplied path if the file is up to date or if an updated version has been copied + * to the local sources directory or null if was not found or the copy failed. */ public Path checkCacheFile(Path filePath) { Path targetPath = cachedPath(filePath); @@ -214,12 +201,14 @@ public Path checkCacheFile(Path filePath) { return null; } + /** - * Create and intialize the source cache used to locate and cache - * sources of a given type as determined by the supplied key. - * @param type an enum identifying both the type of Java sources - * cached by the returned cache and the subdir of the cached - * source subdirectory in which those sources are located. + * Create and intialize the source cache used to locate and cache sources of a given type as + * determined by the supplied key. + * + * @param type an enum identifying both the type of Java sources cached by the returned cache + * and the subdir of the cached source subdirectory in which those sources are + * located. * @return the desired source cache. */ public static SourceCache createSourceCache(SourceCacheType type) { @@ -239,10 +228,12 @@ public static SourceCache createSourceCache(SourceCacheType type) { } return sourceCache; } + /** - * Extend a root path form one file system using a path potentially derived - * from another file system by converting he latter to a text string and - * replacing the file separator if necessary. + * Extend a root path form one file system using a path potentially derived from another file + * system by converting he latter to a text string and replacing the file separator if + * necessary. + * * @param root the path to be extended * @param filePath the subpath to extend it with * @return the extended path @@ -258,43 +249,41 @@ protected Path extendPath(Path root, Path filePath) { } /** - * Convert a potential resolved candidate path to - * the corresponding local Path in this cache. - * @param candidate a resolved candidate path for - * some given resolution request + * Convert a potential resolved candidate path to the corresponding local Path in this cache. + * + * @param candidate a resolved candidate path for some given resolution request * @return the corresponding local Path */ protected Path cachedPath(Path candidate) { return basePath.resolve(candidate); } + /** - * Convert a potential resolved candidate path to - * the corresponding local File in this cache. - * @param candidate a resolved candidate path for - * some given resolution request + * Convert a potential resolved candidate path to the corresponding local File in this cache. + * + * @param candidate a resolved candidate path for some given resolution request * @return the corresponding local File */ protected File cachedFile(Path candidate) { return cachedPath(candidate).toFile(); } + /** - * Indicate whether a source path identifies a - * file in the associated file system. + * Indicate whether a source path identifies a file in the associated file system. + * * @param sourcePath - * @return true if the path identifies a file or - * false if no such file can be found. - * @throws IOException if there is some error in - * resolving the path. + * @return true if the path identifies a file or false if no such file can be found. + * @throws IOException if there is some error in resolving the path. */ private boolean checkSourcePath(Path sourcePath) throws IOException { return Files.isRegularFile(sourcePath); } + /** - * Ensure the directory hierarchy for a path exists - * creating any missing directories if needed. + * Ensure the directory hierarchy for a path exists creating any missing directories if needed. + * * @param targetDir a path to the desired directory - * @throws IOException if it is not possible to create - * one or more directories in the path + * @throws IOException if it is not possible to create one or more directories in the path */ private void ensureTargetDirs(Path targetDir) throws IOException { if (targetDir != null) { @@ -304,8 +293,10 @@ private void ensureTargetDirs(Path targetDir) throws IOException { } } } + /** * Add a path to the list of classpath entries + * * @param path The path to add. */ private static void addClassPathEntry(String path) { @@ -314,6 +305,7 @@ private static void addClassPathEntry(String path) { /** * Add a path to the list of source path entries + * * @param path The path to add. */ private static void addSourcePathEntry(String path) { @@ -321,8 +313,8 @@ private static void addSourcePathEntry(String path) { } /** - * An automatic feature class which acquires the image - * loader class path via the afterAnalysis callback. + * An automatic feature class which acquires the image loader class path via the afterAnalysis + * callback. */ @AutomaticFeature public static class SourceCacheFeature implements Feature { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java index c8f63224db6c..530d612d3a02 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -36,20 +36,18 @@ import java.util.HashMap; /** - * A singleton class responsible for locating source files - * for classes included in a native image and copying them - * into the local sources. + * A singleton class responsible for locating source files for classes included in a native image + * and copying them into the local sources. */ public class SourceManager { /** - * Find and cache a source file for a give Java class and - * return a Path to the file relative to the source. - * @param resolvedType the Java type whose source file - * should be located and cached + * Find and cache a source file for a give Java class and return a Path to the file relative to + * the source. + * + * @param resolvedType the Java type whose source file should be located and cached * @param clazz the Java class associated with the resolved type - * @return a path identifying the location of a successfully - * cached file for inclusion in the generated debug info or - * null if a source file cannot be found or cached. + * @return a path identifying the location of a successfully cached file for inclusion in the + * generated debug info or null if a source file cannot be found or cached. */ public Path findAndCacheSource(ResolvedJavaType resolvedType, Class clazz) { /* short circuit if we have already seen this type */ @@ -60,13 +58,11 @@ public Path findAndCacheSource(ResolvedJavaType resolvedType, Class clazz) { String fileName = computeBaseName(resolvedType); /* - * null for the name means this class - * will not have a source so we skip on that + * null for the name means this class will not have a source so we skip on that */ if (fileName != null) { /* - * we can only provide sources - * for known classes and interfaces + * we can only provide sources for known classes and interfaces */ if (resolvedType.isInstanceClass() || resolvedType.isInterface()) { String packageName = computePackageName(resolvedType); @@ -83,19 +79,16 @@ public Path findAndCacheSource(ResolvedJavaType resolvedType, Class clazz) { } /* memoize the lookup */ verifiedPaths.put(resolvedType, (path != null ? path : INVALID_PATH)); - + return path; } /** - * Construct the base file name for a resolved - * Java class excluding path elements using either - * the source name embedded in the class file or - * the class name itself. - * @param resolvedType the resolved java type whose - * source file name is required - * @return the file name or null if it the class cannot - * be associated with a source file + * Construct the base file name for a resolved Java class excluding path elements using either + * the source name embedded in the class file or the class name itself. + * + * @param resolvedType the resolved java type whose source file name is required + * @return the file name or null if it the class cannot be associated with a source file */ private String computeBaseName(ResolvedJavaType resolvedType) { String fileName = resolvedType.getSourceFileName(); @@ -122,13 +115,12 @@ private String computeBaseName(ResolvedJavaType resolvedType) { } return fileName; } + /** - * Construct the package name for a Java type or - * the empty String if it has no package. - * @param javaType the Java type whose package - * name is required - * @return the package name or the empty String - * if it has no package + * Construct the package name for a Java type or the empty String if it has no package. + * + * @param javaType the Java type whose package name is required + * @return the package name or the empty String if it has no package */ private String computePackageName(ResolvedJavaType javaType) { String name = javaType.toClassName(); @@ -139,16 +131,18 @@ private String computePackageName(ResolvedJavaType javaType) { return ""; } } + /** - * Construct the prototype name for a Java source file - * which can be used to resolve and cache an actual source - * file. + * Construct the prototype name for a Java source file which can be used to resolve and cache an + * actual source file. + * * @param fileName the base file name for the source file * @param packageName the name of the package for the associated Java class - * @param sourceCacheType the sourceCacheType of cache in which to lookup or cache this class's source file + * @param sourceCacheType the sourceCacheType of cache in which to lookup or cache this class's + * source file * @param javaType the java sourceCacheType whose prototype name is required - * @param clazz the class associated with the sourceCacheType used to - * identify the module prefix for JDK classes + * @param clazz the class associated with the sourceCacheType used to identify the module prefix + * for JDK classes * @return a protoype name for the source file */ private Path computePrototypeName(String fileName, String packageName, SourceCacheType sourceCacheType, ResolvedJavaType javaType, Class clazz) { @@ -166,51 +160,48 @@ private Path computePrototypeName(String fileName, String packageName, SourceCac return Paths.get(prefix, packageName.split("\\.")).resolve(fileName); } } + /** - * A whitelist of packages prefixes used to - * pre-filter JDK runtime class lookups. + * A whitelist of packages prefixes used to pre-filter JDK runtime class lookups. */ public static final String[] JDK_SRC_PACKAGE_PREFIXES = { - "java.", - "jdk.", - "javax.", - "sun.", - "com.sun.", - "org.ietf.", - "org.jcp.", - "org.omg.", - "org.w3c.", - "org.xml", + "java.", + "jdk.", + "javax.", + "sun.", + "com.sun.", + "org.ietf.", + "org.jcp.", + "org.omg.", + "org.w3c.", + "org.xml", }; /** - * A whitelist of packages prefixes used to - * pre-filter GraalVM class lookups. + * A whitelist of packages prefixes used to pre-filter GraalVM class lookups. */ public static final String[] GRAALVM_SRC_PACKAGE_PREFIXES = { - "com.oracle.graal.", - "com.oracle.objectfile.", - "com.oracle.svm.", - "com.oracle.truffle.", - "org.graalvm.", + "com.oracle.graal.", + "com.oracle.objectfile.", + "com.oracle.svm.", + "com.oracle.truffle.", + "org.graalvm.", }; /** - * A whitelist of packages prefixes used to - * pre-filter app class lookups which - * includes just the empty string because - * any package will do. + * A whitelist of packages prefixes used to pre-filter app class lookups which includes just the + * empty string because any package will do. */ private static final String[] APP_SRC_PACKAGE_PREFIXES = { - "", + "", }; /** * Check a package name against a whitelist of acceptable packages. + * * @param packageName the package name of the class to be checked - * @param whitelist a list of prefixes one of which may form - * the initial prefix of the package name being checked - * @return true if the package name matches an entry in the - * whitelist otherwise false + * @param whitelist a list of prefixes one of which may form the initial prefix of the package + * name being checked + * @return true if the package name matches an entry in the whitelist otherwise false */ private boolean whiteListPackage(String packageName, String[] whitelist) { for (String prefix : whitelist) { @@ -222,9 +213,9 @@ private boolean whiteListPackage(String packageName, String[] whitelist) { } /** - * Identify which type of source cache should be used - * to locate a given class's source code as determined - * by it's package name. + * Identify which type of source cache should be used to locate a given class's source code as + * determined by it's package name. + * * @param packageName the package name of the class. * @return the corresponding source cache type */ @@ -237,34 +228,30 @@ private SourceCacheType sourceCacheType(String packageName) { } return SourceCacheType.APPLICATION; } + /** - * A map from each of the top level root keys to a - * cache that knows how to handle lookup and caching - * of the associated type of source file. + * A map from each of the top level root keys to a cache that knows how to handle lookup and + * caching of the associated type of source file. */ private static HashMap caches = new HashMap<>(); /** - * A map from a Java type to an associated source paths which - * is known to have an up to date entry in the relevant source - * file cache. This is used to memoize previous lookups. + * A map from a Java type to an associated source paths which is known to have an up to date + * entry in the relevant source file cache. This is used to memoize previous lookups. */ private static HashMap verifiedPaths = new HashMap<>(); /** - * An invalid path used as a marker to track failed lookups - * so we don't waste time looking up the source again. - * Note that all legitimate paths will end with a ".java" - * suffix. + * An invalid path used as a marker to track failed lookups so we don't waste time looking up + * the source again. Note that all legitimate paths will end with a ".java" suffix. */ private static final Path INVALID_PATH = Paths.get("invalid"); /** - * Retrieve the source cache used to locate and cache sources - * of a given type as determined by the supplied key, creating - * and initializing it if it does not already exist. - * @param type an enum identifying the type of Java sources - * cached by the returned cache. + * Retrieve the source cache used to locate and cache sources of a given type as determined by + * the supplied key, creating and initializing it if it does not already exist. + * + * @param type an enum identifying the type of Java sources cached by the returned cache. * @return the desired source cache. */ private SourceCache getOrCreateCache(SourceCacheType type) { @@ -286,4 +273,3 @@ private Path locateSource(String fileName, String packagename, SourceCacheType t } } } - From 07323555445607e5233b98bbb8c7eac63247e943 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 10 Mar 2020 14:47:11 +0000 Subject: [PATCH 099/130] more format changes and fix some small errors in graal cache --- .../elf/dwarf/DwarfARangesSectionImpl.java | 32 +++-- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 59 ++++++--- .../elf/dwarf/DwarfFrameSectionImpl.java | 42 ++++-- .../dwarf/DwarfFrameSectionImplAArch64.java | 11 +- .../dwarf/DwarfFrameSectionImplX86_64.java | 22 ++-- .../elf/dwarf/DwarfInfoSectionImpl.java | 47 ++++--- .../elf/dwarf/DwarfLineSectionImpl.java | 124 +++++++++--------- .../elf/dwarf/DwarfSectionImpl.java | 40 +++--- .../objectfile/elf/dwarf/DwarfSections.java | 93 +++++++------ .../svm/hosted/image/NativeBootImage.java | 16 +-- .../image/sources/GraalVMSourceCache.java | 7 +- .../svm/hosted/image/sources/SourceCache.java | 4 +- .../hosted/image/sources/SourceManager.java | 2 - 13 files changed, 267 insertions(+), 232 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 119798e3a21f..e2bcb27740f7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -39,6 +39,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ARANGES_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; + /** * Section generator for debug_aranges section. */ @@ -62,30 +63,38 @@ public void createContent() { * we need an entry for each compilation unit * *
      + * *
    • uint32 length ............ in bytes (not counting these 4 bytes) + * *
    • uint16 dwarf_version ..... always 2 + * *
    • uint32 info_offset ....... offset of compilation unit on debug_info + * *
    • uint8 address_size ....... always 8 + * *
    • uint8 segment_desc_size .. ??? + * *
    * - * i.e. 12 bytes followed by padding - * aligning up to 2 * address size + * i.e. 12 bytes followed by padding aligning up to 2 * address size * *
      + * *
    • uint8 pad[4] + * *
    * * followed by N + 1 times * - *
      - *
    • uint64 lo ................ lo address of range + *
      • uint64 lo ................ lo address of range + * *
      • uint64 length ............ number of bytes in range + * *
      * - * where N is the number of ranges belonging to the compilation unit - * and the last range contains two zeroes - */ + * where N is the number of ranges belonging to the compilation unit and the last range + * contains two zeroes + */ for (ClassEntry classEntry : getPrimaryClasses()) { pos += DW_AR_HEADER_SIZE; @@ -108,9 +117,8 @@ public byte[] getOrDecideContent(Map alre Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { /* - * this may not be the final vaddr for the text segment - * but it will be close enough to make debug easier - * i.e. to within a 4k page or two + * this may not be the final vaddr for the text segment but it will be close enough + * to make debug easier i.e. to within a 4k page or two */ debugTextBase = ((Number) valueObj).longValue(); } @@ -183,8 +191,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override 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 6e0709ccefef..b3cc40de399b 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 @@ -68,53 +68,70 @@ public String getSectionName() { public void createContent() { int pos = 0; /* - * an abbrev table contains abbrev entries for one or - * more CUs. the table includes a sequence of abbrev - * entries each of which defines a specific DIE layout - * employed to describe some DIE in a CU. a table is - * terminated by a null entry + * an abbrev table contains abbrev entries for one or more CUs. the table includes a + * sequence of abbrev entries each of which defines a specific DIE layout employed to + * describe some DIE in a CU. a table is terminated by a null entry * * a null entry has consists of just a 0 abbrev code + * *
        + * *
      • LEB128 abbrev_code; ...... == 0 + * *
      * * non-null entries have the following format + * *
        - *
      • LEB128 abbrev_code; ...... unique noncode for this layout != 0 - *
      • 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 DIE + * + *
      • LEB128 abbrev_code; ......unique noncode for this layout != 0 + * + *
      • 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 + * DIE + * *
      • attribute_spec* .......... zero or more attributes - *
      • null_attribute_spec ...... terminator - *
      + * + *
    • null_attribute_spec ...... terminator
    * * An attribute_spec consists of an attribute name and form + * *
      + * *
    • LEB128 attr_name; ........ 0 for the null attribute name + * *
    • LEB128 attr_form; ........ 0 for the null attribute form + * *
    * - * For the moment we only use one abbrev table for all CUs. - * It contains two DIEs, the first to describe the compilation - * unit itself and the second to describe each method within + * For the moment we only use one abbrev table for all CUs. It contains two DIEs, the first + * to describe the compilation unit itself and the second to describe each method within * that compilation unit. * * The DIE layouts are as follows: * - *
      - *
    • abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + *
      • abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + * *
      • DW_AT_language : ... DW_FORM_data1 + * *
      • DW_AT_name : ....... DW_FORM_strp + * *
      • DW_AT_low_pc : ..... DW_FORM_address + * *
      • DW_AT_hi_pc : ...... DW_FORM_address - *
      • DW_AT_stmt_list : .. DW_FORM_data4 - *
      * - *
        - *
      • abbrev_code == 2, tag == DW_TAG_subprogram, no_children + *
      • DW_AT_stmt_list : .. DW_FORM_data4
      + * + *
      • abbrev_code == 2, tag == DW_TAG_subprogram, no_children + * *
      • DW_AT_name : ....... DW_FORM_strp + * *
      • DW_AT_hi_pc : ...... DW_FORM_addr + * *
      • DW_AT_external : ... DW_FORM_flag + * *
      */ @@ -220,8 +237,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 3996fa7175b6..a7abe33f8034 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -25,6 +25,7 @@ */ package com.oracle.objectfile.elf.dwarf; + import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; @@ -43,6 +44,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_register; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; + /** * Section generic generator for debug_frame section. */ @@ -62,8 +64,7 @@ public void createContent() { int pos = 0; /* - * the frame section contains one CIE at offset 0 - * followed by an FIE for each method + * the frame section contains one CIE at offset 0 followed by an FIE for each method */ pos = writeCIE(null, pos); pos = writeMethodFrames(null, pos); @@ -81,10 +82,9 @@ public void writeContent() { checkDebug(pos); /* - * there are entries for the prologue region where the - * stack is being built, the method body region(s) where - * the code executes with a fixed size frame and the - * epilogue region(s) where the stack is torn down + * there are entries for the prologue region where the stack is being built, the method body + * region(s) where the code executes with a fixed size frame and the epilogue region(s) + * where the stack is torn down */ pos = writeCIE(buffer, pos); pos = writeMethodFrames(buffer, pos); @@ -97,19 +97,27 @@ public void writeContent() { public int writeCIE(byte[] buffer, int p) { /* - * we only need a vanilla CIE with default fields - * because we have to have at least one - * the layout is + * we only need a vanilla CIE with default fields because we have to have at least one the + * layout is * *
        + * *
      • uint32 : length ............... length of remaining fields in this CIE + * *
      • uint32 : CIE_id ................ unique id for CIE == 0xffffff + * *
      • uint8 : version ................ == 1 + * *
      • uint8[] : augmentation ......... == "" so always 1 byte + * *
      • ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + * *
      • ULEB : data_alignment_factor ... == -8 + * *
      • byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 + * *
      • byte[] : initial_instructions .. includes pad to 8-byte boundary + * *
      */ int pos = p; @@ -190,15 +198,21 @@ public int writeMethodFrames(byte[] buffer, int p) { public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { /* - * we only need a vanilla FDE header with default fields - * the layout is + * we only need a vanilla FDE header with default fields the layout is * *
        + * *
      • uint32 : length ............ length of remaining fields in this FDE - *
      • uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header + * + *
      • uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE + * header + * *
      • uint64 : initial_location .. i.e. method lo address + * *
      • uint64 : address_range ..... i.e. method hi - lo + * *
      • byte[] : instructions ...... includes pad to 8-byte boundary + * *
      */ @@ -365,8 +379,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index ca570a8d3432..89268fd72b7c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -27,8 +27,8 @@ package com.oracle.objectfile.elf.dwarf; /** - * AArch64-specific section generator for debug_frame section - * that knows details of AArch64 registers and frame layout. + * AArch64-specific section generator for debug_frame section that knows details of AArch64 + * registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { // public static final int DW_CFA_FP_IDX = 29; @@ -54,14 +54,15 @@ public int getSPIdx() { public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; /* - * rsp has not been updated and - * caller pc is in lr + * rsp has not been updated and caller pc is in lr + * *
        + * *
      • register r32 (rpc), r30 (lr) + * *
      */ pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); return pos; } } - diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java index eec54f33b13a..275c4ca00a32 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -27,8 +27,8 @@ package com.oracle.objectfile.elf.dwarf; /** - * x86_64-specific section generator for debug_frame section - * that knows details of x86_64 registers and frame layout. + * x86_64-specific section generator for debug_frame section that knows details of x86_64 registers + * and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public static final int DW_CFA_RSP_IDX = 7; @@ -52,19 +52,23 @@ public int getSPIdx() { public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; /* - * rsp points at the word containing the saved rip - * so the frame base (cfa) is at rsp + 8 (why not - ???) + * rsp points at the word containing the saved rip so the frame base (cfa) is at rsp + 8 + * (why not - ???) + * *
        + * *
      • def_cfa r7 (sp) offset 8 + * *
      */ pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); /* - * rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa - * (why not -1 ???) - *
        - *
      • offset r16 (rip) cfa - 8 - *
      • + * rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa (why + * not -1 ???) + * + *
        • offset r16 (rip) cfa - 8 + * + *
        */ pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; 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 25d5439802c2..f13c5c3e1701 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 @@ -40,6 +40,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LANG_Java; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; + /** * Section generator for debug_info section. */ @@ -61,36 +62,52 @@ public String getSectionName() { @Override public void createContent() { /* - * we need a single level 0 DIE for each compilation unit (CU). - * Each CU's Level 0 DIE is preceded by a fixed header - * and terminated by a null DIE: + * we need a single level 0 DIE for each compilation unit (CU). Each CU's Level 0 DIE is + * preceded by a fixed header and terminated by a null DIE: + * *
          + * *
        • uint32 length ......... excluding this length field + * *
        • uint16 dwarf_version .. always 2 ?? + * *
        • uint32 abbrev offset .. always 0 ?? + * *
        • uint8 address_size .... always 8 + * *
        • DIE* .................. sequence of top-level and nested child entries + * *
        • null_DIE .............. == 0 + * *
        * - * a DIE is a recursively defined structure. - * it starts with a code for the associated - * abbrev entry followed by a series of attribute - * values, as determined by the entry, terminated by - * a null value and followed by zero or more child - * DIEs (zero iff has_children == no_children). + * a DIE is a recursively defined structure. it starts with a code for the associated abbrev + * entry followed by a series of attribute values, as determined by the entry, terminated by + * a null value and followed by zero or more child DIEs (zero iff has_children == + * no_children). * *
          - *
        • LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE + * + *
        • LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of + * DIE + * *
        • attribute_value* ......... value sequence as determined by abbrev entry + * *
        • DIE* ..................... sequence of child DIEs (if appropriate) - *
        • ............. == 0 + *
        • + * + *
        • null_value ............... == 0 + * *
        * * note that a null_DIE looks like + * *
          + * *
        • LEB128 abbrev_code ....... == 0 + * *
        + * * i.e. it also looks like a null_value */ @@ -122,8 +139,7 @@ public void writeContent() { debug(" [0x%08x] size = 0x%08x\n", pos, size); for (ClassEntry classEntry : getPrimaryClasses()) { /* - * save the offset of this file's CU so it can - * be used when writing the aranges section + * save the offset of this file's CU so it can be used when writing the aranges section */ classEntry.setCUIndex(pos); int lengthPos = pos; @@ -244,8 +260,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override @@ -253,4 +269,3 @@ public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } } - diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index d73f47b277b3..0dc635f2ad65 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -40,6 +40,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; + /** * Section generator for debug_line section. */ @@ -53,13 +54,11 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final int DW_LN_LINE_BASE = -5; /** - * current generator follows C++ with line range 14 - * giving full range -5 to 8. + * current generator follows C++ with line range 14 giving full range -5 to 8. */ private static final int DW_LN_LINE_RANGE = 14; /** - * current generator uses opcode base of 13 - * which must equal DW_LNS_define_file + 1. + * current generator uses opcode base of 13 which must equal DW_LNS_define_file + 1. */ private static final int DW_LN_OPCODE_BASE = 13; @@ -67,15 +66,15 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { * standard opcodes defined by Dwarf 2 */ /* - * 0 can be returned to indicate an invalid opcode + * 0 can be returned to indicate an invalid opcode */ private static final byte DW_LNS_undefined = 0; /* - * 0 can be inserted as a prefix for extended opcodes + * 0 can be inserted as a prefix for extended opcodes */ private static final byte DW_LNS_extended_prefix = 0; /* - * append current state as matrix row 0 args + * append current state as matrix row 0 args */ private static final byte DW_LNS_copy = 1; /* @@ -83,7 +82,7 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final byte DW_LNS_advance_pc = 2; /* - * increment line 1 sleb arg + * increment line 1 sleb arg */ private static final byte DW_LNS_advance_line = 3; /* @@ -91,15 +90,15 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final byte DW_LNS_set_file = 4; /* - * set column 1 uleb arg + * set column 1 uleb arg */ private static final byte DW_LNS_set_column = 5; /* - * flip is_stmt 0 args + * flip is_stmt 0 args */ private static final byte DW_LNS_negate_stmt = 6; /* - * set end sequence and copy row 0 args + * set end sequence and copy row 0 args */ private static final byte DW_LNS_set_basic_block = 7; /* @@ -120,7 +119,7 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { @SuppressWarnings("unused") private static final byte DW_LNE_undefined = 0; /* - * end sequence of addresses + * end sequence of addresses */ private static final byte DW_LNE_end_sequence = 1; /* @@ -144,8 +143,8 @@ public String getSectionName() { @Override public void createContent() { /* - * we need to create a header, dir table, file table and line - * number table encoding for each CU + * we need to create a header, dir table, file table and line number table encoding for each + * CU */ /* @@ -174,17 +173,29 @@ public void createContent() { public int headerSize() { /* * header size is standard 31 bytes + * *
          + * *
        • uint32 total_length + * *
        • uint16 version + * *
        • uint32 prologue_length + * *
        • uint8 min_insn_length + * *
        • uint8 default_is_stmt + * *
        • int8 line_base + * *
        • uint8 line_range + * *
        • uint8 opcode_base + * *
        • uint8 li_opcode_base + * *
        • uint8[opcode_base-1] standard_opcode_lengths + * *
        */ @@ -193,13 +204,10 @@ public int headerSize() { public int computeDirTableSize(ClassEntry classEntry) { /* - * table contains a sequence of 'nul'-terminated - * dir name bytes followed by an extra 'nul' - * and then a sequence of 'nul'-terminated - * file name bytes followed by an extra 'nul' + * table contains a sequence of 'nul'-terminated dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated file name bytes followed by an extra 'nul' * - * for now we assume dir and file names are ASCII - * byte strings + * for now we assume dir and file names are ASCII byte strings */ int dirSize = 0; for (DirEntry dir : classEntry.getLocalDirs()) { @@ -214,13 +222,10 @@ public int computeDirTableSize(ClassEntry classEntry) { public int computeFileTableSize(ClassEntry classEntry) { /* - * table contains a sequence of 'nul'-terminated - * dir name bytes followed by an extra 'nul' - * and then a sequence of 'nul'-terminated - * file name bytes followed by an extra 'nul' - - * for now we assume dir and file names are ASCII - * byte strings + * table contains a sequence of 'nul'-terminated dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated file name bytes followed by an extra 'nul' + * + * for now we assume dir and file names are ASCII byte strings */ int fileSize = 0; for (FileEntry localEntry : classEntry.getLocalFiles()) { @@ -249,9 +254,9 @@ public int computeFileTableSize(ClassEntry classEntry) { public int computeLineNUmberTableSize(ClassEntry classEntry) { /* - * sigh -- we have to do this by generating the - * content even though we cannot write it into a byte[] - */ + * sigh -- we have to do this by generating the content even though we cannot write it into + * a byte[] + */ return writeLineNumberTable(classEntry, null, 0); } @@ -263,9 +268,8 @@ public byte[] getOrDecideContent(Map alre Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { /* - * this may not be the final vaddr for the text segment - * but it will be close enough to make debug easier - * i.e. to within a 4k page or two + * this may not be the final vaddr for the text segment but it will be close enough + * to make debug easier i.e. to within a 4k page or two */ debugTextBase = ((Number) valueObj).longValue(); } @@ -314,8 +318,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { */ pos = putShort(DW_VERSION_2, buffer, pos); /* - * 4 ubyte prologue length includes rest of header and - * dir + file table section + * 4 ubyte prologue length includes rest of header and dir + file table section */ int prologueSize = classEntry.getLinePrologueSize() - 6; pos = putInt(prologueSize, buffer, pos); @@ -356,7 +359,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { putByte((byte) 0, buffer, pos + 5); /* DW_LNS_set_basic_block */ putByte((byte) 0, buffer, pos + 6); - /* DW_LNS_const_add_pc */ + /* DW_LNS_const_add_pc */ putByte((byte) 0, buffer, pos + 7); /* DW_LNS_fixed_advance_pc */ putByte((byte) 1, buffer, pos + 8); @@ -439,9 +442,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { Range primaryRange = primaryEntry.getPrimary(); assert primaryRange.getFileName().equals(primaryFileName); /* - * each primary represents a method i.e. a contiguous - * sequence of subranges. we assume the default state - * at the start of each sequence because we always post an + * each primary represents a method i.e. a contiguous sequence of subranges. we assume + * the default state at the start of each sequence because we always post an * end_sequence when we finish all the subranges in the method */ long line = primaryRange.getLine(); @@ -457,7 +459,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { * set state for primary */ debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), - primaryRange.getLine()); + primaryRange.getLine()); /* * initialize and write a row for the start of the primary method @@ -466,11 +468,10 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putSetBasicBlock(buffer, pos); /* * address is currently 0 - */ + */ pos = putSetAddress(address, buffer, pos); /* - * state machine value of line is currently 1 - * increment to desired line + * state machine value of line is currently 1 increment to desired line */ if (line != 1) { pos = putAdvanceLine(line - 1, buffer, pos); @@ -503,12 +504,10 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); } /* - * there is a temptation to append end sequence at here - * when the hiAddress lies strictly between the current - * address and the start of the next subrange because, - * ostensibly, we have void space between the end of - * the current subrange and the start of the next one. - * however, debug works better if we treat all the insns up + * there is a temptation to append end sequence at here when the hiAddress lies + * strictly between the current address and the start of the next subrange because, + * ostensibly, we have void space between the end of the current subrange and the + * start of the next one. however, debug works better if we treat all the insns up * to the next range start as belonging to the current line * * if we have to update to a new file then do so @@ -522,8 +521,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { fileIdx = subFileIdx; } /* - * check if we can advance line and/or address in - * one byte with a special opcode + * check if we can advance line and/or address in one byte with a special opcode */ long lineDelta = subLine - line; long addressDelta = subAddressLo - address; @@ -537,15 +535,14 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { } } else { /* - * does it help to divide and conquer using - * a fixed address increment + * does it help to divide and conquer using a fixed address increment */ int remainder = isConstAddPC(addressDelta); if (remainder > 0) { pos = putConstAddPC(buffer, pos); /* - * the remaining address can be handled with a - * special opcode but what about the line delta + * the remaining address can be handled with a special opcode but what about + * the line delta */ opcode = isSpecialOpcode(remainder, lineDelta); if (opcode != DW_LNS_undefined) { @@ -555,8 +552,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putSpecialOpcode(opcode, buffer, pos); } else { /* - * ok, bump the line separately then use a - * special opcode for the address remainder + * ok, bump the line separately then use a special opcode for the + * address remainder */ opcode = isSpecialOpcode(remainder, 0); assert opcode != DW_LNS_undefined; @@ -571,8 +568,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { pos = putAdvanceLine(lineDelta, buffer, pos); } /* - * n.b. we might just have had an out of range line increment - * with a zero address increment + * n.b. we might just have had an out of range line increment with a zero + * address increment */ if (addressDelta > 0) { /* @@ -845,7 +842,7 @@ public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { debugAddress += opcodeAddress(opcode); debugLine += opcodeLine(opcode); debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, pos); } } @@ -861,8 +858,7 @@ public static byte isSpecialOpcode(long addressDelta, long lineDelta) { long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; if (offsetLineDelta < DW_LN_LINE_RANGE) { /* - * line_delta can be encoded - * check if address is ok + * line_delta can be encoded check if address is ok */ if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; @@ -905,8 +901,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, }; @Override 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 c83dce8c5dc6..548ac07ab61a 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 @@ -41,8 +41,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; /** - * class from which all DWARF debug sections - * inherit providing common behaviours. + * class from which all DWARF debug sections inherit providing common behaviours. */ public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { protected DwarfSections dwarfSections; @@ -56,26 +55,20 @@ public DwarfSectionImpl(DwarfSections dwarfSections) { } /** - * creates the target byte[] array used to define the section - * contents. + * creates the target byte[] array used to define the section contents. * - * the main task of this method is to precompute the - * size of the debug section. given the complexity of the - * data layouts that invariably requires performing a dummy - * write of the contents, inserting bytes into a small, - * scratch buffer only when absolutely necessary. subclasses - * may also cache some information for use when writing the - * contents. + * the main task of this method is to precompute the size of the debug section. given the + * complexity of the data layouts that invariably requires performing a dummy write of the + * contents, inserting bytes into a small, scratch buffer only when absolutely necessary. + * subclasses may also cache some information for use when writing the contents. */ public abstract void createContent(); /** - * populates the byte[] array used to contain the section - * contents. + * populates the byte[] array used to contain the section contents. * - * in most cases this task reruns the operations performed - * under createContent but this time actually writing data - * to the target byte[]. + * in most cases this task reruns the operations performed under createContent but this time + * actually writing data to the target byte[]. */ public abstract void writeContent(); @@ -89,8 +82,7 @@ public boolean isLoadable() { public void checkDebug(int pos) { /* - * if the env var relevant to this element - * type is set then switch on debugging + * if the env var relevant to this element type is set then switch on debugging */ String name = getSectionName(); String envVarName = "DWARF_" + name.substring(1).toUpperCase(); @@ -314,22 +306,24 @@ public int writeAttrNull(byte[] buffer, int pos) { } /** - * identify the section after which this debug section - * needs to be ordered when sizing and creating content. + * identify the section after which this debug section needs to be ordered when sizing and + * creating content. + * * @return the name of the preceding section */ public abstract String targetSectionName(); /** - * identify the layout properties of the target section - * which need to have been decided before the contents - * of this section can be created. + * identify the layout properties of the target section which need to have been decided before + * the contents of this section can be created. + * * @return an array of the relevant decision kinds */ public abstract LayoutDecision.Kind[] targetSectionKinds(); /** * identify this debug section by name. + * * @return the name of the debug section */ public abstract String getSectionName(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index d3f8bc99fdda..5d26129bf746 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -43,18 +43,14 @@ import java.util.Map; /** - * A class that models the debug info in an - * organization that facilitates generation of the - * required DWARF sections. It groups common data and - * behaviours for use by the various subclasses of - * class DwarfSectionImpl that take responsibility - * for generating content for a specific section type. + * A class that models the debug info in an organization that facilitates generation of the required + * DWARF sections. It groups common data and behaviours for use by the various subclasses of class + * DwarfSectionImpl that take responsibility for generating content for a specific section type. */ public class DwarfSections { /* - * names of the different ELF sections we create or reference - * in reverse dependency order + * names of the different ELF sections we create or reference in reverse dependency order */ public static final String TEXT_SECTION_NAME = ".text"; public static final String DW_STR_SECTION_NAME = ".debug_str"; @@ -95,7 +91,7 @@ public class DwarfSections { public static final int DW_AT_language = 0x13; public static final int DW_AT_external = 0x3f; @SuppressWarnings("unused") - public static final int DW_AT_return_addr = 0x2a; + public static final int DW_AT_return_addr = 0x2a; @SuppressWarnings("unused") public static final int DW_AT_frame_base = 0x40; /* @@ -149,7 +145,8 @@ public class DwarfSections { * others not yet needed */ @SuppressWarnings("unused") - public static final int DW_AT_type = 0; // only present for non-void functions + public static final int DW_AT_type = 0; // only present for non-void + // functions @SuppressWarnings("unused") public static final int DW_AT_accessibility = 0; @@ -238,15 +235,14 @@ public DwarfLineSectionImpl getLineSectionImpl() { } /** - * a table listing all known strings, some of - * which may be marked for insertion into the + * a table listing all known strings, some of which may be marked for insertion into the * debug_str section. */ private StringTable stringTable = new StringTable(); /** - * index of all dirs in which files are found to reside - * either as part of substrate/compiler or user code. + * index of all dirs in which files are found to reside either as part of substrate/compiler or + * user code. */ private Map dirsIndex = new HashMap<>(); @@ -254,6 +250,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { * The obvious traversal structure for debug records is: * * 1) by top level compiled method (primary Range) ordered by ascending address + * * 2) by inlined method (sub range) within top level method ordered by ascending address * * these can be used to ensure that all debug records are generated in increasing address order @@ -261,21 +258,22 @@ public DwarfLineSectionImpl getLineSectionImpl() { * An alternative traversal option is * * 1) by top level class (String id) + * * 2) by top level compiled method (primary Range) within a class ordered by ascending address + * * 3) by inlined method (sub range) within top level method ordered by ascending address * - * this relies on the (current) fact that methods of a given class always appear - * in a single continuous address range with no intervening code from other methods - * or data values. this means we can treat each class as a compilation unit, allowing - * data common to all methods of the class to be shared. + * this relies on the (current) fact that methods of a given class always appear in a single + * continuous address range with no intervening code from other methods or data values. this + * means we can treat each class as a compilation unit, allowing data common to all methods of + * the class to be shared. * * A third option appears to be to traverse via files, then top level class within file etc. - * Unfortunately, files cannot be treated as the compilation unit. A file F may contain - * multiple classes, say C1 and C2. There is no guarantee that methods for some other - * class C' in file F' will not be compiled into the address space interleaved between - * methods of C1 and C2. That is a shame because generating debug info records one file at a - * time would allow more sharing e.g. enabling all classes in a file to share a single copy - * of the file and dir tables. + * Unfortunately, files cannot be treated as the compilation unit. A file F may contain multiple + * classes, say C1 and C2. There is no guarantee that methods for some other class C' in file F' + * will not be compiled into the address space interleaved between methods of C1 and C2. That is + * a shame because generating debug info records one file at a time would allow more sharing + * e.g. enabling all classes in a file to share a single copy of the file and dir tables. */ /** @@ -283,7 +281,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { */ private LinkedList primaryClasses = new LinkedList<>(); /** - * index of already seen classes. + * index of already seen classes. */ private Map primaryClassesIndex = new HashMap<>(); @@ -294,6 +292,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { /** * indirects this call to the string table. + * * @param string the string to be inserted * @return a unique equivalent String */ @@ -302,11 +301,10 @@ public String uniqueString(String string) { } /** - * indirects this call to the string table, ensuring - * the table entry is marked for inclusion in the - * debug_str section. - * @param string the string to be inserted and - * marked for inclusion in the debug_str section + * indirects this call to the string table, ensuring the table entry is marked for inclusion in + * the debug_str section. + * + * @param string the string to be inserted and marked for inclusion in the debug_str section * @return a unique equivalent String */ public String uniqueDebugString(String string) { @@ -315,26 +313,23 @@ public String uniqueDebugString(String string) { /** * indirects this call to the string table. + * * @param string the string whose index is required - * @return the offset of the string in the .debug_str - * section + * @return the offset of the string in the .debug_str section */ public int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } /** - * entry point allowing ELFObjectFile to pass on information - * about types, code and heap data. - * @param debugInfoProvider provider instance passed by - * ObjectFile client + * entry point allowing ELFObjectFile to pass on information about types, code and heap data. + * + * @param debugInfoProvider provider instance passed by ObjectFile client */ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* - * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); - * for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { - * install types - * } + * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); for + * (DebugTypeInfo debugTypeInfo : typeInfoProvider) { install types } */ /* @@ -359,8 +354,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); /* * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, - * returnTypeName, className, methodName, paramNames, fileName); - * create an infoSection entry for the method + * returnTypeName, className, methodName, paramNames, fileName); create an infoSection + * entry for the method */ addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { @@ -381,11 +376,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { }); }); /* - * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - * for (DebugDataInfo debugDataInfo : dataInfoProvider) { - * install details of heap elements - * String name = debugDataInfo.toString(); - * } + * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); for + * (DebugDataInfo debugDataInfo : dataInfoProvider) { install details of heap elements + * String name = debugDataInfo.toString(); } */ } @@ -449,8 +442,7 @@ public void addSubRange(Range primaryRange, Range subrange) { ClassEntry classEntry = primaryClassesIndex.get(className); FileEntry subrangeFileEntry = ensureFileEntry(subrange); /* - * the primary range should already have been seen - * and associated with a primary class entry + * the primary range should already have been seen and associated with a primary class entry */ assert classEntry.primaryIndexFor(primaryRange) != null; if (subrangeFileEntry != null) { @@ -469,12 +461,15 @@ public DirEntry ensureDirEntry(Path filePath) { } return dirEntry; } + public StringTable getStringTable() { return stringTable; } + public LinkedList getPrimaryClasses() { return primaryClasses; } + public ByteOrder getByteOrder() { return byteOrder; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 1db5af2697a8..72348a508aee 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -980,6 +980,7 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile */ private class NativeImageDebugInfoProvider implements DebugInfoProvider { private final NativeImageCodeCache codeCache; + @SuppressWarnings("unused") private final NativeImageHeap heap; NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { @@ -1004,14 +1005,6 @@ public Stream dataInfoProvider() { } } - private static final String[] GRAAL_SRC_PACKAGE_PREFIXES = { - "org.graalvm", - "com.oracle.graal", - "com.oracle.objectfile", - "com.oracle.svm", - "com.oracle.truffle", - }; - /** * implementation of the DebugCodeInfo API interface that allows code info to be passed to an * ObjectFile when generation of debug info is enabled. @@ -1094,10 +1087,12 @@ public Stream lineInfoProvider() { return compilation.getSourceMappings().stream().map(sourceMapping -> new NativeImageDebugLineInfo(sourceMapping)); } + @Override public int getFrameSize() { return compilation.getTotalFrameSize(); } + @Override public List getFrameSizeChanges() { List frameSizeChanges = new LinkedList<>(); for (Mark mark : compilation.getMarks()) { @@ -1132,8 +1127,8 @@ private class NativeImageDebugLineInfo implements DebugLineInfo { NativeImageDebugLineInfo(SourceMapping sourceMapping) { NodeSourcePosition position = sourceMapping.getSourcePosition(); - int bci = position.getBCI(); - this.bci = (bci >= 0 ? bci : 0); + int posbci = position.getBCI(); + this.bci = (posbci >= 0 ? posbci : 0); this.method = position.getMethod(); this.lo = sourceMapping.getStartOffset(); this.hi = sourceMapping.getEndOffset(); @@ -1148,6 +1143,7 @@ public String fileName() { return null; } + @Override public Path filePath() { if (fullFilePath != null) { return fullFilePath.getParent(); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 9fbf74483c3a..833166c2daff 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -54,14 +54,11 @@ protected final SourceCacheType getType() { private static final String JAVA_CLASSPATH_PROP = "java.class.path"; private void initSrcRoots() { - String javaClassPath = System.getProperty(JAVA_CLASSPATH_PROP); - assert javaClassPath != null; - String[] classPathEntries = javaClassPath.split(File.pathSeparator); for (String classPathEntry : classPathEntries) { tryClassPathRoot(classPathEntry); } for (String sourcePathEntry : sourcePathEntries) { - tryClassPathRoot(sourcePathEntry); + trySourceRoot(sourcePathEntry); } } @@ -127,7 +124,7 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { * @param root A root path under which to locate the desired subdirectory * @return true if a */ - private boolean filterSrcRoot(Path root) { + private static boolean filterSrcRoot(Path root) { String separator = root.getFileSystem().getSeparator(); /* if any of the graal paths exist accept this root */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index ab453b4a816f..0507702ea3a2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -275,7 +275,7 @@ protected File cachedFile(Path candidate) { * @return true if the path identifies a file or false if no such file can be found. * @throws IOException if there is some error in resolving the path. */ - private boolean checkSourcePath(Path sourcePath) throws IOException { + private static boolean checkSourcePath(Path sourcePath) throws IOException { return Files.isRegularFile(sourcePath); } @@ -285,7 +285,7 @@ private boolean checkSourcePath(Path sourcePath) throws IOException { * @param targetDir a path to the desired directory * @throws IOException if it is not possible to create one or more directories in the path */ - private void ensureTargetDirs(Path targetDir) throws IOException { + private static void ensureTargetDirs(Path targetDir) throws IOException { if (targetDir != null) { File targetFile = targetDir.toFile(); if (!targetFile.exists()) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java index 530d612d3a02..cca64372df04 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceManager.java @@ -26,8 +26,6 @@ package com.oracle.svm.hosted.image.sources; -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.meta.ResolvedJavaType; From 356d5d6bcddc679dc368cc278b6db72bdbfd21d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 11 Mar 2020 14:34:55 +0100 Subject: [PATCH 100/130] Demonstrate how to implement hierarchical logging --- .../debuginfo/DebugInfoProvider.java | 5 + .../objectfile/elf/dwarf/DwarfSections.java | 83 +++-- .../svm/hosted/image/NativeBootImage.java | 272 +--------------- .../image/NativeImageDebugInfoProvider.java | 290 ++++++++++++++++++ 4 files changed, 335 insertions(+), 315 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java 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 185de9e86e85..39963c73310b 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 @@ -28,8 +28,11 @@ import java.nio.file.Path; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Stream; +import org.graalvm.compiler.debug.DebugContext; + /** * Interfaces used to allow a native image to communicate details of types, code and data to the * underlying object file so that the latter can insert appropriate debug info. @@ -45,6 +48,8 @@ interface DebugTypeInfo { * access details of a specific compiled method. */ interface DebugCodeInfo { + void debugContext(Consumer action); + /** * @return the name of the file containing a compiled method excluding any path */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 5d26129bf746..83c68b1d3919 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -26,6 +26,15 @@ package com.oracle.objectfile.elf.dwarf; +import java.nio.ByteOrder; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.debug.DebugContext; + import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.DirEntry; import com.oracle.objectfile.debugentry.FileEntry; @@ -35,13 +44,6 @@ import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.elf.ELFMachine; -import java.nio.ByteOrder; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - /** * A class that models the debug info in an organization that facilitates generation of the required * DWARF sections. It groups common data and behaviours for use by the various subclasses of class @@ -90,24 +92,19 @@ public class DwarfSections { public static final int DW_AT_hi_pc = 0x12; public static final int DW_AT_language = 0x13; public static final int DW_AT_external = 0x3f; - @SuppressWarnings("unused") - public static final int DW_AT_return_addr = 0x2a; - @SuppressWarnings("unused") - public static final int DW_AT_frame_base = 0x40; + @SuppressWarnings("unused") public static final int DW_AT_return_addr = 0x2a; + @SuppressWarnings("unused") public static final int DW_AT_frame_base = 0x40; /* * define all the Dwarf attribute forms we need for our DIEs */ public static final int DW_FORM_null = 0x0; - @SuppressWarnings("unused") - private static final int DW_FORM_string = 0x8; + @SuppressWarnings("unused") private static final int DW_FORM_string = 0x8; public static final int DW_FORM_strp = 0xe; public static final int DW_FORM_addr = 0x1; public static final int DW_FORM_data1 = 0x0b; public static final int DW_FORM_data4 = 0x6; - @SuppressWarnings("unused") - public static final int DW_FORM_data8 = 0x7; - @SuppressWarnings("unused") - public static final int DW_FORM_block1 = 0x0a; + @SuppressWarnings("unused") public static final int DW_FORM_data8 = 0x7; + @SuppressWarnings("unused") public static final int DW_FORM_block1 = 0x0a; public static final int DW_FORM_flag = 0xc; /* @@ -121,8 +118,7 @@ public class DwarfSections { /* * DW_FORM_flag attribute values */ - @SuppressWarnings("unused") - public static final byte DW_FLAG_false = 0; + @SuppressWarnings("unused") public static final byte DW_FLAG_false = 0; public static final byte DW_FLAG_true = 1; /* * value for DW_AT_language attribute with form DATA1 @@ -134,21 +130,16 @@ public class DwarfSections { * * not needed until we make functions members */ - @SuppressWarnings("unused") - public static final byte DW_ACCESS_public = 1; - @SuppressWarnings("unused") - public static final byte DW_ACCESS_protected = 2; - @SuppressWarnings("unused") - public static final byte DW_ACCESS_private = 3; + @SuppressWarnings("unused") public static final byte DW_ACCESS_public = 1; + @SuppressWarnings("unused") public static final byte DW_ACCESS_protected = 2; + @SuppressWarnings("unused") public static final byte DW_ACCESS_private = 3; /* * others not yet needed */ - @SuppressWarnings("unused") - public static final int DW_AT_type = 0; // only present for non-void + @SuppressWarnings("unused") public static final int DW_AT_type = 0; // only present for non-void // functions - @SuppressWarnings("unused") - public static final int DW_AT_accessibility = 0; + @SuppressWarnings("unused") public static final int DW_AT_accessibility = 0; /* * CIE and FDE entries @@ -156,36 +147,28 @@ public class DwarfSections { /* full byte/word values */ public static final int DW_CFA_CIE_id = -1; - @SuppressWarnings("unused") - public static final int DW_CFA_FDE_id = 0; + @SuppressWarnings("unused") public static final int DW_CFA_FDE_id = 0; public static final byte DW_CFA_CIE_version = 1; /* values encoded in high 2 bits */ public static final byte DW_CFA_advance_loc = 0x1; public static final byte DW_CFA_offset = 0x2; - @SuppressWarnings("unused") - public static final byte DW_CFA_restore = 0x3; + @SuppressWarnings("unused") public static final byte DW_CFA_restore = 0x3; /* values encoded in low 6 bits */ public static final byte DW_CFA_nop = 0x0; - @SuppressWarnings("unused") - public static final byte DW_CFA_set_loc1 = 0x1; + @SuppressWarnings("unused") public static final byte DW_CFA_set_loc1 = 0x1; public static final byte DW_CFA_advance_loc1 = 0x2; public static final byte DW_CFA_advance_loc2 = 0x3; public static final byte DW_CFA_advance_loc4 = 0x4; - @SuppressWarnings("unused") - public static final byte DW_CFA_offset_extended = 0x5; - @SuppressWarnings("unused") - public static final byte DW_CFA_restore_extended = 0x6; - @SuppressWarnings("unused") - public static final byte DW_CFA_undefined = 0x7; - @SuppressWarnings("unused") - public static final byte DW_CFA_same_value = 0x8; + @SuppressWarnings("unused") public static final byte DW_CFA_offset_extended = 0x5; + @SuppressWarnings("unused") public static final byte DW_CFA_restore_extended = 0x6; + @SuppressWarnings("unused") public static final byte DW_CFA_undefined = 0x7; + @SuppressWarnings("unused") public static final byte DW_CFA_same_value = 0x8; public static final byte DW_CFA_register = 0x9; public static final byte DW_CFA_def_cfa = 0xc; - @SuppressWarnings("unused") - public static final byte DW_CFA_def_cfa_register = 0xd; + @SuppressWarnings("unused") public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; private ByteOrder byteOrder; @@ -326,6 +309,7 @@ public int debugStringIndex(String string) { * * @param debugInfoProvider provider instance passed by ObjectFile client */ + @SuppressWarnings("try") public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); for @@ -337,7 +321,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ uniqueDebugString(""); - debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> { + debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> debugCodeInfo.debugContext((debugContext) -> { /* * primary file name and full method name need to be written to the debug_str section */ @@ -351,7 +335,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int lo = debugCodeInfo.addressLo(); int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); + Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); + debugContext.log("PrimaryRange %s %s.%s", fileName, className, methodName); /* * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, * returnTypeName, className, methodName, paramNames, fileName); create an infoSection @@ -373,8 +359,11 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); + try (DebugContext.Scope s = debugContext.scope("Subranges")) { + debugContext.log("SubRange %s %s %s.%s", fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine); + } }); - }); + })); /* * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); for * (DebugDataInfo debugDataInfo : dataInfoProvider) { install details of heap elements diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index 72348a508aee..d7455163669a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.hosted.image; -import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND; -import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.CONTRACT; import static com.oracle.svm.core.SubstrateUtil.mangleName; import static com.oracle.svm.core.util.VMError.shouldNotReachHere; @@ -46,28 +44,18 @@ import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; -import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; -import com.oracle.svm.core.option.HostedOptionValues; -import com.oracle.svm.hosted.image.sources.SourceManager; -import com.oracle.svm.hosted.meta.HostedType; -import jdk.vm.ci.code.site.Mark; -import jdk.vm.ci.meta.LineNumberTable; import org.graalvm.collections.Pair; import org.graalvm.compiler.code.CompilationResult; -import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; -import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.serviceprovider.BufferUtil; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; @@ -79,15 +67,12 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; -import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugCodeInfo; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugLineInfo; import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.ObjectFile.ProgbitsSectionImpl; import com.oracle.objectfile.ObjectFile.RelocationKind; import com.oracle.objectfile.ObjectFile.Section; import com.oracle.objectfile.SectionName; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.macho.MachOObjectFile; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.Isolates; @@ -108,6 +93,7 @@ import com.oracle.svm.core.image.ImageHeapLayouter; import com.oracle.svm.core.image.ImageHeapPartition; import com.oracle.svm.core.meta.SubstrateObjectConstant; +import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.UserError; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.c.CGlobalDataFeature; @@ -120,6 +106,7 @@ import com.oracle.svm.hosted.code.CEntryPointData; import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.image.RelocatableBuffer.Info; +import com.oracle.svm.hosted.image.sources.SourceManager; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; @@ -476,7 +463,7 @@ public void build(DebugContext debug, ImageHeapLayouter layouter) { // give the object file a chance to install it if (SubstrateOptions.GenerateDebugInfo.getValue(HostedOptionValues.singleton()) > 0) { ImageSingletons.add(SourceManager.class, new SourceManager()); - DebugInfoProvider provider = new NativeImageDebugInfoProvider(codeCache, heap); + DebugInfoProvider provider = new NativeImageDebugInfoProvider(debug, codeCache, heap); objectFile.installDebugInfo(provider); } // - Write the heap, either to its own section, or to the ro and rw data sections. @@ -973,255 +960,4 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final ObjectFile objectFile; protected final NativeImageCodeCache codeCache; } - - /** - * implementation of the DebugInfoProvider API interface that allows type, code and heap data - * info to be passed to an ObjectFile when generation of debug info is enabled. - */ - private class NativeImageDebugInfoProvider implements DebugInfoProvider { - private final NativeImageCodeCache codeCache; - @SuppressWarnings("unused") - private final NativeImageHeap heap; - - NativeImageDebugInfoProvider(NativeImageCodeCache codeCache, NativeImageHeap heap) { - super(); - this.codeCache = codeCache; - this.heap = heap; - } - - @Override - public Stream typeInfoProvider() { - return Stream.empty(); - } - - @Override - public Stream codeInfoProvider() { - return codeCache.compilations.entrySet().stream().map(entry -> new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue())); - } - - @Override - public Stream dataInfoProvider() { - return Stream.empty(); - } - } - - /** - * implementation of the DebugCodeInfo API interface that allows code info to be passed to an - * ObjectFile when generation of debug info is enabled. - */ - private class NativeImageDebugCodeInfo implements DebugCodeInfo { - private final HostedMethod method; - private final ResolvedJavaType javaType; - private final CompilationResult compilation; - private Path fullFilePath; - - NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { - this.method = method; - HostedType declaringClass = method.getDeclaringClass(); - Class clazz = declaringClass.getJavaClass(); - this.javaType = declaringClass.getWrapped(); - this.compilation = compilation; - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(javaType, clazz); - } - - @Override - public String fileName() { - if (fullFilePath != null) { - return fullFilePath.getFileName().toString(); - } - return null; - } - - @Override - public Path filePath() { - if (fullFilePath != null) { - return fullFilePath.getParent(); - } - return null; - } - - @Override - public String className() { - return javaType.toClassName(); - } - - @Override - public String methodName() { - return method.format("%n"); - } - - @Override - public String paramNames() { - return method.format("%P"); - } - - @Override - public String returnTypeName() { - return method.format("%R"); - } - - @Override - public int addressLo() { - return method.getCodeAddressOffset(); - } - - @Override - public int addressHi() { - return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); - } - - @Override - public int line() { - LineNumberTable lineNumberTable = method.getLineNumberTable(); - if (lineNumberTable != null) { - return lineNumberTable.getLineNumber(0); - } - return -1; - } - - @Override - public Stream lineInfoProvider() { - if (fileName().toString().length() == 0) { - return Stream.empty(); - } - return compilation.getSourceMappings().stream().map(sourceMapping -> new NativeImageDebugLineInfo(sourceMapping)); - } - - @Override - public int getFrameSize() { - return compilation.getTotalFrameSize(); - } - - @Override - public List getFrameSizeChanges() { - List frameSizeChanges = new LinkedList<>(); - for (Mark mark : compilation.getMarks()) { - // we only need to observe stack increment or decrement points - if (mark.id.equals("PROLOGUE_DECD_RSP")) { - NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); - frameSizeChanges.add(sizeChange); - // } else if (mark.id.equals("PROLOGUE_END")) { - // can ignore these - // } else if (mark.id.equals("EPILOGUE_START")) { - // can ignore these - } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { - NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); - frameSizeChanges.add(sizeChange); - // } else if(mark.id.equals("EPILOGUE_END")) { - } - } - return frameSizeChanges; - } - } - - /** - * implementation of the DebugLineInfo API interface that allows line number info to be passed - * to an ObjectFile when generation of debug info is enabled. - */ - private class NativeImageDebugLineInfo implements DebugLineInfo { - private final int bci; - private final ResolvedJavaMethod method; - private final int lo; - private final int hi; - private Path fullFilePath; - - NativeImageDebugLineInfo(SourceMapping sourceMapping) { - NodeSourcePosition position = sourceMapping.getSourcePosition(); - int posbci = position.getBCI(); - this.bci = (posbci >= 0 ? posbci : 0); - this.method = position.getMethod(); - this.lo = sourceMapping.getStartOffset(); - this.hi = sourceMapping.getEndOffset(); - computeFullFilePath(); - } - - @Override - public String fileName() { - if (fullFilePath != null) { - return fullFilePath.getFileName().toString(); - } - return null; - } - - @Override - public Path filePath() { - if (fullFilePath != null) { - return fullFilePath.getParent(); - } - return null; - } - - @Override - public String className() { - return method.format("%H"); - } - - @Override - public String methodName() { - return method.format("%n"); - } - - @Override - public int addressLo() { - return lo; - } - - @Override - public int addressHi() { - return hi; - } - - @Override - public int line() { - LineNumberTable lineNumberTable = method.getLineNumberTable(); - if (lineNumberTable != null) { - return lineNumberTable.getLineNumber(bci); - } - return -1; - } - - private void computeFullFilePath() { - ResolvedJavaType declaringClass = method.getDeclaringClass(); - Class clazz = null; - if (declaringClass instanceof OriginalClassProvider) { - clazz = ((OriginalClassProvider) declaringClass).getJavaClass(); - } - /* - * HostedType and AnalysisType punt calls to getSourceFilename to the wrapped class so - * for consistency we need to do the path lookup relative to the wrapped class - */ - if (declaringClass instanceof HostedType) { - declaringClass = ((HostedType) declaringClass).getWrapped(); - } - if (declaringClass instanceof AnalysisType) { - declaringClass = ((AnalysisType) declaringClass).getWrapped(); - } - fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass, clazz); - } - - } - - /** - * implementation of the DebugFrameSizeChange API interface that allows stack frame size change - * info to be passed to an ObjectFile when generation of debug info is enabled. - */ - private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { - private int offset; - private Type type; - - NativeImageDebugFrameSizeChange(int offset, Type type) { - this.offset = offset; - this.type = type; - } - - @Override - public int getOffset() { - return offset; - } - - @Override - public Type getType() { - return type; - } - } } 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 new file mode 100644 index 000000000000..1ab83f7dfb28 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java @@ -0,0 +1,290 @@ +package com.oracle.svm.hosted.image; + +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.CONTRACT; +import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.EXTEND; + +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.SourceMapping; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.nativeimage.ImageSingletons; + +import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; +import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import com.oracle.svm.hosted.image.sources.SourceManager; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedType; + +import jdk.vm.ci.code.site.Mark; +import jdk.vm.ci.meta.LineNumberTable; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Implementation of the DebugInfoProvider API interface that allows type, code and heap data info + * to be passed to an ObjectFile when generation of debug info is enabled. + */ +class NativeImageDebugInfoProvider implements DebugInfoProvider { + private final DebugContext debugContext; + private final NativeImageCodeCache codeCache; + @SuppressWarnings("unused") private final NativeImageHeap heap; + + NativeImageDebugInfoProvider(DebugContext debugContext, NativeImageCodeCache codeCache, NativeImageHeap heap) { + super(); + this.debugContext = debugContext; + this.codeCache = codeCache; + this.heap = heap; + } + + @Override + public Stream typeInfoProvider() { + return Stream.empty(); + } + + @Override + public Stream codeInfoProvider() { + return codeCache.compilations.entrySet().stream().map(entry -> new NativeImageDebugCodeInfo(entry.getKey(), entry.getValue())); + } + + @Override + public Stream dataInfoProvider() { + return Stream.empty(); + } + + /** + * implementation of the DebugCodeInfo API interface that allows code info to be passed to an + * ObjectFile when generation of debug info is enabled. + */ + private class NativeImageDebugCodeInfo implements DebugCodeInfo { + private final HostedMethod method; + private final ResolvedJavaType javaType; + private final CompilationResult compilation; + private Path fullFilePath; + + NativeImageDebugCodeInfo(HostedMethod method, CompilationResult compilation) { + this.method = method; + HostedType declaringClass = method.getDeclaringClass(); + Class clazz = declaringClass.getJavaClass(); + this.javaType = declaringClass.getWrapped(); + this.compilation = compilation; + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(javaType, clazz); + } + + @SuppressWarnings("try") + @Override + public void debugContext(Consumer action) { + try (DebugContext.Scope s = debugContext.scope("DebugCodeInfo", method)) { + action.accept(debugContext); + } catch (Throwable e) { + throw debugContext.handle(e); + } + } + + @Override + public String fileName() { + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return ""; + } + + @Override + public Path filePath() { + if (fullFilePath != null) { + return fullFilePath.getParent(); + } + return null; + } + + @Override + public String className() { + return javaType.toClassName(); + } + + @Override + public String methodName() { + return method.format("%n"); + } + + @Override + public String paramNames() { + return method.format("%P"); + } + + @Override + public String returnTypeName() { + return method.format("%R"); + } + + @Override + public int addressLo() { + return method.getCodeAddressOffset(); + } + + @Override + public int addressHi() { + return method.getCodeAddressOffset() + compilation.getTargetCodeSize(); + } + + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(0); + } + return -1; + } + + @Override + public Stream lineInfoProvider() { + if (fileName().length() == 0) { + return Stream.empty(); + } + return compilation.getSourceMappings().stream().map(sourceMapping -> new NativeImageDebugLineInfo(sourceMapping)); + } + + @Override + public int getFrameSize() { + return compilation.getTotalFrameSize(); + } + + @Override + public List getFrameSizeChanges() { + List frameSizeChanges = new LinkedList<>(); + for (Mark mark : compilation.getMarks()) { + // we only need to observe stack increment or decrement points + if (mark.id.equals("PROLOGUE_DECD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, EXTEND); + frameSizeChanges.add(sizeChange); + // } else if (mark.id.equals("PROLOGUE_END")) { + // can ignore these + // } else if (mark.id.equals("EPILOGUE_START")) { + // can ignore these + } else if (mark.id.equals("EPILOGUE_INCD_RSP")) { + NativeImageDebugFrameSizeChange sizeChange = new NativeImageDebugFrameSizeChange(mark.pcOffset, CONTRACT); + frameSizeChanges.add(sizeChange); + // } else if(mark.id.equals("EPILOGUE_END")) { + } + } + return frameSizeChanges; + } + } + + /** + * implementation of the DebugLineInfo API interface that allows line number info to be passed + * to an ObjectFile when generation of debug info is enabled. + */ + private class NativeImageDebugLineInfo implements DebugLineInfo { + private final int bci; + private final ResolvedJavaMethod method; + private final int lo; + private final int hi; + private Path fullFilePath; + + NativeImageDebugLineInfo(SourceMapping sourceMapping) { + NodeSourcePosition position = sourceMapping.getSourcePosition(); + int posbci = position.getBCI(); + this.bci = (posbci >= 0 ? posbci : 0); + this.method = position.getMethod(); + this.lo = sourceMapping.getStartOffset(); + this.hi = sourceMapping.getEndOffset(); + computeFullFilePath(); + } + + @Override + public String fileName() { + if (fullFilePath != null) { + return fullFilePath.getFileName().toString(); + } + return null; + } + + @Override + public Path filePath() { + if (fullFilePath != null) { + return fullFilePath.getParent(); + } + return null; + } + + @Override + public String className() { + return method.format("%H"); + } + + @Override + public String methodName() { + return method.format("%n"); + } + + @Override + public int addressLo() { + return lo; + } + + @Override + public int addressHi() { + return hi; + } + + @Override + public int line() { + LineNumberTable lineNumberTable = method.getLineNumberTable(); + if (lineNumberTable != null) { + return lineNumberTable.getLineNumber(bci); + } + return -1; + } + + private void computeFullFilePath() { + ResolvedJavaType declaringClass = method.getDeclaringClass(); + Class clazz = null; + if (declaringClass instanceof OriginalClassProvider) { + clazz = ((OriginalClassProvider) declaringClass).getJavaClass(); + } + /* + * HostedType and AnalysisType punt calls to getSourceFilename to the wrapped class so + * for consistency we need to do the path lookup relative to the wrapped class + */ + if (declaringClass instanceof HostedType) { + declaringClass = ((HostedType) declaringClass).getWrapped(); + } + if (declaringClass instanceof AnalysisType) { + declaringClass = ((AnalysisType) declaringClass).getWrapped(); + } + fullFilePath = ImageSingletons.lookup(SourceManager.class).findAndCacheSource(declaringClass, clazz); + } + + } + + /** + * implementation of the DebugFrameSizeChange API interface that allows stack frame size change + * info to be passed to an ObjectFile when generation of debug info is enabled. + */ + private class NativeImageDebugFrameSizeChange implements DebugFrameSizeChange { + private int offset; + private Type type; + + NativeImageDebugFrameSizeChange(int offset, Type type) { + this.offset = offset; + this.type = type; + } + + @Override + public int getOffset() { + return offset; + } + + @Override + public Type getType() { + return type; + } + } +} From 3aa6840c782e4a188ebcf67e72d65f474cddc0cc Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Tue, 17 Mar 2020 14:50:56 +0000 Subject: [PATCH 101/130] support tracing of DWARF debug info modelling and generation to file using a debugContext provided via either the DebugInfoProvider API or via the ObjectFile --- .../src/com/oracle/objectfile/ObjectFile.java | 49 ++++++ .../elf/dwarf/DwarfARangesSectionImpl.java | 18 +-- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 22 ++- .../elf/dwarf/DwarfFrameSectionImpl.java | 10 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 52 +++--- .../elf/dwarf/DwarfLineSectionImpl.java | 151 +++++++++--------- .../elf/dwarf/DwarfSectionImpl.java | 35 ++-- .../objectfile/elf/dwarf/DwarfSections.java | 78 +++++---- .../elf/dwarf/DwarfStrSectionImpl.java | 10 +- .../svm/hosted/image/NativeBootImage.java | 8 +- .../hosted/image/NativeBootImageViaCC.java | 2 +- 11 files changed, 247 insertions(+), 188 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 386978567ebf..c21e161625af 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -43,6 +43,8 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.StreamSupport; import com.oracle.objectfile.debuginfo.DebugInfoProvider; @@ -51,6 +53,8 @@ import com.oracle.objectfile.pecoff.PECoffObjectFile; import sun.nio.ch.DirectBuffer; +import org.graalvm.compiler.debug.DebugContext; +import sun.misc.Unsafe; /** * Abstract superclass for object files. An object file is a binary container for sections, @@ -1737,4 +1741,49 @@ public final SymbolTable getOrCreateSymbolTable() { return createSymbolTable(); } } + + /** + * Temporary storage for a debug context installed in a nested scope under a call. + * to {@link #withDebugContext} + */ + private DebugContext debugContext = null; + + /** + * Allows a function to be executed with a specific debug context in a named subscope bound to + * the object file and accessible to code invoked during the lifetime of the function. Invoked + * code may obtain access to the debug context using method {@link #debugContext}. + * @param context a context to be bound toin the object file for the duration of the function + * execution. + * @param scopeName a name to be used to define a subscope current while the function is being + * executed. + * @param t a value to be injected into the function that performs the action. + * @param function a function to be executed while the context is bound to the object file. + */ + @SuppressWarnings("try") + public R withDebugContext(DebugContext context, String scopeName, T t, Function function) { + try (DebugContext.Scope s = context.scope(scopeName)) { + this.debugContext = context; + return function.apply(t); + } catch (Throwable e) { + throw debugContext.handle(e); + } finally { + debugContext = null; + } + } + + /** + * Allows a consumer to retrieve the debug context currently bound to this object file. This method + * must only called underneath an invocation of method {@link #withDebugContext}. + * @param scopeName a name to be used to define a subscope current while the consumer is active. + * @param action an action parameterised by the debug context. + */ + @SuppressWarnings("try") + public void debugContext(String scopeName, Consumer action) { + assert debugContext != null; + try (DebugContext.Scope s = debugContext.scope(scopeName)) { + action.accept(debugContext); + } catch (Throwable e) { + throw debugContext.handle(e); + } + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index e2bcb27740f7..81451823b808 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -32,6 +32,7 @@ import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import org.graalvm.compiler.debug.DebugContext; import java.util.LinkedList; import java.util.Map; @@ -127,14 +128,14 @@ public byte[] getOrDecideContent(Map alre } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); - debug(" [0x%08x] DEBUG_ARANGES\n", pos); + log(context, " [0x%08x] DEBUG_ARANGES", pos); for (ClassEntry classEntry : getPrimaryClasses()) { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; @@ -145,7 +146,7 @@ public void writeContent() { */ length += classPrimaryEntries.size() * 2 * 8; length += 2 * 8; - debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); + log(context, " [0x%08x] %s CU %d length 0x%x", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); /* dwarf version is always 2 */ pos = putShort(DW_VERSION_2, buffer, pos); @@ -161,10 +162,10 @@ public void writeContent() { for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { pos = putByte((byte) 0, buffer, pos); } - debug(" [0x%08x] Address Length Name\n", pos); + log(context, " [0x%08x] Address Length Name", pos); for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { Range primary = classPrimaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); + log(context, " [0x%08x] %016x %016x %s", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); } @@ -175,11 +176,6 @@ public void writeContent() { assert pos == size; } - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /* * debug_aranges section content depends on debug_info section content and offset */ 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 b3cc40de399b..854d3c0e399b 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 @@ -27,6 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import org.graalvm.compiler.debug.DebugContext; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_compile_unit; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_subprogram; @@ -135,23 +136,23 @@ public void createContent() { *
      */ - pos = writeAbbrev1(null, pos); - pos = writeAbbrev2(null, pos); + pos = writeAbbrev1(null, null, pos); + pos = writeAbbrev2(null, null, pos); byte[] buffer = new byte[pos]; super.setContent(buffer); } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); - pos = writeAbbrev1(buffer, pos); - pos = writeAbbrev2(buffer, pos); + pos = writeAbbrev1(context, buffer, pos); + pos = writeAbbrev2(context, buffer, pos); assert pos == size; } @@ -171,7 +172,7 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { } } - public int writeAbbrev1(byte[] buffer, int p) { + public int writeAbbrev1(DebugContext context, byte[] buffer, int p) { int pos = p; /* * abbrev 1 compile unit @@ -197,7 +198,7 @@ public int writeAbbrev1(byte[] buffer, int p) { return pos; } - public int writeAbbrev2(byte[] buffer, int p) { + public int writeAbbrev2(DebugContext context, byte[] buffer, int p) { int pos = p; /* * abbrev 2 compile unit @@ -221,11 +222,6 @@ public int writeAbbrev2(byte[] buffer, int p) { return pos; } - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /** * debug_abbrev section content depends on debug_frame section content and offset. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index a7abe33f8034..1865ee29c5ec 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -30,6 +30,7 @@ import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import org.graalvm.compiler.debug.DebugContext; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_id; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_version; @@ -74,12 +75,12 @@ public void createContent() { } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); /* * there are entries for the prologue region where the stack is being built, the method body @@ -363,11 +364,6 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { public abstract int writeInitialInstructions(byte[] buffer, int pos); - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /** * debug_frame section content depends on debug_line section content and offset. */ 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 f13c5c3e1701..a3c5e6eac356 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 @@ -30,6 +30,7 @@ import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import org.graalvm.compiler.debug.DebugContext; import java.util.LinkedList; @@ -118,7 +119,7 @@ public void createContent() { int lengthPos = pos; pos = writeCUHeader(buffer, pos); assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); + pos = writeCU(null, classEntry, buffer, pos); /* * no need to backpatch length at lengthPos */ @@ -128,15 +129,15 @@ public void createContent() { } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); - debug(" [0x%08x] DEBUG_INFO\n", pos); - debug(" [0x%08x] size = 0x%08x\n", pos, size); + log(context, " [0x%08x] DEBUG_INFO", pos); + log(context, " [0x%08x] size = 0x%08x", pos, size); for (ClassEntry classEntry : getPrimaryClasses()) { /* * save the offset of this file's CU so it can be used when writing the aranges section @@ -144,9 +145,9 @@ public void writeContent() { classEntry.setCUIndex(pos); int lengthPos = pos; pos = writeCUHeader(buffer, pos); - debug(" [0x%08x] Compilation Unit\n", pos, size); + log(context, " [0x%08x] Compilation Unit", pos, size); assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); + pos = writeCU(context, classEntry, buffer, pos); /* * backpatch length at lengthPos (excluding length field) */ @@ -178,23 +179,23 @@ public int writeCUHeader(byte[] buffer, int p) { } } - public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { + public int writeCU(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); + log(context, " [0x%08x] <0> Abbrev Number %d", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); - debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); + log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); pos = writeAttrData1(DW_LANG_Java, buffer, pos); - debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); + log(context, " [0x%08x] lo_pc 0x%08x", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); - debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); + log(context, " [0x%08x] hi_pc 0x%08x", pos, classPrimaryEntries.getLast().getPrimary().getHi()); pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); - debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); + log(context, " [0x%08x] stmt_list 0x%08x", pos, classEntry.getLineIndex()); pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); for (PrimaryEntry primaryEntry : classPrimaryEntries) { - pos = writePrimary(primaryEntry, buffer, pos); + pos = writePrimary(context, primaryEntry, buffer, pos); } /* * write a terminating null attribute for the the level 2 primaries @@ -203,21 +204,21 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { + public int writePrimary(DebugContext context, PrimaryEntry primaryEntry, byte[] buffer, int p) { int pos = p; Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); + verboseLog(context, " [0x%08x] <1> Abbrev Number %d", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); + verboseLog(context, " [0x%08x] name 0x%X (%s)", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); + verboseLog(context, " [0x%08x] lo_pc 0x%08x", pos, primary.getLo()); pos = writeAttrAddress(primary.getLo(), buffer, pos); - debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); + verboseLog(context, " [0x%08x] hi_pc 0x%08x", pos, primary.getHi()); pos = writeAttrAddress(primary.getHi(), buffer, pos); /* * need to pass true only if method is public */ - debug(" [0x%08x] external true\n", pos); + verboseLog(context, " [0x%08x] external true", pos); return writeFlag(DW_FLAG_true, buffer, pos); } @@ -240,15 +241,6 @@ public int writeAttrString(String value, byte[] buffer, int p) { } } - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - /** * debug_info section content depends on abbrev section content and offset. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 0dc635f2ad65..fb0ed89affae 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -34,6 +34,7 @@ import com.oracle.objectfile.debugentry.FileEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import org.graalvm.compiler.debug.DebugContext; import java.util.Map; @@ -257,7 +258,7 @@ public int computeLineNUmberTableSize(ClassEntry classEntry) { * sigh -- we have to do this by generating the content even though we cannot write it into * a byte[] */ - return writeLineNumberTable(classEntry, null, 0); + return writeLineNumberTable(null, classEntry, null, 0); } @Override @@ -278,30 +279,30 @@ public byte[] getOrDecideContent(Map alre } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int pos = 0; - checkDebug(pos); - debug(" [0x%08x] DEBUG_LINE\n", pos); + enableLog(context, pos); + log(context, " [0x%08x] DEBUG_LINE", pos); for (ClassEntry classEntry : getPrimaryClasses()) { if (classEntry.getFileName().length() != 0) { int startPos = pos; assert classEntry.getLineIndex() == startPos; - debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + log(context, " [0x%08x] Compile Unit for %s", pos, classEntry.getFileName()); pos = writeHeader(classEntry, buffer, pos); - debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + log(context, " [0x%08x] headerSize = 0x%08x", pos, pos - startPos); int dirTablePos = pos; - pos = writeDirTable(classEntry, buffer, pos); - debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + pos = writeDirTable(context, classEntry, buffer, pos); + log(context, " [0x%08x] dirTableSize = 0x%08x", pos, pos - dirTablePos); int fileTablePos = pos; - pos = writeFileTable(classEntry, buffer, pos); - debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + pos = writeFileTable(context, classEntry, buffer, pos); + log(context, " [0x%08x] fileTableSize = 0x%08x", pos, pos - fileTablePos); int lineNumberTablePos = pos; - pos = writeLineNumberTable(classEntry, buffer, pos); - debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); - debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + pos = writeLineNumberTable(context, classEntry, buffer, pos); + log(context, " [0x%08x] lineNumberTableSize = 0x%x", pos, pos - lineNumberTablePos); + log(context, " [0x%08x] size = 0x%x", pos, pos - startPos); } } assert pos == buffer.length; @@ -372,9 +373,9 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { return pos; } - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { + public int writeDirTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - debug(" [0x%08x] Dir Name\n", pos); + verboseLog(context, " [0x%08x] Dir Name", pos); /* * write out the list of dirs referenced form this file entry */ @@ -383,7 +384,7 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { /* * write nul terminated string text. */ - debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); + verboseLog(context, " [0x%08x] %-4d %s", pos, dirIdx, dir.getPath()); pos = putAsciiStringBytes(dir.getPathString(), buffer, pos); dirIdx++; } @@ -394,10 +395,10 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { return pos; } - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { + public int writeFileTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; int fileIdx = 1; - debug(" [0x%08x] Entry Dir Name\n", pos); + verboseLog(context, " [0x%08x] Entry Dir Name", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { /* * we need the file name minus path, the associated dir index, and 0 for time stamps @@ -405,7 +406,7 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { String baseName = localEntry.getFileName(); DirEntry dirEntry = localEntry.getDirEntry(); int dirIdx = classEntry.localDirsIdx(dirEntry); - debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); + verboseLog(context, " [0x%08x] %-5d %-5d %s", pos, fileIdx, dirIdx, baseName); pos = putAsciiStringBytes(baseName, buffer, pos); pos = putULEB(dirIdx, buffer, pos); pos = putULEB(0, buffer, pos); @@ -422,7 +423,7 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { public int debugLine = 1; public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { + public int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; FileEntry fileEntry = classEntry.getFileEntry(); if (fileEntry == null) { @@ -436,8 +437,8 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { String primaryFileName = classEntry.getFileName(); String file = primaryFileName; int fileIdx = 1; - debug(" [0x%08x] primary class %s\n", pos, primaryClassName); - debug(" [0x%08x] primary file %s\n", pos, primaryFileName); + log(context, " [0x%08x] primary class %s", pos, primaryClassName); + log(context, " [0x%08x] primary file %s", pos, primaryFileName); for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { Range primaryRange = primaryEntry.getPrimary(); assert primaryRange.getFileName().equals(primaryFileName); @@ -458,25 +459,25 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * set state for primary */ - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), - primaryRange.getLine()); + log(context, " [0x%08x] primary range [0x%08x, 0x%08x] %s:%d", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), + primaryRange.getLine()); /* * initialize and write a row for the start of the primary method */ - pos = putSetFile(file, fileIdx, buffer, pos); - pos = putSetBasicBlock(buffer, pos); + pos = writeSetFileOp(context, file, fileIdx, buffer, pos); + pos = writeSetBasicBlockOp(context, buffer, pos); /* * address is currently 0 */ - pos = putSetAddress(address, buffer, pos); + pos = writeSetAddressOp(context, address, buffer, pos); /* * state machine value of line is currently 1 increment to desired line */ if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); + pos = writeAdvanceLineOp(context, line - 1, buffer, pos); } - pos = putCopy(buffer, pos); + pos = writeCopyOp(context, buffer, pos); /* * now write a row for each subrange lo and hi @@ -493,7 +494,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); + log(context, " [0x%08x] sub range [0x%08x, 0x%08x] %s:%d", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); if (subLine < 0) { /* * no line info so stay at previous file:line @@ -501,7 +502,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { subLine = line; subfile = file; subFileIdx = fileIdx; - debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); + verboseLog(context, " [0x%08x] missing line info - staying put at %s:%d", pos, file, line); } /* * there is a temptation to append end sequence at here when the hiAddress lies @@ -516,7 +517,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * update the current file */ - pos = putSetFile(subfile, subFileIdx, buffer, pos); + pos = writeSetFileOp(context, subfile, subFileIdx, buffer, pos); file = subfile; fileIdx = subFileIdx; } @@ -531,7 +532,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { * ignore pointless write when addressDelta == lineDelta == 0 */ if (addressDelta != 0 || lineDelta != 0) { - pos = putSpecialOpcode(opcode, buffer, pos); + pos = writeSpecialOpcode(context, opcode, buffer, pos); } } else { /* @@ -539,7 +540,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { */ int remainder = isConstAddPC(addressDelta); if (remainder > 0) { - pos = putConstAddPC(buffer, pos); + pos = writeConstAddPCOp(context, buffer, pos); /* * the remaining address can be handled with a special opcode but what about * the line delta @@ -549,7 +550,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * address remainder and line now fit */ - pos = putSpecialOpcode(opcode, buffer, pos); + pos = writeSpecialOpcode(context, opcode, buffer, pos); } else { /* * ok, bump the line separately then use a special opcode for the @@ -557,15 +558,15 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { */ opcode = isSpecialOpcode(remainder, 0); assert opcode != DW_LNS_undefined; - pos = putAdvanceLine(lineDelta, buffer, pos); - pos = putSpecialOpcode(opcode, buffer, pos); + pos = writeAdvanceLineOp(context, lineDelta, buffer, pos); + pos = writeSpecialOpcode(context, opcode, buffer, pos); } } else { /* * increment line and pc separately */ if (lineDelta != 0) { - pos = putAdvanceLine(lineDelta, buffer, pos); + pos = writeAdvanceLineOp(context, lineDelta, buffer, pos); } /* * n.b. we might just have had an out of range line increment with a zero @@ -576,12 +577,12 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { * see if we can use a ushort for the increment */ if (isFixedAdvancePC(addressDelta)) { - pos = putFixedAdvancePC((short) addressDelta, buffer, pos); + pos = writeFixedAdvancePCOp(context, (short) addressDelta, buffer, pos); } else { - pos = putAdvancePC(addressDelta, buffer, pos); + pos = writeAdvancePCOp(context, addressDelta, buffer, pos); } } - pos = putCopy(buffer, pos); + pos = writeCopyOp(context, buffer, pos); } } /* @@ -598,37 +599,28 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * increment address before we write the end sequence */ - pos = putAdvancePC(addressDelta, buffer, pos); + pos = writeAdvancePCOp(context, addressDelta, buffer, pos); } - pos = putEndSequence(buffer, pos); + pos = writeEndSequenceOp(context, buffer, pos); } - debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); + log(context, " [0x%08x] primary file processed %s", pos, primaryFileName); return pos; } - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - - public int putCopy(byte[] buffer, int p) { + public int writeCopyOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_copy; int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { debugCopyCount++; - debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); + verboseLog(context, " [0x%08x] Copy %d", pos, debugCopyCount); return putByte(opcode, buffer, pos); } } - public int putAdvancePC(long uleb, byte[] buffer, int p) { + public int writeAdvancePCOp(DebugContext context, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_pc; int pos = p; if (buffer == null) { @@ -636,13 +628,13 @@ public int putAdvancePC(long uleb, byte[] buffer, int p) { return pos + putULEB(uleb, scratch, 0); } else { debugAddress += uleb; - debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); + verboseLog(context, " [0x%08x] Advance PC by %d to 0x%08x", pos, uleb, debugAddress); pos = putByte(opcode, buffer, pos); return putULEB(uleb, buffer, pos); } } - public int putAdvanceLine(long sleb, byte[] buffer, int p) { + public int writeAdvanceLineOp(DebugContext context, long sleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_line; int pos = p; if (buffer == null) { @@ -650,27 +642,27 @@ public int putAdvanceLine(long sleb, byte[] buffer, int p) { return pos + putSLEB(sleb, scratch, 0); } else { debugLine += sleb; - debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); + verboseLog(context, " [0x%08x] Advance Line by %d to %d", pos, sleb, debugLine); pos = putByte(opcode, buffer, pos); return putSLEB(sleb, buffer, pos); } } - public int putSetFile(String file, long uleb, byte[] buffer, int p) { + public int writeSetFileOp(DebugContext context, String file, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_file; int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { - debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); + verboseLog(context, " [0x%08x] Set File Name to entry %d in the File Name Table (%s)", pos, uleb, file); pos = putByte(opcode, buffer, pos); return putULEB(uleb, buffer, pos); } } @SuppressWarnings("unused") - public int putSetColumn(long uleb, byte[] buffer, int p) { + public int writeSetColumnOp(DebugContext context, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; int pos = p; if (buffer == null) { @@ -683,7 +675,7 @@ public int putSetColumn(long uleb, byte[] buffer, int p) { } @SuppressWarnings("unused") - public int putNegateStmt(byte[] buffer, int p) { + public int writeNegateStmtOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_negate_stmt; int pos = p; if (buffer == null) { @@ -693,18 +685,18 @@ public int putNegateStmt(byte[] buffer, int p) { } } - public int putSetBasicBlock(byte[] buffer, int p) { + public int writeSetBasicBlockOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { - debug(" [0x%08x] Set basic block\n", pos); + verboseLog(context, " [0x%08x] Set basic block", pos); return putByte(opcode, buffer, pos); } } - public int putConstAddPC(byte[] buffer, int p) { + public int writeConstAddPCOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_const_add_pc; int pos = p; if (buffer == null) { @@ -712,12 +704,12 @@ public int putConstAddPC(byte[] buffer, int p) { } else { int advance = opcodeAddress((byte) 255); debugAddress += advance; - debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); + verboseLog(context, " [0x%08x] Advance PC by constant %d to 0x%08x", pos, advance, debugAddress); return putByte(opcode, buffer, pos); } } - public int putFixedAdvancePC(short arg, byte[] buffer, int p) { + public int writeFixedAdvancePCOp(DebugContext context, short arg, byte[] buffer, int p) { byte opcode = DW_LNS_fixed_advance_pc; int pos = p; if (buffer == null) { @@ -725,13 +717,13 @@ public int putFixedAdvancePC(short arg, byte[] buffer, int p) { return pos + putShort(arg, scratch, 0); } else { debugAddress += arg; - debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); + verboseLog(context, " [0x%08x] Fixed advance Address by %d to 0x%08x", pos, arg, debugAddress); pos = putByte(opcode, buffer, pos); return putShort(arg, buffer, pos); } } - public int putEndSequence(byte[] buffer, int p) { + public int writeEndSequenceOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNE_end_sequence; int pos = p; if (buffer == null) { @@ -742,7 +734,7 @@ public int putEndSequence(byte[] buffer, int p) { pos = pos + putULEB(1, scratch, 0); return pos + putByte(opcode, scratch, 0); } else { - debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); + verboseLog(context, " [0x%08x] Extended opcode 1: End sequence", pos); debugAddress = debugTextBase; debugLine = 1; debugCopyCount = 0; @@ -755,7 +747,7 @@ public int putEndSequence(byte[] buffer, int p) { } } - public int putSetAddress(long arg, byte[] buffer, int p) { + public int writeSetAddressOp(DebugContext context, long arg, byte[] buffer, int p) { byte opcode = DW_LNE_set_address; int pos = p; if (buffer == null) { @@ -768,7 +760,7 @@ public int putSetAddress(long arg, byte[] buffer, int p) { return pos + putLong(arg, scratch, 0); } else { debugAddress = debugTextBase + (int) arg; - debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); + verboseLog(context, " [0x%08x] Extended opcode 2: Set Address to 0x%08x", pos, debugAddress); pos = putByte(DW_LNS_extended_prefix, buffer, pos); /* * insert extended insn byte count as ULEB @@ -779,7 +771,8 @@ public int putSetAddress(long arg, byte[] buffer, int p) { } } - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { + @SuppressWarnings("unused") + public int writeDefineFileOp(DebugContext context, String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; int pos = p; /* @@ -799,7 +792,7 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] pos += putULEB(insnBytes, scratch, 0); return pos + (int) insnBytes; } else { - debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); + verboseLog(context, " [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d", pos, file, uleb1, uleb2, uleb3); pos = putByte(DW_LNS_extended_prefix, buffer, pos); /* * insert insn length as uleb @@ -831,18 +824,18 @@ public static int opcodeLine(byte opcode) { return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { + public int writeSpecialOpcode(DebugContext context, byte opcode, byte[] buffer, int p) { int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { if (debug && opcode == 0) { - debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); + verboseLog(context, " [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d", debugAddress, debugLine); } debugAddress += opcodeAddress(opcode); debugLine += opcodeLine(opcode); - debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + verboseLog(context, " [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d", + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, 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 548ac07ab61a..ae5bf59b796d 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 @@ -33,6 +33,7 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.elf.ELFObjectFile; +import org.graalvm.compiler.debug.DebugContext; import java.nio.ByteOrder; import java.util.Map; @@ -70,7 +71,7 @@ public DwarfSectionImpl(DwarfSections dwarfSections) { * in most cases this task reruns the operations performed under createContent but this time * actually writing data to the target byte[]. */ - public abstract void writeContent(); + public abstract void writeContent(DebugContext debugContext); @Override public boolean isLoadable() { @@ -80,22 +81,32 @@ public boolean isLoadable() { return false; } - public void checkDebug(int pos) { + public String debugSectionLogName() { + return "DWARF_" + getSectionName().substring(1).toUpperCase(); + } + + public void enableLog(DebugContext context, int pos) { /* - * if the env var relevant to this element type is set then switch on debugging + * debug output is disabled during the first pass where we size the buffer. + * this is called to enable it during the second pass where the buffer gets written, + * but only if the scope is enabled. */ - String name = getSectionName(); - String envVarName = "DWARF_" + name.substring(1).toUpperCase(); - if (System.getenv(envVarName) != null) { + if (context.areScopesEnabled()) { debug = true; debugBase = pos; debugAddress = debugTextBase; } } - protected void debug(String format, Object... args) { + protected void log(DebugContext context, String format, Object... args) { + if (debug) { + context.logv(DebugContext.INFO_LEVEL, format, args); + } + } + + protected void verboseLog(DebugContext context, String format, Object... args) { if (debug) { - System.out.format(format, args); + context.logv(DebugContext.VERBOSE_LEVEL, format, args); } } @@ -336,9 +347,13 @@ public byte[] getOrDecideContent(Map alre createContent(); /* - * ensure content byte[] has been written before calling super method + * ensure content byte[] has been written before calling super method. + * + * we do this in a nested debug scope derived from the one set up under the object file write */ - writeContent(); + getOwner().debugContext(debugSectionLogName(), debugContext -> { + writeContent(debugContext); + }); return super.getOrDecideContent(alreadyDecided, contentHint); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 83c68b1d3919..7dd562a042de 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -92,19 +92,24 @@ public class DwarfSections { public static final int DW_AT_hi_pc = 0x12; public static final int DW_AT_language = 0x13; public static final int DW_AT_external = 0x3f; - @SuppressWarnings("unused") public static final int DW_AT_return_addr = 0x2a; - @SuppressWarnings("unused") public static final int DW_AT_frame_base = 0x40; + @SuppressWarnings("unused") + public static final int DW_AT_return_addr = 0x2a; + @SuppressWarnings("unused") + public static final int DW_AT_frame_base = 0x40; /* * define all the Dwarf attribute forms we need for our DIEs */ public static final int DW_FORM_null = 0x0; - @SuppressWarnings("unused") private static final int DW_FORM_string = 0x8; + @SuppressWarnings("unused") + private static final int DW_FORM_string = 0x8; public static final int DW_FORM_strp = 0xe; public static final int DW_FORM_addr = 0x1; public static final int DW_FORM_data1 = 0x0b; public static final int DW_FORM_data4 = 0x6; - @SuppressWarnings("unused") public static final int DW_FORM_data8 = 0x7; - @SuppressWarnings("unused") public static final int DW_FORM_block1 = 0x0a; + @SuppressWarnings("unused") + public static final int DW_FORM_data8 = 0x7; + @SuppressWarnings("unused") + public static final int DW_FORM_block1 = 0x0a; public static final int DW_FORM_flag = 0xc; /* @@ -118,7 +123,8 @@ public class DwarfSections { /* * DW_FORM_flag attribute values */ - @SuppressWarnings("unused") public static final byte DW_FLAG_false = 0; + @SuppressWarnings("unused") + public static final byte DW_FLAG_false = 0; public static final byte DW_FLAG_true = 1; /* * value for DW_AT_language attribute with form DATA1 @@ -130,16 +136,21 @@ public class DwarfSections { * * not needed until we make functions members */ - @SuppressWarnings("unused") public static final byte DW_ACCESS_public = 1; - @SuppressWarnings("unused") public static final byte DW_ACCESS_protected = 2; - @SuppressWarnings("unused") public static final byte DW_ACCESS_private = 3; + @SuppressWarnings("unused") + public static final byte DW_ACCESS_public = 1; + @SuppressWarnings("unused") + public static final byte DW_ACCESS_protected = 2; + @SuppressWarnings("unused") + public static final byte DW_ACCESS_private = 3; /* * others not yet needed */ - @SuppressWarnings("unused") public static final int DW_AT_type = 0; // only present for non-void - // functions - @SuppressWarnings("unused") public static final int DW_AT_accessibility = 0; + @SuppressWarnings("unused") + public static final int DW_AT_type = 0; // only present for non-void + // functions + @SuppressWarnings("unused") + public static final int DW_AT_accessibility = 0; /* * CIE and FDE entries @@ -147,28 +158,36 @@ public class DwarfSections { /* full byte/word values */ public static final int DW_CFA_CIE_id = -1; - @SuppressWarnings("unused") public static final int DW_CFA_FDE_id = 0; + @SuppressWarnings("unused") + public static final int DW_CFA_FDE_id = 0; public static final byte DW_CFA_CIE_version = 1; /* values encoded in high 2 bits */ public static final byte DW_CFA_advance_loc = 0x1; public static final byte DW_CFA_offset = 0x2; - @SuppressWarnings("unused") public static final byte DW_CFA_restore = 0x3; + @SuppressWarnings("unused") + public static final byte DW_CFA_restore = 0x3; /* values encoded in low 6 bits */ public static final byte DW_CFA_nop = 0x0; - @SuppressWarnings("unused") public static final byte DW_CFA_set_loc1 = 0x1; + @SuppressWarnings("unused") + public static final byte DW_CFA_set_loc1 = 0x1; public static final byte DW_CFA_advance_loc1 = 0x2; public static final byte DW_CFA_advance_loc2 = 0x3; public static final byte DW_CFA_advance_loc4 = 0x4; - @SuppressWarnings("unused") public static final byte DW_CFA_offset_extended = 0x5; - @SuppressWarnings("unused") public static final byte DW_CFA_restore_extended = 0x6; - @SuppressWarnings("unused") public static final byte DW_CFA_undefined = 0x7; - @SuppressWarnings("unused") public static final byte DW_CFA_same_value = 0x8; + @SuppressWarnings("unused") + public static final byte DW_CFA_offset_extended = 0x5; + @SuppressWarnings("unused") + public static final byte DW_CFA_restore_extended = 0x6; + @SuppressWarnings("unused") + public static final byte DW_CFA_undefined = 0x7; + @SuppressWarnings("unused") + public static final byte DW_CFA_same_value = 0x8; public static final byte DW_CFA_register = 0x9; public static final byte DW_CFA_def_cfa = 0xc; - @SuppressWarnings("unused") public static final byte DW_CFA_def_cfa_register = 0xd; + @SuppressWarnings("unused") + public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; private ByteOrder byteOrder; @@ -275,8 +294,9 @@ public DwarfLineSectionImpl getLineSectionImpl() { /** * indirects this call to the string table. - * + * * @param string the string to be inserted + * * @return a unique equivalent String */ public String uniqueString(String string) { @@ -286,8 +306,9 @@ public String uniqueString(String string) { /** * indirects this call to the string table, ensuring the table entry is marked for inclusion in * the debug_str section. - * + * * @param string the string to be inserted and marked for inclusion in the debug_str section + * * @return a unique equivalent String */ public String uniqueDebugString(String string) { @@ -296,8 +317,9 @@ public String uniqueDebugString(String string) { /** * indirects this call to the string table. - * + * * @param string the string whose index is required + * * @return the offset of the string in the .debug_str section */ public int debugStringIndex(String string) { @@ -306,7 +328,7 @@ public int debugStringIndex(String string) { /** * entry point allowing ELFObjectFile to pass on information about types, code and heap data. - * + * * @param debugInfoProvider provider instance passed by ObjectFile client */ @SuppressWarnings("try") @@ -337,9 +359,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int primaryLine = debugCodeInfo.line(); Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - debugContext.log("PrimaryRange %s %s.%s", fileName, className, methodName); + debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", className, methodName, filePath, fileName, primaryLine, lo, hi); /* - * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, + * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s", lo, hi, * returnTypeName, className, methodName, paramNames, fileName); create an infoSection * entry for the method */ @@ -360,7 +382,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); try (DebugContext.Scope s = debugContext.scope("Subranges")) { - debugContext.log("SubRange %s %s %s.%s", fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine); + debugContext.log(DebugContext.VERBOSE_LEVEL, "SubRange %s.%s %s %s:%d 0x%x, 0x%x]", classNameAtLine, methodNameAtLine, filePathAtLine, fileNameAtLine, line, loAtLine, hiAtLine); } }); })); @@ -408,7 +430,7 @@ public FileEntry ensureFileEntry(Range range) { * index the file entry by file path */ filesIndex.put(fileAsPath, fileEntry); - if (!range.isPrimary()) { + if(!range.isPrimary()) { /* check we have a file for the corresponding primary range */ Range primaryRange = range.getPrimary(); FileEntry primaryFileEntry = filesIndex.get(primaryRange.getFileAsPath()); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 845ab12ad8b2..5f08ed8dbc2b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -28,6 +28,7 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.debugentry.StringEntry; +import org.graalvm.compiler.debug.DebugContext; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; @@ -60,12 +61,12 @@ public void createContent() { } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); for (StringEntry stringEntry : dwarfSections.getStringTable()) { if (stringEntry.isAddToStrSection()) { @@ -77,11 +78,6 @@ public void writeContent() { assert pos == size; } - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /** * debug_str section content depends on text section content and offset. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index d7455163669a..f910ed54dee6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -164,14 +164,18 @@ public Section getTextSection() { @Override public abstract String[] makeLaunchCommand(NativeImageKind k, String imageName, Path binPath, Path workPath, java.lang.reflect.Method method); - protected final void write(Path outputFile) { + protected final void write(DebugContext context, Path outputFile) { try { Path outFileParent = outputFile.normalize().getParent(); if (outFileParent != null) { Files.createDirectories(outFileParent); } try (FileChannel channel = FileChannel.open(outputFile, StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { - objectFile.write(channel); + objectFile.withDebugContext(context, "ObjectFile.write", channel, c -> { + objectFile.write(c); + // doesn't actually matter what we return + return true; + }); } } catch (Exception ex) { throw shouldNotReachHere(ex); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImageViaCC.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImageViaCC.java index 5b540ed60333..7d7aa41e57df 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImageViaCC.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImageViaCC.java @@ -357,7 +357,7 @@ private static List diagnoseLinkerFailure(String linkerOutput) { public LinkerInvocation write(DebugContext debug, Path outputDirectory, Path tempDirectory, String imageName, BeforeImageWriteAccessImpl config) { try (Indent indent = debug.logAndIndent("Writing native image")) { // 1. write the relocatable file - write(tempDirectory.resolve(imageName + ObjectFile.getFilenameSuffix())); + write(debug, tempDirectory.resolve(imageName + ObjectFile.getFilenameSuffix())); if (NativeImageOptions.ExitAfterRelocatableImageWrite.getValue()) { return null; } From b8b1ccf2648b6b0241eefbde5bafa69379131802 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 10:04:15 +0000 Subject: [PATCH 102/130] modify suite to ensured ObjectFile can acess class DebugContext on jdk8 --- substratevm/mx.substratevm/suite.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index f7c8127f85e6..cd97d8988428 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -619,7 +619,9 @@ "com.oracle.objectfile" : { "subDir": "src", "sourceDirs" : ["src"], - "dependencies" : [], + "dependencies" : [ + "compiler:GRAAL" + ], "checkstyle" : "com.oracle.svm.hosted", "javaCompliance" : "8+", "annotationProcessors" : ["compiler:GRAAL_PROCESSOR"], @@ -936,7 +938,9 @@ "dependencies": [ "com.oracle.objectfile" ], - }, + "distDependencies": [ + "compiler:GRAAL", + ], }, "GRAAL_HOTSPOT_LIBRARY": { "subDir": "src", From 36caf2b173b91f32414d88ab0ad56c0d272b0a01 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 10:06:07 +0000 Subject: [PATCH 103/130] remove dud import pulled in at merge --- .../src/com/oracle/objectfile/ObjectFile.java | 1 - 1 file changed, 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index c21e161625af..0b1607f76f6f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -54,7 +54,6 @@ import sun.nio.ch.DirectBuffer; import org.graalvm.compiler.debug.DebugContext; -import sun.misc.Unsafe; /** * Abstract superclass for object files. An object file is a binary container for sections, From c6f6af7c319d09e435f5ae38a4d4d7960beed1d7 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 11:21:06 +0000 Subject: [PATCH 104/130] simplify withDebugContext to just use a Runnable --- .../src/com/oracle/objectfile/ObjectFile.java | 15 +++++++-------- .../oracle/svm/hosted/image/NativeBootImage.java | 6 ++---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 0b1607f76f6f..e5013c66b3ac 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1748,21 +1748,20 @@ public final SymbolTable getOrCreateSymbolTable() { private DebugContext debugContext = null; /** - * Allows a function to be executed with a specific debug context in a named subscope bound to - * the object file and accessible to code invoked during the lifetime of the function. Invoked + * Allows a task to be executed with a debug context in a named subscope bound to the + * object file and accessible to code executed during the lifetime of the task. Invoked * code may obtain access to the debug context using method {@link #debugContext}. - * @param context a context to be bound toin the object file for the duration of the function + * @param context a context to be bound to the object file for the duration of the task * execution. - * @param scopeName a name to be used to define a subscope current while the function is being + * @param scopeName a name to be used to define a subscope current while the task is being * executed. - * @param t a value to be injected into the function that performs the action. - * @param function a function to be executed while the context is bound to the object file. + * @param task a task to be executed while the context is bound to the object file. */ @SuppressWarnings("try") - public R withDebugContext(DebugContext context, String scopeName, T t, Function function) { + public void withDebugContext(DebugContext context, String scopeName, Runnable task) { try (DebugContext.Scope s = context.scope(scopeName)) { this.debugContext = context; - return function.apply(t); + task.run(); } catch (Throwable e) { throw debugContext.handle(e); } finally { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java index f910ed54dee6..e6eea7a0e541 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeBootImage.java @@ -171,10 +171,8 @@ protected final void write(DebugContext context, Path outputFile) { Files.createDirectories(outFileParent); } try (FileChannel channel = FileChannel.open(outputFile, StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { - objectFile.withDebugContext(context, "ObjectFile.write", channel, c -> { - objectFile.write(c); - // doesn't actually matter what we return - return true; + objectFile.withDebugContext(context, "ObjectFile.write", () -> { + objectFile.write(channel); }); } } catch (Exception ex) { From 05e8e89d871dea8e38bbd8e9a477f6ff4499cc34 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 11:58:34 +0000 Subject: [PATCH 105/130] use dwarf prefix plus section name to label context subscope when generating DwarfSection log messages --- .../com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 ae5bf59b796d..c600795f3fc0 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 @@ -82,7 +82,13 @@ public boolean isLoadable() { } public String debugSectionLogName() { - return "DWARF_" + getSectionName().substring(1).toUpperCase(); + /* + * Use prefix dwarf plus the section name (which already includes a dot separator) for the + * context key. For example messages for info section will be keyed using dwarf.debug_info. + * Other info formats use their own format-specific prefix. + */ + assert getSectionName().startsWith(".debug"); + return "dwarf." + getSectionName(); } public void enableLog(DebugContext context, int pos) { From 597acaa6ccecfd929f384a5de943745bf7a02bfc Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 12:00:30 +0000 Subject: [PATCH 106/130] Checkstyle adjustments for copyright header --- .../.checkstyle_checks.xml | 233 ++++++++++++++++++ .../.checkstyle_checks.xml | 4 +- 2 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 substratevm/src/com.oracle.objectfile/.checkstyle_checks.xml diff --git a/substratevm/src/com.oracle.objectfile/.checkstyle_checks.xml b/substratevm/src/com.oracle.objectfile/.checkstyle_checks.xml new file mode 100644 index 000000000000..788e1fa0b557 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/.checkstyle_checks.xml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/substratevm/src/com.oracle.svm.hosted/.checkstyle_checks.xml b/substratevm/src/com.oracle.svm.hosted/.checkstyle_checks.xml index 2ad8df2430cd..788e1fa0b557 100644 --- a/substratevm/src/com.oracle.svm.hosted/.checkstyle_checks.xml +++ b/substratevm/src/com.oracle.svm.hosted/.checkstyle_checks.xml @@ -208,8 +208,8 @@ - - + + From 536baf5fca1685afe4205fc2bca846568ab5043b Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 13:17:07 +0000 Subject: [PATCH 107/130] avoid repeated dot in scope name --- .../src/com/oracle/objectfile/elf/dwarf/DwarfSectionImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c600795f3fc0..4e04d1d92881 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 @@ -88,7 +88,7 @@ public String debugSectionLogName() { * Other info formats use their own format-specific prefix. */ assert getSectionName().startsWith(".debug"); - return "dwarf." + getSectionName(); + return "dwarf" + getSectionName(); } public void enableLog(DebugContext context, int pos) { From 233efff1437a50508cd4d312916fc6f46a0f96a3 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 16:31:27 +0000 Subject: [PATCH 108/130] fix checkstyle issues --- .../src/com/oracle/objectfile/ObjectFile.java | 1 - .../objectfile/debugentry/ClassEntry.java | 2 +- .../objectfile/debugentry/DirEntry.java | 2 +- .../objectfile/debugentry/FileEntry.java | 2 +- .../objectfile/debugentry/PrimaryEntry.java | 2 +- .../oracle/objectfile/debugentry/Range.java | 2 +- .../objectfile/debugentry/StringEntry.java | 2 +- .../objectfile/debugentry/StringTable.java | 2 +- .../objectfile/elf/dwarf/DwarfSections.java | 2 +- .../image/NativeImageDebugInfoProvider.java | 25 +++++++++++++++++++ .../image/sources/ApplicationSourceCache.java | 2 +- .../image/sources/GraalVMSourceCache.java | 1 - .../svm/hosted/image/sources/SourceCache.java | 14 +++++------ 13 files changed, 41 insertions(+), 18 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index e5013c66b3ac..c4406f5d13cb 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -44,7 +44,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.function.Consumer; -import java.util.function.Function; import java.util.stream.StreamSupport; import com.oracle.objectfile.debuginfo.DebugInfoProvider; 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 bb4917254b59..a4535472284f 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 @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index 019611539160..034653171103 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index 1aedf4dc879b..50764f2aa564 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index b0199d3c3f65..6f789f44fdc3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 191ec29b0532..c8760a5cc8d4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Red Hat, Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java index f8fe7445d8d2..ff754ad86444 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Red Hat, Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java index 9ea823ff00d4..d33a0104f18a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Red Hat, Inc. 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 diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 7dd562a042de..c198f9d75ce8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -430,7 +430,7 @@ public FileEntry ensureFileEntry(Range range) { * index the file entry by file path */ filesIndex.put(fileAsPath, fileEntry); - if(!range.isPrimary()) { + if (!range.isPrimary()) { /* check we have a file for the corresponding primary range */ Range primaryRange = range.getPrimary(); FileEntry primaryFileEntry = filesIndex.get(primaryRange.getFileAsPath()); 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 1ab83f7dfb28..b160732a528c 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 @@ -1,3 +1,28 @@ +/* + * 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.svm.hosted.image; import static com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange.Type.CONTRACT; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java index 2f6dd613ba45..6ab33bfe97b0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/ApplicationSourceCache.java @@ -112,4 +112,4 @@ private void trySourceRoot(String sourceRoot, boolean fromClassPath) { } } } -} \ No newline at end of file +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index 833166c2daff..5bedee921d67 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -26,7 +26,6 @@ package com.oracle.svm.hosted.image.sources; -import java.io.File; import java.io.IOException; import java.nio.file.FileSystem; import java.nio.file.FileSystemNotFoundException; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java index 0507702ea3a2..650d08d54287 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/SourceCache.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 @@ -55,16 +55,16 @@ public abstract class SourceCache { /** - * A list of all entries in the classpath used by the native image classloader + * A list of all entries in the classpath used by the native image classloader. */ protected static final List classPathEntries = new ArrayList<>(); /** - * A list of all entries in the classpath used by the native image classloader + * A list of all entries in the classpath used by the native image classloader. */ protected static final List sourcePathEntries = new ArrayList<>(); /** * A list of root directories which may contain source files from which this cache can be - * populated + * populated. */ protected List srcRoots; @@ -77,7 +77,7 @@ protected SourceCache() { } /** - * Identify the specific type of this source cache + * Identify the specific type of this source cache. * * @return the source cache type */ @@ -295,7 +295,7 @@ private static void ensureTargetDirs(Path targetDir) throws IOException { } /** - * Add a path to the list of classpath entries + * Add a path to the list of classpath entries. * * @param path The path to add. */ @@ -304,7 +304,7 @@ private static void addClassPathEntry(String path) { } /** - * Add a path to the list of source path entries + * Add a path to the list of source path entries. * * @param path The path to add. */ From 46b2fa74210823ff82a49870dd21ed4f03544289 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Fri, 20 Mar 2020 16:56:03 +0000 Subject: [PATCH 109/130] eclipse style check issues --- .../src/com/oracle/objectfile/ObjectFile.java | 22 ++++--- .../elf/dwarf/DwarfLineSectionImpl.java | 7 +-- .../elf/dwarf/DwarfSectionImpl.java | 9 +-- .../objectfile/elf/dwarf/DwarfSections.java | 62 ++++++------------- 4 files changed, 39 insertions(+), 61 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index c4406f5d13cb..c9dabe238e12 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -1741,23 +1741,24 @@ public final SymbolTable getOrCreateSymbolTable() { } /** - * Temporary storage for a debug context installed in a nested scope under a call. - * to {@link #withDebugContext} + * Temporary storage for a debug context installed in a nested scope under a call. to + * {@link #withDebugContext} */ private DebugContext debugContext = null; /** - * Allows a task to be executed with a debug context in a named subscope bound to the - * object file and accessible to code executed during the lifetime of the task. Invoked - * code may obtain access to the debug context using method {@link #debugContext}. + * Allows a task to be executed with a debug context in a named subscope bound to the object + * file and accessible to code executed during the lifetime of the task. Invoked code may obtain + * access to the debug context using method {@link #debugContext}. + * * @param context a context to be bound to the object file for the duration of the task - * execution. + * execution. * @param scopeName a name to be used to define a subscope current while the task is being - * executed. + * executed. * @param task a task to be executed while the context is bound to the object file. */ @SuppressWarnings("try") - public void withDebugContext(DebugContext context, String scopeName, Runnable task) { + public void withDebugContext(DebugContext context, String scopeName, Runnable task) { try (DebugContext.Scope s = context.scope(scopeName)) { this.debugContext = context; task.run(); @@ -1769,8 +1770,9 @@ public void withDebugContext(DebugContext context, String scopeName, Runnable t } /** - * Allows a consumer to retrieve the debug context currently bound to this object file. This method - * must only called underneath an invocation of method {@link #withDebugContext}. + * Allows a consumer to retrieve the debug context currently bound to this object file. This + * method must only called underneath an invocation of method {@link #withDebugContext}. + * * @param scopeName a name to be used to define a subscope current while the consumer is active. * @param action an action parameterised by the debug context. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index fb0ed89affae..d6e7c48717e5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -117,8 +117,7 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * there is no extended opcode 0 */ - @SuppressWarnings("unused") - private static final byte DW_LNE_undefined = 0; + @SuppressWarnings("unused") private static final byte DW_LNE_undefined = 0; /* * end sequence of addresses */ @@ -460,7 +459,7 @@ public int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byt * set state for primary */ log(context, " [0x%08x] primary range [0x%08x, 0x%08x] %s:%d", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), - primaryRange.getLine()); + primaryRange.getLine()); /* * initialize and write a row for the start of the primary method @@ -835,7 +834,7 @@ public int writeSpecialOpcode(DebugContext context, byte opcode, byte[] buffer, debugAddress += opcodeAddress(opcode); debugLine += opcodeLine(opcode); verboseLog(context, " [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, 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 4e04d1d92881..177b8643bc67 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 @@ -93,9 +93,9 @@ public String debugSectionLogName() { public void enableLog(DebugContext context, int pos) { /* - * debug output is disabled during the first pass where we size the buffer. - * this is called to enable it during the second pass where the buffer gets written, - * but only if the scope is enabled. + * debug output is disabled during the first pass where we size the buffer. this is called + * to enable it during the second pass where the buffer gets written, but only if the scope + * is enabled. */ if (context.areScopesEnabled()) { debug = true; @@ -355,7 +355,8 @@ public byte[] getOrDecideContent(Map alre /* * ensure content byte[] has been written before calling super method. * - * we do this in a nested debug scope derived from the one set up under the object file write + * we do this in a nested debug scope derived from the one set up under the object file + * write */ getOwner().debugContext(debugSectionLogName(), debugContext -> { writeContent(debugContext); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index c198f9d75ce8..2a8a6ca0c098 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -92,24 +92,19 @@ public class DwarfSections { public static final int DW_AT_hi_pc = 0x12; public static final int DW_AT_language = 0x13; public static final int DW_AT_external = 0x3f; - @SuppressWarnings("unused") - public static final int DW_AT_return_addr = 0x2a; - @SuppressWarnings("unused") - public static final int DW_AT_frame_base = 0x40; + @SuppressWarnings("unused") public static final int DW_AT_return_addr = 0x2a; + @SuppressWarnings("unused") public static final int DW_AT_frame_base = 0x40; /* * define all the Dwarf attribute forms we need for our DIEs */ public static final int DW_FORM_null = 0x0; - @SuppressWarnings("unused") - private static final int DW_FORM_string = 0x8; + @SuppressWarnings("unused") private static final int DW_FORM_string = 0x8; public static final int DW_FORM_strp = 0xe; public static final int DW_FORM_addr = 0x1; public static final int DW_FORM_data1 = 0x0b; public static final int DW_FORM_data4 = 0x6; - @SuppressWarnings("unused") - public static final int DW_FORM_data8 = 0x7; - @SuppressWarnings("unused") - public static final int DW_FORM_block1 = 0x0a; + @SuppressWarnings("unused") public static final int DW_FORM_data8 = 0x7; + @SuppressWarnings("unused") public static final int DW_FORM_block1 = 0x0a; public static final int DW_FORM_flag = 0xc; /* @@ -123,8 +118,7 @@ public class DwarfSections { /* * DW_FORM_flag attribute values */ - @SuppressWarnings("unused") - public static final byte DW_FLAG_false = 0; + @SuppressWarnings("unused") public static final byte DW_FLAG_false = 0; public static final byte DW_FLAG_true = 1; /* * value for DW_AT_language attribute with form DATA1 @@ -136,21 +130,16 @@ public class DwarfSections { * * not needed until we make functions members */ - @SuppressWarnings("unused") - public static final byte DW_ACCESS_public = 1; - @SuppressWarnings("unused") - public static final byte DW_ACCESS_protected = 2; - @SuppressWarnings("unused") - public static final byte DW_ACCESS_private = 3; + @SuppressWarnings("unused") public static final byte DW_ACCESS_public = 1; + @SuppressWarnings("unused") public static final byte DW_ACCESS_protected = 2; + @SuppressWarnings("unused") public static final byte DW_ACCESS_private = 3; /* * others not yet needed */ - @SuppressWarnings("unused") - public static final int DW_AT_type = 0; // only present for non-void + @SuppressWarnings("unused") public static final int DW_AT_type = 0; // only present for non-void // functions - @SuppressWarnings("unused") - public static final int DW_AT_accessibility = 0; + @SuppressWarnings("unused") public static final int DW_AT_accessibility = 0; /* * CIE and FDE entries @@ -158,36 +147,28 @@ public class DwarfSections { /* full byte/word values */ public static final int DW_CFA_CIE_id = -1; - @SuppressWarnings("unused") - public static final int DW_CFA_FDE_id = 0; + @SuppressWarnings("unused") public static final int DW_CFA_FDE_id = 0; public static final byte DW_CFA_CIE_version = 1; /* values encoded in high 2 bits */ public static final byte DW_CFA_advance_loc = 0x1; public static final byte DW_CFA_offset = 0x2; - @SuppressWarnings("unused") - public static final byte DW_CFA_restore = 0x3; + @SuppressWarnings("unused") public static final byte DW_CFA_restore = 0x3; /* values encoded in low 6 bits */ public static final byte DW_CFA_nop = 0x0; - @SuppressWarnings("unused") - public static final byte DW_CFA_set_loc1 = 0x1; + @SuppressWarnings("unused") public static final byte DW_CFA_set_loc1 = 0x1; public static final byte DW_CFA_advance_loc1 = 0x2; public static final byte DW_CFA_advance_loc2 = 0x3; public static final byte DW_CFA_advance_loc4 = 0x4; - @SuppressWarnings("unused") - public static final byte DW_CFA_offset_extended = 0x5; - @SuppressWarnings("unused") - public static final byte DW_CFA_restore_extended = 0x6; - @SuppressWarnings("unused") - public static final byte DW_CFA_undefined = 0x7; - @SuppressWarnings("unused") - public static final byte DW_CFA_same_value = 0x8; + @SuppressWarnings("unused") public static final byte DW_CFA_offset_extended = 0x5; + @SuppressWarnings("unused") public static final byte DW_CFA_restore_extended = 0x6; + @SuppressWarnings("unused") public static final byte DW_CFA_undefined = 0x7; + @SuppressWarnings("unused") public static final byte DW_CFA_same_value = 0x8; public static final byte DW_CFA_register = 0x9; public static final byte DW_CFA_def_cfa = 0xc; - @SuppressWarnings("unused") - public static final byte DW_CFA_def_cfa_register = 0xd; + @SuppressWarnings("unused") public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; private ByteOrder byteOrder; @@ -360,11 +341,6 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", className, methodName, filePath, fileName, primaryLine, lo, hi); - /* - * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s", lo, hi, - * returnTypeName, className, methodName, paramNames, fileName); create an infoSection - * entry for the method - */ addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); From e68a81a3f6e13efe6151775692de84541fba131a Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Mon, 23 Mar 2020 15:53:23 -0400 Subject: [PATCH 110/130] fix many travis-ci errors --- .../objectfile/elf/dwarf/DwarfSections.java | 4 +- .../objectfile/pecoff/PECoffObjectFile.java | 4 +- .../objectfile/pecoff/cv/CVFileRecord.java | 9 +- .../objectfile/pecoff/cv/CVLineRecord.java | 10 +- .../pecoff/cv/CVLineRecordBuilder.java | 44 ++++---- .../objectfile/pecoff/cv/CVSections.java | 4 +- .../pecoff/cv/CVStringTableRecord.java | 2 +- .../objectfile/pecoff/cv/CVSymbolRecord.java | 14 +-- .../pecoff/cv/CVSymbolRecordBuilder.java | 4 +- .../pecoff/cv/CVSymbolSubrecord.java | 90 ++++++++-------- .../pecoff/cv/CVSymbolSubsection.java | 8 +- .../objectfile/pecoff/cv/CVTypeRecord.java | 100 +++++++++--------- .../pecoff/cv/CVTypeSectionImpl.java | 2 +- .../oracle/objectfile/pecoff/cv/CVUtil.java | 6 +- .../objectfile/pecoff/cv/DebugInfoBase.java | 4 +- 15 files changed, 157 insertions(+), 148 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 6aa82609fa38..1aa225d5983d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -173,7 +173,7 @@ public class DwarfSections { // public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; - private ELFMachine elfMachine; + //private ELFMachine elfMachine; private ByteOrder byteOrder; private DwarfStrSectionImpl dwarfStrSection; private DwarfAbbrevSectionImpl dwarfAbbrevSection; @@ -183,7 +183,7 @@ public class DwarfSections { private DwarfFrameSectionImpl dwarfFameSection; public DwarfSections(ELFMachine elfMachine, ByteOrder byteOrder) { - this.elfMachine = elfMachine; + //this.elfMachine = elfMachine; this.byteOrder = byteOrder; dwarfStrSection = new DwarfStrSectionImpl(this); dwarfAbbrevSection = new DwarfAbbrevSectionImpl(this); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 3c33a33367a3..37f4887c9c98 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -708,8 +708,8 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { CVTypeSectionImpl cvTypeSectionImpl = cvSections.getCVTypeSection(); // now we can create the section elements with empty content - PECoffSection symbolSection = (PECoffSection) newDebugSection(cvSymbolSectionImpl.getSectionName(), cvSymbolSectionImpl); - PECoffSection typeSection = (PECoffSection) newDebugSection(cvTypeSectionImpl.getSectionName(), cvTypeSectionImpl); + newDebugSection(cvSymbolSectionImpl.getSectionName(), cvSymbolSectionImpl); + newDebugSection(cvTypeSectionImpl.getSectionName(), cvTypeSectionImpl); // the byte[] for each implementation's content are created and // written under getOrDecideContent. doing that ensures that all diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index 67d179ca6d0b..1fcf24ddd602 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -66,7 +66,7 @@ final class CVFileRecord extends CVSymbolRecord { * * Currently, don't even try; use the SourceCache system */ - private String fixPath(FileEntry fileEntry) { + private static String fixPath(FileEntry fileEntry) { final String fn; if (fileEntry.getDirEntry() == null) { fn = fileEntry.getFileName(); @@ -100,7 +100,8 @@ public int computeSize(int initialPos) { } @Override - public int computeContents(byte[] buffer, int pos) { + public int computeContents(byte[] buffer, int initialPos) { + int pos = initialPos; CVUtil.debug("file computeContents(%d) nf=%d\n", pos, fileEntryToOffsetMap.size()); for (FileEntry entry : fileEntryToOffsetMap.keySet()) { pos = put(entry, buffer, pos); @@ -125,7 +126,7 @@ private int put(FileEntry entry, byte[] buffer, int initialPos) { return pos; } - private byte[] calculateMD5Sum(String fn) { + private static byte[] calculateMD5Sum(String fn) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(Files.readAllBytes(Paths.get(fn))); @@ -140,7 +141,7 @@ private byte[] calculateMD5Sum(String fn) { @Override public String toString() { - return "CVFileRecord(type=" + type + ",pos=" + pos + ", size=" + 999 + ")"; + return "CVFileRecord(type=" + type + ",pos=" + recordStartPosition + ", size=" + 999 + ")"; } @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index c7f0dcc49def..c50eec884367 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -47,7 +47,7 @@ final class CVLineRecord extends CVSymbolRecord { private static final short CB_HAS_NO_COLUMNS_FLAG = 0x00; private String symbolName; - private PrimaryEntry primaryEntry; + //private PrimaryEntry primaryEntry; private ArrayList fileBlocks = new ArrayList<>(DEFAULT_LINE_BLOCK_COUNT); /* @@ -59,11 +59,11 @@ private static class FileBlock { ArrayList lineEntries = new ArrayList<>(DEFAULT_LINE_ENTRY_COUNT); int highAddr = 0; - FileEntry file; + //FileEntry file; int fileId; FileBlock(FileEntry file, int fileId) { - this.file = file; + //this.file = file; this.fileId = fileId; } @@ -131,7 +131,7 @@ int computeContents(byte[] buffer, int initialPos) { CVLineRecord(CVSections cvSections, String symbolName, PrimaryEntry primaryEntry) { super(cvSections, DEBUG_S_LINES); - this.primaryEntry = primaryEntry; + //this.primaryEntry = primaryEntry; this.symbolName = symbolName; } @@ -187,6 +187,6 @@ protected int computeContents(byte[] buffer, int initialPos) { @Override public String toString() { - return String.format("CVLineRecord(type=0x%04x pos=0x%05x size=0x%d)", type, pos, fileBlocks.size()); + return String.format("CVLineRecord(type=0x%04x pos=0x%05x size=0x%d)", type, recordStartPosition, fileBlocks.size()); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index af913c5d0362..b1898f776183 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -40,7 +40,6 @@ public class CVLineRecordBuilder { private CVSections cvSections; private CVLineRecord lineRecord; - private Range previousRange = null; private PrimaryEntry primaryEntry; CVLineRecordBuilder(CVSections cvSections) { @@ -62,15 +61,15 @@ public class CVLineRecordBuilder { * @param primaryEntry function to build line number table for * @return CVLineRecord containing any entries generated, or null if no entries generated */ - CVLineRecord build(PrimaryEntry primaryEntry, String methodName) { + CVLineRecord build(PrimaryEntry entry, String methodName) { // long lowAddr = Long.MAX_VALUE; // long highAddr = 0; - this.primaryEntry = primaryEntry; + this.primaryEntry = entry; assert (!HAS_COLUMNS); /* can't handle columns yet */ Range primaryRange = primaryEntry.getPrimary(); - previousRange = null; + Range previousRange = null; /* option to not even bother with debug code for Graal */ if (skipGraalInternals && CVRootPackages.isGraalClass(primaryRange.getClassName())) { CVUtil.debug(" skipping Graal internal class %s\n", primaryRange); @@ -79,7 +78,7 @@ CVLineRecord build(PrimaryEntry primaryEntry, String methodName) { CVUtil.debug(" DEBUG_S_LINES linerecord for 0x%05x file: %s:%d\n", primaryRange.getLo(), primaryRange.getFileName(), primaryRange.getLine()); this.lineRecord = new CVLineRecord(cvSections, methodName, primaryEntry); CVUtil.debug(" CVLineRecord.computeContents: processing primary range %s\n", primaryRange); - processRange(primaryRange); + previousRange = processRange(primaryRange, previousRange); // lowAddr = Math.min(lowAddr, primaryRange.getLo()); // highAddr = Math.max(highAddr, primaryRange.getHi()); @@ -89,7 +88,7 @@ CVLineRecord build(PrimaryEntry primaryEntry, String methodName) { if (subFileEntry == null) { continue; } - processRange(subRange); + previousRange = processRange(subRange, previousRange); // lowAddr = Math.min(lowAddr, subRange.getLo()); // highAddr = Math.max(highAddr, subRange.getHi()); } @@ -105,18 +104,20 @@ CVLineRecord build(PrimaryEntry primaryEntry, String methodName) { * - if a range has the same line number, source file and function * * @param range to be merged or added to line number record + * @param previousRange the previously processed Range + * @return new value for previousRange in caller */ - private void processRange(Range range) { + private Range processRange(Range range, Range previousRange) { /* should we merge this range with the previous entry? */ /* i.e. same line in same file, same class and function */ - if (shouldMerge(previousRange, range)) { + if (shouldMerge(range, previousRange)) { CVUtil.debug(" processRange: merging with previous\n"); - return; + return previousRange; //range = new Range(previousRange, range.getLo(), range.getHi()); } /*else if (range.getLine() == -1) { CVUtil.debug(" processRange: ignoring: bad line number\n"); - return; + return previousRange; }*/ /* is this a new file? if so we emit a new file record */ @@ -129,17 +130,18 @@ private void processRange(Range range) { lineRecord.addNewFile(file); } else { CVUtil.debug(" processRange: range has no file: %s\n", range); - return; + return previousRange; } } - if (wantNewRange(previousRange, range)) { + if (wantNewRange(range, previousRange)) { previousRange = range; int lineLoAddr = range.getLo() - primaryEntry.getPrimary().getLo(); int line = range.getLine() < 1 ? 1 : range.getLine(); CVUtil.debug(" processRange: addNewLine: 0x%05x %s\n", lineLoAddr, line); lineRecord.addNewLine(lineLoAddr, line); } + return previousRange; } /** @@ -148,7 +150,7 @@ private void processRange(Range range) { * @param range the second range (higher address) * @return true if the two ranges can be combined */ - private boolean shouldMerge(Range previousRange, Range range) { + private boolean shouldMerge(Range range, Range previousRange) { if (!mergeAdjacentLineRecords) { return false; } @@ -170,24 +172,24 @@ private boolean shouldMerge(Range previousRange, Range range) { * @param range current range * @return true if the current range is on a different line or file from the previous one */ - private boolean wantNewRange(Range previous, Range range) { + private static boolean wantNewRange(Range range, Range previousRange) { return true; /*if (debug) { - if (previous == null) { + if (previousRange == null) { CVUtil.debug("wantNewRange() prevnull:true"); } else { - CVUtil.debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previous.getLine() != range.getLine()) - + " fndiffer:" + (previous.getFilePath() != range.getFilePath()) + " contig:" + (previous.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); + CVUtil.debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previousRange.getLine() != range.getLine()) + + " fndiffer:" + (previousRange.getFilePath() != range.getFilePath()) + " contig:" + (previousRange.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); } }* - if (previous == null) + if (previousRange == null) return true; - if (previous.getLine() != range.getLine()) + if (previousRange.getLine() != range.getLine()) return true; - if (previous.getFilePath() != range.getFilePath()) + if (previousRange.getFilePath() != range.getFilePath()) return true; /* it might actually be fine to merge if there's a gap between ranges * - if (previous.getHi() < range.getLo()) + if (previousRange.getHi() < range.getLo()) return true; //long delta = range.getHi() - previousRange.getLo(); //return delta >= 127; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java index c628558fe559..9fb6f99835d7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java @@ -44,12 +44,12 @@ */ public final class CVSections extends DebugInfoBase { - private PECoffMachine machine; + //private PECoffMachine machine; private CVSymbolSectionImpl cvSymbolSection; private CVTypeSectionImpl cvTypeSection; public CVSections(PECoffMachine machine) { - this.machine = machine; + //this.machine = machine; cvSymbolSection = new CVSymbolSectionImpl(this); cvTypeSection = new CVTypeSectionImpl(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java index 22403573b4ce..47d9c0ac4f8d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java @@ -56,7 +56,7 @@ public int computeContents(byte[] buffer, int pos) { @Override public String toString() { - return String.format("CVStringTableRecord(type=0x%04x pos=0x%06x size=%d)", type, pos, stringTable.size()); + return String.format("CVStringTableRecord(type=0x%04x pos=0x%06x size=%d)", type, recordStartPosition, stringTable.size()); } @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index 59f90d96f7a9..6a7e569d0f32 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -34,7 +34,7 @@ abstract class CVSymbolRecord implements CVDebugConstants { CVSections cvSections; - protected int pos; + protected int recordStartPosition; protected final int type; CVSymbolRecord(CVSections cvSections, int type) { @@ -42,14 +42,14 @@ abstract class CVSymbolRecord implements CVDebugConstants { this.type = type; } - int computeFullSize(int pos) { - this.pos = pos; - pos += Integer.BYTES * 2; + int computeFullSize(int initialPos) { + this.recordStartPosition = initialPos; + int pos = initialPos + Integer.BYTES * 2; return computeSize(pos); } - int computeFullContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(type, buffer, pos); + int computeFullContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(type, buffer, initialPos); int lenPos = pos; pos = computeContents(buffer, pos + Integer.BYTES); /* length does not include debug record header (4 bytes record id + 4 bytes length) */ @@ -62,7 +62,7 @@ int computeFullContents(byte[] buffer, int pos) { @Override public String toString() { - return "CVSymbolRecord(type=" + type + ",pos=" + pos + ")"; + return "CVSymbolRecord(type=" + type + ",pos=" + recordStartPosition + ")"; } public void dump(PrintStream out) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 59f67ef0edb8..a7cc93f5053f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -128,7 +128,7 @@ private String fixMethodName(Range range) { noMainFound = false; methodName = range.getClassAndMethodName(); } else if (functionNamesHashArgs) { - long hash = ((long) range.getParamNames().hashCode()) & 0xffffffffL; + long hash = range.getParamNames().hashCode() & 0xffffffffL; methodName = range.getClassAndMethodName() + "." + hash; } else { methodName = range.getFullMethodName(); @@ -155,7 +155,7 @@ private void addToSymbolRecord(CVSymbolSubrecord record) { /** * add type records for function - * (later add arglist, and arrlist and local types) + * (later add arglist, and return type and local types) * * @return type index of function type */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index 8b436669df1a..c1ad051cc9e7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -40,7 +40,7 @@ */ abstract class CVSymbolSubrecord { - private int initialPos; + private int subrecordStartPosition; private final short cmd; CVSections cvSections; @@ -50,7 +50,7 @@ abstract class CVSymbolSubrecord { } int computeFullSize(int initialPos) { - this.initialPos = initialPos; + this.subrecordStartPosition = initialPos; int prologueLength = Short.BYTES * 2; /* room for length and subcommand */ return computeSize(initialPos + prologueLength); } @@ -67,7 +67,7 @@ int computeFullContents(byte[] buffer, int initialPos) { @Override public String toString() { - return String.format("CVSymbolSubrecord(cmd=0x%04x pos=0x%06x)", cmd, initialPos); + return String.format("CVSymbolSubrecord(cmd=0x%04x pos=0x%06x)", cmd, subrecordStartPosition); } protected abstract int computeSize(int pos); @@ -106,15 +106,15 @@ boolean isValid() { } @Override - protected int computeSize(int pos) { - pos += Integer.BYTES; /* signature = 0; */ + protected int computeSize(int initialPos) { + int pos = initialPos + Integer.BYTES; /* signature = 0; */ pos += objName.getBytes(UTF_8).length + 1; /* inline null terminated */ return pos; } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(0, buffer, pos); /* signature = 0 */ + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(0, buffer, initialPos); /* signature = 0 */ pos = CVUtil.putUTF8StringBytes(objName, buffer, pos); /* inline null terminated */ return pos; } @@ -159,13 +159,13 @@ public static final class CVCompile3Record extends CVSymbolSubrecord { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putByte(language, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putByte(language, buffer, initialPos); pos = CVUtil.putByte(cf1, buffer, pos); pos = CVUtil.putByte(cf2, buffer, pos); pos = CVUtil.putByte(padding, buffer, pos); @@ -232,14 +232,14 @@ private static String findFirstFile(CVSections cvSections) { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { + protected int computeContents(byte[] buffer, int initialPos) { /* flags */ - pos = CVUtil.putByte((byte) 0, buffer, pos); + int pos = CVUtil.putByte((byte) 0, buffer, initialPos); /* key/value pairs */ for (Map.Entry entry : map.entrySet()) { @@ -294,13 +294,13 @@ public static class CVSymbolGProc32Record extends CVSymbolSubrecord { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(pparent, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(pparent, buffer, initialPos); pos = CVUtil.putInt(pend, buffer, pos); pos = CVUtil.putInt(pnext, buffer, pos); pos = CVUtil.putInt(proclen, buffer, pos); @@ -382,13 +382,13 @@ public static final class CVSymbolFrameProcRecord extends CVSymbolSubrecord { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(framelen, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(framelen, buffer, initialPos); pos = CVUtil.putInt(padLen, buffer, pos); pos = CVUtil.putInt(padOffset, buffer, pos); pos = CVUtil.putInt(saveRegsCount, buffer, pos); @@ -415,14 +415,14 @@ public static class CVSymbolEndRecord extends CVSymbolSubrecord { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { + protected int computeContents(byte[] buffer, int initialPos) { // nothing - return pos; + return initialPos; } @Override @@ -446,13 +446,13 @@ public CVSymbolRegRel32Record(CVSections cvSections, String name, int typeIndex, } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(offset, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(offset, buffer, initialPos); pos = CVUtil.putInt(typeIndex, buffer, pos); pos = CVUtil.putShort(reg, buffer, pos); pos = CVUtil.putUTF8StringBytes(name, buffer, pos); @@ -485,13 +485,13 @@ public CVSymbolConstantRecord(CVSections cvSections, String name, int typeIndex, } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(typeIndex, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(typeIndex, buffer, initialPos); pos = CVUtil.putShort(leaf, buffer, pos); pos = CVUtil.putUTF8StringBytes(name, buffer, pos); return pos; @@ -519,13 +519,13 @@ private static abstract class CVSymbolDataRecord extends CVSymbolSubrecord { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(typeIndex, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(typeIndex, buffer, initialPos); pos = CVUtil.putInt(offset, buffer, pos); pos = CVUtil.putShort(segment, buffer, pos); pos = CVUtil.putUTF8StringBytes(name, buffer, pos); @@ -576,8 +576,8 @@ public CVSymbolSSearchRecord(CVSections cvSections, int offset, short segment) { } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(offset, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(offset, buffer, initialPos); pos = CVUtil.putShort(segment, buffer, pos); return pos; } @@ -600,13 +600,13 @@ public CVSymbolUDTRecord(CVSections cvSections, String name, int typeIndex) { } @Override - protected int computeSize(int pos) { - return computeContents(null, pos); + protected int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - protected int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(typeIndex, buffer, pos); + protected int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(typeIndex, buffer, initialPos); pos = CVUtil.putUTF8StringBytes(name, buffer, pos); return pos; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java index 74349566ad18..b1f5ce61ff7e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java @@ -47,7 +47,8 @@ void addRecord(CVSymbolSubrecord subcmd) { void addSubrecords() { } @Override - protected int computeSize(int pos) { + protected int computeSize(int initialPos) { + int pos = initialPos; addSubrecords(); for (CVSymbolSubrecord subcmd : subcmds) { pos = subcmd.computeFullSize(pos); @@ -56,7 +57,8 @@ protected int computeSize(int pos) { } @Override - protected int computeContents(byte[] buffer, int pos) { + protected int computeContents(byte[] buffer, int initialPos) { + int pos = initialPos; for (CVSymbolSubrecord subcmd : subcmds) { pos = subcmd.computeFullContents(buffer, pos); } @@ -65,6 +67,6 @@ protected int computeContents(byte[] buffer, int pos) { @Override public String toString() { - return String.format("CVSymbolSubsection(type=0x%04x pos=0x%05x count=%d)", type, pos, subcmds.size()); + return String.format("CVSymbolSubsection(type=0x%04x pos=0x%05x count=%d)", type, recordStartPosition, subcmds.size()); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java index fc61ae4c01e6..a58da8ad42cc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java @@ -56,17 +56,17 @@ void setSequenceNumber(int sequenceNumber) { this.sequenceNumber = sequenceNumber; } - int computeFullSize(int pos) { - this.startPosition = pos; - pos += Short.BYTES * 2; /* save room for length and leaf type */ + int computeFullSize(int initialPos) { + this.startPosition = initialPos; + int pos = initialPos + Short.BYTES * 2; /* save room for length and leaf type */ pos = computeSize(pos); pos = alignPadded4(null, pos); return pos; } - int computeFullContents(byte[] buffer, int pos) { - int lenPos = pos; /* save position of length short */ - pos += Short.BYTES; /* save room for length short */ + int computeFullContents(byte[] buffer, int initialPos) { + int lenPos = initialPos; /* save position of length short */ + int pos = initialPos + Short.BYTES; /* save room for length short */ pos = CVUtil.putShort(type, buffer, pos); pos = computeContents(buffer, pos); /* length does not include record length (2 bytes)) but does include end padding */ @@ -76,8 +76,8 @@ int computeFullContents(byte[] buffer, int pos) { return pos; } - protected abstract int computeSize(int pos); - protected abstract int computeContents(byte[] buffer, int pos); + protected abstract int computeSize(int initialPos); + protected abstract int computeContents(byte[] buffer, int initialPos); @Override public String toString() { @@ -88,7 +88,7 @@ public void dump(PrintStream out) { out.format("%s\n", this); } - private int alignPadded4(byte[] buffer, int originalpos) { + private static int alignPadded4(byte[] buffer, int originalpos) { int pos = originalpos; int align = pos & 3; if (align == 1) { @@ -139,13 +139,13 @@ private short computeFlags() { return (short) ((addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0)); } @Override - public int computeSize(int pos) { - return pos + Integer.BYTES + Short.BYTES; + public int computeSize(int initialPos) { + return initialPos + Integer.BYTES + Short.BYTES; } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(originalLeaf, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(originalLeaf, buffer, initialPos); pos = CVUtil.putShort(computeFlags(), buffer, pos); return pos; } @@ -207,13 +207,13 @@ private int computeAttributes() { } @Override - public int computeSize(int pos) { - return pos + Integer.BYTES * 2; + public int computeSize(int initialPos) { + return initialPos + Integer.BYTES * 2; } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(originalLeaf, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(originalLeaf, buffer, initialPos); pos = CVUtil.putInt(computeAttributes(), buffer, pos); return pos; } @@ -257,13 +257,13 @@ CVTypeProcedureRecord argList(CVTypeArglistRecord leaf) { } @Override - public int computeSize(int pos) { - return pos + Integer.BYTES + Byte.BYTES + Byte.BYTES + Short.BYTES + Integer.BYTES; + public int computeSize(int initialPos) { + return initialPos + Integer.BYTES + Byte.BYTES + Byte.BYTES + Short.BYTES + Integer.BYTES; } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(returnType, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(returnType, buffer, initialPos); pos = CVUtil.putByte((byte) 0, buffer, pos); // callType pos = CVUtil.putByte((byte) 0, buffer, pos); // funcAttr pos = CVUtil.putShort((short) argList.getSize(), buffer, pos); @@ -305,13 +305,13 @@ CVTypeArglistRecord add(CVTypeRecord argType) { } @Override - public int computeSize(int pos) { - return pos + Integer.BYTES + Integer.BYTES * args.size(); + public int computeSize(int initialPos) { + return initialPos + Integer.BYTES + Integer.BYTES * args.size(); } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(args.size(), buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(args.size(), buffer, initialPos); for (Integer at : args) { pos = CVUtil.putInt(at, buffer, pos); } @@ -356,13 +356,13 @@ static final class CVMemberRecord extends CVTypeRecord { } @Override - public int computeSize(int pos) { - return pos + Short.BYTES + Integer.BYTES; /* + TODO */ + public int computeSize(int initialPos) { + return initialPos + Short.BYTES + Integer.BYTES; /* + TODO */ } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putShort(propertyAttributes, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putShort(propertyAttributes, buffer, initialPos); pos = CVUtil.putInt(fieldIndex, buffer, pos); /* TODO */ return pos; @@ -399,13 +399,13 @@ static class CVBaseClassRecord extends CVTypeRecord { } @Override - public int computeSize(int pos) { - return pos + Short.BYTES + Integer.BYTES; // + TODO + public int computeSize(int initialPos) { + return initialPos + Short.BYTES + Integer.BYTES; // + TODO } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putShort(propertyAttributes, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putShort(propertyAttributes, buffer, initialPos); pos = CVUtil.putInt(fieldIndex, buffer, pos); // TODO return pos; @@ -465,13 +465,13 @@ static class CVClassRecord extends CVTypeRecord { } @Override - public int computeSize(int pos) { - return pos + Short.BYTES + Short.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES; // + TODO + public int computeSize(int initialPos) { + return initialPos + Short.BYTES + Short.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES; // + TODO } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putShort(count, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putShort(count, buffer, initialPos); pos = CVUtil.putShort(propertyAttributes, buffer, pos); pos = CVUtil.putInt(fieldIndex, buffer, pos); pos = CVUtil.putInt(derivedFromIndex, buffer, pos); @@ -537,13 +537,13 @@ static final class CVTypeBitfieldRecord extends CVTypeRecord { } @Override - public int computeSize(int pos) { - return pos + Integer.BYTES + Byte.BYTES + Byte.BYTES; + public int computeSize(int initialPos) { + return initialPos + Integer.BYTES + Byte.BYTES + Byte.BYTES; } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(typeIndex, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(typeIndex, buffer, initialPos); pos = CVUtil.putByte(length, buffer, pos); pos = CVUtil.putByte(position, buffer, pos); return pos; @@ -592,13 +592,13 @@ static final class CVTypeArrayRecord extends CVTypeRecord { } @Override - public int computeSize(int pos) { - return pos + Integer.BYTES * 3; + public int computeSize(int initialPos) { + return initialPos + Integer.BYTES * 3; } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putInt(elementType, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putInt(elementType, buffer, initialPos); pos = CVUtil.putInt(indexType, buffer, pos); pos = CVUtil.putInt(length, buffer, pos); return pos; @@ -645,13 +645,13 @@ static final class CVTypeServer2Record extends CVTypeRecord { } @Override - public int computeSize(int pos) { - return computeContents(null, pos); + public int computeSize(int initialPos) { + return computeContents(null, initialPos); } @Override - public int computeContents(byte[] buffer, int pos) { - pos = CVUtil.putBytes(guid, buffer, pos); + public int computeContents(byte[] buffer, int initialPos) { + int pos = CVUtil.putBytes(guid, buffer, initialPos); pos = CVUtil.putInt(age, buffer, pos); pos = CVUtil.putUTF8StringBytes(fileName, buffer, pos); return pos; @@ -671,7 +671,7 @@ public int hashCode() { return h; } - private void swap(byte[] b, int idx1, int idx2) { + private static void swap(byte[] b, int idx1, int idx2) { byte tmp = b[idx1]; b[idx1] = b[idx2]; b[idx2] = tmp; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java index 5f16d19dc270..d429c87ae2fa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java @@ -110,7 +110,7 @@ private void addRecords() { addClassRecords(); } - private int computeHeaderSize() { + private static int computeHeaderSize() { return Integer.BYTES; /* CV_SIGNATURE_C13 = 4; */ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java index 4aaf588b0c85..4269086aec59 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java @@ -30,6 +30,8 @@ abstract class CVUtil { + private static final boolean DEBUG_ON = false; + /* base level put methods that assume a non-null buffer */ static int putByte(byte b, byte[] buffer, int initialPos) { if (buffer == null) { @@ -161,6 +163,8 @@ static int align4(int initialPos) { } public static void debug(String format, Object ... args) { - //System.out.format(format, args); + if (DEBUG_ON) { + System.out.format(format, args); + } } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java index 2ce1cd693114..1d3de197481d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java @@ -54,7 +54,7 @@ */ public abstract class DebugInfoBase { - private boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { + private static boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { /* TODO: be much more clever; this is merely proof of concept */ //return !(CVConstants.skipGraalInternals && debugCodeInfo.className().startsWith("com.oracle")); return true; @@ -176,7 +176,7 @@ FileEntry ensureFileEntry(Range range) { private void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); - PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); + /*PrimaryEntry entry =*/ classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); } private void addSubRange(Range primaryRange, Range subrange) { From a19d77b0635f5665ddb93fffffacf37cacc5cc05 Mon Sep 17 00:00:00 2001 From: Andrew Dinn Date: Thu, 26 Mar 2020 17:51:00 +0000 Subject: [PATCH 111/130] more code cleanups --- .../objectfile/debugentry/ClassEntry.java | 8 +-- .../objectfile/debugentry/PrimaryEntry.java | 8 +-- .../oracle/objectfile/debugentry/Range.java | 4 +- .../objectfile/debugentry/StringTable.java | 2 +- .../debuginfo/DebugInfoProvider.java | 2 + .../elf/dwarf/DwarfARangesSectionImpl.java | 4 +- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 14 +++-- .../elf/dwarf/DwarfFrameSectionImpl.java | 48 +++++++------- .../dwarf/DwarfFrameSectionImplAArch64.java | 6 +- .../dwarf/DwarfFrameSectionImplX86_64.java | 4 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 13 ++-- .../elf/dwarf/DwarfLineSectionImpl.java | 62 +++++++++---------- .../elf/dwarf/DwarfSectionImpl.java | 52 ++++++++-------- .../objectfile/elf/dwarf/DwarfSections.java | 35 ++--------- .../elf/dwarf/DwarfStrSectionImpl.java | 4 +- 15 files changed, 124 insertions(+), 142 deletions(-) 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 a4535472284f..7c55d291d33a 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 @@ -44,7 +44,7 @@ public class ClassEntry { /** * details of the associated file. */ - FileEntry fileEntry; + private FileEntry fileEntry; /** * a list recording details of all primary ranges included in this class sorted by ascending * address range. @@ -111,14 +111,12 @@ public ClassEntry(String className, FileEntry fileEntry) { this.totalSize = -1; } - public PrimaryEntry addPrimary(Range primary, List frameSizeInfos, int frameSize) { + public void addPrimary(Range primary, List frameSizeInfos, int frameSize) { if (primaryIndex.get(primary) == null) { PrimaryEntry primaryEntry = new PrimaryEntry(primary, frameSizeInfos, frameSize, this); primaryEntries.add(primaryEntry); primaryIndex.put(primary, primaryEntry); - return primaryEntry; } - return null; } public void addSubRange(Range subrange, FileEntry subFileEntry) { @@ -167,6 +165,7 @@ public String getFileName() { } } + @SuppressWarnings("unused") String getFullFileName() { if (fileEntry != null) { return fileEntry.getFullName(); @@ -175,6 +174,7 @@ String getFullFileName() { } } + @SuppressWarnings("unused") String getDirName() { if (fileEntry != null) { return fileEntry.getPathName(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index 6f789f44fdc3..6dfc7e002f61 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -39,19 +39,19 @@ public class PrimaryEntry { /** * The primary range detailed by this object. */ - Range primary; + private Range primary; /** * Details of the class owning this range. */ - ClassEntry classEntry; + private ClassEntry classEntry; /** * A list of subranges associated with the primary range. */ - List subranges; + private List subranges; /** * A mapping from subranges to their associated file entry. */ - HashMap subrangeIndex; + private HashMap subrangeIndex; /** * Details of of compiled method frame size changes. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index c8760a5cc8d4..58519d4e72eb 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -66,7 +66,7 @@ public Range(String fileName, Path filePath, String className, String methodName * currently file name and full method name need to go into the debug_str section other * strings just need to be deduplicated to save space */ - this.fileName = (fileName == null ? fileName : stringTable.uniqueDebugString(fileName)); + this.fileName = (fileName == null ? null : stringTable.uniqueDebugString(fileName)); this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); @@ -133,7 +133,7 @@ public String getFullMethodName() { return fullMethodName; } - public String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { + private String getExtendedMethodName(boolean includeParams, boolean includeReturnType) { StringBuilder builder = new StringBuilder(); if (includeReturnType && returnTypeName.length() > 0) { builder.append(returnTypeName); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java index d33a0104f18a..7abb2b30bf3c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java @@ -83,7 +83,7 @@ private String ensureString(String string, boolean addToStrSection) { * Retrieves the offset at which a given string was written into the debug_str section. This * should only be called after the string section has been written. * - * @param string + * @param string the strng whose offset is to be retrieved * @return the offset or -1 if the string does not define an entry or the entry has not been * written to the debug_str section */ 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 39963c73310b..1468b8501621 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 @@ -177,9 +177,11 @@ enum Type { DebugFrameSizeChange.Type getType(); } + @SuppressWarnings("unused") Stream typeInfoProvider(); Stream codeInfoProvider(); + @SuppressWarnings("unused") Stream dataInfoProvider(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index 81451823b808..80252c046844 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -179,14 +179,14 @@ public void writeContent(DebugContext context) { /* * debug_aranges section content depends on debug_info section content and offset */ - public static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; + private static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] targetSectionKinds = { + private final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; 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 854d3c0e399b..4009883eda62 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 @@ -156,7 +156,7 @@ public void writeContent(DebugContext context) { assert pos == size; } - public int writeAttrType(long code, byte[] buffer, int pos) { + private int writeAttrType(long code, byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(code, scratch, 0); } else { @@ -164,7 +164,7 @@ public int writeAttrType(long code, byte[] buffer, int pos) { } } - public int writeAttrForm(long code, byte[] buffer, int pos) { + private int writeAttrForm(long code, byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(code, scratch, 0); } else { @@ -172,7 +172,8 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { } } - public int writeAbbrev1(DebugContext context, byte[] buffer, int p) { + @SuppressWarnings("unused") + private int writeAbbrev1(DebugContext context, byte[] buffer, int p) { int pos = p; /* * abbrev 1 compile unit @@ -198,7 +199,8 @@ public int writeAbbrev1(DebugContext context, byte[] buffer, int p) { return pos; } - public int writeAbbrev2(DebugContext context, byte[] buffer, int p) { + @SuppressWarnings("unused") + private int writeAbbrev2(DebugContext context, byte[] buffer, int p) { int pos = p; /* * abbrev 2 compile unit @@ -225,14 +227,14 @@ public int writeAbbrev2(DebugContext context, byte[] buffer, int p) { /** * debug_abbrev section content depends on debug_frame section content and offset. */ - public static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; + private static final String TARGET_SECTION_NAME = DW_FRAME_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] targetSectionKinds = { + private final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index 1865ee29c5ec..5859c3d133cd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -51,6 +51,8 @@ */ public abstract class DwarfFrameSectionImpl extends DwarfSectionImpl { + private static final int PADDING_NOPS_ALIGNMENT = 8; + public DwarfFrameSectionImpl(DwarfSections dwarfSections) { super(dwarfSections); } @@ -96,7 +98,7 @@ public void writeContent(DebugContext context) { assert pos == size; } - public int writeCIE(byte[] buffer, int p) { + private int writeCIE(byte[] buffer, int p) { /* * we only need a vanilla CIE with default fields because we have to have at least one the * layout is @@ -137,7 +139,7 @@ public int writeCIE(byte[] buffer, int p) { /* * pad to word alignment */ - pos = writePaddingNops(8, buffer, pos); + pos = writePaddingNops(buffer, pos); /* * no need to write length */ @@ -158,13 +160,13 @@ public int writeCIE(byte[] buffer, int p) { /* * pad to word alignment */ - pos = writePaddingNops(8, buffer, pos); + pos = writePaddingNops(buffer, pos); patchLength(lengthPos, buffer, pos); return pos; } } - public int writeMethodFrames(byte[] buffer, int p) { + private int writeMethodFrames(byte[] buffer, int p) { int pos = p; for (ClassEntry classEntry : getPrimaryClasses()) { for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { @@ -190,14 +192,14 @@ public int writeMethodFrames(byte[] buffer, int p) { pos = writeDefCFAOffset(8, buffer, pos); } } - pos = writePaddingNops(8, buffer, pos); + pos = writePaddingNops(buffer, pos); patchLength(lengthPos, buffer, pos); } } return pos; } - public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { + private int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { /* * we only need a vanilla FDE header with default fields the layout is * @@ -239,10 +241,9 @@ public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { } } - public int writePaddingNops(int alignment, byte[] buffer, int p) { + private int writePaddingNops(byte[] buffer, int p) { int pos = p; - assert (alignment & (alignment - 1)) == 0; - while ((pos & (alignment - 1)) != 0) { + while ((pos & (PADDING_NOPS_ALIGNMENT - 1)) != 0) { if (buffer == null) { pos++; } else { @@ -252,7 +253,7 @@ public int writePaddingNops(int alignment, byte[] buffer, int p) { return pos; } - public int writeDefCFA(int register, int offset, byte[] buffer, int p) { + protected int writeDefCFA(int register, int offset, byte[] buffer, int p) { int pos = p; if (buffer == null) { pos += putByte(DW_CFA_def_cfa, scratch, 0); @@ -265,7 +266,7 @@ public int writeDefCFA(int register, int offset, byte[] buffer, int p) { } } - public int writeDefCFAOffset(int offset, byte[] buffer, int p) { + protected int writeDefCFAOffset(int offset, byte[] buffer, int p) { int pos = p; if (buffer == null) { pos += putByte(DW_CFA_def_cfa_offset, scratch, 0); @@ -276,7 +277,7 @@ public int writeDefCFAOffset(int offset, byte[] buffer, int p) { } } - public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { + protected int writeAdvanceLoc(int offset, byte[] buffer, int pos) { if (offset <= 0x3f) { return writeAdvanceLoc0((byte) offset, buffer, pos); } else if (offset <= 0xff) { @@ -288,7 +289,7 @@ public int writeAdvanceLoc(int offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { + protected int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { byte op = advanceLoc0Op(offset); if (buffer == null) { return pos + putByte(op, scratch, 0); @@ -297,7 +298,7 @@ public int writeAdvanceLoc0(byte offset, byte[] buffer, int pos) { } } - public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { + protected int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { int pos = p; byte op = DW_CFA_advance_loc1; if (buffer == null) { @@ -309,7 +310,7 @@ public int writeAdvanceLoc1(byte offset, byte[] buffer, int p) { } } - public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { + protected int writeAdvanceLoc2(short offset, byte[] buffer, int p) { byte op = DW_CFA_advance_loc2; int pos = p; if (buffer == null) { @@ -321,7 +322,7 @@ public int writeAdvanceLoc2(short offset, byte[] buffer, int p) { } } - public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { + protected int writeAdvanceLoc4(int offset, byte[] buffer, int p) { byte op = DW_CFA_advance_loc4; int pos = p; if (buffer == null) { @@ -333,7 +334,7 @@ public int writeAdvanceLoc4(int offset, byte[] buffer, int p) { } } - public int writeOffset(int register, int offset, byte[] buffer, int p) { + protected int writeOffset(int register, int offset, byte[] buffer, int p) { byte op = offsetOp(register); int pos = p; if (buffer == null) { @@ -345,7 +346,7 @@ public int writeOffset(int register, int offset, byte[] buffer, int p) { } } - public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { + protected int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { int pos = p; if (buffer == null) { pos += putByte(DW_CFA_register, scratch, 0); @@ -358,23 +359,24 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { } } - public abstract int getPCIdx(); + protected abstract int getPCIdx(); - public abstract int getSPIdx(); + @SuppressWarnings("unused") + protected abstract int getSPIdx(); - public abstract int writeInitialInstructions(byte[] buffer, int pos); + protected abstract int writeInitialInstructions(byte[] buffer, int pos); /** * debug_frame section content depends on debug_line section content and offset. */ - public static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; + private static final String TARGET_SECTION_NAME = DW_LINE_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] targetSectionKinds = { + private final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index 89268fd72b7c..2665f82738c3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -32,9 +32,9 @@ */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { // public static final int DW_CFA_FP_IDX = 29; - public static final int DW_CFA_LR_IDX = 30; - public static final int DW_CFA_SP_IDX = 31; - public static final int DW_CFA_PC_IDX = 32; + private static final int DW_CFA_LR_IDX = 30; + private static final int DW_CFA_SP_IDX = 31; + private static final int DW_CFA_PC_IDX = 32; public DwarfFrameSectionImplAArch64(DwarfSections dwarfSections) { super(dwarfSections); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java index 275c4ca00a32..dd207011e975 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -31,8 +31,8 @@ * and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_RSP_IDX = 7; - public static final int DW_CFA_RIP_IDX = 16; + private static final int DW_CFA_RSP_IDX = 7; + private static final int DW_CFA_RIP_IDX = 16; public DwarfFrameSectionImplX86_64(DwarfSections dwarfSections) { super(dwarfSections); 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 a3c5e6eac356..36c22664f0a9 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 @@ -156,7 +156,7 @@ public void writeContent(DebugContext context) { assert pos == size; } - public int writeCUHeader(byte[] buffer, int p) { + private int writeCUHeader(byte[] buffer, int p) { int pos = p; if (buffer == null) { /* CU length */ @@ -179,7 +179,7 @@ public int writeCUHeader(byte[] buffer, int p) { } } - public int writeCU(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + private int writeCU(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); log(context, " [0x%08x] <0> Abbrev Number %d", pos, DW_ABBREV_CODE_compile_unit); @@ -204,7 +204,7 @@ public int writeCU(DebugContext context, ClassEntry classEntry, byte[] buffer, i } - public int writePrimary(DebugContext context, PrimaryEntry primaryEntry, byte[] buffer, int p) { + private int writePrimary(DebugContext context, PrimaryEntry primaryEntry, byte[] buffer, int p) { int pos = p; Range primary = primaryEntry.getPrimary(); verboseLog(context, " [0x%08x] <1> Abbrev Number %d", pos, DW_ABBREV_CODE_subprogram); @@ -222,7 +222,7 @@ public int writePrimary(DebugContext context, PrimaryEntry primaryEntry, byte[] return writeFlag(DW_FLAG_true, buffer, pos); } - public int writeAttrStrp(String value, byte[] buffer, int p) { + private int writeAttrStrp(String value, byte[] buffer, int p) { int pos = p; if (buffer == null) { return pos + putInt(0, scratch, 0); @@ -232,6 +232,7 @@ public int writeAttrStrp(String value, byte[] buffer, int p) { } } + @SuppressWarnings("unused") public int writeAttrString(String value, byte[] buffer, int p) { int pos = p; if (buffer == null) { @@ -244,14 +245,14 @@ public int writeAttrString(String value, byte[] buffer, int p) { /** * debug_info section content depends on abbrev section content and offset. */ - public static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; + private static final String TARGET_SECTION_NAME = DW_ABBREV_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] targetSectionKinds = { + private final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET }; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index d6e7c48717e5..eac696bf25ec 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -170,7 +170,7 @@ public void createContent() { super.setContent(buffer); } - public int headerSize() { + private int headerSize() { /* * header size is standard 31 bytes * @@ -202,7 +202,7 @@ public int headerSize() { return DW_LN_HEADER_SIZE; } - public int computeDirTableSize(ClassEntry classEntry) { + private int computeDirTableSize(ClassEntry classEntry) { /* * table contains a sequence of 'nul'-terminated dir name bytes followed by an extra 'nul' * and then a sequence of 'nul'-terminated file name bytes followed by an extra 'nul' @@ -220,7 +220,7 @@ public int computeDirTableSize(ClassEntry classEntry) { return dirSize; } - public int computeFileTableSize(ClassEntry classEntry) { + private int computeFileTableSize(ClassEntry classEntry) { /* * table contains a sequence of 'nul'-terminated dir name bytes followed by an extra 'nul' * and then a sequence of 'nul'-terminated file name bytes followed by an extra 'nul' @@ -252,7 +252,7 @@ public int computeFileTableSize(ClassEntry classEntry) { return fileSize; } - public int computeLineNUmberTableSize(ClassEntry classEntry) { + private int computeLineNUmberTableSize(ClassEntry classEntry) { /* * sigh -- we have to do this by generating the content even though we cannot write it into * a byte[] @@ -307,7 +307,7 @@ public void writeContent(DebugContext context) { assert pos == buffer.length; } - public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { + private int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { int pos = p; /* * 4 ubyte length field @@ -372,7 +372,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { return pos; } - public int writeDirTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + private int writeDirTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; verboseLog(context, " [0x%08x] Dir Name", pos); /* @@ -394,7 +394,7 @@ public int writeDirTable(DebugContext context, ClassEntry classEntry, byte[] buf return pos; } - public int writeFileTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + private int writeFileTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; int fileIdx = 1; verboseLog(context, " [0x%08x] Entry Dir Name", pos); @@ -419,10 +419,10 @@ public int writeFileTable(DebugContext context, ClassEntry classEntry, byte[] bu return pos; } - public int debugLine = 1; - public int debugCopyCount = 0; + private int debugLine = 1; + private int debugCopyCount = 0; - public int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { + private int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; FileEntry fileEntry = classEntry.getFileEntry(); if (fileEntry == null) { @@ -607,7 +607,7 @@ public int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byt return pos; } - public int writeCopyOp(DebugContext context, byte[] buffer, int p) { + private int writeCopyOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_copy; int pos = p; if (buffer == null) { @@ -619,7 +619,7 @@ public int writeCopyOp(DebugContext context, byte[] buffer, int p) { } } - public int writeAdvancePCOp(DebugContext context, long uleb, byte[] buffer, int p) { + private int writeAdvancePCOp(DebugContext context, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_pc; int pos = p; if (buffer == null) { @@ -633,7 +633,7 @@ public int writeAdvancePCOp(DebugContext context, long uleb, byte[] buffer, int } } - public int writeAdvanceLineOp(DebugContext context, long sleb, byte[] buffer, int p) { + private int writeAdvanceLineOp(DebugContext context, long sleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_line; int pos = p; if (buffer == null) { @@ -647,7 +647,7 @@ public int writeAdvanceLineOp(DebugContext context, long sleb, byte[] buffer, in } } - public int writeSetFileOp(DebugContext context, String file, long uleb, byte[] buffer, int p) { + private int writeSetFileOp(DebugContext context, String file, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_file; int pos = p; if (buffer == null) { @@ -661,7 +661,7 @@ public int writeSetFileOp(DebugContext context, String file, long uleb, byte[] b } @SuppressWarnings("unused") - public int writeSetColumnOp(DebugContext context, long uleb, byte[] buffer, int p) { + private int writeSetColumnOp(DebugContext context, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; int pos = p; if (buffer == null) { @@ -674,7 +674,7 @@ public int writeSetColumnOp(DebugContext context, long uleb, byte[] buffer, int } @SuppressWarnings("unused") - public int writeNegateStmtOp(DebugContext context, byte[] buffer, int p) { + private int writeNegateStmtOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_negate_stmt; int pos = p; if (buffer == null) { @@ -684,7 +684,7 @@ public int writeNegateStmtOp(DebugContext context, byte[] buffer, int p) { } } - public int writeSetBasicBlockOp(DebugContext context, byte[] buffer, int p) { + private int writeSetBasicBlockOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; int pos = p; if (buffer == null) { @@ -695,7 +695,7 @@ public int writeSetBasicBlockOp(DebugContext context, byte[] buffer, int p) { } } - public int writeConstAddPCOp(DebugContext context, byte[] buffer, int p) { + private int writeConstAddPCOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_const_add_pc; int pos = p; if (buffer == null) { @@ -708,7 +708,7 @@ public int writeConstAddPCOp(DebugContext context, byte[] buffer, int p) { } } - public int writeFixedAdvancePCOp(DebugContext context, short arg, byte[] buffer, int p) { + private int writeFixedAdvancePCOp(DebugContext context, short arg, byte[] buffer, int p) { byte opcode = DW_LNS_fixed_advance_pc; int pos = p; if (buffer == null) { @@ -722,7 +722,7 @@ public int writeFixedAdvancePCOp(DebugContext context, short arg, byte[] buffer, } } - public int writeEndSequenceOp(DebugContext context, byte[] buffer, int p) { + private int writeEndSequenceOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNE_end_sequence; int pos = p; if (buffer == null) { @@ -746,7 +746,7 @@ public int writeEndSequenceOp(DebugContext context, byte[] buffer, int p) { } } - public int writeSetAddressOp(DebugContext context, long arg, byte[] buffer, int p) { + private int writeSetAddressOp(DebugContext context, long arg, byte[] buffer, int p) { byte opcode = DW_LNE_set_address; int pos = p; if (buffer == null) { @@ -771,7 +771,7 @@ public int writeSetAddressOp(DebugContext context, long arg, byte[] buffer, int } @SuppressWarnings("unused") - public int writeDefineFileOp(DebugContext context, String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { + private int writeDefineFileOp(DebugContext context, String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; int pos = p; /* @@ -808,22 +808,22 @@ public int writeDefineFileOp(DebugContext context, String file, long uleb1, long } } - public static int opcodeId(byte opcode) { + private static int opcodeId(byte opcode) { int iopcode = opcode & 0xff; return iopcode - DW_LN_OPCODE_BASE; } - public static int opcodeAddress(byte opcode) { + private static int opcodeAddress(byte opcode) { int iopcode = opcode & 0xff; return (iopcode - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; } - public static int opcodeLine(byte opcode) { + private static int opcodeLine(byte opcode) { int iopcode = opcode & 0xff; return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int writeSpecialOpcode(DebugContext context, byte opcode, byte[] buffer, int p) { + private int writeSpecialOpcode(DebugContext context, byte opcode, byte[] buffer, int p) { int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); @@ -842,7 +842,7 @@ public int writeSpecialOpcode(DebugContext context, byte opcode, byte[] buffer, private static final int MAX_ADDRESS_ONLY_DELTA = (0xff - DW_LN_OPCODE_BASE) / DW_LN_LINE_RANGE; private static final int MAX_ADDPC_DELTA = MAX_ADDRESS_ONLY_DELTA + (MAX_ADDRESS_ONLY_DELTA - 1); - public static byte isSpecialOpcode(long addressDelta, long lineDelta) { + private static byte isSpecialOpcode(long addressDelta, long lineDelta) { if (addressDelta < 0) { return DW_LNS_undefined; } @@ -867,7 +867,7 @@ public static byte isSpecialOpcode(long addressDelta, long lineDelta) { return DW_LNS_undefined; } - public static int isConstAddPC(long addressDelta) { + private static int isConstAddPC(long addressDelta) { if (addressDelta < MAX_ADDRESS_ONLY_DELTA) { return 0; } @@ -878,21 +878,21 @@ public static int isConstAddPC(long addressDelta) { } } - public static boolean isFixedAdvancePC(long addressDiff) { + private static boolean isFixedAdvancePC(long addressDiff) { return addressDiff >= 0 && addressDiff < 0xffff; } /** * debug_line section content depends on debug_str section content and offset. */ - public static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; + private static final String TARGET_SECTION_NAME = DW_STR_SECTION_NAME; @Override public String targetSectionName() { return TARGET_SECTION_NAME; } - public final LayoutDecision.Kind[] targetSectionKinds = { + private final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, }; 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 177b8643bc67..c45edbee9ddf 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 @@ -46,10 +46,10 @@ */ public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { protected DwarfSections dwarfSections; - public boolean debug = false; - public long debugTextBase = 0; - public long debugAddress = 0; - public int debugBase = 0; + protected boolean debug = false; + protected long debugTextBase = 0; + protected long debugAddress = 0; + protected int debugBase = 0; public DwarfSectionImpl(DwarfSections dwarfSections) { this.dwarfSections = dwarfSections; @@ -81,7 +81,7 @@ public boolean isLoadable() { return false; } - public String debugSectionLogName() { + private String debugSectionLogName() { /* * Use prefix dwarf plus the section name (which already includes a dot separator) for the * context key. For example messages for info section will be keyed using dwarf.debug_info. @@ -91,7 +91,7 @@ public String debugSectionLogName() { return "dwarf" + getSectionName(); } - public void enableLog(DebugContext context, int pos) { + protected void enableLog(DebugContext context, int pos) { /* * debug output is disabled during the first pass where we size the buffer. this is called * to enable it during the second pass where the buffer gets written, but only if the scope @@ -124,13 +124,13 @@ protected boolean littleEndian() { * base level put methods that assume a non-null buffer */ - public int putByte(byte b, byte[] buffer, int p) { + protected int putByte(byte b, byte[] buffer, int p) { int pos = p; buffer[pos++] = b; return pos; } - public int putShort(short s, byte[] buffer, int p) { + protected int putShort(short s, byte[] buffer, int p) { int pos = p; if (littleEndian()) { buffer[pos++] = (byte) (s & 0xff); @@ -142,7 +142,7 @@ public int putShort(short s, byte[] buffer, int p) { return pos; } - public int putInt(int i, byte[] buffer, int p) { + protected int putInt(int i, byte[] buffer, int p) { int pos = p; if (littleEndian()) { buffer[pos++] = (byte) (i & 0xff); @@ -158,7 +158,7 @@ public int putInt(int i, byte[] buffer, int p) { return pos; } - public int putLong(long l, byte[] buffer, int p) { + protected int putLong(long l, byte[] buffer, int p) { int pos = p; if (littleEndian()) { buffer[pos++] = (byte) (l & 0xff); @@ -182,7 +182,7 @@ public int putLong(long l, byte[] buffer, int p) { return pos; } - public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { + protected int putRelocatableCodeOffset(long l, byte[] buffer, int p) { int pos = p; /* * mark address so it is relocated relative to the start of the text segment @@ -192,7 +192,7 @@ public int putRelocatableCodeOffset(long l, byte[] buffer, int p) { return pos; } - public int putULEB(long val, byte[] buffer, int p) { + protected int putULEB(long val, byte[] buffer, int p) { long l = val; int pos = p; for (int i = 0; i < 9; i++) { @@ -210,7 +210,7 @@ public int putULEB(long val, byte[] buffer, int p) { return pos; } - public int putSLEB(long val, byte[] buffer, int p) { + protected int putSLEB(long val, byte[] buffer, int p) { long l = val; int pos = p; for (int i = 0; i < 9; i++) { @@ -229,11 +229,11 @@ public int putSLEB(long val, byte[] buffer, int p) { return pos; } - public int putAsciiStringBytes(String s, byte[] buffer, int pos) { + protected int putAsciiStringBytes(String s, byte[] buffer, int pos) { return putAsciiStringBytes(s, 0, buffer, pos); } - public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { + protected int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { int pos = p; for (int l = startChar; l < s.length(); l++) { char c = s.charAt(l); @@ -250,14 +250,14 @@ public int putAsciiStringBytes(String s, int startChar, byte[] buffer, int p) { * common write methods that check for a null buffer */ - public void patchLength(int lengthPos, byte[] buffer, int pos) { + protected void patchLength(int lengthPos, byte[] buffer, int pos) { if (buffer != null) { int length = pos - (lengthPos + 4); putInt(length, buffer, lengthPos); } } - public int writeAbbrevCode(long code, byte[] buffer, int pos) { + protected int writeAbbrevCode(long code, byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(code, scratch, 0); } else { @@ -265,7 +265,7 @@ public int writeAbbrevCode(long code, byte[] buffer, int pos) { } } - public int writeTag(long code, byte[] buffer, int pos) { + protected int writeTag(long code, byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(code, scratch, 0); } else { @@ -273,7 +273,7 @@ public int writeTag(long code, byte[] buffer, int pos) { } } - public int writeFlag(byte flag, byte[] buffer, int pos) { + protected int writeFlag(byte flag, byte[] buffer, int pos) { if (buffer == null) { return pos + putByte(flag, scratch, 0); } else { @@ -281,7 +281,7 @@ public int writeFlag(byte flag, byte[] buffer, int pos) { } } - public int writeAttrAddress(long address, byte[] buffer, int pos) { + protected int writeAttrAddress(long address, byte[] buffer, int pos) { if (buffer == null) { return pos + 8; } else { @@ -290,7 +290,7 @@ public int writeAttrAddress(long address, byte[] buffer, int pos) { } @SuppressWarnings("unused") - public int writeAttrData8(long value, byte[] buffer, int pos) { + protected int writeAttrData8(long value, byte[] buffer, int pos) { if (buffer == null) { return pos + putLong(value, scratch, 0); } else { @@ -298,7 +298,7 @@ public int writeAttrData8(long value, byte[] buffer, int pos) { } } - public int writeAttrData4(int value, byte[] buffer, int pos) { + protected int writeAttrData4(int value, byte[] buffer, int pos) { if (buffer == null) { return pos + putInt(value, scratch, 0); } else { @@ -306,7 +306,7 @@ public int writeAttrData4(int value, byte[] buffer, int pos) { } } - public int writeAttrData1(byte value, byte[] buffer, int pos) { + protected int writeAttrData1(byte value, byte[] buffer, int pos) { if (buffer == null) { return pos + putByte(value, scratch, 0); } else { @@ -314,7 +314,7 @@ public int writeAttrData1(byte value, byte[] buffer, int pos) { } } - public int writeAttrNull(byte[] buffer, int pos) { + protected int writeAttrNull(byte[] buffer, int pos) { if (buffer == null) { return pos + putSLEB(0, scratch, 0); } else { @@ -358,9 +358,7 @@ public byte[] getOrDecideContent(Map alre * we do this in a nested debug scope derived from the one set up under the object file * write */ - getOwner().debugContext(debugSectionLogName(), debugContext -> { - writeContent(debugContext); - }); + getOwner().debugContext(debugSectionLogName(), this::writeContent); return super.getOrDecideContent(alreadyDecided, contentHint); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 2a8a6ca0c098..68554c776bcf 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -273,29 +273,6 @@ public DwarfLineSectionImpl getLineSectionImpl() { */ private Map filesIndex = new HashMap<>(); - /** - * indirects this call to the string table. - * - * @param string the string to be inserted - * - * @return a unique equivalent String - */ - public String uniqueString(String string) { - return stringTable.uniqueString(string); - } - - /** - * indirects this call to the string table, ensuring the table entry is marked for inclusion in - * the debug_str section. - * - * @param string the string to be inserted and marked for inclusion in the debug_str section - * - * @return a unique equivalent String - */ - public String uniqueDebugString(String string) { - return stringTable.uniqueDebugString(string); - } - /** * indirects this call to the string table. * @@ -322,7 +299,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* * ensure we have a null string in the string section */ - uniqueDebugString(""); + stringTable.uniqueDebugString(""); debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> debugCodeInfo.debugContext((debugContext) -> { /* @@ -369,7 +346,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ } - public ClassEntry ensureClassEntry(Range range) { + private ClassEntry ensureClassEntry(Range range) { String className = range.getClassName(); /* * see if we already have an entry @@ -388,7 +365,7 @@ public ClassEntry ensureClassEntry(Range range) { return classEntry; } - public FileEntry ensureFileEntry(Range range) { + private FileEntry ensureFileEntry(Range range) { String fileName = range.getFileName(); if (fileName == null) { return null; @@ -416,13 +393,13 @@ public FileEntry ensureFileEntry(Range range) { return fileEntry; } - public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { + private void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); } - public void addSubRange(Range primaryRange, Range subrange) { + private void addSubRange(Range primaryRange, Range subrange) { assert primaryRange.isPrimary(); assert !subrange.isPrimary(); String className = primaryRange.getClassName(); @@ -437,7 +414,7 @@ public void addSubRange(Range primaryRange, Range subrange) { } } - public DirEntry ensureDirEntry(Path filePath) { + private DirEntry ensureDirEntry(Path filePath) { if (filePath == null) { return null; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 5f08ed8dbc2b..7b7c17c3a3b3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -81,7 +81,7 @@ public void writeContent(DebugContext context) { /** * debug_str section content depends on text section content and offset. */ - public static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; + private static final String TARGET_SECTION_NAME = TEXT_SECTION_NAME; @Override public String targetSectionName() { @@ -91,7 +91,7 @@ public String targetSectionName() { /** * debug_str section content depends on text section content and offset. */ - public final LayoutDecision.Kind[] targetSectionKinds = { + private final LayoutDecision.Kind[] targetSectionKinds = { LayoutDecision.Kind.CONTENT, LayoutDecision.Kind.OFFSET, /* add this so we can use the text section base address for debug */ From 0605bd8d9e6e3039c5a6516262250378fe02d249 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 26 Mar 2020 15:03:08 -0400 Subject: [PATCH 112/130] merge with adinn --- .../src/com/oracle/objectfile/ObjectFile.java | 57 +++- .../objectfile/debugentry/ClassEntry.java | 32 +- .../objectfile/debugentry/DirEntry.java | 14 +- .../objectfile/debugentry/FileEntry.java | 3 +- .../objectfile/debugentry/PrimaryEntry.java | 9 +- .../oracle/objectfile/debugentry/Range.java | 16 +- .../objectfile/debugentry/StringEntry.java | 8 +- .../objectfile/debugentry/StringTable.java | 41 ++- .../debuginfo/DebugInfoProvider.java | 86 ++--- .../objectfile/elf/ELFRelocationSection.java | 5 +- .../elf/dwarf/DwarfARangesSectionImpl.java | 68 ++-- .../elf/dwarf/DwarfAbbrevSectionImpl.java | 108 ++++--- .../elf/dwarf/DwarfFrameSectionImpl.java | 80 +++-- .../dwarf/DwarfFrameSectionImplAArch64.java | 17 +- .../dwarf/DwarfFrameSectionImplX86_64.java | 24 +- .../elf/dwarf/DwarfInfoSectionImpl.java | 127 ++++---- .../elf/dwarf/DwarfLineSectionImpl.java | 297 +++++++++--------- .../elf/dwarf/DwarfSectionImpl.java | 81 +++-- .../objectfile/elf/dwarf/DwarfSections.java | 197 ++++++------ .../elf/dwarf/DwarfStrSectionImpl.java | 19 +- 20 files changed, 695 insertions(+), 594 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index ede349881240..101f350c43ba 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -43,6 +43,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.function.Consumer; import java.util.stream.StreamSupport; import com.oracle.objectfile.debuginfo.DebugInfoProvider; @@ -51,6 +52,7 @@ import com.oracle.objectfile.pecoff.PECoffObjectFile; import sun.nio.ch.DirectBuffer; +import org.graalvm.compiler.debug.DebugContext; /** * Abstract superclass for object files. An object file is a binary container for sections, @@ -1098,10 +1100,11 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int } /** - * API method provided to allow a native image generator to provide details of - * types, code and heap data inserted into a native image. - * @param debugInfoProvider an implementation of the provider interface that - * communicates details of the relevant types, code and heap data. + * API method provided to allow a native image generator to provide details of types, code and + * heap data inserted into a native image. + * + * @param debugInfoProvider an implementation of the provider interface that communicates + * details of the relevant types, code and heap data. */ public void installDebugInfo(@SuppressWarnings("unused") DebugInfoProvider debugInfoProvider) { // do nothing by default @@ -1746,4 +1749,50 @@ public final SymbolTable getOrCreateSymbolTable() { return createSymbolTable(); } } + + /** + * Temporary storage for a debug context installed in a nested scope under a call. to + * {@link #withDebugContext} + */ + private DebugContext debugContext = null; + + /** + * Allows a task to be executed with a debug context in a named subscope bound to the object + * file and accessible to code executed during the lifetime of the task. Invoked code may obtain + * access to the debug context using method {@link #debugContext}. + * + * @param context a context to be bound to the object file for the duration of the task + * execution. + * @param scopeName a name to be used to define a subscope current while the task is being + * executed. + * @param task a task to be executed while the context is bound to the object file. + */ + @SuppressWarnings("try") + public void withDebugContext(DebugContext context, String scopeName, Runnable task) { + try (DebugContext.Scope s = context.scope(scopeName)) { + this.debugContext = context; + task.run(); + } catch (Throwable e) { + throw debugContext.handle(e); + } finally { + debugContext = null; + } + } + + /** + * Allows a consumer to retrieve the debug context currently bound to this object file. This + * method must only called underneath an invocation of method {@link #withDebugContext}. + * + * @param scopeName a name to be used to define a subscope current while the consumer is active. + * @param action an action parameterised by the debug context. + */ + @SuppressWarnings("try") + public void debugContext(String scopeName, Consumer action) { + assert debugContext != null; + try (DebugContext.Scope s = debugContext.scope(scopeName)) { + action.accept(debugContext); + } catch (Throwable e) { + throw debugContext.handle(e); + } + } } 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 b1a9cf22a1ee..a4535472284f 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 @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 @@ -37,28 +37,25 @@ * track debug info associated with a Java class. */ public class ClassEntry { - /** + /** * the name of the associated class. - */ + */ private String className; /** * details of the associated file. */ FileEntry fileEntry; /** - * a list recording details of all primary - * ranges included in this class sorted by - * ascending address range. + * a list recording details of all primary ranges included in this class sorted by ascending + * address range. */ private LinkedList primaryEntries; /** - * an index identifying primary ranges which - * have already been encountered. + * an index identifying primary ranges which have already been encountered. */ private Map primaryIndex; /** - * an index of all primary and secondary files - * referenced from this class's compilation unit. + * an index of all primary and secondary files referenced from this class's compilation unit. */ private Map localFilesIndex; /** @@ -66,8 +63,7 @@ public class ClassEntry { */ private LinkedList localFiles; /** - * an index of all primary and secondary dirs - * referenced from this class's compilation unit. + * an index of all primary and secondary dirs referenced from this class's compilation unit. */ private HashMap localDirsIndex; /** @@ -75,23 +71,19 @@ public class ClassEntry { */ private LinkedList localDirs; /** - * index of debug_info section compilation unit - * for this class. + * index of debug_info section compilation unit for this class. */ private int cuIndex; /** - * index into debug_line section for associated - * compilation unit. + * index into debug_line section for associated compilation unit. */ private int lineIndex; /** - * size of line number info prologue region for - * associated compilation unit. + * size of line number info prologue region for associated compilation unit. */ private int linePrologueSize; /** - * total size of line number info region for - * associated compilation unit. + * total size of line number info region for associated compilation unit. */ private int totalSize; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java index c5f6fa045c67..034653171103 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/DirEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 @@ -29,15 +29,11 @@ import java.nio.file.Path; /** - * Tracks the directory associated with one or - * more source files. + * Tracks the directory associated with one or more source files. * - * This is identified separately from each FileEntry - * idenityfing files that reside in the directory. - * That is necessary because the line info generator - * needs to collect and write out directory names - * into directory tables once only rather than once - * per file. + * This is identified separately from each FileEntry idenityfing files that reside in the directory. + * That is necessary because the line info generator needs to collect and write out directory names + * into directory tables once only rather than once per file. */ public class DirEntry { private Path path; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java index 04126352885e..4cad616912d7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/FileEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 @@ -52,6 +52,7 @@ public String getPathName() { public String getFullName() { return getDirEntry().getPath().resolve(getFileName()).toString(); } + /** * The directory entry associated with this file entry. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java index 93696d7f8889..6f789f44fdc3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/PrimaryEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, Red Hat Inc. 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 @@ -33,8 +33,7 @@ import java.util.List; /** - * Tracks debug info associated with a primary method. - * i.e. a top level compiled method + * Tracks debug info associated with a primary method. i.e. a top level compiled method */ public class PrimaryEntry { /** @@ -61,6 +60,7 @@ public class PrimaryEntry { * Size of compiled method frame. */ private int frameSize; + public PrimaryEntry(Range primary, List frameSizeInfos, int frameSize, ClassEntry classEntry) { this.primary = primary; this.classEntry = classEntry; @@ -77,8 +77,7 @@ public void addSubRange(Range subrange, FileEntry subFileEntry) { assert !subranges.contains(subrange); assert subrangeIndex.get(subrange) == null; /* - * we need to generate a file table entry - * for all ranges + * we need to generate a file table entry for all ranges */ subranges.add(subrange); subrangeIndex.put(subrange, subFileEntry); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index f5e87b74d822..58a0988d0eb3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Red Hat, Inc. 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 @@ -28,11 +28,11 @@ import java.nio.file.Path; import java.nio.file.Paths; + /** - * Details of a specific address range in a compiled method - * either a primary range identifying a whole method - * or a sub-range identifying a sequence of - * instructions that belong to an inlined method. + * Details of a specific address range in a compiled method either a primary range identifying a + * whole method or a sub-range identifying a sequence of instructions that belong to an inlined + * method. */ public class Range { @@ -67,11 +67,11 @@ public Range(String fileName, Path filePath, String className, String methodName */ public Range(String fileName, Path filePath, String className, String methodName, String paramNames, String returnTypeName, StringTable stringTable, int lo, int hi, int line, Range primary) { /* - * currently file name and full method name need to go into the debug_str section - * other strings just need to be deduplicated to save space + * currently file name and full method name need to go into the debug_str section other + * strings just need to be deduplicated to save space */ this.fileName = (fileName == null ? fileName : stringTable.uniqueDebugString(fileName)); - this.filePath = filePath; + this.filePath = filePath; this.className = stringTable.uniqueString(className); this.methodName = stringTable.uniqueString(methodName); this.paramNames = stringTable.uniqueString(paramNames); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java index d1ebb16be685..ff754ad86444 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Red Hat, Inc. 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 @@ -27,10 +27,8 @@ package com.oracle.objectfile.debugentry; /** - * Used to retain a unique (up to equals) copy of a - * String. Also flag swhether the String needs to be - * located in the debug_string section and, if so, - * tracks the offset at which it gets written. + * Used to retain a unique (up to equals) copy of a String. Also flags whether the String needs to + * be located in the debug_string section and, if so, tracks the offset at which it gets written. */ public class StringEntry { private String string; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java index 721c77940ee5..d33a0104f18a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/StringTable.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020 Red Hat, Inc. 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 @@ -30,10 +30,9 @@ import java.util.Iterator; /** - * Allows incoming strings to be reduced to unique (up - * to equals) instances and supports marking of strings - * which need to be written to the debug_str section - * and retrieval of the location offset after writing. + * Allows incoming strings to be reduced to unique (up to equals) instances and supports marking of + * strings which need to be written to the debug_str section and retrieval of the location offset + * after writing. */ public class StringTable implements Iterable { @@ -44,10 +43,10 @@ public StringTable() { } /** - * Ensures a unique instance of a string exists in the - * table, inserting the supplied String if no equivalent - * String is already present. This should only be called - * before the string section has been written. + * Ensures a unique instance of a string exists in the table, inserting the supplied String if + * no equivalent String is already present. This should only be called before the string section + * has been written. + * * @param string the string to be included in the table * @return the unique instance of the String */ @@ -56,13 +55,12 @@ public String uniqueString(String string) { } /** - * Ensures a unique instance of a string exists in the - * table and is marked for inclusion in the debug_str - * section, inserting the supplied String if no equivalent - * String is already present. This should only be called - * before the string section has been written. - * @param string the string to be included in the table - * and marked for inclusion in the debug_str section + * Ensures a unique instance of a string exists in the table and is marked for inclusion in the + * debug_str section, inserting the supplied String if no equivalent String is already present. + * This should only be called before the string section has been written. + * + * @param string the string to be included in the table and marked for inclusion in the + * debug_str section * @return the unique instance of the String */ public String uniqueDebugString(String string) { @@ -82,13 +80,12 @@ private String ensureString(String string, boolean addToStrSection) { } /** - * Retrieves the offset at which a given string was written - * into the debug_str section. This should only be called - * after the string section has been written. + * Retrieves the offset at which a given string was written into the debug_str section. This + * should only be called after the string section has been written. + * * @param string - * @return the offset or -1 if the string does not - * define an entry or the entry has nto been written - * to the debug_str section + * @return the offset or -1 if the string does not define an entry or the entry has not been + * written to the debug_str section */ public int debugStringIndex(String string) { StringEntry stringEntry = table.get(string); 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 444be49613ac..39963c73310b 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 @@ -28,13 +28,14 @@ import java.nio.file.Path; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Stream; +import org.graalvm.compiler.debug.DebugContext; + /** - * interfaces used to allow a native image to communicate - * details of types, code and data to the underlying - * object file so that the latter can insert appropriate - * debug info. + * Interfaces used to allow a native image to communicate details of types, code and data to the + * underlying object file so that the latter can insert appropriate debug info. */ public interface DebugInfoProvider { /** @@ -47,62 +48,70 @@ interface DebugTypeInfo { * access details of a specific compiled method. */ interface DebugCodeInfo { + void debugContext(Consumer action); + /** - * @return the name of the file containing a compiled - * method excluding any path + * @return the name of the file containing a compiled method excluding any path */ String fileName(); + /** - * @return a relative path to the file containing a compiled - * method derived from its package name or null if the method - * is in the empty package + * @return a relative path to the file containing a compiled method derived from its package + * name or null if the method is in the empty package */ Path filePath(); + /** - * @return the fully qualified name of the class owning the - * compiled method + * @return the fully qualified name of the class owning the compiled method */ String className(); + /** - * @return the name of the compiled method including - * signature + * @return the name of the compiled method including signature */ String methodName(); + /** - * @return the lowest address containing code generated for - * the method represented as an offset into the code segment + * @return the lowest address containing code generated for the method represented as an + * offset into the code segment */ int addressLo(); + /** - * @return the first address above the code generated for - * the method represented as an offset into the code segment + * @return the first address above the code generated for the method represented as an + * offset into the code segment */ int addressHi(); + /** * @return the starting line number for the method */ int line(); + /** - * @return a stream of records detailing line numbers - * and addresses within the compiled method + * @return a stream of records detailing line numbers and addresses within the compiled + * method */ Stream lineInfoProvider(); + /** * @return a string identifying the method parameters */ String paramNames(); + /** * @return a string identifying the method return type */ String returnTypeName(); + /** - * @return the size of the method frame between prologue - * and epilogue + * @return the size of the method frame between prologue and epilogue */ int getFrameSize(); + /** - * @return a list of positions at which the stack is extended - * to a full frame or torn down to an empty frame + * @return a list of positions at which the stack is extended to a full frame or torn down + * to an empty frame */ List getFrameSizeChanges(); } @@ -114,42 +123,43 @@ interface DebugDataInfo { } /** - * access details of code generated for a specific outer - * or inlined method at a given line number. + * access details of code generated for a specific outer or inlined method at a given line + * number. */ interface DebugLineInfo { /** - * @return the name of the file containing the outer - * or inlined method excluding any path + * @return the name of the file containing the outer or inlined method excluding any path */ String fileName(); + /** - * @return a relative path to the file containing the outer - * or inlined method derived from its package name or null - * if the method is in the empty package + * @return a relative path to the file containing the outer or inlined method derived from + * its package name or null if the method is in the empty package */ Path filePath(); + /** - * @return the fully qualified name of the class owning the - * outer or inlined method + * @return the fully qualified name of the class owning the outer or inlined method */ String className(); + /** * @return the name of the outer or inlined method including signature */ String methodName(); + /** - * @return the lowest address containing code generated for - * an outer or inlined code segment reported at this line - * represented as an offset into the code segment + * @return the lowest address containing code generated for an outer or inlined code segment + * reported at this line represented as an offset into the code segment */ int addressLo(); + /** - * @return the first address above the code generated for - * an outer or inlined code segment reported at this line - * represented as an offset into the code segment + * @return the first address above the code generated for an outer or inlined code segment + * reported at this line represented as an offset into the code segment */ int addressHi(); + /** * @return the line number for the outer or inlined segment */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java index 7826a6a786ba..8aa18d5344f4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/ELFRelocationSection.java @@ -240,10 +240,9 @@ public Iterable getDependencies(Map // our content depends on the content of the section being relocated // (because entries only get registered during generation) if (relocated != null) { - LayoutDecision relocatedSectionContent = - decisions.get(relocated).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision relocatedSectionContent = decisions.get(relocated).getDecision(LayoutDecision.Kind.CONTENT); deps.add(BuildDependency.createOrGet(ourContent, - relocatedSectionContent)); + relocatedSectionContent)); } if (isDynamic()) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java index c20e9b27af0a..81451823b808 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfARangesSectionImpl.java @@ -32,6 +32,7 @@ import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import org.graalvm.compiler.debug.DebugContext; import java.util.LinkedList; import java.util.Map; @@ -39,6 +40,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ARANGES_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; + /** * Section generator for debug_aranges section. */ @@ -61,25 +63,39 @@ public void createContent() { /* * we need an entry for each compilation unit * - * uint32 length ............ in bytes (not counting these 4 bytes) - * uint16 dwarf_version ..... always 2 - * uint32 info_offset ....... offset of compilation unit on debug_info - * uint8 address_size ....... always 8 - * uint8 segment_desc_size .. ??? + *
        + * + *
      • uint32 length ............ in bytes (not counting these 4 bytes) + * + *
      • uint16 dwarf_version ..... always 2 + * + *
      • uint32 info_offset ....... offset of compilation unit on debug_info + * + *
      • uint8 address_size ....... always 8 + * + *
      • uint8 segment_desc_size .. ??? + * + *
      * - * i.e. 12 bytes followed by padding - * aligning up to 2 * address size + * i.e. 12 bytes followed by padding aligning up to 2 * address size * - * uint8 pad[4] + *
        + * + *
      • uint8 pad[4] + * + *
      * * followed by N + 1 times * - * uint64 lo ................ lo address of range - * uint64 length ............ number of bytes in range + *
      • uint64 lo ................ lo address of range + * + *
      • uint64 length ............ number of bytes in range + * + *
      * - * where N is the number of ranges belonging to the compilation unit - * and the last range contains two zeroes - */ + * where N is the number of ranges belonging to the compilation unit and the last range + * contains two zeroes + */ for (ClassEntry classEntry : getPrimaryClasses()) { pos += DW_AR_HEADER_SIZE; @@ -102,9 +118,8 @@ public byte[] getOrDecideContent(Map alre Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { /* - * this may not be the final vaddr for the text segment - * but it will be close enough to make debug easier - * i.e. to within a 4k page or two + * this may not be the final vaddr for the text segment but it will be close enough + * to make debug easier i.e. to within a 4k page or two */ debugTextBase = ((Number) valueObj).longValue(); } @@ -113,14 +128,14 @@ public byte[] getOrDecideContent(Map alre } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); - debug(" [0x%08x] DEBUG_ARANGES\n", pos); + log(context, " [0x%08x] DEBUG_ARANGES", pos); for (ClassEntry classEntry : getPrimaryClasses()) { int lastpos = pos; int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4; @@ -131,7 +146,7 @@ public void writeContent() { */ length += classPrimaryEntries.size() * 2 * 8; length += 2 * 8; - debug(" [0x%08x] %s CU %d length 0x%x\n", pos, classEntry.getFileName(), cuIndex, length); + log(context, " [0x%08x] %s CU %d length 0x%x", pos, classEntry.getFileName(), cuIndex, length); pos = putInt(length, buffer, pos); /* dwarf version is always 2 */ pos = putShort(DW_VERSION_2, buffer, pos); @@ -147,10 +162,10 @@ public void writeContent() { for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) { pos = putByte((byte) 0, buffer, pos); } - debug(" [0x%08x] Address Length Name\n", pos); + log(context, " [0x%08x] Address Length Name", pos); for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) { Range primary = classPrimaryEntry.getPrimary(); - debug(" [0x%08x] %016x %016x %s\n", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); + log(context, " [0x%08x] %016x %016x %s", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName()); pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos); pos = putLong(primary.getHi() - primary.getLo(), buffer, pos); } @@ -161,11 +176,6 @@ public void writeContent() { assert pos == size; } - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /* * debug_aranges section content depends on debug_info section content and offset */ @@ -177,8 +187,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override 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 c8f97729dd95..854d3c0e399b 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 @@ -27,6 +27,7 @@ package com.oracle.objectfile.elf.dwarf; import com.oracle.objectfile.LayoutDecision; +import org.graalvm.compiler.debug.DebugContext; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_compile_unit; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_ABBREV_CODE_subprogram; @@ -68,64 +69,90 @@ public String getSectionName() { public void createContent() { int pos = 0; /* - * an abbrev table contains abbrev entries for one or - * more CUs. the table includes a sequence of abbrev - * entries each of which defines a specific DIE layout - * employed to describe some DIE in a CU. a table is - * terminated by a null entry + * an abbrev table contains abbrev entries for one or more CUs. the table includes a + * sequence of abbrev entries each of which defines a specific DIE layout employed to + * describe some DIE in a CU. a table is terminated by a null entry * * a null entry has consists of just a 0 abbrev code - * LEB128 abbrev_code; ...... == 0 + * + *
        + * + *
      • LEB128 abbrev_code; ...... == 0 + * + *
      * * non-null entries have the following format - * LEB128 abbrev_code; ...... unique noncode for this layout != 0 - * 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 DIE - * * ........ zero or more attributes - * .... terminator + * + *
        + * + *
      • LEB128 abbrev_code; ......unique noncode for this layout != 0 + * + *
      • 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 + * DIE + * + *
      • attribute_spec* .......... zero or more attributes + * + *
      • null_attribute_spec ...... terminator
      * * An attribute_spec consists of an attribute name and form - * LEB128 attr_name; ........ 0 for the null attribute name - * LEB128 attr_form; ........ 0 for the null attribute form * - * For the moment we only use one abbrev table for all CUs. - * It contains two DIEs, the first to describe the compilation - * unit itself and the second to describe each method within + *
        + * + *
      • LEB128 attr_name; ........ 0 for the null attribute name + * + *
      • LEB128 attr_form; ........ 0 for the null attribute form + * + *
      + * + * For the moment we only use one abbrev table for all CUs. It contains two DIEs, the first + * to describe the compilation unit itself and the second to describe each method within * that compilation unit. * * The DIE layouts are as follows: * - * abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children - * DW_AT_language : ... DW_FORM_data1 - * DW_AT_name : ....... DW_FORM_strp - * DW_AT_low_pc : ..... DW_FORM_address - * DW_AT_hi_pc : ...... DW_FORM_address - * DW_AT_stmt_list : .. DW_FORM_data4 - * - * abbrev_code == 2, tag == DW_TAG_subprogram, no_children - * DW_AT_name : ....... DW_FORM_strp - * DW_AT_low_pc : ..... DW_FORM_addr - * DW_AT_hi_pc : ...... DW_FORM_addr - * DW_AT_external : ... DW_FORM_flag + *
      • abbrev_code == 1, tag == DW_TAG_compilation_unit, has_children + * + *
      • DW_AT_language : ... DW_FORM_data1 + * + *
      • DW_AT_name : ....... DW_FORM_strp + * + *
      • DW_AT_low_pc : ..... DW_FORM_address + * + *
      • DW_AT_hi_pc : ...... DW_FORM_address + * + *
      • DW_AT_stmt_list : .. DW_FORM_data4
      + * + *
      • abbrev_code == 2, tag == DW_TAG_subprogram, no_children + * + *
      • DW_AT_name : ....... DW_FORM_strp + * + *
      • DW_AT_hi_pc : ...... DW_FORM_addr + * + *
      • DW_AT_external : ... DW_FORM_flag + * + *
      */ - pos = writeAbbrev1(null, pos); - pos = writeAbbrev2(null, pos); + pos = writeAbbrev1(null, null, pos); + pos = writeAbbrev2(null, null, pos); byte[] buffer = new byte[pos]; super.setContent(buffer); } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); - pos = writeAbbrev1(buffer, pos); - pos = writeAbbrev2(buffer, pos); + pos = writeAbbrev1(context, buffer, pos); + pos = writeAbbrev2(context, buffer, pos); assert pos == size; } @@ -145,7 +172,7 @@ public int writeAttrForm(long code, byte[] buffer, int pos) { } } - public int writeAbbrev1(byte[] buffer, int p) { + public int writeAbbrev1(DebugContext context, byte[] buffer, int p) { int pos = p; /* * abbrev 1 compile unit @@ -171,7 +198,7 @@ public int writeAbbrev1(byte[] buffer, int p) { return pos; } - public int writeAbbrev2(byte[] buffer, int p) { + public int writeAbbrev2(DebugContext context, byte[] buffer, int p) { int pos = p; /* * abbrev 2 compile unit @@ -195,11 +222,6 @@ public int writeAbbrev2(byte[] buffer, int p) { return pos; } - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /** * debug_abbrev section content depends on debug_frame section content and offset. */ @@ -211,8 +233,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java index d8d7ad23af74..1865ee29c5ec 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImpl.java @@ -25,10 +25,12 @@ */ package com.oracle.objectfile.elf.dwarf; + import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debuginfo.DebugInfoProvider; +import org.graalvm.compiler.debug.DebugContext; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_id; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_CIE_version; @@ -43,6 +45,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_CFA_register; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_FRAME_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; + /** * Section generic generator for debug_frame section. */ @@ -62,8 +65,7 @@ public void createContent() { int pos = 0; /* - * the frame section contains one CIE at offset 0 - * followed by an FIE for each method + * the frame section contains one CIE at offset 0 followed by an FIE for each method */ pos = writeCIE(null, pos); pos = writeMethodFrames(null, pos); @@ -73,18 +75,17 @@ public void createContent() { } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); /* - * there are entries for the prologue region where the - * stack is being built, the method body region(s) where - * the code executes with a fixed size frame and the - * epilogue region(s) where the stack is torn down + * there are entries for the prologue region where the stack is being built, the method body + * region(s) where the code executes with a fixed size frame and the epilogue region(s) + * where the stack is torn down */ pos = writeCIE(buffer, pos); pos = writeMethodFrames(buffer, pos); @@ -97,18 +98,28 @@ public void writeContent() { public int writeCIE(byte[] buffer, int p) { /* - * we only need a vanilla CIE with default fields - * because we have to have at least one - * the layout is + * we only need a vanilla CIE with default fields because we have to have at least one the + * layout is + * + *
        + * + *
      • uint32 : length ............... length of remaining fields in this CIE + * + *
      • uint32 : CIE_id ................ unique id for CIE == 0xffffff + * + *
      • uint8 : version ................ == 1 + * + *
      • uint8[] : augmentation ......... == "" so always 1 byte + * + *
      • ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) + * + *
      • ULEB : data_alignment_factor ... == -8 + * + *
      • byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 * - * uint32 : length ............... length of remaining fields in this CIE - * uint32 : CIE_id ................ unique id for CIE == 0xffffff - * uint8 : version ................ == 1 - * uint8[] : augmentation ......... == "" so always 1 byte - * ULEB : code_alignment_factor ... == 1 (could use 4 for Aarch64) - * ULEB : data_alignment_factor ... == -8 - * byte : ret_addr reg id ......... x86_64 => 16 AArch64 => 32 - * byte[] : initial_instructions .. includes pad to 8-byte boundary + *
      • byte[] : initial_instructions .. includes pad to 8-byte boundary + * + *
      */ int pos = p; if (buffer == null) { @@ -188,14 +199,22 @@ public int writeMethodFrames(byte[] buffer, int p) { public int writeFDEHeader(int lo, int hi, byte[] buffer, int p) { /* - * we only need a vanilla FDE header with default fields - * the layout is + * we only need a vanilla FDE header with default fields the layout is + * + *
        + * + *
      • uint32 : length ............ length of remaining fields in this FDE + * + *
      • uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE + * header + * + *
      • uint64 : initial_location .. i.e. method lo address * - * uint32 : length ........... length of remaining fields in this FDE - * uint32 : CIE_offset ........ always 0 i.e. identifies our only CIE header - * uint64 : initial_location .. i.e. method lo address - * uint64 : address_range ..... i.e. method hi - lo - * byte[] : instructions ...... includes pad to 8-byte boundary + *
      • uint64 : address_range ..... i.e. method hi - lo + * + *
      • byte[] : instructions ...... includes pad to 8-byte boundary + * + *
      */ int pos = p; @@ -345,11 +364,6 @@ public int writeRegister(int savedReg, int savedToReg, byte[] buffer, int p) { public abstract int writeInitialInstructions(byte[] buffer, int pos); - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /** * debug_frame section content depends on debug_line section content and offset. */ @@ -361,8 +375,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java index 8f4ab1818ec4..89268fd72b7c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplAArch64.java @@ -27,11 +27,11 @@ package com.oracle.objectfile.elf.dwarf; /** - * AArch64-specific section generator for debug_frame section - * that knows details of AArch64 registers and frame layout. + * AArch64-specific section generator for debug_frame section that knows details of AArch64 + * registers and frame layout. */ public class DwarfFrameSectionImplAArch64 extends DwarfFrameSectionImpl { - public static final int DW_CFA_FP_IDX = 29; + // public static final int DW_CFA_FP_IDX = 29; public static final int DW_CFA_LR_IDX = 30; public static final int DW_CFA_SP_IDX = 31; public static final int DW_CFA_PC_IDX = 32; @@ -54,12 +54,15 @@ public int getSPIdx() { public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; /* - * rsp has not been updated - * caller pc is in lr - * register r32 (rpc), r30 (lr) + * rsp has not been updated and caller pc is in lr + * + *
        + * + *
      • register r32 (rpc), r30 (lr) + * + *
      */ pos = writeRegister(DW_CFA_PC_IDX, DW_CFA_LR_IDX, buffer, pos); return pos; } } - diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java index 7fabf34ad449..275c4ca00a32 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfFrameSectionImplX86_64.java @@ -27,8 +27,8 @@ package com.oracle.objectfile.elf.dwarf; /** - * x86_64-specific section generator for debug_frame section - * that knows details of x86_64 registers and frame layout. + * x86_64-specific section generator for debug_frame section that knows details of x86_64 registers + * and frame layout. */ public class DwarfFrameSectionImplX86_64 extends DwarfFrameSectionImpl { public static final int DW_CFA_RSP_IDX = 7; @@ -52,15 +52,23 @@ public int getSPIdx() { public int writeInitialInstructions(byte[] buffer, int p) { int pos = p; /* - * rsp points at the word containing the saved rip - * so the frame base (cfa) is at rsp + 8 (why not - ???) - * def_cfa r7 (sp) offset 8 + * rsp points at the word containing the saved rip so the frame base (cfa) is at rsp + 8 + * (why not - ???) + * + *
        + * + *
      • def_cfa r7 (sp) offset 8 + * + *
      */ pos = writeDefCFA(DW_CFA_RSP_IDX, 8, buffer, pos); /* - * and rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa - * (why not -1 ???) - * offset r16 (rip) cfa - 8 + * rip is saved at offset 8 (coded as 1 which gets scaled by dataAlignment) from cfa (why + * not -1 ???) + * + *
      • offset r16 (rip) cfa - 8 + * + *
      */ pos = writeOffset(DW_CFA_RIP_IDX, 1, buffer, pos); return pos; 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 025450fca2de..a3c5e6eac356 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 @@ -30,6 +30,7 @@ import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import org.graalvm.compiler.debug.DebugContext; import java.util.LinkedList; @@ -40,6 +41,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_INFO_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LANG_Java; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; + /** * Section generator for debug_info section. */ @@ -61,30 +63,52 @@ public String getSectionName() { @Override public void createContent() { /* - * we need a single level 0 DIE for each compilation unit (CU) - * Each CU's Level 0 DIE is preceded by a fixed header: - * and terminated by a null DIE - * uint32 length ......... excluding this length field - * uint16 dwarf_version .. always 2 ?? - * uint32 abbrev offset .. always 0 ?? - * uint8 address_size .... always 8 - * * ................ sequence of top-level and nested child entries - * ............ == 0 - * - * a DIE is a recursively defined structure - * it starts with a code for the associated - * abbrev entry followed by a series of attribute - * values as determined by the entry terminated by - * a null value and followed by zero or more child - * DIEs (zero iff has_children == no_children) - * - * LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of DIE - * * ....... value sequence as determined by abbrev entry - * * ................... sequence of child DIEs (if appropriate) - * ............. == 0 + * we need a single level 0 DIE for each compilation unit (CU). Each CU's Level 0 DIE is + * preceded by a fixed header and terminated by a null DIE: + * + *
        + * + *
      • uint32 length ......... excluding this length field + * + *
      • uint16 dwarf_version .. always 2 ?? + * + *
      • uint32 abbrev offset .. always 0 ?? + * + *
      • uint8 address_size .... always 8 + * + *
      • DIE* .................. sequence of top-level and nested child entries + * + *
      • null_DIE .............. == 0 + * + *
      + * + * a DIE is a recursively defined structure. it starts with a code for the associated abbrev + * entry followed by a series of attribute values, as determined by the entry, terminated by + * a null value and followed by zero or more child DIEs (zero iff has_children == + * no_children). + * + *
        + * + *
      • LEB128 abbrev_code != 0 .. non-zero value indexes tag + attr layout of + * DIE + * + *
      • attribute_value* ......... value sequence as determined by abbrev entry + * + *
      • DIE* ..................... sequence of child DIEs (if appropriate) + *
      • + * + *
      • null_value ............... == 0 + * + *
      * * note that a null_DIE looks like - * LEB128 abbrev_code ....... == 0 + * + *
        + * + *
      • LEB128 abbrev_code ....... == 0 + * + *
      + * * i.e. it also looks like a null_value */ @@ -95,7 +119,7 @@ public void createContent() { int lengthPos = pos; pos = writeCUHeader(buffer, pos); assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); + pos = writeCU(null, classEntry, buffer, pos); /* * no need to backpatch length at lengthPos */ @@ -105,26 +129,25 @@ public void createContent() { } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); - debug(" [0x%08x] DEBUG_INFO\n", pos); - debug(" [0x%08x] size = 0x%08x\n", pos, size); + log(context, " [0x%08x] DEBUG_INFO", pos); + log(context, " [0x%08x] size = 0x%08x", pos, size); for (ClassEntry classEntry : getPrimaryClasses()) { /* - * save the offset of this file's CU so it can - * be used when writing the aranges section + * save the offset of this file's CU so it can be used when writing the aranges section */ classEntry.setCUIndex(pos); int lengthPos = pos; pos = writeCUHeader(buffer, pos); - debug(" [0x%08x] Compilation Unit\n", pos, size); + log(context, " [0x%08x] Compilation Unit", pos, size); assert pos == lengthPos + DW_DIE_HEADER_SIZE; - pos = writeCU(classEntry, buffer, pos); + pos = writeCU(context, classEntry, buffer, pos); /* * backpatch length at lengthPos (excluding length field) */ @@ -156,23 +179,23 @@ public int writeCUHeader(byte[] buffer, int p) { } } - public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { + public int writeCU(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; LinkedList classPrimaryEntries = classEntry.getPrimaryEntries(); - debug(" [0x%08x] <0> Abbrev Number %d\n", pos, DW_ABBREV_CODE_compile_unit); + log(context, " [0x%08x] <0> Abbrev Number %d", pos, DW_ABBREV_CODE_compile_unit); pos = writeAbbrevCode(DW_ABBREV_CODE_compile_unit, buffer, pos); - debug(" [0x%08x] language %s\n", pos, "DW_LANG_Java"); + log(context, " [0x%08x] language %s", pos, "DW_LANG_Java"); pos = writeAttrData1(DW_LANG_Java, buffer, pos); - debug(" [0x%08x] name 0x%x (%s)\n", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); + log(context, " [0x%08x] name 0x%x (%s)", pos, debugStringIndex(classEntry.getFileName()), classEntry.getFileName()); pos = writeAttrStrp(classEntry.getFileName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); + log(context, " [0x%08x] lo_pc 0x%08x", pos, classPrimaryEntries.getFirst().getPrimary().getLo()); pos = writeAttrAddress(classPrimaryEntries.getFirst().getPrimary().getLo(), buffer, pos); - debug(" [0x%08x] hi_pc 0x%08x\n", pos, classPrimaryEntries.getLast().getPrimary().getHi()); + log(context, " [0x%08x] hi_pc 0x%08x", pos, classPrimaryEntries.getLast().getPrimary().getHi()); pos = writeAttrAddress(classPrimaryEntries.getLast().getPrimary().getHi(), buffer, pos); - debug(" [0x%08x] stmt_list 0x%08x\n", pos, classEntry.getLineIndex()); + log(context, " [0x%08x] stmt_list 0x%08x", pos, classEntry.getLineIndex()); pos = writeAttrData4(classEntry.getLineIndex(), buffer, pos); for (PrimaryEntry primaryEntry : classPrimaryEntries) { - pos = writePrimary(primaryEntry, buffer, pos); + pos = writePrimary(context, primaryEntry, buffer, pos); } /* * write a terminating null attribute for the the level 2 primaries @@ -181,21 +204,21 @@ public int writeCU(ClassEntry classEntry, byte[] buffer, int p) { } - public int writePrimary(PrimaryEntry primaryEntry, byte[] buffer, int p) { + public int writePrimary(DebugContext context, PrimaryEntry primaryEntry, byte[] buffer, int p) { int pos = p; Range primary = primaryEntry.getPrimary(); - debug(" [0x%08x] <1> Abbrev Number %d\n", pos, DW_ABBREV_CODE_subprogram); + verboseLog(context, " [0x%08x] <1> Abbrev Number %d", pos, DW_ABBREV_CODE_subprogram); pos = writeAbbrevCode(DW_ABBREV_CODE_subprogram, buffer, pos); - debug(" [0x%08x] name 0x%X (%s)\n", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); + verboseLog(context, " [0x%08x] name 0x%X (%s)", pos, debugStringIndex(primary.getFullMethodName()), primary.getFullMethodName()); pos = writeAttrStrp(primary.getFullMethodName(), buffer, pos); - debug(" [0x%08x] low_pc 0x%08x\n", pos, primary.getLo()); + verboseLog(context, " [0x%08x] lo_pc 0x%08x", pos, primary.getLo()); pos = writeAttrAddress(primary.getLo(), buffer, pos); - debug(" [0x%08x] high_pc 0x%08x\n", pos, primary.getHi()); + verboseLog(context, " [0x%08x] hi_pc 0x%08x", pos, primary.getHi()); pos = writeAttrAddress(primary.getHi(), buffer, pos); /* * need to pass true only if method is public */ - debug(" [0x%08x] external true\n", pos); + verboseLog(context, " [0x%08x] external true", pos); return writeFlag(DW_FLAG_true, buffer, pos); } @@ -218,15 +241,6 @@ public int writeAttrString(String value, byte[] buffer, int p) { } } - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - /** * debug_info section content depends on abbrev section content and offset. */ @@ -238,8 +252,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET }; @Override @@ -247,4 +261,3 @@ public LayoutDecision.Kind[] targetSectionKinds() { return targetSectionKinds; } } - diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java index 97818d1f280e..d6e7c48717e5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfLineSectionImpl.java @@ -34,12 +34,14 @@ import com.oracle.objectfile.debugentry.FileEntry; import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; +import org.graalvm.compiler.debug.DebugContext; import java.util.Map; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_LINE_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_VERSION_2; + /** * Section generator for debug_line section. */ @@ -53,13 +55,11 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final int DW_LN_LINE_BASE = -5; /** - * current generator follows C++ with line range 14 - * giving full range -5 to 8. + * current generator follows C++ with line range 14 giving full range -5 to 8. */ private static final int DW_LN_LINE_RANGE = 14; /** - * current generator uses opcode base of 13 - * which must equal DW_LNS_define_file + 1. + * current generator uses opcode base of 13 which must equal DW_LNS_define_file + 1. */ private static final int DW_LN_OPCODE_BASE = 13; @@ -67,15 +67,15 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { * standard opcodes defined by Dwarf 2 */ /* - * 0 can be returned to indicate an invalid opcode + * 0 can be returned to indicate an invalid opcode */ private static final byte DW_LNS_undefined = 0; /* - * 0 can be inserted as a prefix for extended opcodes + * 0 can be inserted as a prefix for extended opcodes */ private static final byte DW_LNS_extended_prefix = 0; /* - * append current state as matrix row 0 args + * append current state as matrix row 0 args */ private static final byte DW_LNS_copy = 1; /* @@ -83,7 +83,7 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final byte DW_LNS_advance_pc = 2; /* - * increment line 1 sleb arg + * increment line 1 sleb arg */ private static final byte DW_LNS_advance_line = 3; /* @@ -91,15 +91,15 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { */ private static final byte DW_LNS_set_file = 4; /* - * set column 1 uleb arg + * set column 1 uleb arg */ private static final byte DW_LNS_set_column = 5; /* - * flip is_stmt 0 args + * flip is_stmt 0 args */ private static final byte DW_LNS_negate_stmt = 6; /* - * set end sequence and copy row 0 args + * set end sequence and copy row 0 args */ private static final byte DW_LNS_set_basic_block = 7; /* @@ -117,9 +117,9 @@ public class DwarfLineSectionImpl extends DwarfSectionImpl { /* * there is no extended opcode 0 */ - // private static final byte DW_LNE_undefined = 0; + @SuppressWarnings("unused") private static final byte DW_LNE_undefined = 0; /* - * end sequence of addresses + * end sequence of addresses */ private static final byte DW_LNE_end_sequence = 1; /* @@ -143,8 +143,8 @@ public String getSectionName() { @Override public void createContent() { /* - * we need to create a header, dir table, file table and line - * number table encoding for each CU + * we need to create a header, dir table, file table and line number table encoding for each + * CU */ /* @@ -173,16 +173,30 @@ public void createContent() { public int headerSize() { /* * header size is standard 31 bytes - * uint32 total_length - * uint16 version - * uint32 prologue_length - * uint8 min_insn_length - * uint8 default_is_stmt - * int8 line_base - * uint8 line_range - * uint8 opcode_base - * uint8 li_opcode_base - * uint8[opcode_base-1] standard_opcode_lengths + * + *
        + * + *
      • uint32 total_length + * + *
      • uint16 version + * + *
      • uint32 prologue_length + * + *
      • uint8 min_insn_length + * + *
      • uint8 default_is_stmt + * + *
      • int8 line_base + * + *
      • uint8 line_range + * + *
      • uint8 opcode_base + * + *
      • uint8 li_opcode_base + * + *
      • uint8[opcode_base-1] standard_opcode_lengths + * + *
      */ return DW_LN_HEADER_SIZE; @@ -190,13 +204,10 @@ public int headerSize() { public int computeDirTableSize(ClassEntry classEntry) { /* - * table contains a sequence of 'nul'-terminated - * dir name bytes followed by an extra 'nul' - * and then a sequence of 'nul'-terminated - * file name bytes followed by an extra 'nul' + * table contains a sequence of 'nul'-terminated dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated file name bytes followed by an extra 'nul' * - * for now we assume dir and file names are ASCII - * byte strings + * for now we assume dir and file names are ASCII byte strings */ int dirSize = 0; for (DirEntry dir : classEntry.getLocalDirs()) { @@ -211,13 +222,10 @@ public int computeDirTableSize(ClassEntry classEntry) { public int computeFileTableSize(ClassEntry classEntry) { /* - * table contains a sequence of 'nul'-terminated - * dir name bytes followed by an extra 'nul' - * and then a sequence of 'nul'-terminated - * file name bytes followed by an extra 'nul' - - * for now we assume dir and file names are ASCII - * byte strings + * table contains a sequence of 'nul'-terminated dir name bytes followed by an extra 'nul' + * and then a sequence of 'nul'-terminated file name bytes followed by an extra 'nul' + * + * for now we assume dir and file names are ASCII byte strings */ int fileSize = 0; for (FileEntry localEntry : classEntry.getLocalFiles()) { @@ -246,10 +254,10 @@ public int computeFileTableSize(ClassEntry classEntry) { public int computeLineNUmberTableSize(ClassEntry classEntry) { /* - * sigh -- we have to do this by generating the - * content even though we cannot write it into a byte[] - */ - return writeLineNumberTable(classEntry, null, 0); + * sigh -- we have to do this by generating the content even though we cannot write it into + * a byte[] + */ + return writeLineNumberTable(null, classEntry, null, 0); } @Override @@ -260,9 +268,8 @@ public byte[] getOrDecideContent(Map alre Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR); if (valueObj != null && valueObj instanceof Number) { /* - * this may not be the final vaddr for the text segment - * but it will be close enough to make debug easier - * i.e. to within a 4k page or two + * this may not be the final vaddr for the text segment but it will be close enough + * to make debug easier i.e. to within a 4k page or two */ debugTextBase = ((Number) valueObj).longValue(); } @@ -271,30 +278,30 @@ public byte[] getOrDecideContent(Map alre } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int pos = 0; - checkDebug(pos); - debug(" [0x%08x] DEBUG_LINE\n", pos); + enableLog(context, pos); + log(context, " [0x%08x] DEBUG_LINE", pos); for (ClassEntry classEntry : getPrimaryClasses()) { if (classEntry.getFileName().length() != 0) { int startPos = pos; assert classEntry.getLineIndex() == startPos; - debug(" [0x%08x] Compile Unit for %s\n", pos, classEntry.getFileName()); + log(context, " [0x%08x] Compile Unit for %s", pos, classEntry.getFileName()); pos = writeHeader(classEntry, buffer, pos); - debug(" [0x%08x] headerSize = 0x%08x\n", pos, pos - startPos); + log(context, " [0x%08x] headerSize = 0x%08x", pos, pos - startPos); int dirTablePos = pos; - pos = writeDirTable(classEntry, buffer, pos); - debug(" [0x%08x] dirTableSize = 0x%08x\n", pos, pos - dirTablePos); + pos = writeDirTable(context, classEntry, buffer, pos); + log(context, " [0x%08x] dirTableSize = 0x%08x", pos, pos - dirTablePos); int fileTablePos = pos; - pos = writeFileTable(classEntry, buffer, pos); - debug(" [0x%08x] fileTableSize = 0x%08x\n", pos, pos - fileTablePos); + pos = writeFileTable(context, classEntry, buffer, pos); + log(context, " [0x%08x] fileTableSize = 0x%08x", pos, pos - fileTablePos); int lineNumberTablePos = pos; - pos = writeLineNumberTable(classEntry, buffer, pos); - debug(" [0x%08x] lineNumberTableSize = 0x%x\n", pos, pos - lineNumberTablePos); - debug(" [0x%08x] size = 0x%x\n", pos, pos - startPos); + pos = writeLineNumberTable(context, classEntry, buffer, pos); + log(context, " [0x%08x] lineNumberTableSize = 0x%x", pos, pos - lineNumberTablePos); + log(context, " [0x%08x] size = 0x%x", pos, pos - startPos); } } assert pos == buffer.length; @@ -311,8 +318,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { */ pos = putShort(DW_VERSION_2, buffer, pos); /* - * 4 ubyte prologue length includes rest of header and - * dir + file table section + * 4 ubyte prologue length includes rest of header and dir + file table section */ int prologueSize = classEntry.getLinePrologueSize() - 6; pos = putInt(prologueSize, buffer, pos); @@ -353,7 +359,7 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { putByte((byte) 0, buffer, pos + 5); /* DW_LNS_set_basic_block */ putByte((byte) 0, buffer, pos + 6); - /* DW_LNS_const_add_pc */ + /* DW_LNS_const_add_pc */ putByte((byte) 0, buffer, pos + 7); /* DW_LNS_fixed_advance_pc */ putByte((byte) 1, buffer, pos + 8); @@ -366,9 +372,9 @@ public int writeHeader(ClassEntry classEntry, byte[] buffer, int p) { return pos; } - public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { + public int writeDirTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; - debug(" [0x%08x] Dir Name\n", pos); + verboseLog(context, " [0x%08x] Dir Name", pos); /* * write out the list of dirs referenced form this file entry */ @@ -377,7 +383,7 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { /* * write nul terminated string text. */ - debug(" [0x%08x] %-4d %s\n", pos, dirIdx, dir.getPath()); + verboseLog(context, " [0x%08x] %-4d %s", pos, dirIdx, dir.getPath()); pos = putAsciiStringBytes(dir.getPathString(), buffer, pos); dirIdx++; } @@ -388,10 +394,10 @@ public int writeDirTable(ClassEntry classEntry, byte[] buffer, int p) { return pos; } - public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { + public int writeFileTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; int fileIdx = 1; - debug(" [0x%08x] Entry Dir Name\n", pos); + verboseLog(context, " [0x%08x] Entry Dir Name", pos); for (FileEntry localEntry : classEntry.getLocalFiles()) { /* * we need the file name minus path, the associated dir index, and 0 for time stamps @@ -399,7 +405,7 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { String baseName = localEntry.getFileName(); DirEntry dirEntry = localEntry.getDirEntry(); int dirIdx = classEntry.localDirsIdx(dirEntry); - debug(" [0x%08x] %-5d %-5d %s\n", pos, fileIdx, dirIdx, baseName); + verboseLog(context, " [0x%08x] %-5d %-5d %s", pos, fileIdx, dirIdx, baseName); pos = putAsciiStringBytes(baseName, buffer, pos); pos = putULEB(dirIdx, buffer, pos); pos = putULEB(0, buffer, pos); @@ -416,7 +422,7 @@ public int writeFileTable(ClassEntry classEntry, byte[] buffer, int p) { public int debugLine = 1; public int debugCopyCount = 0; - public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { + public int writeLineNumberTable(DebugContext context, ClassEntry classEntry, byte[] buffer, int p) { int pos = p; FileEntry fileEntry = classEntry.getFileEntry(); if (fileEntry == null) { @@ -430,15 +436,14 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { String primaryFileName = classEntry.getFileName(); String file = primaryFileName; int fileIdx = 1; - debug(" [0x%08x] primary class %s\n", pos, primaryClassName); - debug(" [0x%08x] primary file %s\n", pos, primaryFileName); + log(context, " [0x%08x] primary class %s", pos, primaryClassName); + log(context, " [0x%08x] primary file %s", pos, primaryFileName); for (PrimaryEntry primaryEntry : classEntry.getPrimaryEntries()) { Range primaryRange = primaryEntry.getPrimary(); assert primaryRange.getFileName().equals(primaryFileName); /* - * each primary represents a method i.e. a contiguous - * sequence of subranges. we assume the default state - * at the start of each sequence because we always post an + * each primary represents a method i.e. a contiguous sequence of subranges. we assume + * the default state at the start of each sequence because we always post an * end_sequence when we finish all the subranges in the method */ long line = primaryRange.getLine(); @@ -453,26 +458,25 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * set state for primary */ - debug(" [0x%08x] primary range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), - primaryRange.getLine()); + log(context, " [0x%08x] primary range [0x%08x, 0x%08x] %s:%d", pos, debugTextBase + primaryRange.getLo(), debugTextBase + primaryRange.getHi(), primaryRange.getFullMethodName(), + primaryRange.getLine()); /* * initialize and write a row for the start of the primary method */ - pos = putSetFile(file, fileIdx, buffer, pos); - pos = putSetBasicBlock(buffer, pos); + pos = writeSetFileOp(context, file, fileIdx, buffer, pos); + pos = writeSetBasicBlockOp(context, buffer, pos); /* * address is currently 0 - */ - pos = putSetAddress(address, buffer, pos); + */ + pos = writeSetAddressOp(context, address, buffer, pos); /* - * state machine value of line is currently 1 - * increment to desired line + * state machine value of line is currently 1 increment to desired line */ if (line != 1) { - pos = putAdvanceLine(line - 1, buffer, pos); + pos = writeAdvanceLineOp(context, line - 1, buffer, pos); } - pos = putCopy(buffer, pos); + pos = writeCopyOp(context, buffer, pos); /* * now write a row for each subrange lo and hi @@ -489,7 +493,7 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { long subLine = subrange.getLine(); long subAddressLo = subrange.getLo(); long subAddressHi = subrange.getHi(); - debug(" [0x%08x] sub range [0x%08x, 0x%08x] %s:%d\n", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); + log(context, " [0x%08x] sub range [0x%08x, 0x%08x] %s:%d", pos, debugTextBase + subAddressLo, debugTextBase + subAddressHi, subrange.getFullMethodName(), subLine); if (subLine < 0) { /* * no line info so stay at previous file:line @@ -497,15 +501,13 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { subLine = line; subfile = file; subFileIdx = fileIdx; - debug(" [0x%08x] missing line info - staying put at %s:%d\n", pos, file, line); + verboseLog(context, " [0x%08x] missing line info - staying put at %s:%d", pos, file, line); } /* - * there is a temptation to append end sequence at here - * when the hiAddress lies strictly between the current - * address and the start of the next subrange because, - * ostensibly, we have void space between the end of - * the current subrange and the start of the next one. - * however, debug works better if we treat all the insns up + * there is a temptation to append end sequence at here when the hiAddress lies + * strictly between the current address and the start of the next subrange because, + * ostensibly, we have void space between the end of the current subrange and the + * start of the next one. however, debug works better if we treat all the insns up * to the next range start as belonging to the current line * * if we have to update to a new file then do so @@ -514,13 +516,12 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * update the current file */ - pos = putSetFile(subfile, subFileIdx, buffer, pos); + pos = writeSetFileOp(context, subfile, subFileIdx, buffer, pos); file = subfile; fileIdx = subFileIdx; } /* - * check if we can advance line and/or address in - * one byte with a special opcode + * check if we can advance line and/or address in one byte with a special opcode */ long lineDelta = subLine - line; long addressDelta = subAddressLo - address; @@ -530,58 +531,57 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { * ignore pointless write when addressDelta == lineDelta == 0 */ if (addressDelta != 0 || lineDelta != 0) { - pos = putSpecialOpcode(opcode, buffer, pos); + pos = writeSpecialOpcode(context, opcode, buffer, pos); } } else { /* - * does it help to divide and conquer using - * a fixed address increment + * does it help to divide and conquer using a fixed address increment */ int remainder = isConstAddPC(addressDelta); if (remainder > 0) { - pos = putConstAddPC(buffer, pos); + pos = writeConstAddPCOp(context, buffer, pos); /* - * the remaining address can be handled with a - * special opcode but what about the line delta + * the remaining address can be handled with a special opcode but what about + * the line delta */ opcode = isSpecialOpcode(remainder, lineDelta); if (opcode != DW_LNS_undefined) { /* * address remainder and line now fit */ - pos = putSpecialOpcode(opcode, buffer, pos); + pos = writeSpecialOpcode(context, opcode, buffer, pos); } else { /* - * ok, bump the line separately then use a - * special opcode for the address remainder + * ok, bump the line separately then use a special opcode for the + * address remainder */ opcode = isSpecialOpcode(remainder, 0); assert opcode != DW_LNS_undefined; - pos = putAdvanceLine(lineDelta, buffer, pos); - pos = putSpecialOpcode(opcode, buffer, pos); + pos = writeAdvanceLineOp(context, lineDelta, buffer, pos); + pos = writeSpecialOpcode(context, opcode, buffer, pos); } } else { /* * increment line and pc separately */ if (lineDelta != 0) { - pos = putAdvanceLine(lineDelta, buffer, pos); + pos = writeAdvanceLineOp(context, lineDelta, buffer, pos); } /* - * n.b. we might just have had an out of range line increment - * with a zero address increment + * n.b. we might just have had an out of range line increment with a zero + * address increment */ if (addressDelta > 0) { /* * see if we can use a ushort for the increment */ if (isFixedAdvancePC(addressDelta)) { - pos = putFixedAdvancePC((short) addressDelta, buffer, pos); + pos = writeFixedAdvancePCOp(context, (short) addressDelta, buffer, pos); } else { - pos = putAdvancePC(addressDelta, buffer, pos); + pos = writeAdvancePCOp(context, addressDelta, buffer, pos); } } - pos = putCopy(buffer, pos); + pos = writeCopyOp(context, buffer, pos); } } /* @@ -598,37 +598,28 @@ public int writeLineNumberTable(ClassEntry classEntry, byte[] buffer, int p) { /* * increment address before we write the end sequence */ - pos = putAdvancePC(addressDelta, buffer, pos); + pos = writeAdvancePCOp(context, addressDelta, buffer, pos); } - pos = putEndSequence(buffer, pos); + pos = writeEndSequenceOp(context, buffer, pos); } - debug(" [0x%08x] primary file processed %s\n", pos, primaryFileName); + log(context, " [0x%08x] primary file processed %s", pos, primaryFileName); return pos; } - @Override - protected void debug(String format, Object... args) { - if (((int) args[0] - debugBase) < 0x100000) { - super.debug(format, args); - } else if (format.startsWith(" [0x%08x] primary file")) { - super.debug(format, args); - } - } - - public int putCopy(byte[] buffer, int p) { + public int writeCopyOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_copy; int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { debugCopyCount++; - debug(" [0x%08x] Copy %d\n", pos, debugCopyCount); + verboseLog(context, " [0x%08x] Copy %d", pos, debugCopyCount); return putByte(opcode, buffer, pos); } } - public int putAdvancePC(long uleb, byte[] buffer, int p) { + public int writeAdvancePCOp(DebugContext context, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_pc; int pos = p; if (buffer == null) { @@ -636,13 +627,13 @@ public int putAdvancePC(long uleb, byte[] buffer, int p) { return pos + putULEB(uleb, scratch, 0); } else { debugAddress += uleb; - debug(" [0x%08x] Advance PC by %d to 0x%08x\n", pos, uleb, debugAddress); + verboseLog(context, " [0x%08x] Advance PC by %d to 0x%08x", pos, uleb, debugAddress); pos = putByte(opcode, buffer, pos); return putULEB(uleb, buffer, pos); } } - public int putAdvanceLine(long sleb, byte[] buffer, int p) { + public int writeAdvanceLineOp(DebugContext context, long sleb, byte[] buffer, int p) { byte opcode = DW_LNS_advance_line; int pos = p; if (buffer == null) { @@ -650,26 +641,27 @@ public int putAdvanceLine(long sleb, byte[] buffer, int p) { return pos + putSLEB(sleb, scratch, 0); } else { debugLine += sleb; - debug(" [0x%08x] Advance Line by %d to %d\n", pos, sleb, debugLine); + verboseLog(context, " [0x%08x] Advance Line by %d to %d", pos, sleb, debugLine); pos = putByte(opcode, buffer, pos); return putSLEB(sleb, buffer, pos); } } - public int putSetFile(String file, long uleb, byte[] buffer, int p) { + public int writeSetFileOp(DebugContext context, String file, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_file; int pos = p; if (buffer == null) { pos = pos + putByte(opcode, scratch, 0); return pos + putULEB(uleb, scratch, 0); } else { - debug(" [0x%08x] Set File Name to entry %d in the File Name Table (%s)\n", pos, uleb, file); + verboseLog(context, " [0x%08x] Set File Name to entry %d in the File Name Table (%s)", pos, uleb, file); pos = putByte(opcode, buffer, pos); return putULEB(uleb, buffer, pos); } } - public int putSetColumn(long uleb, byte[] buffer, int p) { + @SuppressWarnings("unused") + public int writeSetColumnOp(DebugContext context, long uleb, byte[] buffer, int p) { byte opcode = DW_LNS_set_column; int pos = p; if (buffer == null) { @@ -681,7 +673,8 @@ public int putSetColumn(long uleb, byte[] buffer, int p) { } } - public int putNegateStmt(byte[] buffer, int p) { + @SuppressWarnings("unused") + public int writeNegateStmtOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_negate_stmt; int pos = p; if (buffer == null) { @@ -691,18 +684,18 @@ public int putNegateStmt(byte[] buffer, int p) { } } - public int putSetBasicBlock(byte[] buffer, int p) { + public int writeSetBasicBlockOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_set_basic_block; int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { - debug(" [0x%08x] Set basic block\n", pos); + verboseLog(context, " [0x%08x] Set basic block", pos); return putByte(opcode, buffer, pos); } } - public int putConstAddPC(byte[] buffer, int p) { + public int writeConstAddPCOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNS_const_add_pc; int pos = p; if (buffer == null) { @@ -710,12 +703,12 @@ public int putConstAddPC(byte[] buffer, int p) { } else { int advance = opcodeAddress((byte) 255); debugAddress += advance; - debug(" [0x%08x] Advance PC by constant %d to 0x%08x\n", pos, advance, debugAddress); + verboseLog(context, " [0x%08x] Advance PC by constant %d to 0x%08x", pos, advance, debugAddress); return putByte(opcode, buffer, pos); } } - public int putFixedAdvancePC(short arg, byte[] buffer, int p) { + public int writeFixedAdvancePCOp(DebugContext context, short arg, byte[] buffer, int p) { byte opcode = DW_LNS_fixed_advance_pc; int pos = p; if (buffer == null) { @@ -723,13 +716,13 @@ public int putFixedAdvancePC(short arg, byte[] buffer, int p) { return pos + putShort(arg, scratch, 0); } else { debugAddress += arg; - debug(" [0x%08x] Fixed advance Address by %d to 0x%08x\n", pos, arg, debugAddress); + verboseLog(context, " [0x%08x] Fixed advance Address by %d to 0x%08x", pos, arg, debugAddress); pos = putByte(opcode, buffer, pos); return putShort(arg, buffer, pos); } } - public int putEndSequence(byte[] buffer, int p) { + public int writeEndSequenceOp(DebugContext context, byte[] buffer, int p) { byte opcode = DW_LNE_end_sequence; int pos = p; if (buffer == null) { @@ -740,7 +733,7 @@ public int putEndSequence(byte[] buffer, int p) { pos = pos + putULEB(1, scratch, 0); return pos + putByte(opcode, scratch, 0); } else { - debug(" [0x%08x] Extended opcode 1: End sequence\n", pos); + verboseLog(context, " [0x%08x] Extended opcode 1: End sequence", pos); debugAddress = debugTextBase; debugLine = 1; debugCopyCount = 0; @@ -753,7 +746,7 @@ public int putEndSequence(byte[] buffer, int p) { } } - public int putSetAddress(long arg, byte[] buffer, int p) { + public int writeSetAddressOp(DebugContext context, long arg, byte[] buffer, int p) { byte opcode = DW_LNE_set_address; int pos = p; if (buffer == null) { @@ -766,7 +759,7 @@ public int putSetAddress(long arg, byte[] buffer, int p) { return pos + putLong(arg, scratch, 0); } else { debugAddress = debugTextBase + (int) arg; - debug(" [0x%08x] Extended opcode 2: Set Address to 0x%08x\n", pos, debugAddress); + verboseLog(context, " [0x%08x] Extended opcode 2: Set Address to 0x%08x", pos, debugAddress); pos = putByte(DW_LNS_extended_prefix, buffer, pos); /* * insert extended insn byte count as ULEB @@ -777,7 +770,8 @@ public int putSetAddress(long arg, byte[] buffer, int p) { } } - public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { + @SuppressWarnings("unused") + public int writeDefineFileOp(DebugContext context, String file, long uleb1, long uleb2, long uleb3, byte[] buffer, int p) { byte opcode = DW_LNE_define_file; int pos = p; /* @@ -797,7 +791,7 @@ public int putDefineFile(String file, long uleb1, long uleb2, long uleb3, byte[] pos += putULEB(insnBytes, scratch, 0); return pos + (int) insnBytes; } else { - debug(" [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d\n", pos, file, uleb1, uleb2, uleb3); + verboseLog(context, " [0x%08x] Extended opcode 3: Define File %s idx %d ts1 %d ts2 %d", pos, file, uleb1, uleb2, uleb3); pos = putByte(DW_LNS_extended_prefix, buffer, pos); /* * insert insn length as uleb @@ -829,18 +823,18 @@ public static int opcodeLine(byte opcode) { return ((iopcode - DW_LN_OPCODE_BASE) % DW_LN_LINE_RANGE) + DW_LN_LINE_BASE; } - public int putSpecialOpcode(byte opcode, byte[] buffer, int p) { + public int writeSpecialOpcode(DebugContext context, byte opcode, byte[] buffer, int p) { int pos = p; if (buffer == null) { return pos + putByte(opcode, scratch, 0); } else { if (debug && opcode == 0) { - debug(" [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d\n", debugAddress, debugLine); + verboseLog(context, " [0x%08x] ERROR Special Opcode %d: Address 0x%08x Line %d", debugAddress, debugLine); } debugAddress += opcodeAddress(opcode); debugLine += opcodeLine(opcode); - debug(" [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d\n", - pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); + verboseLog(context, " [0x%08x] Special Opcode %d: advance Address by %d to 0x%08x and Line by %d to %d", + pos, opcodeId(opcode), opcodeAddress(opcode), debugAddress, opcodeLine(opcode), debugLine); return putByte(opcode, buffer, pos); } } @@ -856,8 +850,7 @@ public static byte isSpecialOpcode(long addressDelta, long lineDelta) { long offsetLineDelta = lineDelta - DW_LN_LINE_BASE; if (offsetLineDelta < DW_LN_LINE_RANGE) { /* - * line_delta can be encoded - * check if address is ok + * line_delta can be encoded check if address is ok */ if (addressDelta <= MAX_ADDRESS_ONLY_DELTA) { long opcode = DW_LN_OPCODE_BASE + (addressDelta * DW_LN_LINE_RANGE) + offsetLineDelta; @@ -900,8 +893,8 @@ public String targetSectionName() { } public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, }; @Override 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 7b4a1d6fd8b1..177b8643bc67 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 @@ -33,6 +33,7 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.elf.ELFObjectFile; +import org.graalvm.compiler.debug.DebugContext; import java.nio.ByteOrder; import java.util.Map; @@ -41,8 +42,7 @@ import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; /** - * class from which all DWARF debug sections - * inherit providing common behaviours. + * class from which all DWARF debug sections inherit providing common behaviours. */ public abstract class DwarfSectionImpl extends BasicProgbitsSectionImpl { protected DwarfSections dwarfSections; @@ -56,28 +56,22 @@ public DwarfSectionImpl(DwarfSections dwarfSections) { } /** - * creates the target byte[] array used to define the section - * contents. + * creates the target byte[] array used to define the section contents. * - * the main task of this method is to precompute the - * size of the debug section. given the complexity of the - * data layouts that invariably requires performing a dummy - * write of the contents, inserting bytes into a small, - * scratch buffer only when absolutely necessary. subclasses - * may also cache some information for use when writing the - * contents. + * the main task of this method is to precompute the size of the debug section. given the + * complexity of the data layouts that invariably requires performing a dummy write of the + * contents, inserting bytes into a small, scratch buffer only when absolutely necessary. + * subclasses may also cache some information for use when writing the contents. */ public abstract void createContent(); /** - * populates the byte[] array used to contain the section - * contents. + * populates the byte[] array used to contain the section contents. * - * in most cases this task reruns the operations performed - * under createContent but this time actually writing data - * to the target byte[]. + * in most cases this task reruns the operations performed under createContent but this time + * actually writing data to the target byte[]. */ - public abstract void writeContent(); + public abstract void writeContent(DebugContext debugContext); @Override public boolean isLoadable() { @@ -87,23 +81,38 @@ public boolean isLoadable() { return false; } - public void checkDebug(int pos) { + public String debugSectionLogName() { /* - * if the env var relevant to this element - * type is set then switch on debugging + * Use prefix dwarf plus the section name (which already includes a dot separator) for the + * context key. For example messages for info section will be keyed using dwarf.debug_info. + * Other info formats use their own format-specific prefix. */ - String name = getSectionName(); - String envVarName = "DWARF_" + name.substring(1).toUpperCase(); - if (System.getenv(envVarName) != null) { + assert getSectionName().startsWith(".debug"); + return "dwarf" + getSectionName(); + } + + public void enableLog(DebugContext context, int pos) { + /* + * debug output is disabled during the first pass where we size the buffer. this is called + * to enable it during the second pass where the buffer gets written, but only if the scope + * is enabled. + */ + if (context.areScopesEnabled()) { debug = true; debugBase = pos; debugAddress = debugTextBase; } } - protected void debug(String format, Object... args) { + protected void log(DebugContext context, String format, Object... args) { + if (debug) { + context.logv(DebugContext.INFO_LEVEL, format, args); + } + } + + protected void verboseLog(DebugContext context, String format, Object... args) { if (debug) { - System.out.format(format, args); + context.logv(DebugContext.VERBOSE_LEVEL, format, args); } } @@ -280,6 +289,7 @@ public int writeAttrAddress(long address, byte[] buffer, int pos) { } } + @SuppressWarnings("unused") public int writeAttrData8(long value, byte[] buffer, int pos) { if (buffer == null) { return pos + putLong(value, scratch, 0); @@ -313,22 +323,24 @@ public int writeAttrNull(byte[] buffer, int pos) { } /** - * identify the section after which this debug section - * needs to be ordered when sizing and creating content. + * identify the section after which this debug section needs to be ordered when sizing and + * creating content. + * * @return the name of the preceding section */ public abstract String targetSectionName(); /** - * identify the layout properties of the target section - * which need to have been decided before the contents - * of this section can be created. + * identify the layout properties of the target section which need to have been decided before + * the contents of this section can be created. + * * @return an array of the relevant decision kinds */ public abstract LayoutDecision.Kind[] targetSectionKinds(); /** * identify this debug section by name. + * * @return the name of the debug section */ public abstract String getSectionName(); @@ -341,9 +353,14 @@ public byte[] getOrDecideContent(Map alre createContent(); /* - * ensure content byte[] has been written before calling super method + * ensure content byte[] has been written before calling super method. + * + * we do this in a nested debug scope derived from the one set up under the object file + * write */ - writeContent(); + getOwner().debugContext(debugSectionLogName(), debugContext -> { + writeContent(debugContext); + }); return super.getOrDecideContent(alreadyDecided, contentHint); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java index 1aa225d5983d..2a8a6ca0c098 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java @@ -26,36 +26,33 @@ package com.oracle.objectfile.elf.dwarf; +import java.nio.ByteOrder; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.graalvm.compiler.debug.DebugContext; + import com.oracle.objectfile.debugentry.ClassEntry; import com.oracle.objectfile.debugentry.DirEntry; import com.oracle.objectfile.debugentry.FileEntry; -import com.oracle.objectfile.debugentry.PrimaryEntry; import com.oracle.objectfile.debugentry.Range; import com.oracle.objectfile.debugentry.StringTable; import com.oracle.objectfile.debuginfo.DebugInfoProvider; import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; import com.oracle.objectfile.elf.ELFMachine; -import java.nio.ByteOrder; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - /** - * A class that models the debug info in an - * organization that facilitates generation of the - * required DWARF sections. It groups common data and - * behaviours for use by the various subclasses of - * class DwarfSectionImpl that take responsibility - * for generating content for a specific section type. + * A class that models the debug info in an organization that facilitates generation of the required + * DWARF sections. It groups common data and behaviours for use by the various subclasses of class + * DwarfSectionImpl that take responsibility for generating content for a specific section type. */ public class DwarfSections { /* - * names of the different ELF sections we create or reference - * in reverse dependency order + * names of the different ELF sections we create or reference in reverse dependency order */ public static final String TEXT_SECTION_NAME = ".text"; public static final String DW_STR_SECTION_NAME = ".debug_str"; @@ -95,19 +92,19 @@ public class DwarfSections { public static final int DW_AT_hi_pc = 0x12; public static final int DW_AT_language = 0x13; public static final int DW_AT_external = 0x3f; - // public static final int DW_AT_return_addr = 0x2a; - // public static final int DW_AT_frame_base = 0x40; + @SuppressWarnings("unused") public static final int DW_AT_return_addr = 0x2a; + @SuppressWarnings("unused") public static final int DW_AT_frame_base = 0x40; /* * define all the Dwarf attribute forms we need for our DIEs */ public static final int DW_FORM_null = 0x0; - // private static final int DW_FORM_string = 0x8; + @SuppressWarnings("unused") private static final int DW_FORM_string = 0x8; public static final int DW_FORM_strp = 0xe; public static final int DW_FORM_addr = 0x1; public static final int DW_FORM_data1 = 0x0b; public static final int DW_FORM_data4 = 0x6; - // public static final int DW_FORM_data8 = 0x7; - // public static final int DW_FORM_block1 = 0x0a; + @SuppressWarnings("unused") public static final int DW_FORM_data8 = 0x7; + @SuppressWarnings("unused") public static final int DW_FORM_block1 = 0x0a; public static final int DW_FORM_flag = 0xc; /* @@ -121,7 +118,7 @@ public class DwarfSections { /* * DW_FORM_flag attribute values */ - // public static final byte DW_FLAG_false = 0; + @SuppressWarnings("unused") public static final byte DW_FLAG_false = 0; public static final byte DW_FLAG_true = 1; /* * value for DW_AT_language attribute with form DATA1 @@ -133,15 +130,16 @@ public class DwarfSections { * * not needed until we make functions members */ - // public static final byte DW_ACCESS_public = 1; - // public static final byte DW_ACCESS_protected = 2; - // public static final byte DW_ACCESS_private = 3; + @SuppressWarnings("unused") public static final byte DW_ACCESS_public = 1; + @SuppressWarnings("unused") public static final byte DW_ACCESS_protected = 2; + @SuppressWarnings("unused") public static final byte DW_ACCESS_private = 3; /* * others not yet needed */ - // public static final int DW_AT_type = 0; // only present for non-void functions - // public static final int DW_AT_accessibility = 0; + @SuppressWarnings("unused") public static final int DW_AT_type = 0; // only present for non-void + // functions + @SuppressWarnings("unused") public static final int DW_AT_accessibility = 0; /* * CIE and FDE entries @@ -149,31 +147,30 @@ public class DwarfSections { /* full byte/word values */ public static final int DW_CFA_CIE_id = -1; - // public static final int DW_CFA_FDE_id = 0; + @SuppressWarnings("unused") public static final int DW_CFA_FDE_id = 0; public static final byte DW_CFA_CIE_version = 1; /* values encoded in high 2 bits */ public static final byte DW_CFA_advance_loc = 0x1; public static final byte DW_CFA_offset = 0x2; - // public static final byte DW_CFA_restore = 0x3; + @SuppressWarnings("unused") public static final byte DW_CFA_restore = 0x3; /* values encoded in low 6 bits */ public static final byte DW_CFA_nop = 0x0; - // public static final byte DW_CFA_set_loc1 = 0x1; + @SuppressWarnings("unused") public static final byte DW_CFA_set_loc1 = 0x1; public static final byte DW_CFA_advance_loc1 = 0x2; public static final byte DW_CFA_advance_loc2 = 0x3; public static final byte DW_CFA_advance_loc4 = 0x4; - // public static final byte DW_CFA_offset_extended = 0x5; - // public static final byte DW_CFA_restore_extended = 0x6; - // public static final byte DW_CFA_undefined = 0x7; - // public static final byte DW_CFA_same_value = 0x8; + @SuppressWarnings("unused") public static final byte DW_CFA_offset_extended = 0x5; + @SuppressWarnings("unused") public static final byte DW_CFA_restore_extended = 0x6; + @SuppressWarnings("unused") public static final byte DW_CFA_undefined = 0x7; + @SuppressWarnings("unused") public static final byte DW_CFA_same_value = 0x8; public static final byte DW_CFA_register = 0x9; public static final byte DW_CFA_def_cfa = 0xc; - // public static final byte DW_CFA_def_cfa_register = 0xd; + @SuppressWarnings("unused") public static final byte DW_CFA_def_cfa_register = 0xd; public static final byte DW_CFA_def_cfa_offset = 0xe; - //private ELFMachine elfMachine; private ByteOrder byteOrder; private DwarfStrSectionImpl dwarfStrSection; private DwarfAbbrevSectionImpl dwarfAbbrevSection; @@ -183,7 +180,6 @@ public class DwarfSections { private DwarfFrameSectionImpl dwarfFameSection; public DwarfSections(ELFMachine elfMachine, ByteOrder byteOrder) { - //this.elfMachine = elfMachine; this.byteOrder = byteOrder; dwarfStrSection = new DwarfStrSectionImpl(this); dwarfAbbrevSection = new DwarfAbbrevSectionImpl(this); @@ -222,19 +218,14 @@ public DwarfLineSectionImpl getLineSectionImpl() { } /** - * a table listing all known strings, some of - * which may be marked for insertion into the + * a table listing all known strings, some of which may be marked for insertion into the * debug_str section. */ private StringTable stringTable = new StringTable(); /** - * list detailing all dirs in which files are found to reside - * either as part of substrate/compiler or user code. - */ - private LinkedList dirs = new LinkedList<>(); - /** - * index of already seen dirs. + * index of all dirs in which files are found to reside either as part of substrate/compiler or + * user code. */ private Map dirsIndex = new HashMap<>(); @@ -242,6 +233,7 @@ public DwarfLineSectionImpl getLineSectionImpl() { * The obvious traversal structure for debug records is: * * 1) by top level compiled method (primary Range) ordered by ascending address + * * 2) by inlined method (sub range) within top level method ordered by ascending address * * these can be used to ensure that all debug records are generated in increasing address order @@ -249,21 +241,22 @@ public DwarfLineSectionImpl getLineSectionImpl() { * An alternative traversal option is * * 1) by top level class (String id) + * * 2) by top level compiled method (primary Range) within a class ordered by ascending address + * * 3) by inlined method (sub range) within top level method ordered by ascending address * - * this relies on the (current) fact that methods of a given class always appear - * in a single continuous address range with no intervening code from other methods - * or data values. this means we can treat each class as a compilation unit, allowing - * data common to all methods of the class to be shared. + * this relies on the (current) fact that methods of a given class always appear in a single + * continuous address range with no intervening code from other methods or data values. this + * means we can treat each class as a compilation unit, allowing data common to all methods of + * the class to be shared. * * A third option appears to be to traverse via files, then top level class within file etc. - * Unfortunately, files cannot be treated as the compilation unit. A file F may contain - * multiple classes, say C1 and C2. There is no guarantee that methods for some other - * class C' in file F' will not be compiled into the address space interleaved between - * methods of C1 and C2. That is a shame because generating debug info records one file at a - * time would allow more sharing e.g. enabling all classes in a file to share a single copy - * of the file and dir tables. + * Unfortunately, files cannot be treated as the compilation unit. A file F may contain multiple + * classes, say C1 and C2. There is no guarantee that methods for some other class C' in file F' + * will not be compiled into the address space interleaved between methods of C1 and C2. That is + * a shame because generating debug info records one file at a time would allow more sharing + * e.g. enabling all classes in a file to share a single copy of the file and dir tables. */ /** @@ -271,26 +264,20 @@ public DwarfLineSectionImpl getLineSectionImpl() { */ private LinkedList primaryClasses = new LinkedList<>(); /** - * index of already seen classes. + * index of already seen classes. */ private Map primaryClassesIndex = new HashMap<>(); /** - * list of files which contain primary ranges. - */ - private LinkedList primaryFiles = new LinkedList<>(); - /** - * List of files which contain primary or secondary ranges. - */ - private LinkedList files = new LinkedList<>(); - /** - * index of already seen files. + * index of files which contain primary or secondary ranges. */ private Map filesIndex = new HashMap<>(); /** * indirects this call to the string table. + * * @param string the string to be inserted + * * @return a unique equivalent String */ public String uniqueString(String string) { @@ -298,11 +285,11 @@ public String uniqueString(String string) { } /** - * indirects this call to the string table, ensuring - * the table entry is marked for inclusion in the - * debug_str section. - * @param string the string to be inserted and - * marked for inclusion in the debug_str section + * indirects this call to the string table, ensuring the table entry is marked for inclusion in + * the debug_str section. + * + * @param string the string to be inserted and marked for inclusion in the debug_str section + * * @return a unique equivalent String */ public String uniqueDebugString(String string) { @@ -311,26 +298,25 @@ public String uniqueDebugString(String string) { /** * indirects this call to the string table. + * * @param string the string whose index is required - * @return the offset of the string in the .debug_str - * section + * + * @return the offset of the string in the .debug_str section */ public int debugStringIndex(String string) { return stringTable.debugStringIndex(string); } /** - * entry point allowing ELFObjectFile to pass on information - * about types, code and heap data. - * @param debugInfoProvider provider instance passed by - * ObjectFile client + * entry point allowing ELFObjectFile to pass on information about types, code and heap data. + * + * @param debugInfoProvider provider instance passed by ObjectFile client */ + @SuppressWarnings("try") public void installDebugInfo(DebugInfoProvider debugInfoProvider) { /* - * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); - * for (DebugTypeInfo debugTypeInfo : typeInfoProvider) { - * install types - * } + * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); for + * (DebugTypeInfo debugTypeInfo : typeInfoProvider) { install types } */ /* @@ -338,7 +324,7 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ uniqueDebugString(""); - debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> { + debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> debugCodeInfo.debugContext((debugContext) -> { /* * primary file name and full method name need to be written to the debug_str section */ @@ -352,12 +338,9 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { int lo = debugCodeInfo.addressLo(); int hi = debugCodeInfo.addressHi(); int primaryLine = debugCodeInfo.line(); + Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - /* - * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, - * returnTypeName, className, methodName, paramNames, fileName); - * create an infoSection entry for the method - */ + debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", className, methodName, filePath, fileName, primaryLine, lo, hi); addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { String fileNameAtLine = debugLineInfo.fileName(); @@ -374,14 +357,15 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { */ Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); addSubRange(primaryRange, subRange); + try (DebugContext.Scope s = debugContext.scope("Subranges")) { + debugContext.log(DebugContext.VERBOSE_LEVEL, "SubRange %s.%s %s %s:%d 0x%x, 0x%x]", classNameAtLine, methodNameAtLine, filePathAtLine, fileNameAtLine, line, loAtLine, hiAtLine); + } }); - }); + })); /* - * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - * for (DebugDataInfo debugDataInfo : dataInfoProvider) { - * install details of heap elements - * String name = debugDataInfo.toString(); - * } + * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); for + * (DebugDataInfo debugDataInfo : dataInfoProvider) { install details of heap elements + * String name = debugDataInfo.toString(); } */ } @@ -418,17 +402,15 @@ public FileEntry ensureFileEntry(Range range) { if (fileEntry == null) { DirEntry dirEntry = ensureDirEntry(filePath); fileEntry = new FileEntry(fileName, dirEntry); - files.add(fileEntry); - filesIndex.put(fileAsPath, fileEntry); /* - * if this is a primary entry then add it to the primary list + * index the file entry by file path */ - if (range.isPrimary()) { - primaryFiles.add(fileEntry); - } else { + filesIndex.put(fileAsPath, fileEntry); + if (!range.isPrimary()) { + /* check we have a file for the corresponding primary range */ Range primaryRange = range.getPrimary(); - FileEntry primaryEntry = filesIndex.get(primaryRange.getFileAsPath()); - assert primaryEntry != null; + FileEntry primaryFileEntry = filesIndex.get(primaryRange.getFileAsPath()); + assert primaryFileEntry != null; } } return fileEntry; @@ -437,7 +419,7 @@ public FileEntry ensureFileEntry(Range range) { public void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { assert primaryRange.isPrimary(); ClassEntry classEntry = ensureClassEntry(primaryRange); - PrimaryEntry entry = classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); + classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); } public void addSubRange(Range primaryRange, Range subrange) { @@ -445,14 +427,13 @@ public void addSubRange(Range primaryRange, Range subrange) { assert !subrange.isPrimary(); String className = primaryRange.getClassName(); ClassEntry classEntry = primaryClassesIndex.get(className); - FileEntry subrangeEntry = ensureFileEntry(subrange); + FileEntry subrangeFileEntry = ensureFileEntry(subrange); /* - * the primary range should already have been seen - * and associated with a primary class entry + * the primary range should already have been seen and associated with a primary class entry */ assert classEntry.primaryIndexFor(primaryRange) != null; - if (subrangeEntry != null) { - classEntry.addSubRange(subrange, subrangeEntry); + if (subrangeFileEntry != null) { + classEntry.addSubRange(subrange, subrangeFileEntry); } } @@ -464,16 +445,18 @@ public DirEntry ensureDirEntry(Path filePath) { if (dirEntry == null) { dirEntry = new DirEntry(filePath); dirsIndex.put(filePath, dirEntry); - dirs.add(dirEntry); } return dirEntry; } + public StringTable getStringTable() { return stringTable; } + public LinkedList getPrimaryClasses() { return primaryClasses; } + public ByteOrder getByteOrder() { return byteOrder; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java index 1ee212b112b5..5f08ed8dbc2b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfStrSectionImpl.java @@ -28,9 +28,11 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.debugentry.StringEntry; +import org.graalvm.compiler.debug.DebugContext; import static com.oracle.objectfile.elf.dwarf.DwarfSections.DW_STR_SECTION_NAME; import static com.oracle.objectfile.elf.dwarf.DwarfSections.TEXT_SECTION_NAME; + /** * generator for debug_str section. */ @@ -59,12 +61,12 @@ public void createContent() { } @Override - public void writeContent() { + public void writeContent(DebugContext context) { byte[] buffer = getContent(); int size = buffer.length; int pos = 0; - checkDebug(pos); + enableLog(context, pos); for (StringEntry stringEntry : dwarfSections.getStringTable()) { if (stringEntry.isAddToStrSection()) { @@ -76,11 +78,6 @@ public void writeContent() { assert pos == size; } - @Override - protected void debug(String format, Object... args) { - super.debug(format, args); - } - /** * debug_str section content depends on text section content and offset. */ @@ -95,10 +92,10 @@ public String targetSectionName() { * debug_str section content depends on text section content and offset. */ public final LayoutDecision.Kind[] targetSectionKinds = { - LayoutDecision.Kind.CONTENT, - LayoutDecision.Kind.OFFSET, - /* add this so we can use the text section base address for debug */ - LayoutDecision.Kind.VADDR, + LayoutDecision.Kind.CONTENT, + LayoutDecision.Kind.OFFSET, + /* add this so we can use the text section base address for debug */ + LayoutDecision.Kind.VADDR, }; @Override From 4410852bc9cc044733b0314def8b4e18c53b125c Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 27 Mar 2020 14:47:20 -0400 Subject: [PATCH 113/130] clean up errors from travis-ci build --- .../objectfile/pecoff/cv/CVLineRecord.java | 10 +++++----- .../pecoff/cv/CVLineRecordBuilder.java | 16 ++++++---------- .../oracle/objectfile/pecoff/cv/CVSections.java | 10 +++++----- .../pecoff/cv/CVStringTableRecord.java | 3 ++- .../pecoff/cv/CVSymbolRecordBuilder.java | 3 ++- .../objectfile/pecoff/cv/CVSymbolSubrecord.java | 3 +-- .../objectfile/pecoff/cv/DebugInfoBase.java | 1 - 7 files changed, 21 insertions(+), 25 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index c50eec884367..946aef49666a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -47,7 +47,7 @@ final class CVLineRecord extends CVSymbolRecord { private static final short CB_HAS_NO_COLUMNS_FLAG = 0x00; private String symbolName; - //private PrimaryEntry primaryEntry; + @SuppressWarnings("unused") private PrimaryEntry primaryEntry; private ArrayList fileBlocks = new ArrayList<>(DEFAULT_LINE_BLOCK_COUNT); /* @@ -59,11 +59,11 @@ private static class FileBlock { ArrayList lineEntries = new ArrayList<>(DEFAULT_LINE_ENTRY_COUNT); int highAddr = 0; - //FileEntry file; + @SuppressWarnings("unused") FileEntry file; int fileId; FileBlock(FileEntry file, int fileId) { - //this.file = file; + this.file = file; this.fileId = fileId; } @@ -129,9 +129,9 @@ int computeContents(byte[] buffer, int initialPos) { } } - CVLineRecord(CVSections cvSections, String symbolName, PrimaryEntry primaryEntry) { + CVLineRecord(CVSections cvSections, String symbolName, PrimaryEntry entry) { super(cvSections, DEBUG_S_LINES); - //this.primaryEntry = primaryEntry; + this.primaryEntry = entry; this.symbolName = symbolName; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index b1898f776183..8f8218fc17ce 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -58,7 +58,7 @@ public class CVLineRecordBuilder { /** * build line number records for a function - * @param primaryEntry function to build line number table for + * @param entry function to build line number table for * @return CVLineRecord containing any entries generated, or null if no entries generated */ CVLineRecord build(PrimaryEntry entry, String methodName) { @@ -104,10 +104,12 @@ CVLineRecord build(PrimaryEntry entry, String methodName) { * - if a range has the same line number, source file and function * * @param range to be merged or added to line number record - * @param previousRange the previously processed Range + * @param oldPreviousRange the previously processed Range * @return new value for previousRange in caller */ - private Range processRange(Range range, Range previousRange) { + private Range processRange(Range range, Range oldPreviousRange) { + + Range previousRange = oldPreviousRange; /* should we merge this range with the previous entry? */ /* i.e. same line in same file, same class and function */ @@ -168,7 +170,7 @@ private boolean shouldMerge(Range range, Range previousRange) { /** * test to see if a new line record should be emitted - * @param previous previous range + * @param previousRange previous range * @param range current range * @return true if the current range is on a different line or file from the previous one */ @@ -195,10 +197,4 @@ private static boolean wantNewRange(Range range, Range previousRange) { //return delta >= 127; return false; */ } - - - @Override - public String toString() { - return "CVLineRecordBuilder()"; - } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java index 9fb6f99835d7..2020cbfefa4c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java @@ -44,12 +44,12 @@ */ public final class CVSections extends DebugInfoBase { - //private PECoffMachine machine; + @SuppressWarnings("unused") private PECoffMachine machine; private CVSymbolSectionImpl cvSymbolSection; private CVTypeSectionImpl cvTypeSection; - public CVSections(PECoffMachine machine) { - //this.machine = machine; + public CVSections(PECoffMachine targetMachine) { + machine = targetMachine; cvSymbolSection = new CVSymbolSectionImpl(this); cvTypeSection = new CVTypeSectionImpl(); } @@ -122,7 +122,7 @@ public byte[] getOrDecideContent(Map alre public Set getDependencies(Map decisions) { Set deps = super.getDependencies(decisions); String targetName = getSectionName(); - PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); + @SuppressWarnings("unused") PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); //LayoutDecision.Kind[] targetKinds = targetSectionKinds(); @@ -133,9 +133,9 @@ public Set getDependencies(Map Date: Tue, 7 Apr 2020 10:18:29 -0400 Subject: [PATCH 114/130] delete obsolete file --- .../objectfile/elf/dwarf/DwarfSections.java | 440 ------------------ 1 file changed, 440 deletions(-) delete mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java deleted file mode 100644 index 68554c776bcf..000000000000 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/elf/dwarf/DwarfSections.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 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.nio.ByteOrder; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import org.graalvm.compiler.debug.DebugContext; - -import com.oracle.objectfile.debugentry.ClassEntry; -import com.oracle.objectfile.debugentry.DirEntry; -import com.oracle.objectfile.debugentry.FileEntry; -import com.oracle.objectfile.debugentry.Range; -import com.oracle.objectfile.debugentry.StringTable; -import com.oracle.objectfile.debuginfo.DebugInfoProvider; -import com.oracle.objectfile.debuginfo.DebugInfoProvider.DebugFrameSizeChange; -import com.oracle.objectfile.elf.ELFMachine; - -/** - * A class that models the debug info in an organization that facilitates generation of the required - * DWARF sections. It groups common data and behaviours for use by the various subclasses of class - * DwarfSectionImpl that take responsibility for generating content for a specific section type. - */ -public class DwarfSections { - - /* - * names of the different ELF sections we create or reference in reverse dependency order - */ - public static final String TEXT_SECTION_NAME = ".text"; - public static final String DW_STR_SECTION_NAME = ".debug_str"; - public static final String DW_LINE_SECTION_NAME = ".debug_line"; - public static final String DW_FRAME_SECTION_NAME = ".debug_frame"; - public static final String DW_ABBREV_SECTION_NAME = ".debug_abbrev"; - public static final String DW_INFO_SECTION_NAME = ".debug_info"; - public static final String DW_ARANGES_SECTION_NAME = ".debug_aranges"; - - /** - * currently generated debug info relies on DWARF spec vesion 2. - */ - public static final short DW_VERSION_2 = 2; - - /* - * define all the abbrev section codes we need for our DIEs - */ - // public static final int DW_ABBREV_CODE_null = 0; - public static final int DW_ABBREV_CODE_compile_unit = 1; - public static final int DW_ABBREV_CODE_subprogram = 2; - - /* - * define all the Dwarf tags we need for our DIEs - */ - public static final int DW_TAG_compile_unit = 0x11; - public static final int DW_TAG_subprogram = 0x2e; - /* - * define all the Dwarf attributes we need for our DIEs - */ - public static final int DW_AT_null = 0x0; - public static final int DW_AT_name = 0x3; - /* - * public static final int DW_AT_comp_dir = 0x1b; - */ - public static final int DW_AT_stmt_list = 0x10; - public static final int DW_AT_low_pc = 0x11; - public static final int DW_AT_hi_pc = 0x12; - public static final int DW_AT_language = 0x13; - public static final int DW_AT_external = 0x3f; - @SuppressWarnings("unused") public static final int DW_AT_return_addr = 0x2a; - @SuppressWarnings("unused") public static final int DW_AT_frame_base = 0x40; - /* - * define all the Dwarf attribute forms we need for our DIEs - */ - public static final int DW_FORM_null = 0x0; - @SuppressWarnings("unused") private static final int DW_FORM_string = 0x8; - public static final int DW_FORM_strp = 0xe; - public static final int DW_FORM_addr = 0x1; - public static final int DW_FORM_data1 = 0x0b; - public static final int DW_FORM_data4 = 0x6; - @SuppressWarnings("unused") public static final int DW_FORM_data8 = 0x7; - @SuppressWarnings("unused") public static final int DW_FORM_block1 = 0x0a; - public static final int DW_FORM_flag = 0xc; - - /* - * define specific attribute values for given attribute or form types - */ - /* - * DIE header has_children attribute values - */ - public static final byte DW_CHILDREN_no = 0; - public static final byte DW_CHILDREN_yes = 1; - /* - * DW_FORM_flag attribute values - */ - @SuppressWarnings("unused") public static final byte DW_FLAG_false = 0; - public static final byte DW_FLAG_true = 1; - /* - * value for DW_AT_language attribute with form DATA1 - */ - public static final byte DW_LANG_Java = 0xb; - - /* - * DW_AT_Accessibility attribute values - * - * not needed until we make functions members - */ - @SuppressWarnings("unused") public static final byte DW_ACCESS_public = 1; - @SuppressWarnings("unused") public static final byte DW_ACCESS_protected = 2; - @SuppressWarnings("unused") public static final byte DW_ACCESS_private = 3; - - /* - * others not yet needed - */ - @SuppressWarnings("unused") public static final int DW_AT_type = 0; // only present for non-void - // functions - @SuppressWarnings("unused") public static final int DW_AT_accessibility = 0; - - /* - * CIE and FDE entries - */ - - /* full byte/word values */ - public static final int DW_CFA_CIE_id = -1; - @SuppressWarnings("unused") public static final int DW_CFA_FDE_id = 0; - - public static final byte DW_CFA_CIE_version = 1; - - /* values encoded in high 2 bits */ - public static final byte DW_CFA_advance_loc = 0x1; - public static final byte DW_CFA_offset = 0x2; - @SuppressWarnings("unused") public static final byte DW_CFA_restore = 0x3; - - /* values encoded in low 6 bits */ - public static final byte DW_CFA_nop = 0x0; - @SuppressWarnings("unused") public static final byte DW_CFA_set_loc1 = 0x1; - public static final byte DW_CFA_advance_loc1 = 0x2; - public static final byte DW_CFA_advance_loc2 = 0x3; - public static final byte DW_CFA_advance_loc4 = 0x4; - @SuppressWarnings("unused") public static final byte DW_CFA_offset_extended = 0x5; - @SuppressWarnings("unused") public static final byte DW_CFA_restore_extended = 0x6; - @SuppressWarnings("unused") public static final byte DW_CFA_undefined = 0x7; - @SuppressWarnings("unused") public static final byte DW_CFA_same_value = 0x8; - public static final byte DW_CFA_register = 0x9; - public static final byte DW_CFA_def_cfa = 0xc; - @SuppressWarnings("unused") public static final byte DW_CFA_def_cfa_register = 0xd; - public static final byte DW_CFA_def_cfa_offset = 0xe; - - private ByteOrder byteOrder; - private DwarfStrSectionImpl dwarfStrSection; - private DwarfAbbrevSectionImpl dwarfAbbrevSection; - private DwarfInfoSectionImpl dwarfInfoSection; - private DwarfARangesSectionImpl dwarfARangesSection; - private DwarfLineSectionImpl dwarfLineSection; - private DwarfFrameSectionImpl dwarfFameSection; - - public DwarfSections(ELFMachine elfMachine, ByteOrder byteOrder) { - this.byteOrder = byteOrder; - dwarfStrSection = new DwarfStrSectionImpl(this); - dwarfAbbrevSection = new DwarfAbbrevSectionImpl(this); - dwarfInfoSection = new DwarfInfoSectionImpl(this); - dwarfARangesSection = new DwarfARangesSectionImpl(this); - dwarfLineSection = new DwarfLineSectionImpl(this); - if (elfMachine == ELFMachine.AArch64) { - dwarfFameSection = new DwarfFrameSectionImplAArch64(this); - } else { - dwarfFameSection = new DwarfFrameSectionImplX86_64(this); - } - } - - public DwarfStrSectionImpl getStrSectionImpl() { - return dwarfStrSection; - } - - public DwarfAbbrevSectionImpl getAbbrevSectionImpl() { - return dwarfAbbrevSection; - } - - public DwarfFrameSectionImpl getFrameSectionImpl() { - return dwarfFameSection; - } - - public DwarfInfoSectionImpl getInfoSectionImpl() { - return dwarfInfoSection; - } - - public DwarfARangesSectionImpl getARangesSectionImpl() { - return dwarfARangesSection; - } - - public DwarfLineSectionImpl getLineSectionImpl() { - return dwarfLineSection; - } - - /** - * a table listing all known strings, some of which may be marked for insertion into the - * debug_str section. - */ - private StringTable stringTable = new StringTable(); - - /** - * index of all dirs in which files are found to reside either as part of substrate/compiler or - * user code. - */ - private Map dirsIndex = new HashMap<>(); - - /* - * The obvious traversal structure for debug records is: - * - * 1) by top level compiled method (primary Range) ordered by ascending address - * - * 2) by inlined method (sub range) within top level method ordered by ascending address - * - * these can be used to ensure that all debug records are generated in increasing address order - * - * An alternative traversal option is - * - * 1) by top level class (String id) - * - * 2) by top level compiled method (primary Range) within a class ordered by ascending address - * - * 3) by inlined method (sub range) within top level method ordered by ascending address - * - * this relies on the (current) fact that methods of a given class always appear in a single - * continuous address range with no intervening code from other methods or data values. this - * means we can treat each class as a compilation unit, allowing data common to all methods of - * the class to be shared. - * - * A third option appears to be to traverse via files, then top level class within file etc. - * Unfortunately, files cannot be treated as the compilation unit. A file F may contain multiple - * classes, say C1 and C2. There is no guarantee that methods for some other class C' in file F' - * will not be compiled into the address space interleaved between methods of C1 and C2. That is - * a shame because generating debug info records one file at a time would allow more sharing - * e.g. enabling all classes in a file to share a single copy of the file and dir tables. - */ - - /** - * list of class entries detailing class info for primary ranges. - */ - private LinkedList primaryClasses = new LinkedList<>(); - /** - * index of already seen classes. - */ - private Map primaryClassesIndex = new HashMap<>(); - - /** - * index of files which contain primary or secondary ranges. - */ - private Map filesIndex = new HashMap<>(); - - /** - * indirects this call to the string table. - * - * @param string the string whose index is required - * - * @return the offset of the string in the .debug_str section - */ - public int debugStringIndex(String string) { - return stringTable.debugStringIndex(string); - } - - /** - * entry point allowing ELFObjectFile to pass on information about types, code and heap data. - * - * @param debugInfoProvider provider instance passed by ObjectFile client - */ - @SuppressWarnings("try") - public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - /* - * DebugTypeInfoProvider typeInfoProvider = debugInfoProvider.typeInfoProvider(); for - * (DebugTypeInfo debugTypeInfo : typeInfoProvider) { install types } - */ - - /* - * ensure we have a null string in the string section - */ - stringTable.uniqueDebugString(""); - - debugInfoProvider.codeInfoProvider().forEach(debugCodeInfo -> debugCodeInfo.debugContext((debugContext) -> { - /* - * primary file name and full method name need to be written to the debug_str section - */ - String fileName = debugCodeInfo.fileName(); - Path filePath = debugCodeInfo.filePath(); - // switch '$' in class names for '.' - String className = debugCodeInfo.className().replaceAll("\\$", "."); - String methodName = debugCodeInfo.methodName(); - String paramNames = debugCodeInfo.paramNames(); - String returnTypeName = debugCodeInfo.returnTypeName(); - int lo = debugCodeInfo.addressLo(); - int hi = debugCodeInfo.addressHi(); - int primaryLine = debugCodeInfo.line(); - - Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - debugContext.log(DebugContext.INFO_LEVEL, "PrimaryRange %s.%s %s %s:%d [0x%x, 0x%x]", className, methodName, filePath, fileName, primaryLine, lo, hi); - addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); - debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { - String fileNameAtLine = debugLineInfo.fileName(); - Path filePathAtLine = debugLineInfo.filePath(); - // switch '$' in class names for '.' - String classNameAtLine = debugLineInfo.className().replaceAll("\\$", "."); - String methodNameAtLine = debugLineInfo.methodName(); - int loAtLine = lo + debugLineInfo.addressLo(); - int hiAtLine = lo + debugLineInfo.addressHi(); - int line = debugLineInfo.line(); - /* - * record all subranges even if they have no line or file so we at least get a - * symbol for them - */ - Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); - addSubRange(primaryRange, subRange); - try (DebugContext.Scope s = debugContext.scope("Subranges")) { - debugContext.log(DebugContext.VERBOSE_LEVEL, "SubRange %s.%s %s %s:%d 0x%x, 0x%x]", classNameAtLine, methodNameAtLine, filePathAtLine, fileNameAtLine, line, loAtLine, hiAtLine); - } - }); - })); - /* - * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); for - * (DebugDataInfo debugDataInfo : dataInfoProvider) { install details of heap elements - * String name = debugDataInfo.toString(); } - */ - } - - private ClassEntry ensureClassEntry(Range range) { - String className = range.getClassName(); - /* - * see if we already have an entry - */ - ClassEntry classEntry = primaryClassesIndex.get(className); - if (classEntry == null) { - /* - * create and index the entry associating it with the right file - */ - FileEntry fileEntry = ensureFileEntry(range); - classEntry = new ClassEntry(className, fileEntry); - primaryClasses.add(classEntry); - primaryClassesIndex.put(className, classEntry); - } - assert classEntry.getClassName().equals(className); - return classEntry; - } - - private FileEntry ensureFileEntry(Range range) { - String fileName = range.getFileName(); - if (fileName == null) { - return null; - } - Path filePath = range.getFilePath(); - Path fileAsPath = range.getFileAsPath(); - /* - * ensure we have an entry - */ - FileEntry fileEntry = filesIndex.get(fileAsPath); - if (fileEntry == null) { - DirEntry dirEntry = ensureDirEntry(filePath); - fileEntry = new FileEntry(fileName, dirEntry); - /* - * index the file entry by file path - */ - filesIndex.put(fileAsPath, fileEntry); - if (!range.isPrimary()) { - /* check we have a file for the corresponding primary range */ - Range primaryRange = range.getPrimary(); - FileEntry primaryFileEntry = filesIndex.get(primaryRange.getFileAsPath()); - assert primaryFileEntry != null; - } - } - return fileEntry; - } - - private void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { - assert primaryRange.isPrimary(); - ClassEntry classEntry = ensureClassEntry(primaryRange); - classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); - } - - private void addSubRange(Range primaryRange, Range subrange) { - assert primaryRange.isPrimary(); - assert !subrange.isPrimary(); - String className = primaryRange.getClassName(); - ClassEntry classEntry = primaryClassesIndex.get(className); - FileEntry subrangeFileEntry = ensureFileEntry(subrange); - /* - * the primary range should already have been seen and associated with a primary class entry - */ - assert classEntry.primaryIndexFor(primaryRange) != null; - if (subrangeFileEntry != null) { - classEntry.addSubRange(subrange, subrangeFileEntry); - } - } - - private DirEntry ensureDirEntry(Path filePath) { - if (filePath == null) { - return null; - } - DirEntry dirEntry = dirsIndex.get(filePath); - if (dirEntry == null) { - dirEntry = new DirEntry(filePath); - dirsIndex.put(filePath, dirEntry); - } - return dirEntry; - } - - public StringTable getStringTable() { - return stringTable; - } - - public LinkedList getPrimaryClasses() { - return primaryClasses; - } - - public ByteOrder getByteOrder() { - return byteOrder; - } -} From 1e4d3c8e3b4392333fcc47555b92dd7e81580035 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 7 Apr 2020 13:25:57 -0400 Subject: [PATCH 115/130] use adinns debugInfoBase, rfactor constant interfaces to classes --- .../objectfile/pecoff/PECoffObjectFile.java | 2 +- .../objectfile/pecoff/cv/CVConstants.java | 52 +-- .../pecoff/cv/CVDebugConstants.java | 46 +-- .../objectfile/pecoff/cv/CVFileRecord.java | 2 +- .../objectfile/pecoff/cv/CVLineRecord.java | 2 +- .../pecoff/cv/CVLineRecordBuilder.java | 10 +- .../objectfile/pecoff/cv/CVRootPackages.java | 2 +- .../objectfile/pecoff/cv/CVSections.java | 5 +- .../pecoff/cv/CVStringTableRecord.java | 2 +- .../objectfile/pecoff/cv/CVSymbolRecord.java | 2 +- .../pecoff/cv/CVSymbolRecordBuilder.java | 10 +- .../pecoff/cv/CVSymbolSubsection.java | 2 +- .../objectfile/pecoff/cv/CVTypeConstants.java | 120 +++---- .../objectfile/pecoff/cv/CVTypeRecord.java | 22 +- .../pecoff/cv/CVTypeSectionImpl.java | 2 +- .../objectfile/pecoff/cv/DebugInfoBase.java | 314 ------------------ 16 files changed, 151 insertions(+), 444 deletions(-) delete mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 37f4887c9c98..15078ad9175d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -701,7 +701,7 @@ public Section newDebugSection(String name, ElementImpl impl) { @Override public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - CVSections cvSections = new CVSections(getMachine()); + CVSections cvSections = new CVSections(getMachine(), getByteOrder()); // we need an implementation for each section CVSymbolSectionImpl cvSymbolSectionImpl = cvSections.getCVSymbolSection(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index 9cadb23ab13b..fee7c64f79d9 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -26,23 +26,23 @@ package com.oracle.objectfile.pecoff.cv; -public interface CVConstants { +public abstract class CVConstants { /* names of relevant CodeView sections */ - String CV_SYMBOL_SECTION_NAME = ".debug$S"; - String CV_TYPE_SECTION_NAME = ".debug$T"; - //String CV_RDATA_SECTION_NAME = ".rdata"; - //String CV_PDATA_SECTION_NAME = ".pdata"; - //String CV_XDATA_SECTION_NAME = ".xdata"; - //String TEXT_SECTION_NAME = ".text"; - //String DATA_SECTION_NAME = ".data"; + static final String CV_SYMBOL_SECTION_NAME = ".debug$S"; + static final String CV_TYPE_SECTION_NAME = ".debug$T"; + //static final String CV_RDATA_SECTION_NAME = ".rdata"; + //static final String CV_PDATA_SECTION_NAME = ".pdata"; + //static final String CV_XDATA_SECTION_NAME = ".xdata"; + //static final String TEXT_SECTION_NAME = ".text"; + //static final String DATA_SECTION_NAME = ".data"; /* CodeView section header signature */ - int CV_SIGNATURE_C13 = 4; + static final int CV_SIGNATURE_C13 = 4; - /* - * Knobs - * + /* + * Knobs + * * (some may become Graal options in the future) */ @@ -50,38 +50,38 @@ public interface CVConstants { * path to JDK source code (for example unzipped src.zip) * If set, source paths for JDK classes in the object file will be * $JDK_SOURCE_BASE/java/package/someclass.java - * instead of + * instead of * (cache directory)/sources/jdk/java/package/someclass.java * or (if source cache is disabled) * java/package/someclass.java - * + * * example * JDK_SOURCE_BASE = C:\\tmp\\graal-8\\jdk8_jvmci\\src\\"; */ - String JDK_SOURCE_BASE = ""; + static final String JDK_SOURCE_BASE = ""; /* * path to Graal source code base (for examplke checked out Graal source repository) * if set source paths will be inferred from appropriate Graal package directories * (behaves similarly to JDK_SOURCE_BASE) - * + * * Example: * GRAAL_SOURCE_BASE = "C:\\tmp\\graal-8\\graal8\\"; */ - String GRAAL_SOURCE_BASE = ""; + static final String GRAAL_SOURCE_BASE = ""; - boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ - boolean skipJDKInternals = false; /* (unimplemented) if true, don't emit debug code for JDK classes */ - boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ - boolean mergeAdjacentLineRecords = true; /* if a line record is the same line in the same file as the previous record, merge them */ - boolean emitUnadornedMain = true; /* if true, first main() does not have args in the debug name */ - String replaceMainFunctionName = null; /* first main() becomes this name (with no class name or arg list at all) (set null to disable) */ + static final boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ + static final boolean skipJDKInternals = false; /* (unimplemented) if true, don't emit debug code for JDK classes */ + static final boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ + static final boolean mergeAdjacentLineRecords = true; /* if a line record is the same line in the same file as the previous record, merge them */ + static final boolean emitUnadornedMain = true; /* if true, first main() does not have args in the debug name */ + static final String replaceMainFunctionName = null; /* first main() becomes this name (with no class name or arg list at all) (set null to disable) */ - /* + /* * The standard link.exe can't handle odd characters (parentheses or commas, for example) in external names. - * Setting functionNamesHashArgs true replaces those names, + * Setting functionNamesHashArgs true replaces those names, * so that "Foo.function(String[] args)" becomes "Foo.function_617849326". * If functionNamesHashArgs is false, currently the linker will fail. */ - boolean functionNamesHashArgs = true; /* if true, arg lists become obscure integers (and link.exe will not work properly) */ + static final boolean functionNamesHashArgs = true; /* if true, arg lists become obscure integers (and link.exe will not work properly) */ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java index 9c6856563853..3bc4ca269d54 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java @@ -26,32 +26,32 @@ package com.oracle.objectfile.pecoff.cv; -public interface CVDebugConstants { +public abstract class CVDebugConstants { - //int DEBUG_S_IGNORE = 0x00; - int DEBUG_S_SYMBOLS = 0xf1; - int DEBUG_S_LINES = 0xf2; - int DEBUG_S_STRINGTABLE = 0xf3; - int DEBUG_S_FILECHKSMS = 0xf4; + //static final int DEBUG_S_IGNORE = 0x00; + static final int DEBUG_S_SYMBOLS = 0xf1; + static final int DEBUG_S_LINES = 0xf2; + static final int DEBUG_S_STRINGTABLE = 0xf3; + static final int DEBUG_S_FILECHKSMS = 0xf4; /* subcommands in DEBUG_S_SYMBOLS section */ - //short S_COMPILE = 0x0001; - short S_SSEARCH = 0x0005; - short S_END = 0x0006; - short S_OBJNAME = 0x1101; - short S_LDATA32_ST = 0x1007; - short S_FRAMEPROC = 0x1012; - short S_CONSTANT = 0x1107; - short S_UDT = 0x1108; - short S_LDATA32 = 0x110c; - short S_GDATA32 = 0x110d; - short S_GPROC32 = 0x1110; - short S_REGREL32 = 0x1111; - short S_COMPILE3 = 0x113c; - short S_ENVBLOCK = 0x113d; - short S_GPROC32_ID = 0x1147; - short S_PROC_ID_END = 0x114f; - //short S_BUILDINFO = 0x114c; + //static final short S_COMPILE = 0x0001; + static final short S_SSEARCH = 0x0005; + static final short S_END = 0x0006; + static final short S_OBJNAME = 0x1101; + static final short S_LDATA32_ST = 0x1007; + static final short S_FRAMEPROC = 0x1012; + static final short S_CONSTANT = 0x1107; + static final short S_UDT = 0x1108; + static final short S_LDATA32 = 0x110c; + static final short S_GDATA32 = 0x110d; + static final short S_GPROC32 = 0x1110; + static final short S_REGREL32 = 0x1111; + static final short S_COMPILE3 = 0x113c; + static final short S_ENVBLOCK = 0x113d; + static final short S_GPROC32_ID = 0x1147; + static final short S_PROC_ID_END = 0x114f; + //static final short S_BUILDINFO = 0x114c; /* enums are more typesafe but the IDE no longer knows which enum constant is unused enum CV_RECORD { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index 1fcf24ddd602..ff5d7019af58 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -55,7 +55,7 @@ final class CVFileRecord extends CVSymbolRecord { private Map fileEntryToOffsetMap = new LinkedHashMap<>(FILE_TABLE_INITIAL_SIZE); CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { - super(cvSections, DEBUG_S_FILECHKSMS); + super(cvSections, CVDebugConstants.DEBUG_S_FILECHKSMS); this.cvSections = cvSections; this.strings = strings; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 946aef49666a..9b23955b9a23 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -130,7 +130,7 @@ int computeContents(byte[] buffer, int initialPos) { } CVLineRecord(CVSections cvSections, String symbolName, PrimaryEntry entry) { - super(cvSections, DEBUG_S_LINES); + super(cvSections, CVDebugConstants.DEBUG_S_LINES); this.primaryEntry = entry; this.symbolName = symbolName; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 8f8218fc17ce..b17d74f38630 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -51,9 +51,9 @@ public class CVLineRecordBuilder { * to handle this, first we decide if we want to merge this with the previous range (only if same file and start of this range is end of previous range) * if we are emitting a new range to the same file, write the range, save it as the previous range and go on * If this is a different file, then update the length of the previous file header, write the new file header and write the new range - * At the very end, make sure we update the last file header + * At the very end, make sure we update the last file header. * - * In addition, optionally ignore Ranges that point into Graal innards, just adding them to the current enclosing ramge + * In addition, optionally ignore Ranges that point into Graal innards, just adding them to the current enclosing range */ /** @@ -125,7 +125,7 @@ private Range processRange(Range range, Range oldPreviousRange) { /* is this a new file? if so we emit a new file record */ boolean wantNewFile = previousRange == null || !previousRange.getFileAsPath().equals(range.getFileAsPath()); if (wantNewFile) { - FileEntry file = cvSections.ensureFileEntry(range); + FileEntry file = cvSections.findFile(range.getFileAsPath()); if (file != null && file.getFileName() != null) { previousRange = null; CVUtil.debug(" processRange: addNewFile: %s\n", file); @@ -153,7 +153,7 @@ private Range processRange(Range range, Range oldPreviousRange) { * @return true if the two ranges can be combined */ private boolean shouldMerge(Range range, Range previousRange) { - if (!mergeAdjacentLineRecords) { + if (!CVConstants.mergeAdjacentLineRecords) { return false; } if (previousRange == null) { @@ -162,7 +162,7 @@ private boolean shouldMerge(Range range, Range previousRange) { /* if we're in a different class that the primary Class, this is inlined code */ final boolean isInlinedCode = !range.getClassName().equals(primaryEntry.getClassEntry().getClassName()); // if (isInlinedCode && skipInlinedCode) { return true; } - if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { + if (isInlinedCode && CVConstants.skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { return true; } return previousRange.getFileAsPath().equals(range.getFileAsPath()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java index f3fd55f3baf3..ff9f2a95293d 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -195,7 +195,7 @@ static boolean isGraalClass(String cn) { } /** - * is class a Graal intrinsic class + * is class a Graal intrinsic class? * * @param cn class name of code * @return true if this is Graal intrinsic code diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java index 2020cbfefa4c..5b99e292748f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java @@ -31,9 +31,11 @@ import com.oracle.objectfile.LayoutDecision; import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.debugentry.DebugInfoBase; import com.oracle.objectfile.pecoff.PECoffMachine; import com.oracle.objectfile.pecoff.PECoffObjectFile; +import java.nio.ByteOrder; import java.util.Map; import java.util.Set; @@ -48,7 +50,8 @@ public final class CVSections extends DebugInfoBase { private CVSymbolSectionImpl cvSymbolSection; private CVTypeSectionImpl cvTypeSection; - public CVSections(PECoffMachine targetMachine) { + public CVSections(PECoffMachine targetMachine, ByteOrder byteOrder) { + super(byteOrder); machine = targetMachine; cvSymbolSection = new CVSymbolSectionImpl(this); cvTypeSection = new CVTypeSectionImpl(); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java index 56c018b5aa5e..afc96f64728c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVStringTableRecord.java @@ -33,7 +33,7 @@ final class CVStringTableRecord extends CVSymbolRecord { private final CVSymbolSectionImpl.CVStringTable stringTable; CVStringTableRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable stringTable) { - super(cvSections, DEBUG_S_STRINGTABLE); + super(cvSections, CVDebugConstants.DEBUG_S_STRINGTABLE); this.stringTable = stringTable; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index 6a7e569d0f32..74281fcac936 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -31,7 +31,7 @@ /* * A Symbol record is a top-level record in the CodeView .debug$S section */ -abstract class CVSymbolRecord implements CVDebugConstants { +abstract class CVSymbolRecord { CVSections cvSections; protected int recordStartPosition; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 2902290c0044..0ba3f15e3d13 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -49,7 +49,7 @@ final class CVSymbolRecordBuilder { } /** - * build DEBUG_S_SYMBOLS record from all classEntries + * build DEBUG_S_SYMBOLS record from all classEntries. * (could probably build one per class or one per function) */ void build() { @@ -60,7 +60,7 @@ void build() { } /** - * build all debug info for a classEntry + * build all debug info for a classEntry. * (does not yet handle member variables) * * @param classEntry current class @@ -86,7 +86,7 @@ private void build(ClassEntry classEntry) { * S_FRAMEPROC * S_END * (later: type records as required) - * line number records + * line number records. * * @param primaryEntry primary entry for this function * @param methodName method name alias as it will be seen by the user @@ -108,7 +108,7 @@ private void build(PrimaryEntry primaryEntry, String methodName) { private boolean noMainFound = true; /** - * renames a method name ot something user friendly in the debugger + * renames a method name ot something user friendly in the debugger. * (does not affect external symbols used by linker) * * first main function becomes class.main (unless replaceMainFunctionName is non-null) @@ -154,7 +154,7 @@ private void addToSymbolRecord(CVSymbolSubrecord record) { } /** - * add type records for function + * add type records for function. * (later add arglist, and return type and local types) * @param entry primaryEntry containing entities whoses type records must be added * diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java index b1f5ce61ff7e..907382611d2a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java @@ -37,7 +37,7 @@ class CVSymbolSubsection extends CVSymbolRecord { private ArrayList subcmds = new ArrayList<>(20); CVSymbolSubsection(CVSections cvSections) { - super(cvSections, DEBUG_S_SYMBOLS); + super(cvSections, CVDebugConstants.DEBUG_S_SYMBOLS); } void addRecord(CVSymbolSubrecord subcmd) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java index efaaacf17f71..dacdb0e289f7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java @@ -26,73 +26,73 @@ package com.oracle.objectfile.pecoff.cv; -public interface CVTypeConstants { +abstract class CVTypeConstants { /* type table */ - short T_NOTYPE = 0x0000; - short T_VOID = 0x0003; - //short T_CHAR = 0x0010; /* 8 bit signed (java type) */ - //short T_WCHAR = 0x0071; - //short T_CHAR16 = 0x007a; /* 16 bit unicode (Java type) */ - //short T_SHORT = 0x0011; /* 16 bit signed short (Java type) */ - //short T_LONG = 0x0014; /* 32 bit signed (java type? maybe T_short4?) */ - short T_QUAD = 0x0013; /* 64 bit signed long long (Java type) */ - //short T_REAL32 = 0x0040; /* 32 bit float (Java type) */ - //short T_REAL64 = 0x0041; /* 64 but double (Java type) */ - //short T_RCHAR = 0x0070; /* ?? "really a char" */ + static final short T_NOTYPE = 0x0000; + static final short T_VOID = 0x0003; + //static final short T_CHAR = 0x0010; /* 8 bit signed (java type) */ + //static final short T_WCHAR = 0x0071; + //static final short T_CHAR16 = 0x007a; /* 16 bit unicode (Java type) */ + //static final short T_SHORT = 0x0011; /* 16 bit signed short (Java type) */ + //static final short T_LONG = 0x0014; /* 32 bit signed (java type? maybe T_short4?) */ + static final short T_QUAD = 0x0013; /* 64 bit signed long long (Java type) */ + //static final short T_REAL32 = 0x0040; /* 32 bit float (Java type) */ + //static final short T_REAL64 = 0x0041; /* 64 but double (Java type) */ + //static final short T_RCHAR = 0x0070; /* ?? "really a char" */ - //short T_INT4 = T_LONG; /* ?? is tis right */ - short T_UQUAD = T_QUAD; /* ?? */ + //static final short T_INT4 = T_LONG; /* ?? is tis right */ + static final short T_UQUAD = T_QUAD; /* ?? */ - //short T_POINTER_BITS = 0x0700; - //short T_POINTER32 = 0x0400; /* 32 bit pointer */ - //short T_POINTER64 = 0x0600; /* 64 bit pointer */ + //static final short T_POINTER_BITS = 0x0700; + //static final short T_POINTER32 = 0x0400; /* 32 bit pointer */ + //static final short T_POINTER64 = 0x0600; /* 64 bit pointer */ - short LF_MODIFIER = 0x1001; - short LF_POINTER = 0x1002; - short LF_PROCEDURE = 0x1008; - short LF_ARGLIST = 0x1201; - //short LF_FIELDLIST = 0x1203; - short LF_BITFIELD = 0x1205; - short LF_BCLASS = 0x1400; - short LF_ARRAY = 0x1503; - short LF_CLASS = 0x1504; - short LF_STRUCTURE = 0x1505; - //short LF_UNION = 0x1506; - //short LF_ENUM = 0x1507; - short LF_MEMBER = 0x150d; - short LF_TYPESERVER2 = 0x1515; - short LF_INTERFACE = 0x1519; - short LF_BINTERFACE = 0x151a; + static final short LF_MODIFIER = 0x1001; + static final short LF_POINTER = 0x1002; + static final short LF_PROCEDURE = 0x1008; + static final short LF_ARGLIST = 0x1201; + //static final short LF_FIELDLIST = 0x1203; + static final short LF_BITFIELD = 0x1205; + static final short LF_BCLASS = 0x1400; + static final short LF_ARRAY = 0x1503; + static final short LF_CLASS = 0x1504; + static final short LF_STRUCTURE = 0x1505; + //static final short LF_UNION = 0x1506; + //static final short LF_ENUM = 0x1507; + static final short LF_MEMBER = 0x150d; + static final short LF_TYPESERVER2 = 0x1515; + static final short LF_INTERFACE = 0x1519; + static final short LF_BINTERFACE = 0x151a; /* - short LF_CHAR = (short) 0x8000; - short LF_SHORT = (short) 0x8001; - short LF_USHORT = (short) 0x8002; - short LF_LONG = (short) 0x8003; - short LF_ULONG = (short) 0x8004; - short LF_REAL32 = (short) 0x8005; - short LF_REAL64 = (short) 0x8006; - short LF_QUADWORD = (short) 0x8009; - short LF_UQUADWORD = (short) 0x800a; - short LF_OCTWORD = (short) 0x8017; - short LF_UOCTWORD = (short) 0x8018; + static final short LF_CHAR = (short) 0x8000; + static final short LF_SHORT = (short) 0x8001; + static final short LF_USHORT = (short) 0x8002; + static final short LF_LONG = (short) 0x8003; + static final short LF_ULONG = (short) 0x8004; + static final short LF_REAL32 = (short) 0x8005; + static final short LF_REAL64 = (short) 0x8006; + static final short LF_QUADWORD = (short) 0x8009; + static final short LF_UQUADWORD = (short) 0x800a; + static final short LF_OCTWORD = (short) 0x8017; + static final short LF_UOCTWORD = (short) 0x8018; */ - //byte LF_PAD0 = (byte) 0xf0; - byte LF_PAD1 = (byte) 0xf1; - byte LF_PAD2 = (byte) 0xf2; - byte LF_PAD3 = (byte) 0xf3; - /*byte LF_PAD4 = (byte) 0xf4; - byte LF_PAD5 = (byte) 0xf5; - byte LF_PAD6 = (byte) 0xf6; - byte LF_PAD7 = (byte) 0xf7; - byte LF_PAD8 = (byte) 0xf8; - byte LF_PAD9 = (byte) 0xf9; - byte LF_PAD10 = (byte) 0xfa; - byte LF_PAD11 = (byte) 0xfb; - byte LF_PAD12 = (byte) 0xfc; - byte LF_PAD13 = (byte) 0xfd; - byte LF_PAD14 = (byte) 0xfe; - byte LF_PAD15 = (byte) 0xff;*/ + //static final byte LF_PAD0 = (byte) 0xf0; + static final byte LF_PAD1 = (byte) 0xf1; + static final byte LF_PAD2 = (byte) 0xf2; + static final byte LF_PAD3 = (byte) 0xf3; + /*static final byte LF_PAD4 = (byte) 0xf4; + static final byte LF_PAD5 = (byte) 0xf5; + static final byte LF_PAD6 = (byte) 0xf6; + static final byte LF_PAD7 = (byte) 0xf7; + static final byte LF_PAD8 = (byte) 0xf8; + static final byte LF_PAD9 = (byte) 0xf9; + static final byte LF_PAD10 = (byte) 0xfa; + static final byte LF_PAD11 = (byte) 0xfb; + static final byte LF_PAD12 = (byte) 0xfc; + static final byte LF_PAD13 = (byte) 0xfd; + static final byte LF_PAD14 = (byte) 0xfe; + static final byte LF_PAD15 = (byte) 0xff;*/ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java index a58da8ad42cc..fc9162797007 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java @@ -30,17 +30,35 @@ import java.util.ArrayList; import java.util.Arrays; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_ARGLIST; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_ARRAY; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_BCLASS; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_BINTERFACE; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_BITFIELD; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_CLASS; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_INTERFACE; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_MEMBER; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_MODIFIER; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_PAD1; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_PAD2; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_PAD3; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_POINTER; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_PROCEDURE; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_STRUCTURE; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.LF_TYPESERVER2; +import static com.oracle.objectfile.pecoff.cv.CVTypeConstants.T_UQUAD; + /* * CV Type Record format (little-endian): * uint16 length * uint16 leaf (a.k.a. record type) * (contents) */ -abstract class CVTypeRecord implements CVTypeConstants { +abstract class CVTypeRecord { protected final short type; private int startPosition; - private int sequenceNumber; // 1000 on up + private int sequenceNumber; /* CodeView type records are numbered 1000 on up */ CVTypeRecord(short type) { this.type = type; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java index d429c87ae2fa..96d883c48d65 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java @@ -43,7 +43,7 @@ import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SYMBOL_SECTION_NAME; import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_TYPE_SECTION_NAME; -public final class CVTypeSectionImpl extends CVSectionImplBase implements CVTypeConstants { +public final class CVTypeSectionImpl extends CVSectionImplBase { private static final int CV_VECTOR_DEFAULT_SIZE = 200; private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java deleted file mode 100644 index f753b420a464..000000000000 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/DebugInfoBase.java +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 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.pecoff.cv; - -import com.oracle.objectfile.debugentry.ClassEntry; -import com.oracle.objectfile.debugentry.DirEntry; -import com.oracle.objectfile.debugentry.FileEntry; -import com.oracle.objectfile.debugentry.Range; -import com.oracle.objectfile.debugentry.StringTable; -import com.oracle.objectfile.debuginfo.DebugInfoProvider; - -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.LinkedList; - -/** - * Accept debugCodeInfo (etc) and populate the local debug database. - */ - -/* - * TODO: - * - share this with ELF/DWARF and Mach-O code - * - abstract out the original code in elf.dwarf package and reuse it. - * - speed this up - * - move the nested classes outside - * - handle stack frames - */ -public abstract class DebugInfoBase { - - private static boolean isWanted(DebugInfoProvider.DebugCodeInfo debugCodeInfo) { - /* TODO: be much more clever; this is merely proof of concept */ - //return !(CVConstants.skipGraalInternals && debugCodeInfo.className().startsWith("com.oracle")); - return true; - } - - public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - - /* - * ensure we have a null string in the string section - */ - uniqueDebugString(""); - - debugInfoProvider.codeInfoProvider().filter(debugCodeInfo -> isWanted(debugCodeInfo)).forEach(debugCodeInfo -> { - /* - * primary file name and full method name need to be written to the debug_str section - */ - String fileName = debugCodeInfo.fileName(); - Path filePath = debugCodeInfo.filePath(); - // switch '$' in class names for '.' - String className = debugCodeInfo.className().replaceAll("\\$", "."); - String methodName = debugCodeInfo.methodName(); - String paramNames = debugCodeInfo.paramNames(); - String returnTypeName = debugCodeInfo.returnTypeName(); - int lo = debugCodeInfo.addressLo(); - int hi = debugCodeInfo.addressHi(); - int primaryLine = debugCodeInfo.line(); - CVUtil.debug("primaryrange: [0x%08x,0x%08x,l=%d) %s.%s(%s) %s\n", lo, hi, primaryLine, className, methodName, paramNames, fileName); - Range primaryRange = new Range(fileName, filePath, className, methodName, paramNames, returnTypeName, stringTable, lo, hi, primaryLine); - /* - * System.out.format("arange: [0x%08x,0x%08x) %s %s::%s(%s) %s\n", lo, hi, - * returnTypeName, className, methodName, paramNames, fileName); - * create an infoSection entry for the method - */ - addRange(primaryRange, debugCodeInfo.getFrameSizeChanges(), debugCodeInfo.getFrameSize()); - debugCodeInfo.lineInfoProvider().forEach(debugLineInfo -> { - String fileNameAtLine = debugLineInfo.fileName(); - Path filePathAtLine = debugLineInfo.filePath(); - /* switch '$' in class names for '.' */ - String classNameAtLine = debugLineInfo.className().replaceAll("\\$", "."); - String methodNameAtLine = debugLineInfo.methodName(); - int loAtLine = lo + debugLineInfo.addressLo(); - int hiAtLine = lo + debugLineInfo.addressHi(); - int line = debugLineInfo.line(); - /* - * record all subranges even if they have no line or file so we at least get a - * symbol for them - */ - //CVUtil.debug(" lineinfo: [0x%08x,0x%08x) %s.%s (%s:%d)\n", loAtLine, hiAtLine, classNameAtLine, methodNameAtLine, fileNameAtLine, line); - Range subRange = new Range(fileNameAtLine, filePathAtLine, classNameAtLine, methodNameAtLine, "", "", stringTable, loAtLine, hiAtLine, line, primaryRange); - addSubRange(primaryRange, subRange); - }); - }); - /* - * DebugDataInfoProvider dataInfoProvider = debugInfoProvider.dataInfoProvider(); - * for (DebugDataInfo debugDataInfo : dataInfoProvider) { - * install details of heap elements - * String name = debugDataInfo.toString(); - * } - */ - } - - public LinkedList getFiles() { - return files; - } - - public LinkedList getPrimaryFiles() { - return primaryFiles; - } - - private ClassEntry ensureClassEntry(Range range) { - String className = range.getClassName(); - /* - * see if we already have an entry - */ - ClassEntry classEntry = primaryClassesIndex.get(className); - if (classEntry == null) { - /* - * create and index the entry associating it with the right file - */ - FileEntry fileEntry = ensureFileEntry(range); - classEntry = new ClassEntry(className, fileEntry); - primaryClasses.add(classEntry); - primaryClassesIndex.put(className, classEntry); - } - assert classEntry.getClassName().equals(className); - return classEntry; - } - - FileEntry ensureFileEntry(Range range) { - String fileName = range.getFileName(); - if (fileName == null) { - return null; - } - Path filePath = range.getFilePath(); - Path fileAsPath = range.getFileAsPath(); - /* - * ensure we have an entry - */ - FileEntry fileEntry = filesIndex.get(fileAsPath); - if (fileEntry == null) { - DirEntry dirEntry = ensureDirEntry(filePath); - fileEntry = new FileEntry(fileName, dirEntry); - files.add(fileEntry); - filesIndex.put(fileAsPath, fileEntry); - /* - * if this is a primary entry then add it to the primary list - */ - if (range.isPrimary()) { - primaryFiles.add(fileEntry); - } else { - Range primaryRange = range.getPrimary(); - FileEntry primaryEntry = filesIndex.get(primaryRange.getFileAsPath()); - assert primaryEntry != null; - } - } - return fileEntry; - } - - private void addRange(Range primaryRange, List frameSizeInfos, int frameSize) { - assert primaryRange.isPrimary(); - ClassEntry classEntry = ensureClassEntry(primaryRange); - /*PrimaryEntry entry =*/ classEntry.addPrimary(primaryRange, frameSizeInfos, frameSize); - } - - private void addSubRange(Range primaryRange, Range subrange) { - assert primaryRange.isPrimary(); - assert !subrange.isPrimary(); - String className = primaryRange.getClassName(); - ClassEntry classEntry = primaryClassesIndex.get(className); - FileEntry subrangeEntry = ensureFileEntry(subrange); - /* - * the primary range should already have been seen - * and associated with a primary class entry - */ - assert classEntry.primaryIndexFor(primaryRange) != null; - if (subrangeEntry != null) { - classEntry.addSubRange(subrange, subrangeEntry); - } - } - - private DirEntry ensureDirEntry(Path filePath) { - if (filePath == null) { - return null; - } - DirEntry dirEntry = dirsIndex.get(filePath); - if (dirEntry == null) { - dirEntry = new DirEntry(filePath); - dirsIndex.put(filePath, dirEntry); - dirs.add(dirEntry); - } - return dirEntry; - } - public StringTable getStringTable() { - return stringTable; - } - public LinkedList getPrimaryClasses() { - return primaryClasses; - } - - /** - * a table listing all known strings, some of - * which may be marked for insertion into the - * debug_str section. - */ - private StringTable stringTable = new StringTable(); - - /** - * list detailing all dirs in which files are found to reside - * either as part of substrate/compiler or user code. - */ - private LinkedList dirs = new LinkedList<>(); - /** - * index of already seen dirs. - */ - private Map dirsIndex = new HashMap<>(); - - /* - * The obvious traversal structure for debug records is: - * - * 1) by top level compiled method (primary Range) ordered by ascending address - * 2) by inlined method (sub range) within top level method ordered by ascending address - * - * these can be used to ensure that all debug records are generated in increasing address order - * - * An alternative traversal option is - * - * 1) by top level class (String id) - * 2) by top level compiled method (primary Range) within a class ordered by ascending address - * 3) by inlined method (sub range) within top level method ordered by ascending address - * - * this relies on the (current) fact that methods of a given class always appear - * in a single continuous address range with no intervening code from other methods - * or data values. this means we can treat each class as a compilation unit, allowing - * data common to all methods of the class to be shared. - * - * A third option appears to be to traverse via files, then top level class within file etc. - * Unfortunately, files cannot be treated as the compilation unit. A file F may contain - * multiple classes, say C1 and C2. There is no guarantee that methods for some other - * class C' in file F' will not be compiled into the address space interleaved between - * methods of C1 and C2. That is a shame because generating debug info records one file at a - * time would allow more sharing e.g. enabling all classes in a file to share a single copy - * of the file and dir tables. - */ - - /** - * list of class entries detailing class info for primary ranges. - */ - private LinkedList primaryClasses = new LinkedList<>(); - /** - * index of already seen classes. - */ - private Map primaryClassesIndex = new HashMap<>(); - - /** - * list of files which contain primary ranges. - */ - private LinkedList primaryFiles = new LinkedList<>(); - /** - * List of files which contain primary or secondary ranges. - */ - private LinkedList files = new LinkedList<>(); - /** - * index of already seen files. - */ - private Map filesIndex = new HashMap<>(); - - /** - * indirects this call to the string table. - * @param string the string to be inserted - * @return a unique equivalent String - */ - public String uniqueString(String string) { - return stringTable.uniqueString(string); - } - - /** - * indirects this call to the string table, ensuring - * the table entry is marked for inclusion in the - * debug_str section. - * @param string the string to be inserted and - * marked for inclusion in the debug_str section - * @return a unique equivalent String - */ - public String uniqueDebugString(String string) { - return stringTable.uniqueDebugString(string); - } - - /** - * indirects this call to the string table. - * @param string the string whose index is required - * @return the offset of the string in the .debug_str - * section - */ - public int debugStringIndex(String string) { - return stringTable.debugStringIndex(string); - } - -} From 9bbddfd9010c3fd66a6dc72d1c88ff309d13970e Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 7 Apr 2020 15:21:55 -0400 Subject: [PATCH 116/130] more cleanup, slight refactor --- .../objectfile/pecoff/cv/CVFileRecord.java | 1 - .../objectfile/pecoff/cv/CVLineRecord.java | 4 +- .../pecoff/cv/CVLineRecordBuilder.java | 10 +- .../objectfile/pecoff/cv/CVSectionImpl.java | 117 ++++++++++++++++++ .../objectfile/pecoff/cv/CVSections.java | 89 +------------ .../objectfile/pecoff/cv/CVSymbolRecord.java | 2 +- .../pecoff/cv/CVSymbolRecordBuilder.java | 4 +- .../pecoff/cv/CVSymbolSectionImpl.java | 4 +- .../pecoff/cv/CVSymbolSubrecord.java | 2 +- .../pecoff/cv/CVTypeSectionImpl.java | 3 +- 10 files changed, 130 insertions(+), 106 deletions(-) create mode 100644 substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index ff5d7019af58..6cdacfbb23c1 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -56,7 +56,6 @@ final class CVFileRecord extends CVSymbolRecord { CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { super(cvSections, CVDebugConstants.DEBUG_S_FILECHKSMS); - this.cvSections = cvSections; this.strings = strings; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 9b23955b9a23..59edf88d0dfa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -106,7 +106,7 @@ static class LineEntry { int addr; int lineAndFLags; -/* + LineEntry(int addr, int line, int deltaEnd, boolean isStatement) { this.addr = addr; assert line <= 0xffffff; @@ -115,7 +115,7 @@ static class LineEntry { assert deltaEnd >= 0; lineAndFLags = line | (deltaEnd << 24) | (isStatement ? 0x80000000 : 0); } -*/ + LineEntry(int addr, int line) { this.addr = addr; this.lineAndFLags = line; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index b17d74f38630..6470bf381ca3 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -57,7 +57,7 @@ public class CVLineRecordBuilder { */ /** - * build line number records for a function + * Build line number records for a function. * @param entry function to build line number table for * @return CVLineRecord containing any entries generated, or null if no entries generated */ @@ -147,13 +147,13 @@ private Range processRange(Range range, Range oldPreviousRange) { } /** - * test to see if two ranges are adjacent, and can be combined into one + * Test to see if two ranges are adjacent, and can be combined into one. * @param previousRange the first range (lower address) * @param range the second range (higher address) * @return true if the two ranges can be combined */ private boolean shouldMerge(Range range, Range previousRange) { - if (!CVConstants.mergeAdjacentLineRecords) { + if (!mergeAdjacentLineRecords) { return false; } if (previousRange == null) { @@ -162,14 +162,14 @@ private boolean shouldMerge(Range range, Range previousRange) { /* if we're in a different class that the primary Class, this is inlined code */ final boolean isInlinedCode = !range.getClassName().equals(primaryEntry.getClassEntry().getClassName()); // if (isInlinedCode && skipInlinedCode) { return true; } - if (isInlinedCode && CVConstants.skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { + if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { return true; } return previousRange.getFileAsPath().equals(range.getFileAsPath()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); } /** - * test to see if a new line record should be emitted + * Test to see if a new line record should be emitted. * @param previousRange previous range * @param range current range * @return true if the current range is on a different line or file from the previous one diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java new file mode 100644 index 000000000000..1cd2206689b8 --- /dev/null +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 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.pecoff.cv; + +import com.oracle.objectfile.BasicProgbitsSectionImpl; +import com.oracle.objectfile.BuildDependency; +import com.oracle.objectfile.LayoutDecision; +import com.oracle.objectfile.LayoutDecisionMap; +import com.oracle.objectfile.ObjectFile; +import com.oracle.objectfile.pecoff.PECoffObjectFile; + +import java.util.Map; +import java.util.Set; + +abstract class CVSectionImpl extends BasicProgbitsSectionImpl { + + int debugLevel = 1; + long debugTextBase = 0; + long debugAddress = 0; + int debugBase = 0; + + CVSectionImpl() { + checkDebug(0); + } + + @Override + public void setElement(ObjectFile.Element e) { + super.setElement(e); + /* define the section as a COFF symbol */ + getOwner().createDefinedSymbol(getSectionName(), getElement(), 0, 0, false, false); + } + + void checkDebug(int pos) { + /* if the env var relevant to this element type is set then switch on debugging */ + String envVarName = "DEBUG_" + getSectionName().substring(1).toUpperCase(); + if (System.getenv(envVarName) != null) { + debugLevel = 1; + debugBase = pos; + debugAddress = debugTextBase; + } + } + + @Override + public int getAlignment() { + return 1; + } + + public void debug(String format, Object ... args) { + if (debugLevel > 1) { + CVUtil.debug(format + "\n", args); + } + } + + public void info(String format, Object ... args) { + if (debugLevel > 0) { + CVUtil.debug(format + "\n", args); + } + } + + @Override + public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + /* ensure content byte[] has been created before calling super method */ + createContent(); + + /* ensure content byte[] has been written before calling super method */ + writeContent(); + + return super.getOrDecideContent(alreadyDecided, contentHint); + } + + @Override + public Set getDependencies(Map decisions) { + Set deps = super.getDependencies(decisions); + String targetName = getSectionName(); + @SuppressWarnings("unused") PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + //LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + /* make our content depend on the size and content of the target */ + //for (LayoutDecision.Kind targetKind : targetKinds) { + // LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + // deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + //} + /* make our size depend on our content */ + deps.add(BuildDependency.createOrGet(ourSize, ourContent)); + return deps; + } + + //public abstract LayoutDecision.Kind[] targetSectionKinds(); + public abstract void createContent(); + public abstract void writeContent(); + public abstract String getSectionName(); +} diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java index 5b99e292748f..4276b1f62118 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java @@ -26,22 +26,14 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.BasicProgbitsSectionImpl; -import com.oracle.objectfile.BuildDependency; -import com.oracle.objectfile.LayoutDecision; -import com.oracle.objectfile.LayoutDecisionMap; -import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.debugentry.DebugInfoBase; import com.oracle.objectfile.pecoff.PECoffMachine; -import com.oracle.objectfile.pecoff.PECoffObjectFile; import java.nio.ByteOrder; -import java.util.Map; -import java.util.Set; /** * CVSections is a container class for all the CodeView sections to be emitted in the object file. - * Currently, that will be .debug$S (CVSymbolSectionImpl) (and .debug$T (CVTypeSectionImpl) when implemented) + * Currently, that will be .debug$S (CVSymbolSectionImpl) and .debug$T (CVTypeSectionImpl) * Common data (useful to more than one CodeView section) goes here, mostly that gathered by calls to installDebugInfo->addRange() and installDebugInfo->addSubRange() */ public final class CVSections extends DebugInfoBase { @@ -65,83 +57,4 @@ public CVTypeSectionImpl getCVTypeSection() { return cvTypeSection; } - abstract static class CVSectionImplBase extends BasicProgbitsSectionImpl { - - int debugLevel = 1; - long debugTextBase = 0; - long debugAddress = 0; - int debugBase = 0; - - CVSectionImplBase() { - checkDebug(0); - } - - @Override - public void setElement(ObjectFile.Element e) { - super.setElement(e); - /* define the section as a COFF symbol */ - getOwner().createDefinedSymbol(getSectionName(), getElement(), 0, 0, false, false); - } - - void checkDebug(int pos) { - /* if the env var relevant to this element type is set then switch on debugging */ - String envVarName = "DEBUG_" + getSectionName().substring(1).toUpperCase(); - if (System.getenv(envVarName) != null) { - debugLevel = 1; - debugBase = pos; - debugAddress = debugTextBase; - } - } - - @Override - public int getAlignment() { - return 1; - } - - public void debug(String format, Object ... args) { - if (debugLevel > 1) { - CVUtil.debug(format + "\n", args); - } - } - - public void info(String format, Object ... args) { - if (debugLevel > 0) { - CVUtil.debug(format + "\n", args); - } - } - - @Override - public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { - /* ensure content byte[] has been created before calling super method */ - createContent(); - - /* ensure content byte[] has been written before calling super method */ - writeContent(); - - return super.getOrDecideContent(alreadyDecided, contentHint); - } - - @Override - public Set getDependencies(Map decisions) { - Set deps = super.getDependencies(decisions); - String targetName = getSectionName(); - @SuppressWarnings("unused") PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); - //LayoutDecision.Kind[] targetKinds = targetSectionKinds(); - /* make our content depend on the size and content of the target */ - //for (LayoutDecision.Kind targetKind : targetKinds) { - // LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); - // deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); - //} - /* make our size depend on our content */ - deps.add(BuildDependency.createOrGet(ourSize, ourContent)); - return deps; - } - - //public abstract LayoutDecision.Kind[] targetSectionKinds(); - public abstract void createContent(); - public abstract void writeContent(); - public abstract String getSectionName(); - } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index 74281fcac936..9b4b6fb0cb71 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -33,7 +33,7 @@ */ abstract class CVSymbolRecord { - CVSections cvSections; + protected CVSections cvSections; protected int recordStartPosition; protected final int type; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 0ba3f15e3d13..a1659a4f3c35 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -39,13 +39,11 @@ final class CVSymbolRecordBuilder { private final CVSections cvSections; - private final CVTypeSectionImpl typeSection; private final CVSymbolSubsection symbolRecord; CVSymbolRecordBuilder(CVSections cvSections) { this.symbolRecord = new CVSymbolSubsection(cvSections); this.cvSections = cvSections; - this.typeSection = cvSections.getCVTypeSection(); } /** @@ -93,7 +91,7 @@ private void build(ClassEntry classEntry) { */ private void build(PrimaryEntry primaryEntry, String methodName) { final Range primaryRange = primaryEntry.getPrimary(); - CVUtil.debug("addfunc(" + methodName + ") numtypes = %d\n", typeSection.getRecords().size()); + CVUtil.debug("addfunc(" + methodName + ") numtypes = %d\n", cvSections.getCVTypeSection().getRecords().size()); int functionTypeIndex = addTypeRecords(primaryEntry); byte funcFlags = 0; CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvSections, methodName, 0, 0, 0, primaryRange.getHi() - primaryRange.getLo(), 0, 0, functionTypeIndex, primaryRange.getLo(), (short) 0, funcFlags); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java index 6572640e9148..9b6a3dc01fdc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java @@ -26,8 +26,6 @@ package com.oracle.objectfile.pecoff.cv; -import com.oracle.objectfile.pecoff.cv.CVSections.CVSectionImplBase; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -38,7 +36,7 @@ import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SIGNATURE_C13; import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SYMBOL_SECTION_NAME; -public final class CVSymbolSectionImpl extends CVSectionImplBase { +public final class CVSymbolSectionImpl extends CVSectionImpl { private static final int CV_VECTOR_DEFAULT_SIZE = 200; private static final int CV_STRINGTABLE_DEFAULT_SIZE = 200; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index 6015289fcc5a..00bfbf788264 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -193,7 +193,7 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { * Example: * cwd = C:\tmp\graal-8 * cl = C:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\Bin\x86_amd64\cl.exe - * cmd = -Zi -MT -IC:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\INCLUDE -IC:\tmp\graal-8\ojdkbuild\tools\toolchain\sdk71\INCLUDE -IC:\tmp\graal-8\ojdkbuild\tools\toolchain\sdk71\INCLUDE\gl -TC -X + * cmd = -Zi -MT -IC:\tmp\graal-8\tools\toolchain\vs2010e\VC\INCLUDE -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE\gl -TC -X * src = helloworld.c * pdb = C:\tmp\graal-8\vc100.pdb */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java index 96d883c48d65..a94036d84434 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java @@ -31,7 +31,6 @@ import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.pecoff.PECoffObjectFile; -import com.oracle.objectfile.pecoff.cv.CVSections.CVSectionImplBase; import java.util.ArrayList; import java.util.Collections; @@ -43,7 +42,7 @@ import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_SYMBOL_SECTION_NAME; import static com.oracle.objectfile.pecoff.cv.CVConstants.CV_TYPE_SECTION_NAME; -public final class CVTypeSectionImpl extends CVSectionImplBase { +public final class CVTypeSectionImpl extends CVSectionImpl { private static final int CV_VECTOR_DEFAULT_SIZE = 200; private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); From 44b8696e067c0866e1e4ecba66157a5f6f31a312 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Wed, 8 Apr 2020 15:46:44 -0400 Subject: [PATCH 117/130] slight refactor to use standard debugcontext-based logging --- .../objectfile/pecoff/PECoffObjectFile.java | 10 +- .../cv/{CVSections.java => CVDebugInfo.java} | 10 +- .../objectfile/pecoff/cv/CVFileRecord.java | 9 +- .../objectfile/pecoff/cv/CVLineRecord.java | 10 +- .../pecoff/cv/CVLineRecordBuilder.java | 34 +++--- .../objectfile/pecoff/cv/CVRootPackages.java | 1 - .../objectfile/pecoff/cv/CVSectionImpl.java | 47 +++++--- .../pecoff/cv/CVStringTableRecord.java | 4 +- .../objectfile/pecoff/cv/CVSymbolRecord.java | 6 +- .../pecoff/cv/CVSymbolRecordBuilder.java | 36 +++--- .../pecoff/cv/CVSymbolSectionImpl.java | 54 +++++---- .../pecoff/cv/CVSymbolSubrecord.java | 108 +++++++++--------- .../pecoff/cv/CVSymbolSubsection.java | 8 +- .../pecoff/cv/CVTypeSectionImpl.java | 24 ++-- .../oracle/objectfile/pecoff/cv/CVUtil.java | 31 ++--- 15 files changed, 204 insertions(+), 188 deletions(-) rename substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/{CVSections.java => CVDebugInfo.java} (82%) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java index 15078ad9175d..a633c89e351e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/PECoffObjectFile.java @@ -44,7 +44,7 @@ import com.oracle.objectfile.io.OutputAssembler; import com.oracle.objectfile.pecoff.PECoff.IMAGE_FILE_HEADER; import com.oracle.objectfile.pecoff.PECoff.IMAGE_SECTION_HEADER; -import com.oracle.objectfile.pecoff.cv.CVSections; +import com.oracle.objectfile.pecoff.cv.CVDebugInfo; import com.oracle.objectfile.pecoff.cv.CVSymbolSectionImpl; import com.oracle.objectfile.pecoff.cv.CVTypeSectionImpl; @@ -701,11 +701,11 @@ public Section newDebugSection(String name, ElementImpl impl) { @Override public void installDebugInfo(DebugInfoProvider debugInfoProvider) { - CVSections cvSections = new CVSections(getMachine(), getByteOrder()); + CVDebugInfo cvDebugInfo = new CVDebugInfo(getMachine(), getByteOrder()); // we need an implementation for each section - CVSymbolSectionImpl cvSymbolSectionImpl = cvSections.getCVSymbolSection(); - CVTypeSectionImpl cvTypeSectionImpl = cvSections.getCVTypeSection(); + CVSymbolSectionImpl cvSymbolSectionImpl = cvDebugInfo.getCVSymbolSection(); + CVTypeSectionImpl cvTypeSectionImpl = cvDebugInfo.getCVTypeSection(); // now we can create the section elements with empty content newDebugSection(cvSymbolSectionImpl.getSectionName(), cvSymbolSectionImpl); @@ -724,6 +724,6 @@ public void installDebugInfo(DebugInfoProvider debugInfoProvider) { cvTypeSectionImpl.getOrCreateRelocationElement(false); // ok now we can populate the implementations - cvSections.installDebugInfo(debugInfoProvider); + cvDebugInfo.installDebugInfo(debugInfoProvider); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java similarity index 82% rename from substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java rename to substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java index 4276b1f62118..5d9f959796ff 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSections.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java @@ -32,17 +32,17 @@ import java.nio.ByteOrder; /** - * CVSections is a container class for all the CodeView sections to be emitted in the object file. - * Currently, that will be .debug$S (CVSymbolSectionImpl) and .debug$T (CVTypeSectionImpl) - * Common data (useful to more than one CodeView section) goes here, mostly that gathered by calls to installDebugInfo->addRange() and installDebugInfo->addSubRange() + * CVDebugInfo is a container class for all the CodeView sections to be emitted in the object file. + * Currently, that is .debug$S (CVSymbolSectionImpl) and .debug$T (CVTypeSectionImpl) + * Common data (useful to more than one CodeView section) goes here */ -public final class CVSections extends DebugInfoBase { +public final class CVDebugInfo extends DebugInfoBase { @SuppressWarnings("unused") private PECoffMachine machine; private CVSymbolSectionImpl cvSymbolSection; private CVTypeSectionImpl cvTypeSection; - public CVSections(PECoffMachine targetMachine, ByteOrder byteOrder) { + public CVDebugInfo(PECoffMachine targetMachine, ByteOrder byteOrder) { super(byteOrder); machine = targetMachine; cvSymbolSection = new CVSymbolSectionImpl(this); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index 6cdacfbb23c1..eb8a5490a150 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -54,8 +54,8 @@ final class CVFileRecord extends CVSymbolRecord { private int currentOffset = 0; private Map fileEntryToOffsetMap = new LinkedHashMap<>(FILE_TABLE_INITIAL_SIZE); - CVFileRecord(CVSections cvSections, CVSymbolSectionImpl.CVStringTable strings) { - super(cvSections, CVDebugConstants.DEBUG_S_FILECHKSMS); + CVFileRecord(CVDebugInfo cvDebugInfo, CVSymbolSectionImpl.CVStringTable strings) { + super(cvDebugInfo, CVDebugConstants.DEBUG_S_FILECHKSMS); this.strings = strings; } @@ -75,7 +75,7 @@ private static String fixPath(FileEntry fileEntry) { return fn; } - public int addFile(FileEntry entry) { + int addFile(FileEntry entry) { if (fileEntryToOffsetMap.containsKey(entry)) { return fileEntryToOffsetMap.get(entry); } else { @@ -92,7 +92,7 @@ public int computeSize(int initialPos) { /* add all fileEntries; duplicates are ignored */ /* probably don't need to do this because if it isn't already here it's probably referenced by the debug info */ /* consider moving this to CVSymbolSectionImpl */ - for (FileEntry entry : cvSections.getFiles()) { + for (FileEntry entry : cvDebugInfo.getFiles()) { addFile(entry); } return initialPos + (fileEntryToOffsetMap.size() * FILE_RECORD_LENGTH); @@ -101,7 +101,6 @@ public int computeSize(int initialPos) { @Override public int computeContents(byte[] buffer, int initialPos) { int pos = initialPos; - CVUtil.debug("file computeContents(%d) nf=%d\n", pos, fileEntryToOffsetMap.size()); for (FileEntry entry : fileEntryToOffsetMap.keySet()) { pos = put(entry, buffer, pos); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 59edf88d0dfa..0939ac8596d4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -129,14 +129,14 @@ int computeContents(byte[] buffer, int initialPos) { } } - CVLineRecord(CVSections cvSections, String symbolName, PrimaryEntry entry) { - super(cvSections, CVDebugConstants.DEBUG_S_LINES); + CVLineRecord(CVDebugInfo cvDebugInfo, String symbolName, PrimaryEntry entry) { + super(cvDebugInfo, CVDebugConstants.DEBUG_S_LINES); this.primaryEntry = entry; this.symbolName = symbolName; } void addNewFile(FileEntry file) { - CVFileRecord fr = cvSections.getCVSymbolSection().getFileRecord(); + CVFileRecord fr = cvDebugInfo.getCVSymbolSection().getFileRecord(); int fileId = fr.addFile(file); fileBlocks.add(new FileBlock(file, fileId)); } @@ -165,11 +165,11 @@ protected int computeContents(byte[] buffer, int initialPos) { assert !HAS_COLUMNS; if (buffer != null) { - cvSections.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, symbolName, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, symbolName, false, 1L); } pos = CVUtil.putInt(0, buffer, pos); if (buffer != null) { - cvSections.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, symbolName, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, symbolName, false, 1L); } pos = CVUtil.putShort((short) 0, buffer, pos); final short flags = HAS_COLUMNS ? CB_HAS_COLUMNS_FLAG : CB_HAS_NO_COLUMNS_FLAG; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 6470bf381ca3..280c0fb4ee91 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -38,12 +38,16 @@ public class CVLineRecordBuilder { private static final boolean HAS_COLUMNS = false; - private CVSections cvSections; + private CVDebugInfo cvDebugInfo; private CVLineRecord lineRecord; private PrimaryEntry primaryEntry; - CVLineRecordBuilder(CVSections cvSections) { - this.cvSections = cvSections; + CVLineRecordBuilder(CVDebugInfo cvDebugInfo) { + this.cvDebugInfo = cvDebugInfo; + } + + public static void debug(String format, Object ... args) { + //System.out.format(format, args); } /* @@ -72,18 +76,18 @@ CVLineRecord build(PrimaryEntry entry, String methodName) { Range previousRange = null; /* option to not even bother with debug code for Graal */ if (skipGraalInternals && CVRootPackages.isGraalClass(primaryRange.getClassName())) { - CVUtil.debug(" skipping Graal internal class %s\n", primaryRange); + debug("skipping Graal internal class %s\n", primaryRange); return null; } - CVUtil.debug(" DEBUG_S_LINES linerecord for 0x%05x file: %s:%d\n", primaryRange.getLo(), primaryRange.getFileName(), primaryRange.getLine()); - this.lineRecord = new CVLineRecord(cvSections, methodName, primaryEntry); - CVUtil.debug(" CVLineRecord.computeContents: processing primary range %s\n", primaryRange); + debug("DEBUG_S_LINES linerecord for 0x%05x file: %s:%d\n", primaryRange.getLo(), primaryRange.getFileName(), primaryRange.getLine()); + this.lineRecord = new CVLineRecord(cvDebugInfo, methodName, primaryEntry); + debug("CVLineRecord.computeContents: processing primary range %s\n", primaryRange); previousRange = processRange(primaryRange, previousRange); // lowAddr = Math.min(lowAddr, primaryRange.getLo()); // highAddr = Math.max(highAddr, primaryRange.getHi()); for (Range subRange : primaryEntry.getSubranges()) { - CVUtil.debug(" CVLineRecord.computeContents: processing range %s\n", subRange); + debug("CVLineRecord.computeContents: processing range %s\n", subRange); FileEntry subFileEntry = primaryEntry.getSubrangeFileEntry(subRange); if (subFileEntry == null) { continue; @@ -114,7 +118,7 @@ private Range processRange(Range range, Range oldPreviousRange) { /* should we merge this range with the previous entry? */ /* i.e. same line in same file, same class and function */ if (shouldMerge(range, previousRange)) { - CVUtil.debug(" processRange: merging with previous\n"); + debug("processRange: merging with previous\n"); return previousRange; //range = new Range(previousRange, range.getLo(), range.getHi()); } /*else if (range.getLine() == -1) { @@ -125,13 +129,13 @@ private Range processRange(Range range, Range oldPreviousRange) { /* is this a new file? if so we emit a new file record */ boolean wantNewFile = previousRange == null || !previousRange.getFileAsPath().equals(range.getFileAsPath()); if (wantNewFile) { - FileEntry file = cvSections.findFile(range.getFileAsPath()); + FileEntry file = cvDebugInfo.findFile(range.getFileAsPath()); if (file != null && file.getFileName() != null) { previousRange = null; - CVUtil.debug(" processRange: addNewFile: %s\n", file); + debug("processRange: addNewFile: %s\n", file); lineRecord.addNewFile(file); } else { - CVUtil.debug(" processRange: range has no file: %s\n", range); + debug("processRange: range has no file: %s\n", range); return previousRange; } } @@ -140,7 +144,7 @@ private Range processRange(Range range, Range oldPreviousRange) { previousRange = range; int lineLoAddr = range.getLo() - primaryEntry.getPrimary().getLo(); int line = range.getLine() < 1 ? 1 : range.getLine(); - CVUtil.debug(" processRange: addNewLine: 0x%05x %s\n", lineLoAddr, line); + debug("processRange: addNewLine: 0x%05x %s\n", lineLoAddr, line); lineRecord.addNewLine(lineLoAddr, line); } return previousRange; @@ -178,9 +182,9 @@ private static boolean wantNewRange(Range range, Range previousRange) { return true; /*if (debug) { if (previousRange == null) { - CVUtil.debug("wantNewRange() prevnull:true"); + debug("wantNewRange() prevnull:true"); } else { - CVUtil.debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previousRange.getLine() != range.getLine()) + debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previousRange.getLine() != range.getLine()) + " fndiffer:" + (previousRange.getFilePath() != range.getFilePath()) + " contig:" + (previousRange.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); } }* diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java index ff9f2a95293d..bfc682f8cb79 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -201,7 +201,6 @@ static boolean isGraalClass(String cn) { * @return true if this is Graal intrinsic code */ static boolean isGraalIntrinsic(String cn) { - //CVUtil.debug("XXXXX isGraalIntrinsic " + cn + " " + intrinsicClassNameSet.contains(cn)); return intrinsicClassNameSet.contains(cn); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java index 1cd2206689b8..01f5ec857376 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java @@ -32,19 +32,19 @@ import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.pecoff.PECoffObjectFile; +import org.graalvm.compiler.debug.DebugContext; import java.util.Map; import java.util.Set; abstract class CVSectionImpl extends BasicProgbitsSectionImpl { - int debugLevel = 1; + boolean debug = false; long debugTextBase = 0; long debugAddress = 0; int debugBase = 0; CVSectionImpl() { - checkDebug(0); } @Override @@ -54,11 +54,23 @@ public void setElement(ObjectFile.Element e) { getOwner().createDefinedSymbol(getSectionName(), getElement(), 0, 0, false, false); } - void checkDebug(int pos) { - /* if the env var relevant to this element type is set then switch on debugging */ - String envVarName = "DEBUG_" + getSectionName().substring(1).toUpperCase(); - if (System.getenv(envVarName) != null) { - debugLevel = 1; + private String debugSectionLogName() { + /* + * Use prefix cv4 plus the section name (which already includes a dot separator) for the + * context key. For example messages for type section will be keyed using "cv4.debug$T". + * Other info formats use their own format-specific prefix. + */ + assert getSectionName().startsWith(".debug$"); + return "cv4" + getSectionName(); + } + + protected void enableLog(DebugContext context, int pos) { + /* + * Unlike in the Dwarf debug code, debug output is enabled in both the sizing and writing phases. + * At this time, debugBase and debugAddress aren't used but are there for the future. + */ + if (context.areScopesEnabled()) { + debug = true; debugBase = pos; debugAddress = debugTextBase; } @@ -69,25 +81,26 @@ public int getAlignment() { return 1; } - public void debug(String format, Object ... args) { - if (debugLevel > 1) { - CVUtil.debug(format + "\n", args); + protected void log(DebugContext context, String format, Object... args) { + if (debug) { + context.logv(DebugContext.INFO_LEVEL, format, args); } } - public void info(String format, Object ... args) { - if (debugLevel > 0) { - CVUtil.debug(format + "\n", args); + protected void verboseLog(DebugContext context, String format, Object... args) { + if (debug) { + context.logv(DebugContext.VERBOSE_LEVEL, format, args); } } @Override public byte[] getOrDecideContent(Map alreadyDecided, byte[] contentHint) { + /* ensure content byte[] has been created before calling super method */ - createContent(); + getOwner().debugContext(debugSectionLogName(), this::createContent); /* ensure content byte[] has been written before calling super method */ - writeContent(); + getOwner().debugContext(debugSectionLogName(), this::writeContent); return super.getOrDecideContent(alreadyDecided, contentHint); } @@ -111,7 +124,7 @@ public Set getDependencies(Map T addTypeRecord(T record) { - return cvSections.getCVTypeSection().addRecord(record); + cvDebugInfo.getCVSymbolSection().verboseLog(debugContext, "added type record: %s hash=%d\n", record, record.hashCode()); + return cvDebugInfo.getCVTypeSection().addRecord(record); } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java index 9b6a3dc01fdc..145404ca79f2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java @@ -26,6 +26,8 @@ package com.oracle.objectfile.pecoff.cv; +import org.graalvm.compiler.debug.DebugContext; + import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -41,14 +43,14 @@ public final class CVSymbolSectionImpl extends CVSectionImpl { private static final int CV_VECTOR_DEFAULT_SIZE = 200; private static final int CV_STRINGTABLE_DEFAULT_SIZE = 200; - private CVSections cvSections; + private CVDebugInfo cvDebugInfo; private CVFileRecord fileRecord; private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); private CVStringTable stringTable = new CVStringTable(CV_STRINGTABLE_DEFAULT_SIZE); - CVSymbolSectionImpl(CVSections cvSections) { - this.cvSections = cvSections; + CVSymbolSectionImpl(CVDebugInfo cvDebugInfo) { + this.cvDebugInfo = cvDebugInfo; } @Override @@ -60,71 +62,73 @@ public String getSectionName() { * the CodeView symbol section ("debug$S") is actually a list of records containing sub-records */ @Override - public void createContent() { - info("CVSymbolSectionImpl.createContent() adding records"); - addRecords(); - info("CVSymbolSectionImpl.createContent() start"); + public void createContent(DebugContext debugContext) { int pos = 0; + enableLog(debugContext, pos); + log(debugContext, "CVSymbolSectionImpl.createContent() adding records"); + addRecords(debugContext); + log(debugContext, "CVSymbolSectionImpl.createContent() start"); /* add header size */ pos += Integer.BYTES; /* add sum of all record sizes */ for (CVSymbolRecord record : cvRecords) { - info("CVSymbolSectionImpl.createContent() computeFullSize %s", record); + log(debugContext, "CVSymbolSectionImpl.createContent() computeFullSize %s", record); pos = CVUtil.align4(pos); pos = record.computeFullSize(pos); } /* create a buffer that holds it all */ byte[] buffer = new byte[pos]; super.setContent(buffer); - info("CVSymbolSectionImpl.createContent() end"); + log(debugContext, "CVSymbolSectionImpl.createContent() end"); } @Override - public void writeContent() { - info("CVSymbolSectionImpl.writeContent() start"); - byte[] buffer = getContent(); + public void writeContent(DebugContext debugContext) { int pos = 0; + enableLog(debugContext, pos); + log(debugContext, "CVSymbolSectionImpl.writeContent() start"); + byte[] buffer = getContent(); /* write section header */ pos = CVUtil.putInt(CV_SIGNATURE_C13, buffer, pos); /* write all records */ for (CVSymbolRecord record : cvRecords) { - info("CVSymbolSectionImpl.createContent() computeFullContentt %s", record); + log(debugContext, "CVSymbolSectionImpl.createContent() computeFullContentt %s", record); pos = CVUtil.align4(pos); pos = record.computeFullContents(buffer, pos); } - info("CVSymbolSectionImpl.writeContent() end"); + log(debugContext, "CVSymbolSectionImpl.writeContent() end"); } - private void addRecords() { + private void addRecords(DebugContext debugContext) { addPrologueRecords(); - addFunctionRecords(); + addFunctionRecords(debugContext); addTypeRecords(); addFileRecords(); addStringTableRecord(); } private void addPrologueRecords() { - CVSymbolRecord prologue = new CVSymbolSubsection(cvSections) { + CVSymbolRecord prologue = new CVSymbolSubsection(cvDebugInfo) { @Override void addSubrecords() { - CVSymbolSubrecord.CVObjectNameRecord objectNameRecord = new CVSymbolSubrecord.CVObjectNameRecord(cvSections); + CVSymbolSubrecord.CVObjectNameRecord objectNameRecord = new CVSymbolSubrecord.CVObjectNameRecord(cvDebugInfo); if (objectNameRecord.isValid()) { addRecord(objectNameRecord); } - addRecord(new CVSymbolSubrecord.CVCompile3Record(cvSections)); - addRecord(new CVSymbolSubrecord.CVEnvBlockRecord(cvSections)); + addRecord(new CVSymbolSubrecord.CVCompile3Record(cvDebugInfo)); + addRecord(new CVSymbolSubrecord.CVEnvBlockRecord(cvDebugInfo)); } }; addRecord(prologue); } - private void addFunctionRecords() { - new CVSymbolRecordBuilder(cvSections).build(); + private void addFunctionRecords(DebugContext debugContext) { + new CVSymbolRecordBuilder(cvDebugInfo).build(debugContext); } private void addTypeRecords() { /* not yet implemented. S_UDT, etc */ - //CVSymbolRecord externs = new CVSymbolSubsection.CVExternalSymbolRecord(cvSections); + //CVSymbolRecord externs = new CVSymbolSubsection.CVExternalSymbolRecord(cvDebugInfo); //addRecord(externs); } @@ -134,13 +138,13 @@ private void addFileRecords() { CVFileRecord getFileRecord() { if (fileRecord == null) { - this.fileRecord = new CVFileRecord(cvSections, stringTable); + this.fileRecord = new CVFileRecord(cvDebugInfo, stringTable); } return fileRecord; } private void addStringTableRecord() { - CVSymbolRecord stringTableRecord = new CVStringTableRecord(cvSections, stringTable); + CVSymbolRecord stringTableRecord = new CVStringTableRecord(cvDebugInfo, stringTable); addRecord(stringTableRecord); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index 00bfbf788264..dbbd74394d5c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -42,10 +42,10 @@ abstract class CVSymbolSubrecord { private int subrecordStartPosition; private final short cmd; - CVSections cvSections; + CVDebugInfo cvDebugInfo; - CVSymbolSubrecord(CVSections cvSections, short cmd) { - this.cvSections = cvSections; + CVSymbolSubrecord(CVDebugInfo cvDebugInfo, short cmd) { + this.cvDebugInfo = cvDebugInfo; this.cmd = cmd; } @@ -77,19 +77,19 @@ public static final class CVObjectNameRecord extends CVSymbolSubrecord { String objName; /* TODO: how to find the full path to object file we will produce */ - CVObjectNameRecord(CVSections cvSections, String objName) { - super(cvSections, CVDebugConstants.S_OBJNAME); + CVObjectNameRecord(CVDebugInfo cvDebugInfo, String objName) { + super(cvDebugInfo, CVDebugConstants.S_OBJNAME); this.objName = objName; } - CVObjectNameRecord(CVSections cvSections) { - this(cvSections, findObjectName(cvSections)); + CVObjectNameRecord(CVDebugInfo cvDebugInfo) { + this(cvDebugInfo, findObjectName(cvDebugInfo)); } - private static String findObjectName(CVSections cvSections) { + private static String findObjectName(CVDebugInfo cvDebugInfo) { /* Get file from first class object */ String fn = null; - for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { + for (ClassEntry classEntry : cvDebugInfo.getPrimaryClasses()) { if (classEntry.getFileName() != null) { fn = classEntry.getFileEntry().getFileName(); if (fn.endsWith(".java")) { @@ -140,8 +140,8 @@ public static final class CVCompile3Record extends CVSymbolSubrecord { private short beQFE; private String compiler; - CVCompile3Record(CVSections cvSections) { - super(cvSections, CVDebugConstants.S_COMPILE3); + CVCompile3Record(CVDebugInfo cvDebugInfo) { + super(cvDebugInfo, CVDebugConstants.S_COMPILE3); language = 0; cf1 = HAS_DEBUG_FLAG; cf2 = (byte) 0; @@ -198,8 +198,8 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { * pdb = C:\tmp\graal-8\vc100.pdb */ - CVEnvBlockRecord(CVSections cvSections) { - super(cvSections, CVDebugConstants.S_ENVBLOCK); + CVEnvBlockRecord(CVDebugInfo cvDebugInfo) { + super(cvDebugInfo, CVDebugConstants.S_ENVBLOCK); /* current directory */ map.put("cwd", System.getProperty("user.dir")); @@ -211,7 +211,7 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { //map.put("cmd", "-Zi -MT -wishfulthinking"); /* find first source file - which, for Graal would be a class file on the command line */ - String fn = findFirstFile(cvSections); + String fn = findFirstFile(cvDebugInfo); if (fn != null) { map.put("src", fn); } @@ -220,9 +220,9 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { //map.put("pdb", System.getProperty("user.dir") + File.separator + "vc100.pdb"); } - private static String findFirstFile(CVSections cvSections) { + private static String findFirstFile(CVDebugInfo cvDebugInfo) { String fn = null; - for (ClassEntry classEntry : cvSections.getPrimaryClasses()) { + for (ClassEntry classEntry : cvDebugInfo.getPrimaryClasses()) { if (classEntry.getFileName() != null) { fn = classEntry.getFileEntry().getFileName(); break; @@ -274,8 +274,8 @@ public static class CVSymbolGProc32Record extends CVSymbolSubrecord { byte flags; String name; - CVSymbolGProc32Record(CVSections cvSections, short cmd, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { - super(cvSections, cmd); + CVSymbolGProc32Record(CVDebugInfo cvDebugInfo, short cmd, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + super(cvDebugInfo, cmd); this.name = name; this.pparent = pparent; this.pend = pend; @@ -289,8 +289,8 @@ public static class CVSymbolGProc32Record extends CVSymbolSubrecord { this.flags = flags; } - CVSymbolGProc32Record(CVSections cvSections, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { - this(cvSections, CVDebugConstants.S_GPROC32, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); + CVSymbolGProc32Record(CVDebugInfo cvDebugInfo, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + this(cvDebugInfo, CVDebugConstants.S_GPROC32, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); } @Override @@ -308,16 +308,16 @@ protected int computeContents(byte[] buffer, int initialPos) { pos = CVUtil.putInt(debugEnd, buffer, pos); pos = CVUtil.putInt(typeIndex, buffer, pos); if (buffer == null) { - cvSections.getCVSymbolSection().getOwner().createDefinedSymbol(name, getTextSection(), offset, proclen, true, true); + cvDebugInfo.getCVSymbolSection().getOwner().createDefinedSymbol(name, getTextSection(), offset, proclen, true, true); } if (buffer != null) { //CVUtil.debug("CVSymbolGProc32Record() adding SECREL reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); - cvSections.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, name, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, name, false, 1L); } pos = CVUtil.putInt(0, buffer, pos); if (buffer != null) { //CVUtil.debug("CVSymbolGProc32Record() adding SECTION reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); - cvSections.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, name, false, 1L); + cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, name, false, 1L); } pos = CVUtil.putShort((short) 0, buffer, pos); pos = CVUtil.putByte(flags, buffer, pos); @@ -327,7 +327,7 @@ protected int computeContents(byte[] buffer, int initialPos) { private ObjectFile.Element getTextSection() { if (textSection == null) { - textSection = cvSections.getCVSymbolSection().getOwner().elementForName(SectionName.TEXT.getFormatDependentName(ObjectFile.Format.PECOFF)); + textSection = cvDebugInfo.getCVSymbolSection().getOwner().elementForName(SectionName.TEXT.getFormatDependentName(ObjectFile.Format.PECOFF)); } return textSection; } @@ -340,13 +340,13 @@ public String toString() { /* public static final class CVSymbolGProc32IDRecord extends CVSymbolGProc32Record { - CVSymbolGProc32IDRecord(CVSections cvSections, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { - super(cvSections, CVDebugConstants.S_GPROC32_ID, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); + CVSymbolGProc32IDRecord(CVDebugInfo cvDebugInfo, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + super(cvDebugInfo, CVDebugConstants.S_GPROC32_ID, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); } /* this is almost certainly bad; only for debugging * - CVSymbolGProc32IDRecord(CVSections cvSections, String name, int offset, int proclen) { - super(cvSections, CVDebugConstants.S_GPROC32_ID, name, 0, 0, 0, proclen, 0, 0, 0, offset, (short)0, (byte)0); + CVSymbolGProc32IDRecord(CVDebugInfo cvDebugInfo, String name, int offset, int proclen) { + super(cvDebugInfo, CVDebugConstants.S_GPROC32_ID, name, 0, 0, 0, proclen, 0, 0, 0, offset, (short)0, (byte)0); } @Override @@ -365,8 +365,8 @@ public static final class CVSymbolFrameProcRecord extends CVSymbolSubrecord { short ehSection; int flags; - CVSymbolFrameProcRecord(CVSections cvSections, int framelen, int padLen, int padOffset, int saveRegsCount, int ehOffset, short ehSection, int flags) { - super(cvSections, CVDebugConstants.S_FRAMEPROC); + CVSymbolFrameProcRecord(CVDebugInfo cvDebugInfo, int framelen, int padLen, int padOffset, int saveRegsCount, int ehOffset, short ehSection, int flags) { + super(cvDebugInfo, CVDebugConstants.S_FRAMEPROC); this.framelen = framelen; this.padLen = padLen; this.padOffset = padOffset; @@ -376,8 +376,8 @@ public static final class CVSymbolFrameProcRecord extends CVSymbolSubrecord { this.flags = flags; } - CVSymbolFrameProcRecord(CVSections cvSections, int framelen, int flags) { - this(cvSections, framelen, 0, 0, 0, 0, (short) 0, flags); + CVSymbolFrameProcRecord(CVDebugInfo cvDebugInfo, int framelen, int flags) { + this(cvDebugInfo, framelen, 0, 0, 0, 0, (short) 0, flags); } @Override @@ -405,12 +405,12 @@ public String toString() { public static class CVSymbolEndRecord extends CVSymbolSubrecord { - CVSymbolEndRecord(CVSections cvSections, short cmd) { - super(cvSections, cmd); + CVSymbolEndRecord(CVDebugInfo cvDebugInfo, short cmd) { + super(cvDebugInfo, cmd); } - CVSymbolEndRecord(CVSections cvSections) { - this(cvSections, CVDebugConstants.S_END); + CVSymbolEndRecord(CVDebugInfo cvDebugInfo) { + this(cvDebugInfo, CVDebugConstants.S_END); } @Override @@ -437,8 +437,8 @@ public static final class CVSymbolRegRel32Record extends CVSymbolSubrecord { int offset; String name; - public CVSymbolRegRel32Record(CVSections cvSections, String name, int typeIndex, int offset, short reg) { - super(cvSections, CVDebugConstants.S_REGREL32); + public CVSymbolRegRel32Record(CVDebugInfo cvDebugInfo, String name, int typeIndex, int offset, short reg) { + super(cvDebugInfo, CVDebugConstants.S_REGREL32); this.name = name; this.typeIndex = typeIndex; this.offset = offset; @@ -465,8 +465,8 @@ public String toString() { } public static class CVSymbolProcIdEndRecord extends CVSymbolEndRecord { - CVSymbolProcIdEndRecord(CVSections cvSections) { - super(cvSections, CVDebugConstants.S_PROC_ID_END); + CVSymbolProcIdEndRecord(CVDebugInfo cvDebugInfo) { + super(cvDebugInfo, CVDebugConstants.S_PROC_ID_END); } } @@ -476,8 +476,8 @@ public static final class CVSymbolConstantRecord extends CVSymbolSubrecord { short leaf; String name; - public CVSymbolConstantRecord(CVSections cvSections, String name, int typeIndex, short leaf) { - super(cvSections, CVDebugConstants.S_CONSTANT); + public CVSymbolConstantRecord(CVDebugInfo cvDebugInfo, String name, int typeIndex, short leaf) { + super(cvDebugInfo, CVDebugConstants.S_CONSTANT); this.name = name; this.typeIndex = typeIndex; this.leaf = leaf; @@ -509,8 +509,8 @@ private static abstract class CVSymbolDataRecord extends CVSymbolSubrecord { short segment; String name; - CVSymbolDataRecord(CVSections cvSections, short recordType, String name, int typeIndex, int offset, short segment) { - super(cvSections, recordType); + CVSymbolDataRecord(CVDebugInfo cvDebugInfo, short recordType, String name, int typeIndex, int offset, short segment) { + super(cvDebugInfo, recordType); this.name = name; this.typeIndex = typeIndex; this.offset = offset; @@ -534,8 +534,8 @@ protected int computeContents(byte[] buffer, int initialPos) { public static final class CVSymbolLData32Record extends CVSymbolDataRecord { - public CVSymbolLData32Record(CVSections cvSections, String name, int typeIndex, int offset, short segment) { - super(cvSections, CVDebugConstants.S_LDATA32, name, typeIndex, offset, segment); + public CVSymbolLData32Record(CVDebugInfo cvDebugInfo, String name, int typeIndex, int offset, short segment) { + super(cvDebugInfo, CVDebugConstants.S_LDATA32, name, typeIndex, offset, segment); } @Override @@ -546,8 +546,8 @@ public String toString() { public static final class CVSymbolLData32STRecord extends CVSymbolDataRecord { - public CVSymbolLData32STRecord(CVSections cvSections, String name, int typeIndex, int offset, short segment) { - super(cvSections, CVDebugConstants.S_LDATA32_ST, name, typeIndex, offset, segment); + public CVSymbolLData32STRecord(CVDebugInfo cvDebugInfo, String name, int typeIndex, int offset, short segment) { + super(cvDebugInfo, CVDebugConstants.S_LDATA32_ST, name, typeIndex, offset, segment); } @Override @@ -558,8 +558,8 @@ public String toString() { public static final class CVSymbolGData32Record extends CVSymbolDataRecord { - public CVSymbolGData32Record(CVSections cvSections, String name, int typeIndex, int offset, short segment) { - super(cvSections, CVDebugConstants.S_GDATA32, name, typeIndex, offset, segment); + public CVSymbolGData32Record(CVDebugInfo cvDebugInfo, String name, int typeIndex, int offset, short segment) { + super(cvDebugInfo, CVDebugConstants.S_GDATA32, name, typeIndex, offset, segment); } @Override @@ -570,8 +570,8 @@ public String toString() { public static final class CVSymbolSSearchRecord extends CVSymbolDataRecord { - public CVSymbolSSearchRecord(CVSections cvSections, int offset, short segment) { - super(cvSections, CVDebugConstants.S_SSEARCH, null, 0, offset, segment); + public CVSymbolSSearchRecord(CVDebugInfo cvDebugInfo, int offset, short segment) { + super(cvDebugInfo, CVDebugConstants.S_SSEARCH, null, 0, offset, segment); } @Override @@ -592,8 +592,8 @@ public static final class CVSymbolUDTRecord extends CVSymbolSubrecord { int typeIndex; String name; - public CVSymbolUDTRecord(CVSections cvSections, String name, int typeIndex) { - super(cvSections, CVDebugConstants.S_UDT); + public CVSymbolUDTRecord(CVDebugInfo cvDebugInfo, String name, int typeIndex) { + super(cvDebugInfo, CVDebugConstants.S_UDT); this.name = name; this.typeIndex = typeIndex; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java index 907382611d2a..f93e68deb400 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java @@ -34,10 +34,12 @@ */ class CVSymbolSubsection extends CVSymbolRecord { - private ArrayList subcmds = new ArrayList<>(20); + private static final int SUBCMD_INITIAL_CAPACITY = 100; - CVSymbolSubsection(CVSections cvSections) { - super(cvSections, CVDebugConstants.DEBUG_S_SYMBOLS); + private ArrayList subcmds = new ArrayList<>(SUBCMD_INITIAL_CAPACITY); + + CVSymbolSubsection(CVDebugInfo cvDebugInfo) { + super(cvDebugInfo, CVDebugConstants.DEBUG_S_SYMBOLS); } void addRecord(CVSymbolSubrecord subcmd) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java index a94036d84434..4e183761d6be 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java @@ -31,6 +31,7 @@ import com.oracle.objectfile.LayoutDecisionMap; import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.pecoff.PECoffObjectFile; +import org.graalvm.compiler.debug.DebugContext; import java.util.ArrayList; import java.util.Collections; @@ -44,8 +45,8 @@ public final class CVTypeSectionImpl extends CVSectionImpl { - private static final int CV_VECTOR_DEFAULT_SIZE = 200; - private ArrayList cvRecords = new ArrayList<>(CV_VECTOR_DEFAULT_SIZE); + private static final int CV_RECORD_INITIAL_CAPACITY = 200; + private ArrayList cvRecords = new ArrayList<>(CV_RECORD_INITIAL_CAPACITY); private CVTypeRecordBuilder builder = new CVTypeRecordBuilder(this); CVTypeSectionImpl() { @@ -57,29 +58,29 @@ public String getSectionName() { } @Override - public void createContent() { - info("CVTypeSectionImpl.createContent() start"); - addRecords(); + public void createContent(DebugContext debugContext) { int pos = 0; + log(debugContext, "CVTypeSectionImpl.createContent() start"); + addRecords(); pos += computeHeaderSize(); for (CVTypeRecord record : cvRecords) { pos = record.computeFullSize(pos); } byte[] buffer = new byte[pos]; super.setContent(buffer); - info("CVTypeSectionImpl.createContent() end"); + log(debugContext, "CVTypeSectionImpl.createContent() end"); } @Override - public void writeContent() { - info("CVTypeSectionImpl.writeContent() start"); - byte[] buffer = getContent(); + public void writeContent(DebugContext debugContext) { int pos = 0; + log(debugContext, "CVTypeSectionImpl.writeContent() start"); + byte[] buffer = getContent(); pos = CVUtil.putInt(CV_SIGNATURE_C13, buffer, pos); for (CVTypeRecord record : cvRecords) { pos = record.computeFullContents(buffer, pos); } - info("CVTypeSectionImpl.writeContent() end"); + log(debugContext, "CVTypeSectionImpl.writeContent() end"); } public List getRecords() { @@ -93,13 +94,12 @@ void addUniqueRecord(CVTypeRecord r) { T addRecord(T newRecord) { //CVUtil.debug("adding type record: %s hash=%d\n", newRecord, newRecord.hashCode()); T actual = builder.buildFrom(newRecord); - CVUtil.debug("added type record: %s hash=%d\n", actual, actual.hashCode()); return actual; } private void addClassRecords() { /* we may have done this already when emiting globals in debug$S section */ - //for (DebugInfoBase.ClassEntry classEntry : cvSections.getPrimaryClasses()) { + //for (DebugInfoBase.ClassEntry classEntry : cvDebugInfo.getPrimaryClasses()) { // TODO - emit all members, all types, etc //} } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java index 4269086aec59..f5e322ab50f4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java @@ -30,8 +30,6 @@ abstract class CVUtil { - private static final boolean DEBUG_ON = false; - /* base level put methods that assume a non-null buffer */ static int putByte(byte b, byte[] buffer, int initialPos) { if (buffer == null) { @@ -85,8 +83,8 @@ static int putBytes(byte[] inbuff, byte[] buffer, int initialPos) { return initialPos + inbuff.length; } int pos = initialPos; - for (int l = 0; l < inbuff.length; l++) { - buffer[pos++] = inbuff[l]; + for (byte b : inbuff) { + buffer[pos++] = b; } return pos; } @@ -101,11 +99,11 @@ private static int putUTF8StringBytes(String s, int startChar, byte[] buffer, in return initialPos + buff.length + 1; } int pos = initialPos; - for (int l = 0; l < buff.length; l++) { - if (buff[l] == 0) { + for (byte b : buff) { + if (b == 0) { throw new RuntimeException("oops : string has internal NULL character! " + s); } - buffer[pos++] = buff[l]; + buffer[pos++] = b; } buffer[pos++] = '\0'; return pos; @@ -117,7 +115,6 @@ static int getInt(byte[] buffer, int initialPos) { i += (buffer[pos++] & 0xff) << 8; i += (buffer[pos++] & 0xff) << 16; i += (buffer[pos] & 0xff) << 24; - debug("getint returns %d\n", i); return i; } @@ -125,19 +122,19 @@ static short getShort(byte[] buffer, int initialPos) { int pos = initialPos; short i = (short) (buffer[pos++] & 0xff); i = (short) (i + ((buffer[pos] & 0xff) << 8)); - debug("getshort returns %d\n", i); return i; } + /* static void dump(String msg, byte[] buffer, int initialPos, int len) { if (buffer == null) { return; } - debug("%s0x%06x", msg, initialPos); + System.out.format("%s0x%06x", msg, initialPos); for (int i = 0; i < len; i++) { - debug(" %02x", buffer[initialPos + i]); + System.out.format(" %02x", buffer[initialPos + i]); } - debug("\n"); + System.out.format("\n"); } static void dump(byte[] buffer, int len) { @@ -145,9 +142,9 @@ static void dump(byte[] buffer, int len) { return; } for (int i = 0; i < len; i++) { - debug("%02x", buffer[i]); + System.out.format("%02x", buffer[i]); } - } + }*/ /** * align on 4 byte boundary. @@ -161,10 +158,4 @@ static int align4(int initialPos) { } return pos; } - - public static void debug(String format, Object ... args) { - if (DEBUG_ON) { - System.out.format(format, args); - } - } } From c7e3471a85c6e802a8c1b949469c2baa6a4c5152 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Wed, 8 Apr 2020 15:47:16 -0400 Subject: [PATCH 118/130] emit graal intrinsic information --- .../src/com/oracle/objectfile/pecoff/cv/CVConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index fee7c64f79d9..5624e2759869 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -72,7 +72,7 @@ public abstract class CVConstants { static final boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ static final boolean skipJDKInternals = false; /* (unimplemented) if true, don't emit debug code for JDK classes */ - static final boolean skipGraalIntrinsics = true; /* Graal inlined code treated as generated code */ + static final boolean skipGraalIntrinsics = false; /* Graal inlined code treated as generated code */ static final boolean mergeAdjacentLineRecords = true; /* if a line record is the same line in the same file as the previous record, merge them */ static final boolean emitUnadornedMain = true; /* if true, first main() does not have args in the debug name */ static final String replaceMainFunctionName = null; /* first main() becomes this name (with no class name or arg list at all) (set null to disable) */ From 52171acd3124f052d87046249832797abf8504c4 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 9 Apr 2020 08:11:02 -0400 Subject: [PATCH 119/130] fix for travis-ci build tests --- .../objectfile/pecoff/cv/CVLineRecordBuilder.java | 11 +++++++---- .../objectfile/pecoff/cv/CVSymbolRecordBuilder.java | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 280c0fb4ee91..9d11e162d6ed 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -46,7 +46,7 @@ public class CVLineRecordBuilder { this.cvDebugInfo = cvDebugInfo; } - public static void debug(String format, Object ... args) { + public static void debug(@SuppressWarnings("unused") String format, @SuppressWarnings("unused") Object ... args) { //System.out.format(format, args); } @@ -65,6 +65,7 @@ public static void debug(String format, Object ... args) { * @param entry function to build line number table for * @return CVLineRecord containing any entries generated, or null if no entries generated */ + @SuppressWarnings("unused") CVLineRecord build(PrimaryEntry entry, String methodName) { // long lowAddr = Long.MAX_VALUE; // long highAddr = 0; @@ -74,6 +75,7 @@ CVLineRecord build(PrimaryEntry entry, String methodName) { Range primaryRange = primaryEntry.getPrimary(); Range previousRange = null; + /* option to not even bother with debug code for Graal */ if (skipGraalInternals && CVRootPackages.isGraalClass(primaryRange.getClassName())) { debug("skipping Graal internal class %s\n", primaryRange); @@ -143,7 +145,7 @@ private Range processRange(Range range, Range oldPreviousRange) { if (wantNewRange(range, previousRange)) { previousRange = range; int lineLoAddr = range.getLo() - primaryEntry.getPrimary().getLo(); - int line = range.getLine() < 1 ? 1 : range.getLine(); + int line = Math.max(range.getLine(), 1); debug("processRange: addNewLine: 0x%05x %s\n", lineLoAddr, line); lineRecord.addNewLine(lineLoAddr, line); } @@ -156,6 +158,7 @@ private Range processRange(Range range, Range oldPreviousRange) { * @param range the second range (higher address) * @return true if the two ranges can be combined */ + @SuppressWarnings("unused") private boolean shouldMerge(Range range, Range previousRange) { if (!mergeAdjacentLineRecords) { return false; @@ -166,7 +169,7 @@ private boolean shouldMerge(Range range, Range previousRange) { /* if we're in a different class that the primary Class, this is inlined code */ final boolean isInlinedCode = !range.getClassName().equals(primaryEntry.getClassEntry().getClassName()); // if (isInlinedCode && skipInlinedCode) { return true; } - if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { + if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { return true; } return previousRange.getFileAsPath().equals(range.getFileAsPath()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); @@ -178,7 +181,7 @@ private boolean shouldMerge(Range range, Range previousRange) { * @param range current range * @return true if the current range is on a different line or file from the previous one */ - private static boolean wantNewRange(Range range, Range previousRange) { + private static boolean wantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { return true; /*if (debug) { if (previousRange == null) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 7756c1b45cb5..f2351c3ec576 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -52,8 +52,8 @@ final class CVSymbolRecordBuilder { * build DEBUG_S_SYMBOLS record from all classEntries. * (could probably build one per class or one per function) */ - void build(DebugContext debugContext) { - this.debugContext = debugContext; + void build(DebugContext theDebugContext) { + this.debugContext = theDebugContext; for (ClassEntry classEntry : cvDebugInfo.getPrimaryClasses()) { build(classEntry); } From ddf9bfe635c53a0f4021d90ab5f6dc9a349824a9 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 14 Apr 2020 08:43:51 -0400 Subject: [PATCH 120/130] incorporate eclipse formatting changes --- .../src/com/oracle/objectfile/ObjectFile.java | 14 +- .../oracle/objectfile/debugentry/Range.java | 9 +- .../objectfile/pecoff/cv/CVConstants.java | 84 ++++-- .../pecoff/cv/CVDebugConstants.java | 42 +-- .../objectfile/pecoff/cv/CVDebugInfo.java | 6 +- .../objectfile/pecoff/cv/CVFileRecord.java | 9 +- .../objectfile/pecoff/cv/CVLineRecord.java | 23 +- .../pecoff/cv/CVLineRecordBuilder.java | 77 +++-- .../objectfile/pecoff/cv/CVRootPackages.java | 279 +++++++++--------- .../objectfile/pecoff/cv/CVSectionImpl.java | 26 +- .../objectfile/pecoff/cv/CVSymbolRecord.java | 1 + .../pecoff/cv/CVSymbolRecordBuilder.java | 43 ++- .../pecoff/cv/CVSymbolSectionImpl.java | 12 +- .../pecoff/cv/CVSymbolSubrecord.java | 62 ++-- .../pecoff/cv/CVSymbolSubsection.java | 3 +- .../objectfile/pecoff/cv/CVTypeConstants.java | 80 ++--- .../objectfile/pecoff/cv/CVTypeRecord.java | 41 +-- .../pecoff/cv/CVTypeRecordBuilder.java | 8 +- .../pecoff/cv/CVTypeSectionImpl.java | 16 +- .../oracle/objectfile/pecoff/cv/CVUtil.java | 6 +- 20 files changed, 463 insertions(+), 378 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java index 101f350c43ba..f0f8c6981d68 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/ObjectFile.java @@ -253,13 +253,13 @@ public enum RelocationKind { */ DIRECT_HI, /** - * The index of the object file section containing the relocation's symbol supplies the fixup bytes. - * (used in CodeView debug information) + * The index of the object file section containing the relocation's symbol supplies the + * fixup bytes. (used in CodeView debug information) */ SECTION, /** - * The address of the object file section containing the relocation's symbol (+addend( supplies the fixup bytes. - * (used in CodeView debug information) + * The address of the object file section containing the relocation's symbol (+addend( + * supplies the fixup bytes. (used in CodeView debug information) */ SECREL, /** @@ -1102,7 +1102,7 @@ protected boolean elementsCanSharePage(Element s1, Element s2, int offset1, int /** * API method provided to allow a native image generator to provide details of types, code and * heap data inserted into a native image. - * + * * @param debugInfoProvider an implementation of the provider interface that communicates * details of the relevant types, code and heap data. */ @@ -1760,7 +1760,7 @@ public final SymbolTable getOrCreateSymbolTable() { * Allows a task to be executed with a debug context in a named subscope bound to the object * file and accessible to code executed during the lifetime of the task. Invoked code may obtain * access to the debug context using method {@link #debugContext}. - * + * * @param context a context to be bound to the object file for the duration of the task * execution. * @param scopeName a name to be used to define a subscope current while the task is being @@ -1782,7 +1782,7 @@ public void withDebugContext(DebugContext context, String scopeName, Runnable ta /** * Allows a consumer to retrieve the debug context currently bound to this object file. This * method must only called underneath an invocation of method {@link #withDebugContext}. - * + * * @param scopeName a name to be used to define a subscope current while the consumer is active. * @param action an action parameterised by the debug context. */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java index 098bb3c102ce..4f88f5fd9308 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/debugentry/Range.java @@ -84,14 +84,13 @@ public Range(String fileName, Path filePath, String className, String methodName } /* - * Create a slightly different copy of a previously constructed range. - * Because the previous range was constructed by one of the other constructors, - * a valid assumption is that all the strings have previously been inserted int he stringTable, - * and we can avoid doing that again. + * Create a slightly different copy of a previously constructed range. Because the previous + * range was constructed by one of the other constructors, a valid assumption is that all the + * strings have previously been inserted int he stringTable, and we can avoid doing that again. */ public Range(Range other, int lo, int hi) { this.fileName = other.fileName; - this.filePath = other.filePath; + this.filePath = other.filePath; this.className = other.className; this.methodName = other.methodName; this.paramNames = other.paramNames; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index 5624e2759869..23ac27af784c 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -31,11 +31,11 @@ public abstract class CVConstants { /* names of relevant CodeView sections */ static final String CV_SYMBOL_SECTION_NAME = ".debug$S"; static final String CV_TYPE_SECTION_NAME = ".debug$T"; - //static final String CV_RDATA_SECTION_NAME = ".rdata"; - //static final String CV_PDATA_SECTION_NAME = ".pdata"; - //static final String CV_XDATA_SECTION_NAME = ".xdata"; - //static final String TEXT_SECTION_NAME = ".text"; - //static final String DATA_SECTION_NAME = ".data"; + // static final String CV_RDATA_SECTION_NAME = ".rdata"; + // static final String CV_PDATA_SECTION_NAME = ".pdata"; + // static final String CV_XDATA_SECTION_NAME = ".xdata"; + // static final String TEXT_SECTION_NAME = ".text"; + // static final String DATA_SECTION_NAME = ".data"; /* CodeView section header signature */ static final int CV_SIGNATURE_C13 = 4; @@ -47,41 +47,65 @@ public abstract class CVConstants { */ /* - * path to JDK source code (for example unzipped src.zip) - * If set, source paths for JDK classes in the object file will be - * $JDK_SOURCE_BASE/java/package/someclass.java - * instead of - * (cache directory)/sources/jdk/java/package/someclass.java - * or (if source cache is disabled) - * java/package/someclass.java + * path to JDK source code (for example unzipped src.zip) If set, source paths for JDK classes + * in the object file will be $JDK_SOURCE_BASE/java/package/someclass.java instead of (cache + * directory)/sources/jdk/java/package/someclass.java or (if source cache is disabled) + * java/package/someclass.java * - * example - * JDK_SOURCE_BASE = C:\\tmp\\graal-8\\jdk8_jvmci\\src\\"; + * example JDK_SOURCE_BASE = C:\\tmp\\graal-8\\jdk8_jvmci\\src\\"; */ static final String JDK_SOURCE_BASE = ""; /* - * path to Graal source code base (for examplke checked out Graal source repository) - * if set source paths will be inferred from appropriate Graal package directories - * (behaves similarly to JDK_SOURCE_BASE) + * path to Graal source code base (for examplke checked out Graal source repository) if set + * source paths will be inferred from appropriate Graal package directories (behaves similarly + * to JDK_SOURCE_BASE) * - * Example: - * GRAAL_SOURCE_BASE = "C:\\tmp\\graal-8\\graal8\\"; + * Example: GRAAL_SOURCE_BASE = "C:\\tmp\\graal-8\\graal8\\"; */ static final String GRAAL_SOURCE_BASE = ""; - static final boolean skipGraalInternals = false; /* if true, don't emit debug code for Graal classes */ - static final boolean skipJDKInternals = false; /* (unimplemented) if true, don't emit debug code for JDK classes */ - static final boolean skipGraalIntrinsics = false; /* Graal inlined code treated as generated code */ - static final boolean mergeAdjacentLineRecords = true; /* if a line record is the same line in the same file as the previous record, merge them */ - static final boolean emitUnadornedMain = true; /* if true, first main() does not have args in the debug name */ - static final String replaceMainFunctionName = null; /* first main() becomes this name (with no class name or arg list at all) (set null to disable) */ + /* + * if true, don't emit debug code for Graal classes. + */ + static final boolean skipGraalInternals = false; + + /* + * (unimplemented) if true, don't emit debug code for JDK classes. + */ + static final boolean skipJDKInternals = false; + + /* + * if true, Graal inlined code treated as user generated code. + * (less complicated for user-level debugging) + */ + static final boolean skipGraalIntrinsics = false; + + /* + * if a line record is the same line in the same file as the previous record, + * merge them. + */ + static final boolean mergeAdjacentLineRecords = true; + + /* + * if true, first main() does not have args in the debug name. + */ + static final boolean emitUnadornedMain = true; /* - * The standard link.exe can't handle odd characters (parentheses or commas, for example) in external names. - * Setting functionNamesHashArgs true replaces those names, - * so that "Foo.function(String[] args)" becomes "Foo.function_617849326". - * If functionNamesHashArgs is false, currently the linker will fail. + * if true, first main() becomes this name (with no class name or arg list at all) (set null + * to disable). + */ + static final String replaceMainFunctionName = null; + + /* + * The standard link.exe can't handle odd characters (parentheses or commas, for example) in + * external names. Setting functionNamesHashArgs true replaces those names, so that + * "Foo.function(String[] args)" becomes "Foo.function_617849326". If functionNamesHashArgs is + * false, currently the linker will fail. + * + * if true, arg lists become obscure integers (and link.exe will work properly) + * TODO: strip illegal characters from arg lists instead */ - static final boolean functionNamesHashArgs = true; /* if true, arg lists become obscure integers (and link.exe will not work properly) */ + static final boolean functionNamesHashArgs = true; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java index 3bc4ca269d54..7b2b8a555c80 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java @@ -28,32 +28,33 @@ public abstract class CVDebugConstants { - //static final int DEBUG_S_IGNORE = 0x00; - static final int DEBUG_S_SYMBOLS = 0xf1; - static final int DEBUG_S_LINES = 0xf2; + // static final int DEBUG_S_IGNORE = 0x00; + static final int DEBUG_S_SYMBOLS = 0xf1; + static final int DEBUG_S_LINES = 0xf2; static final int DEBUG_S_STRINGTABLE = 0xf3; - static final int DEBUG_S_FILECHKSMS = 0xf4; + static final int DEBUG_S_FILECHKSMS = 0xf4; /* subcommands in DEBUG_S_SYMBOLS section */ - //static final short S_COMPILE = 0x0001; - static final short S_SSEARCH = 0x0005; - static final short S_END = 0x0006; - static final short S_OBJNAME = 0x1101; + // static final short S_COMPILE = 0x0001; + static final short S_SSEARCH = 0x0005; + static final short S_END = 0x0006; + static final short S_OBJNAME = 0x1101; static final short S_LDATA32_ST = 0x1007; static final short S_FRAMEPROC = 0x1012; - static final short S_CONSTANT = 0x1107; - static final short S_UDT = 0x1108; - static final short S_LDATA32 = 0x110c; - static final short S_GDATA32 = 0x110d; - static final short S_GPROC32 = 0x1110; - static final short S_REGREL32 = 0x1111; - static final short S_COMPILE3 = 0x113c; - static final short S_ENVBLOCK = 0x113d; - static final short S_GPROC32_ID = 0x1147; + static final short S_CONSTANT = 0x1107; + static final short S_UDT = 0x1108; + static final short S_LDATA32 = 0x110c; + static final short S_GDATA32 = 0x110d; + static final short S_GPROC32 = 0x1110; + static final short S_REGREL32 = 0x1111; + static final short S_COMPILE3 = 0x113c; + static final short S_ENVBLOCK = 0x113d; + static final short S_GPROC32_ID = 0x1147; static final short S_PROC_ID_END = 0x114f; - //static final short S_BUILDINFO = 0x114c; + // static final short S_BUILDINFO = 0x114c; - /* enums are more typesafe but the IDE no longer knows which enum constant is unused + /* enums are more typesafe but the IDE no longer knows which enum constant is unused */ + @SuppressWarnings("unused") enum CV_RECORD { CV_SIGNATURE_C13(4), S_COMPILE(0x0001), @@ -82,6 +83,7 @@ public int command() { } } + @SuppressWarnings("unused") enum DEBUG_S { DEBUG_S_IGNORE(0x00), DEBUG_S_SYMBOLS(0xf1), @@ -98,5 +100,5 @@ enum DEBUG_S { public short command() { return cmd; } - } */ + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java index 5d9f959796ff..0bf60cab5103 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugInfo.java @@ -33,8 +33,8 @@ /** * CVDebugInfo is a container class for all the CodeView sections to be emitted in the object file. - * Currently, that is .debug$S (CVSymbolSectionImpl) and .debug$T (CVTypeSectionImpl) - * Common data (useful to more than one CodeView section) goes here + * Currently, that is .debug$S (CVSymbolSectionImpl) and .debug$T (CVTypeSectionImpl) Common data + * (useful to more than one CodeView section) goes here */ public final class CVDebugInfo extends DebugInfoBase { @@ -46,7 +46,7 @@ public CVDebugInfo(PECoffMachine targetMachine, ByteOrder byteOrder) { super(byteOrder); machine = targetMachine; cvSymbolSection = new CVSymbolSectionImpl(this); - cvTypeSection = new CVTypeSectionImpl(); + cvTypeSection = new CVTypeSectionImpl(); } public CVSymbolSectionImpl getCVSymbolSection() { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java index eb8a5490a150..7d0fb971702a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVFileRecord.java @@ -60,8 +60,8 @@ final class CVFileRecord extends CVSymbolRecord { } /* - * Convert a simple path into an absolute path by determining if it's - * part of Graal, the JDK, or use code. + * Convert a simple path into an absolute path by determining if it's part of Graal, the JDK, or + * use code. * * Currently, don't even try; use the SourceCache system */ @@ -90,7 +90,10 @@ int addFile(FileEntry entry) { @Override public int computeSize(int initialPos) { /* add all fileEntries; duplicates are ignored */ - /* probably don't need to do this because if it isn't already here it's probably referenced by the debug info */ + /* + * probably don't need to do this because if it isn't already here it's probably referenced + * by the debug info + */ /* consider moving this to CVSymbolSectionImpl */ for (FileEntry entry : cvDebugInfo.getFiles()) { addFile(entry); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java index 0939ac8596d4..d15468cf48b2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecord.java @@ -51,9 +51,10 @@ final class CVLineRecord extends CVSymbolRecord { private ArrayList fileBlocks = new ArrayList<>(DEFAULT_LINE_BLOCK_COUNT); /* - * FileBlock is a section of contiguous code in a compilation unit, associated with a single source file. - * if a function includes inlined code, that code needs its own FileBlock, surrounded by FileBlocks describing the enclosing source file - * A FileBlock consists of a list of LineEntries + * FileBlock is a section of contiguous code in a compilation unit, associated with a single + * source file. if a function includes inlined code, that code needs its own FileBlock, + * surrounded by FileBlocks describing the enclosing source file A FileBlock consists of a list + * of LineEntries */ private static class FileBlock { @@ -97,8 +98,8 @@ int getHighAddr() { } /* - * LineEntry associates some object code (at 'addr', relative to the start of this DEBUG_S_LINES record) - * with a source line in the current FileBlock file + * LineEntry associates some object code (at 'addr', relative to the start of this DEBUG_S_LINES + * record) with a source line in the current FileBlock file */ static class LineEntry { @@ -168,15 +169,21 @@ protected int computeContents(byte[] buffer, int initialPos) { cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, symbolName, false, 1L); } pos = CVUtil.putInt(0, buffer, pos); + if (buffer != null) { cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, symbolName, false, 1L); } pos = CVUtil.putShort((short) 0, buffer, pos); + final short flags = HAS_COLUMNS ? CB_HAS_COLUMNS_FLAG : CB_HAS_NO_COLUMNS_FLAG; - pos = CVUtil.putShort(flags, buffer, pos); /* flags */ - final int cbConPos = pos; /* save position of length int32 */ - pos = CVUtil.putInt(0, buffer, pos); /* highAddr = length of this chunk in object file (fill in correctly later) */ + pos = CVUtil.putShort(flags, buffer, pos); /* flags */ + + /* + * highAddr = length of this chunk in object file (fill in correctly later) + */ + final int cbConPos = pos; /* save position of length int32 */ int highAddr = 0; + pos = CVUtil.putInt(highAddr, buffer, pos); for (FileBlock fileBlock : fileBlocks) { highAddr = Math.max(highAddr, fileBlock.getHighAddr()); pos = fileBlock.computeContents(buffer, pos); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 9d11e162d6ed..40e21efed4b2 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -46,29 +46,32 @@ public class CVLineRecordBuilder { this.cvDebugInfo = cvDebugInfo; } - public static void debug(@SuppressWarnings("unused") String format, @SuppressWarnings("unused") Object ... args) { - //System.out.format(format, args); + public static void debug(@SuppressWarnings("unused") String format, @SuppressWarnings("unused") Object... args) { + // System.out.format(format, args); } /* * In CV4, the line table consists of a series of file headers followed by line number entries - * to handle this, first we decide if we want to merge this with the previous range (only if same file and start of this range is end of previous range) - * if we are emitting a new range to the same file, write the range, save it as the previous range and go on - * If this is a different file, then update the length of the previous file header, write the new file header and write the new range - * At the very end, make sure we update the last file header. + * to handle this, first we decide if we want to merge this with the previous range (only if + * same file and start of this range is end of previous range) if we are emitting a new range to + * the same file, write the range, save it as the previous range and go on If this is a + * different file, then update the length of the previous file header, write the new file header + * and write the new range At the very end, make sure we update the last file header. * - * In addition, optionally ignore Ranges that point into Graal innards, just adding them to the current enclosing range + * In addition, optionally ignore Ranges that point into Graal innards, just adding them to the + * current enclosing range */ /** * Build line number records for a function. + * * @param entry function to build line number table for * @return CVLineRecord containing any entries generated, or null if no entries generated */ @SuppressWarnings("unused") CVLineRecord build(PrimaryEntry entry, String methodName) { - // long lowAddr = Long.MAX_VALUE; - // long highAddr = 0; + // long lowAddr = Long.MAX_VALUE; + // long highAddr = 0; this.primaryEntry = entry; assert (!HAS_COLUMNS); /* can't handle columns yet */ @@ -85,8 +88,8 @@ CVLineRecord build(PrimaryEntry entry, String methodName) { this.lineRecord = new CVLineRecord(cvDebugInfo, methodName, primaryEntry); debug("CVLineRecord.computeContents: processing primary range %s\n", primaryRange); previousRange = processRange(primaryRange, previousRange); - // lowAddr = Math.min(lowAddr, primaryRange.getLo()); - // highAddr = Math.max(highAddr, primaryRange.getHi()); + // lowAddr = Math.min(lowAddr, primaryRange.getLo()); + // highAddr = Math.max(highAddr, primaryRange.getHi()); for (Range subRange : primaryEntry.getSubranges()) { debug("CVLineRecord.computeContents: processing range %s\n", subRange); @@ -95,19 +98,17 @@ CVLineRecord build(PrimaryEntry entry, String methodName) { continue; } previousRange = processRange(subRange, previousRange); - // lowAddr = Math.min(lowAddr, subRange.getLo()); - // highAddr = Math.max(highAddr, subRange.getHi()); + // lowAddr = Math.min(lowAddr, subRange.getLo()); + // highAddr = Math.max(highAddr, subRange.getHi()); } return lineRecord; } /** - * Merge input Range structures into line number table. - * The Range structures are assumed to be ordered by ascending address - * merge with previous line entry if: - * - if a Range has a negative linenumber - * - if a range is part of Graal or the JDK, and skipGraalOption is true - * - if a range has the same line number, source file and function + * Merge input Range structures into line number table. The Range structures are assumed to be + * ordered by ascending address merge with previous line entry if: - if a Range has a negative + * linenumber - if a range is part of Graal or the JDK, and skipGraalOption is true - if a range + * has the same line number, source file and function * * @param range to be merged or added to line number record * @param oldPreviousRange the previously processed Range @@ -122,11 +123,11 @@ private Range processRange(Range range, Range oldPreviousRange) { if (shouldMerge(range, previousRange)) { debug("processRange: merging with previous\n"); return previousRange; - //range = new Range(previousRange, range.getLo(), range.getHi()); - } /*else if (range.getLine() == -1) { - CVUtil.debug(" processRange: ignoring: bad line number\n"); - return previousRange; - }*/ + // range = new Range(previousRange, range.getLo(), range.getHi()); + } /* + * else if (range.getLine() == -1) { CVUtil.debug( + * " processRange: ignoring: bad line number\n"); return previousRange; } + */ /* is this a new file? if so we emit a new file record */ boolean wantNewFile = previousRange == null || !previousRange.getFileAsPath().equals(range.getFileAsPath()); @@ -154,6 +155,7 @@ private Range processRange(Range range, Range oldPreviousRange) { /** * Test to see if two ranges are adjacent, and can be combined into one. + * * @param previousRange the first range (lower address) * @param range the second range (higher address) * @return true if the two ranges can be combined @@ -169,7 +171,7 @@ private boolean shouldMerge(Range range, Range previousRange) { /* if we're in a different class that the primary Class, this is inlined code */ final boolean isInlinedCode = !range.getClassName().equals(primaryEntry.getClassEntry().getClassName()); // if (isInlinedCode && skipInlinedCode) { return true; } - if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { + if (isInlinedCode && skipGraalIntrinsics && CVRootPackages.isGraalIntrinsic(range.getClassName())) { return true; } return previousRange.getFileAsPath().equals(range.getFileAsPath()) && (range.getLine() == -1 || previousRange.getLine() == range.getLine()); @@ -177,13 +179,26 @@ private boolean shouldMerge(Range range, Range previousRange) { /** * Test to see if a new line record should be emitted. + * * @param previousRange previous range * @param range current range * @return true if the current range is on a different line or file from the previous one */ private static boolean wantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { + /* return true for now; this will be a further optimization (see unused_wantNewRange) */ return true; - /*if (debug) { + } + + /** + * Test to see if a new line record should be emitted. + * + * @param previousRange previous range + * @param range current range + * @return true if the current range is on a different line or file from the previous one + */ + @SupressWarnings("unused") + private static boolean unused_wantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { + if (debug) { if (previousRange == null) { debug("wantNewRange() prevnull:true"); } else { @@ -197,11 +212,9 @@ private static boolean wantNewRange(@SuppressWarnings("unused") Range range, @Su return true; if (previousRange.getFilePath() != range.getFilePath()) return true; - /* it might actually be fine to merge if there's a gap between ranges * - if (previousRange.getHi() < range.getLo()) - return true; - //long delta = range.getHi() - previousRange.getLo(); - //return delta >= 127; - return false; */ + /* it might actually be fine to merge if there's a gap between ranges */ + // if (previousRange.getHi() < range.getLo()) + // return true; + return false; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java index bfc682f8cb79..df4d0bb54cf4 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -31,144 +31,144 @@ abstract class CVRootPackages { private static final String[] rootPackageNames = { - /* substrate root packages */ - "com.oracle.graal.pointsto", - "com.oracle.objectfile", - "com.oracle.svm.agent", - "com.oracle.svm.configure", - "com.oracle.svm.core", - "com.oracle.svm.core.genscavenge", - "com.oracle.svm.core.graal", - "com.oracle.svm.core.graal.aarch64", - "com.oracle.svm.core.graal.amd64", - "com.oracle.svm.core.graal.llvm", - "com.oracle.svm.core.jdk11", - "com.oracle.svm.core.jdk8", - "com.oracle.svm.core.posix", - "com.oracle.svm.core.posix.jdk11", - "com.oracle.svm.core.windows", - "com.oracle.svm.driver", - "com.oracle.svm.graal", - "com.oracle.svm.graal.hotspot.libgraal", - "com.oracle.svm.hosted", - "com.oracle.svm.jline", - "com.oracle.svm.jni", - "com.oracle.svm.junit", - "com.oracle.svm.libffi", - "com.oracle.svm.native.jvm.posix", - "com.oracle.svm.native.jvm.windows", - "com.oracle.svm.native.libchelper", - "com.oracle.svm.native.strictmath", - "com.oracle.svm.polyglot", - "com.oracle.svm.reflect", - "com.oracle.svm.test", - "com.oracle.svm.test.jdk11", - "com.oracle.svm.thirdparty", - "com.oracle.svm.truffle", - "com.oracle.svm.truffle.nfi", - "com.oracle.svm.truffle.nfi.posix", - "com.oracle.svm.truffle.nfi.windows", - "com.oracle.svm.tutorial", - "com.oracle.svm.util", - "com.oracle.svm.util.jdk11", - "org.graalvm.polyglot.nativeapi", - /* compiler root packages */ - "jdk.tools.jaotc", - "jdk.tools.jaotc.binformat", - "jdk.tools.jaotc", - "org.graalvm.compiler.api.directives", - "org.graalvm.compiler.api.replacements", - "org.graalvm.compiler.api.runtime", - "org.graalvm.compiler.asm", - "org.graalvm.compiler.asm.aarch64", - "org.graalvm.compiler.asm.amd64", - "org.graalvm.compiler.asm.sparc", - "org.graalvm.compiler.bytecode", - "org.graalvm.compiler.code", - "org.graalvm.compiler.core", - "org.graalvm.compiler.core.aarch64", - "org.graalvm.compiler.core.amd64", - "org.graalvm.compiler.core.common", - "org.graalvm.compiler.core.llvm", - "org.graalvm.compiler.core.match.processor", - "org.graalvm.compiler.core.sparc", - "org.graalvm.compiler.debug", - "org.graalvm.compiler.graph", - "org.graalvm.compiler.hotspot", - "org.graalvm.compiler.hotspot.aarch64", - "org.graalvm.compiler.hotspot.amd64", - "org.graalvm.compiler.hotspot.jdk8", - "org.graalvm.compiler.hotspot.management", - "org.graalvm.compiler.hotspot.sparc", - "org.graalvm.compiler.java", - "org.graalvm.compiler.jtt", - "org.graalvm.compiler.lir", - "org.graalvm.compiler.lir.aarch64", - "org.graalvm.compiler.lir.amd64", - "org.graalvm.compiler.lir.jtt", - "org.graalvm.compiler.lir.sparc", - "org.graalvm.compiler.loop", - "org.graalvm.compiler.loop.phases", - "org.graalvm.compiler.microbenchmarks", - "org.graalvm.compiler.nodeinfo", - "org.graalvm.compiler.nodeinfo.processor", - "org.graalvm.compiler.nodes", - "org.graalvm.compiler.options", - "org.graalvm.compiler.options.processor", - "org.graalvm.compiler.phases", - "org.graalvm.compiler.phases.common", - "org.graalvm.compiler.printer", - "org.graalvm.compiler.processor", - "org.graalvm.compiler.replacements", - "org.graalvm.compiler.replacements.aarch64", - "org.graalvm.compiler.replacements.amd64", - "org.graalvm.compiler.replacements.processor", - "org.graalvm.compiler.replacements.sparc", - "org.graalvm.compiler.runtime", - "org.graalvm.compiler.serviceprovider", - "org.graalvm.compiler.serviceprovider.jdk8", - "org.graalvm.compiler.serviceprovider.processor", - "org.graalvm.compiler.truffle.common", - "org.graalvm.compiler.truffle.common.hotspot", - "org.graalvm.compiler.truffle.common.hotspot.libgraal", - "org.graalvm.compiler.truffle.common.processor", - "org.graalvm.compiler.truffle.compiler", - "org.graalvm.compiler.truffle.compiler.amd64", - "org.graalvm.compiler.truffle.compiler.hotspot", - "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", - "org.graalvm.compiler.truffle.compiler.hotspot.amd64", - "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", - "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", - "org.graalvm.compiler.truffle.compiler.hotspot.sparc", - "org.graalvm.compiler.truffle.runtime", - "org.graalvm.compiler.truffle.runtime.hotspot", - "org.graalvm.compiler.truffle.runtime.hotspot.java", - "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", - "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", - "org.graalvm.compiler.truffle.runtime.serviceprovider", - "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", - "org.graalvm.compiler.virtual", - "org.graalvm.compiler.virtual.bench", - "org.graalvm.compiler.word", - "org.graalvm.graphio", - "org.graalvm.libgraal", - "org.graalvm.libgraal.jdk8", - "org.graalvm.micro.benchmarks", - "org.graalvm.util", + /* substrate root packages */ + "com.oracle.graal.pointsto", + "com.oracle.objectfile", + "com.oracle.svm.agent", + "com.oracle.svm.configure", + "com.oracle.svm.core", + "com.oracle.svm.core.genscavenge", + "com.oracle.svm.core.graal", + "com.oracle.svm.core.graal.aarch64", + "com.oracle.svm.core.graal.amd64", + "com.oracle.svm.core.graal.llvm", + "com.oracle.svm.core.jdk11", + "com.oracle.svm.core.jdk8", + "com.oracle.svm.core.posix", + "com.oracle.svm.core.posix.jdk11", + "com.oracle.svm.core.windows", + "com.oracle.svm.driver", + "com.oracle.svm.graal", + "com.oracle.svm.graal.hotspot.libgraal", + "com.oracle.svm.hosted", + "com.oracle.svm.jline", + "com.oracle.svm.jni", + "com.oracle.svm.junit", + "com.oracle.svm.libffi", + "com.oracle.svm.native.jvm.posix", + "com.oracle.svm.native.jvm.windows", + "com.oracle.svm.native.libchelper", + "com.oracle.svm.native.strictmath", + "com.oracle.svm.polyglot", + "com.oracle.svm.reflect", + "com.oracle.svm.test", + "com.oracle.svm.test.jdk11", + "com.oracle.svm.thirdparty", + "com.oracle.svm.truffle", + "com.oracle.svm.truffle.nfi", + "com.oracle.svm.truffle.nfi.posix", + "com.oracle.svm.truffle.nfi.windows", + "com.oracle.svm.tutorial", + "com.oracle.svm.util", + "com.oracle.svm.util.jdk11", + "org.graalvm.polyglot.nativeapi", + /* compiler root packages */ + "jdk.tools.jaotc", + "jdk.tools.jaotc.binformat", + "jdk.tools.jaotc", + "org.graalvm.compiler.api.directives", + "org.graalvm.compiler.api.replacements", + "org.graalvm.compiler.api.runtime", + "org.graalvm.compiler.asm", + "org.graalvm.compiler.asm.aarch64", + "org.graalvm.compiler.asm.amd64", + "org.graalvm.compiler.asm.sparc", + "org.graalvm.compiler.bytecode", + "org.graalvm.compiler.code", + "org.graalvm.compiler.core", + "org.graalvm.compiler.core.aarch64", + "org.graalvm.compiler.core.amd64", + "org.graalvm.compiler.core.common", + "org.graalvm.compiler.core.llvm", + "org.graalvm.compiler.core.match.processor", + "org.graalvm.compiler.core.sparc", + "org.graalvm.compiler.debug", + "org.graalvm.compiler.graph", + "org.graalvm.compiler.hotspot", + "org.graalvm.compiler.hotspot.aarch64", + "org.graalvm.compiler.hotspot.amd64", + "org.graalvm.compiler.hotspot.jdk8", + "org.graalvm.compiler.hotspot.management", + "org.graalvm.compiler.hotspot.sparc", + "org.graalvm.compiler.java", + "org.graalvm.compiler.jtt", + "org.graalvm.compiler.lir", + "org.graalvm.compiler.lir.aarch64", + "org.graalvm.compiler.lir.amd64", + "org.graalvm.compiler.lir.jtt", + "org.graalvm.compiler.lir.sparc", + "org.graalvm.compiler.loop", + "org.graalvm.compiler.loop.phases", + "org.graalvm.compiler.microbenchmarks", + "org.graalvm.compiler.nodeinfo", + "org.graalvm.compiler.nodeinfo.processor", + "org.graalvm.compiler.nodes", + "org.graalvm.compiler.options", + "org.graalvm.compiler.options.processor", + "org.graalvm.compiler.phases", + "org.graalvm.compiler.phases.common", + "org.graalvm.compiler.printer", + "org.graalvm.compiler.processor", + "org.graalvm.compiler.replacements", + "org.graalvm.compiler.replacements.aarch64", + "org.graalvm.compiler.replacements.amd64", + "org.graalvm.compiler.replacements.processor", + "org.graalvm.compiler.replacements.sparc", + "org.graalvm.compiler.runtime", + "org.graalvm.compiler.serviceprovider", + "org.graalvm.compiler.serviceprovider.jdk8", + "org.graalvm.compiler.serviceprovider.processor", + "org.graalvm.compiler.truffle.common", + "org.graalvm.compiler.truffle.common.hotspot", + "org.graalvm.compiler.truffle.common.hotspot.libgraal", + "org.graalvm.compiler.truffle.common.processor", + "org.graalvm.compiler.truffle.compiler", + "org.graalvm.compiler.truffle.compiler.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot", + "org.graalvm.compiler.truffle.compiler.hotspot.aarch64", + "org.graalvm.compiler.truffle.compiler.hotspot.amd64", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal", + "org.graalvm.compiler.truffle.compiler.hotspot.libgraal.processor", + "org.graalvm.compiler.truffle.compiler.hotspot.sparc", + "org.graalvm.compiler.truffle.runtime", + "org.graalvm.compiler.truffle.runtime.hotspot", + "org.graalvm.compiler.truffle.runtime.hotspot.java", + "org.graalvm.compiler.truffle.runtime.hotspot.jdk8+13", + "org.graalvm.compiler.truffle.runtime.hotspot.libgraal", + "org.graalvm.compiler.truffle.runtime.serviceprovider", + "org.graalvm.compiler.truffle.runtime.serviceprovider.jdk8", + "org.graalvm.compiler.virtual", + "org.graalvm.compiler.virtual.bench", + "org.graalvm.compiler.word", + "org.graalvm.graphio", + "org.graalvm.libgraal", + "org.graalvm.libgraal.jdk8", + "org.graalvm.micro.benchmarks", + "org.graalvm.util", }; private static final String[] intrinsicClassNames = { - "com.oracle.svm.core.genscavenge.AlignedHeapChunk", - "com.oracle.svm.core.genscavenge.CardTable", - "com.oracle.svm.core.genscavenge.ObjectHeaderImpl", - "com.oracle.svm.core.genscavenge.graal.GenScavengeAllocationSnippets", - "com.oracle.svm.core.genscavenge.graal.BarrierSnippets", - "com.oracle.svm.core.snippets.KnownIntrinsics", - "com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets", - "com.oracle.svm.core.threadlocal.FastThreadLocalBytes", - "org.graalvm.compiler.replacements.AllocationSnippets", - "org.graalvm.compiler.nodes.PrefetchAllocateNode", - "com.oracle.svm.core.os.CopyingImageHeapProvider" + "com.oracle.svm.core.genscavenge.AlignedHeapChunk", + "com.oracle.svm.core.genscavenge.CardTable", + "com.oracle.svm.core.genscavenge.ObjectHeaderImpl", + "com.oracle.svm.core.genscavenge.graal.GenScavengeAllocationSnippets", + "com.oracle.svm.core.genscavenge.graal.BarrierSnippets", + "com.oracle.svm.core.snippets.KnownIntrinsics", + "com.oracle.svm.core.graal.snippets.SubstrateAllocationSnippets", + "com.oracle.svm.core.threadlocal.FastThreadLocalBytes", + "org.graalvm.compiler.replacements.AllocationSnippets", + "org.graalvm.compiler.nodes.PrefetchAllocateNode", + "com.oracle.svm.core.os.CopyingImageHeapProvider" }; private static final HashSet rootPackageSet; @@ -205,10 +205,13 @@ static boolean isGraalIntrinsic(String cn) { } static boolean isJavaPackage(String pn) { + /* TODO : make more accurate */ return pn.startsWith("java.") || pn.startsWith("javax.") || pn.startsWith("sun."); } -/* - static boolean isJavaFile(String pn) { + + @SupressWarnings("unused") + private static boolean isJavaFile(String pn) { + /* TODO : make more accurate */ return pn.startsWith("java/") || pn.startsWith("javax/") || pn.startsWith("sun/"); - }*/ + } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java index 01f5ec857376..7ad66b796dd8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSectionImpl.java @@ -66,8 +66,9 @@ private String debugSectionLogName() { protected void enableLog(DebugContext context, int pos) { /* - * Unlike in the Dwarf debug code, debug output is enabled in both the sizing and writing phases. - * At this time, debugBase and debugAddress aren't used but are there for the future. + * Unlike in the Dwarf debug code, debug output is enabled in both the sizing and writing + * phases. At this time, debugBase and debugAddress aren't used but are there for the + * future. */ if (context.areScopesEnabled()) { debug = true; @@ -109,22 +110,25 @@ public byte[] getOrDecideContent(Map alre public Set getDependencies(Map decisions) { Set deps = super.getDependencies(decisions); String targetName = getSectionName(); - @SuppressWarnings("unused") PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); - //LayoutDecision.Kind[] targetKinds = targetSectionKinds(); + @SuppressWarnings("unused") + PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(targetName); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + // LayoutDecision.Kind[] targetKinds = targetSectionKinds(); /* make our content depend on the size and content of the target */ - //for (LayoutDecision.Kind targetKind : targetKinds) { - // LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); - // deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); - //} + // for (LayoutDecision.Kind targetKind : targetKinds) { + // LayoutDecision targetDecision = decisions.get(targetSection).getDecision(targetKind); + // deps.add(BuildDependency.createOrGet(ourContent, targetDecision)); + // } /* make our size depend on our content */ deps.add(BuildDependency.createOrGet(ourSize, ourContent)); return deps; } - //public abstract LayoutDecision.Kind[] targetSectionKinds(); + // public abstract LayoutDecision.Kind[] targetSectionKinds(); public abstract void createContent(DebugContext debugContext); + public abstract void writeContent(DebugContext debugContext); + public abstract String getSectionName(); } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java index 97fa59d5bb8d..ad84627d40fa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecord.java @@ -58,6 +58,7 @@ int computeFullContents(byte[] buffer, int initialPos) { } protected abstract int computeSize(int pos); + protected abstract int computeContents(byte[] buffer, int pos); @Override diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index f2351c3ec576..2beeb7ddbaa8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -49,8 +49,8 @@ final class CVSymbolRecordBuilder { } /** - * build DEBUG_S_SYMBOLS record from all classEntries. - * (could probably build one per class or one per function) + * build DEBUG_S_SYMBOLS record from all classEntries. (could probably build one per class or + * one per function) */ void build(DebugContext theDebugContext) { this.debugContext = theDebugContext; @@ -61,8 +61,7 @@ void build(DebugContext theDebugContext) { } /** - * build all debug info for a classEntry. - * (does not yet handle member variables) + * build all debug info for a classEntry. (does not yet handle member variables) * * @param classEntry current class */ @@ -82,22 +81,20 @@ private void build(ClassEntry classEntry) { } /** - * emit records for each function: - * PROC32 - * S_FRAMEPROC - * S_END - * (later: type records as required) - * line number records. + * emit records for each function: PROC32 S_FRAMEPROC S_END and line number records. + * (later: type records as required) * * @param primaryEntry primary entry for this function * @param methodName method name alias as it will be seen by the user */ private void build(PrimaryEntry primaryEntry, String methodName) { final Range primaryRange = primaryEntry.getPrimary(); - //debug("addfunc(" + methodName + ") numtypes = %d\n", cvDebugInfo.getCVTypeSection().getRecords().size()); + // debug("addfunc(" + methodName + ") numtypes = %d\n", + // cvDebugInfo.getCVTypeSection().getRecords().size()); int functionTypeIndex = addTypeRecords(primaryEntry); byte funcFlags = 0; - CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvDebugInfo, methodName, 0, 0, 0, primaryRange.getHi() - primaryRange.getLo(), 0, 0, functionTypeIndex, primaryRange.getLo(), (short) 0, funcFlags); + CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvDebugInfo, methodName, 0, 0, 0, primaryRange.getHi() - primaryRange.getLo(), 0, 0, + functionTypeIndex, primaryRange.getLo(), (short) 0, funcFlags); addToSymbolRecord(proc32); int frameFlags = 0; /* LLVM uses 0x14000; */ addToSymbolRecord(new CVSymbolSubrecord.CVSymbolFrameProcRecord(cvDebugInfo, primaryRange.getHi() - primaryRange.getLo(), frameFlags)); @@ -109,12 +106,12 @@ private void build(PrimaryEntry primaryEntry, String methodName) { private boolean noMainFound = true; /** - * renames a method name ot something user friendly in the debugger. - * (does not affect external symbols used by linker) + * renames a method name ot something user friendly in the debugger. (does not affect external + * symbols used by linker) * - * first main function becomes class.main (unless replaceMainFunctionName is non-null) - * if functionNamesHashArgs is true (which it must be for the linker to work properly) - * all other functions become class.function.999 (where 999 is a hash of the arglist) + * first main function becomes class.main (unless replaceMainFunctionName is non-null) if + * functionNamesHashArgs is true (which it must be for the linker to work properly) all other + * functions become class.function.999 (where 999 is a hash of the arglist) * * @param range Range contained in the method of interest * @return user debugger friendly method name @@ -134,15 +131,15 @@ private String fixMethodName(Range range) { } else { methodName = range.getFullMethodName(); } - //debug("replacing %s with %s\n", range.getFullMethodName(), methodName); + // debug("replacing %s with %s\n", range.getFullMethodName(), methodName); return methodName; } private void addLineNumberRecords(PrimaryEntry primaryEntry, String methodName) { CVLineRecord record = new CVLineRecordBuilder(cvDebugInfo).build(primaryEntry, methodName); /* - * if the builder decides this entry is uninteresting, we don't build a record. - * for example, Graal intrinsics may be uninteresting. + * if the builder decides this entry is uninteresting, we don't build a record. for example, + * Graal intrinsics may be uninteresting. */ if (record != null) { cvDebugInfo.getCVSymbolSection().addRecord(record); @@ -150,13 +147,13 @@ private void addLineNumberRecords(PrimaryEntry primaryEntry, String methodName) } private void addToSymbolRecord(CVSymbolSubrecord record) { - //debug("adding symbol subrecord: %s\n", record); + // debug("adding symbol subrecord: %s\n", record); symbolRecord.addRecord(record); } /** - * add type records for function. - * (later add arglist, and return type and local types) + * add type records for function. (later add arglist, and return type and local types) + * * @param entry primaryEntry containing entities whoses type records must be added * * @return type index of function type diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java index 145404ca79f2..25526ecd21ca 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSectionImpl.java @@ -127,9 +127,9 @@ private void addFunctionRecords(DebugContext debugContext) { } private void addTypeRecords() { - /* not yet implemented. S_UDT, etc */ - //CVSymbolRecord externs = new CVSymbolSubsection.CVExternalSymbolRecord(cvDebugInfo); - //addRecord(externs); + /* not yet implemented. S_UDT, etc */ + // CVSymbolRecord externs = new CVSymbolSubsection.CVExternalSymbolRecord(cvDebugInfo); + // addRecord(externs); } private void addFileRecords() { @@ -153,6 +153,7 @@ static final class CVStringTable { static final class StringTableEntry { public int offset; public String text; + StringTableEntry(int offset, String text) { this.offset = offset; this.text = text; @@ -173,7 +174,10 @@ int add(String s) { StringTableEntry newEntry = new StringTableEntry(currentOffset, s); StringTableEntry entry = strings.putIfAbsent(s, newEntry); if (entry == null) { - int utf8Length = s.getBytes(UTF_8).length; /* TODO: getting the enecoded size should be made more efficient */ + /* + * TODO: getting the enecoded size should be made more efficient + */ + int utf8Length = s.getBytes(UTF_8).length; currentOffset += utf8Length + 1; } return entry == null ? newEntry.offset : entry.offset; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index dbbd74394d5c..d829c2737c74 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -71,11 +71,12 @@ public String toString() { } protected abstract int computeSize(int pos); + protected abstract int computeContents(byte[] buffer, int pos); public static final class CVObjectNameRecord extends CVSymbolSubrecord { - String objName; /* TODO: how to find the full path to object file we will produce */ + String objName; /* TODO: how to find the full path to object file we will produce */ CVObjectNameRecord(CVDebugInfo cvDebugInfo, String objName) { super(cvDebugInfo, CVDebugConstants.S_OBJNAME); @@ -108,14 +109,14 @@ boolean isValid() { @Override protected int computeSize(int initialPos) { int pos = initialPos + Integer.BYTES; /* signature = 0; */ - pos += objName.getBytes(UTF_8).length + 1; /* inline null terminated */ + pos += objName.getBytes(UTF_8).length + 1; /* inline null terminated */ return pos; } @Override protected int computeContents(byte[] buffer, int initialPos) { - int pos = CVUtil.putInt(0, buffer, initialPos); /* signature = 0 */ - pos = CVUtil.putUTF8StringBytes(objName, buffer, pos); /* inline null terminated */ + int pos = CVUtil.putInt(0, buffer, initialPos); /* signature = 0 */ + pos = CVUtil.putUTF8StringBytes(objName, buffer, pos); /* inline null terminated */ return pos; } } @@ -123,7 +124,7 @@ protected int computeContents(byte[] buffer, int initialPos) { public static final class CVCompile3Record extends CVSymbolSubrecord { private static final byte HAS_DEBUG_FLAG = 0; - //private static final byte HAS_NO_DEBUG_FLAG = (byte)0x80; + // private static final byte HAS_NO_DEBUG_FLAG = (byte)0x80; private byte language; private byte cf1; @@ -190,12 +191,12 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { private Map map = new HashMap<>(ENVMAP_INITIAL_CAPACITY); /* - * Example: - * cwd = C:\tmp\graal-8 - * cl = C:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\Bin\x86_amd64\cl.exe - * cmd = -Zi -MT -IC:\tmp\graal-8\tools\toolchain\vs2010e\VC\INCLUDE -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE\gl -TC -X - * src = helloworld.c - * pdb = C:\tmp\graal-8\vc100.pdb + * Example: cwd = C:\tmp\graal-8 cl = + * C:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\Bin\x86_amd64\cl.exe cmd = -Zi -MT + * -IC:\tmp\graal-8\tools\toolchain\vs2010e\VC\INCLUDE + * -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE + * -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE\gl -TC -X src = helloworld.c pdb = + * C:\tmp\graal-8\vc100.pdb */ CVEnvBlockRecord(CVDebugInfo cvDebugInfo) { @@ -205,19 +206,21 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { map.put("cwd", System.getProperty("user.dir")); /* compiler executable */ - //map.put("cl", "cl.exe"); + // map.put("cl", "cl.exe"); /* argument list */ - //map.put("cmd", "-Zi -MT -wishfulthinking"); + // map.put("cmd", "-Zi -MT -wishfulthinking"); - /* find first source file - which, for Graal would be a class file on the command line */ + /* + * find first source file - which, for Graal would be a class file on the command line + */ String fn = findFirstFile(cvDebugInfo); if (fn != null) { map.put("src", fn); } /* Graal doesn't yet create PDB files; all type info is stored in object file */ - //map.put("pdb", System.getProperty("user.dir") + File.separator + "vc100.pdb"); + // map.put("pdb", System.getProperty("user.dir") + File.separator + "vc100.pdb"); } private static String findFirstFile(CVDebugInfo cvDebugInfo) { @@ -254,9 +257,9 @@ protected int computeContents(byte[] buffer, int initialPos) { } /* - * creating a proc32 record has side effects. - * - a global symbol is added to the COFF symbol section - * - two relocation entries are added to the section relocation table, they refer to the global symbol + * creating a proc32 record has side effects. - a global symbol is added to the COFF symbol + * section - two relocation entries are added to the section relocation table, they refer to the + * global symbol */ public static class CVSymbolGProc32Record extends CVSymbolSubrecord { @@ -274,7 +277,8 @@ public static class CVSymbolGProc32Record extends CVSymbolSubrecord { byte flags; String name; - CVSymbolGProc32Record(CVDebugInfo cvDebugInfo, short cmd, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { + CVSymbolGProc32Record(CVDebugInfo cvDebugInfo, short cmd, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, + byte flags) { super(cvDebugInfo, cmd); this.name = name; this.pparent = pparent; @@ -311,12 +315,14 @@ protected int computeContents(byte[] buffer, int initialPos) { cvDebugInfo.getCVSymbolSection().getOwner().createDefinedSymbol(name, getTextSection(), offset, proclen, true, true); } if (buffer != null) { - //CVUtil.debug("CVSymbolGProc32Record() adding SECREL reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); + // CVUtil.debug("CVSymbolGProc32Record() adding SECREL reloc at pos=0x%x for func=%s + // addr=0x%x\n", pos, name, offset); cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 4, ObjectFile.RelocationKind.SECREL, name, false, 1L); } pos = CVUtil.putInt(0, buffer, pos); if (buffer != null) { - //CVUtil.debug("CVSymbolGProc32Record() adding SECTION reloc at pos=0x%x for func=%s addr=0x%x\n", pos, name, offset); + // CVUtil.debug("CVSymbolGProc32Record() adding SECTION reloc at pos=0x%x for + // func=%s addr=0x%x\n", pos, name, offset); cvDebugInfo.getCVSymbolSection().markRelocationSite(pos, 2, ObjectFile.RelocationKind.SECTION, name, false, 1L); } pos = CVUtil.putShort((short) 0, buffer, pos); @@ -334,17 +340,19 @@ private ObjectFile.Element getTextSection() { @Override public String toString() { - return String.format("S_GPROC32(name=%s parent=%d startaddr=0x%x end=0x%x len=0x%x offset=0x%x type=0x%x flags=0x%x)", name, pparent, debugStart, debugEnd, proclen, offset, typeIndex, flags); + return String.format("S_GPROC32(name=%s parent=%d startaddr=0x%x end=0x%x len=0x%x offset=0x%x type=0x%x flags=0x%x)", name, pparent, debugStart, debugEnd, proclen, offset, typeIndex, + flags); } } -/* + + /*- public static final class CVSymbolGProc32IDRecord extends CVSymbolGProc32Record { CVSymbolGProc32IDRecord(CVDebugInfo cvDebugInfo, String name, int pparent, int pend, int pnext, int proclen, int debugStart, int debugEnd, int typeIndex, int offset, short segment, byte flags) { super(cvDebugInfo, CVDebugConstants.S_GPROC32_ID, name, pparent, pend, pnext, proclen, debugStart, debugEnd, typeIndex, offset, segment, flags); } - /* this is almost certainly bad; only for debugging * + /* this is almost certainly bad (not enough information); use only for debugging * CVSymbolGProc32IDRecord(CVDebugInfo cvDebugInfo, String name, int offset, int proclen) { super(cvDebugInfo, CVDebugConstants.S_GPROC32_ID, name, 0, 0, 0, proclen, 0, 0, 0, offset, (short)0, (byte)0); } @@ -354,7 +362,8 @@ public String toString() { return String.format("S_GPROC32_ID(name=%s parent=%d startaddr=0x%x end=0x%x len=0x%x offset=0x%x type=0x%x flags=0x%x)", name, pparent, debugStart, debugEnd, proclen, offset, typeIndex, flags); } } -*/ + */ + public static final class CVSymbolFrameProcRecord extends CVSymbolSubrecord { int framelen; @@ -429,7 +438,8 @@ public String toString() { return "S_END"; } } -/* + + /*- public static final class CVSymbolRegRel32Record extends CVSymbolSubrecord { int typeIndex; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java index f93e68deb400..7bdaa9e54ff7 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubsection.java @@ -46,7 +46,8 @@ void addRecord(CVSymbolSubrecord subcmd) { subcmds.add(subcmd); } - void addSubrecords() { } + void addSubrecords() { + } @Override protected int computeSize(int initialPos) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java index dacdb0e289f7..a0b5159abffa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeConstants.java @@ -29,43 +29,43 @@ abstract class CVTypeConstants { /* type table */ - static final short T_NOTYPE = 0x0000; - static final short T_VOID = 0x0003; - //static final short T_CHAR = 0x0010; /* 8 bit signed (java type) */ - //static final short T_WCHAR = 0x0071; - //static final short T_CHAR16 = 0x007a; /* 16 bit unicode (Java type) */ - //static final short T_SHORT = 0x0011; /* 16 bit signed short (Java type) */ - //static final short T_LONG = 0x0014; /* 32 bit signed (java type? maybe T_short4?) */ - static final short T_QUAD = 0x0013; /* 64 bit signed long long (Java type) */ - //static final short T_REAL32 = 0x0040; /* 32 bit float (Java type) */ - //static final short T_REAL64 = 0x0041; /* 64 but double (Java type) */ - //static final short T_RCHAR = 0x0070; /* ?? "really a char" */ + static final short T_NOTYPE = 0x0000; + static final short T_VOID = 0x0003; + // static final short T_CHAR = 0x0010; /* 8 bit signed (java type) */ + // static final short T_WCHAR = 0x0071; + // static final short T_CHAR16 = 0x007a; /* 16 bit unicode (Java type) */ + // static final short T_SHORT = 0x0011; /* 16 bit signed short (Java type) */ + // static final short T_LONG = 0x0014; /* 32 bit signed (java type? maybe T_short4?) */ + static final short T_QUAD = 0x0013; /* 64 bit signed long long (Java type) */ + // static final short T_REAL32 = 0x0040; /* 32 bit float (Java type) */ + // static final short T_REAL64 = 0x0041; /* 64 but double (Java type) */ + // static final short T_RCHAR = 0x0070; /* ?? "really a char" */ - //static final short T_INT4 = T_LONG; /* ?? is tis right */ - static final short T_UQUAD = T_QUAD; /* ?? */ + // static final short T_INT4 = T_LONG; /* ?? is tis right */ + static final short T_UQUAD = T_QUAD; /* ?? */ - //static final short T_POINTER_BITS = 0x0700; - //static final short T_POINTER32 = 0x0400; /* 32 bit pointer */ - //static final short T_POINTER64 = 0x0600; /* 64 bit pointer */ + // static final short T_POINTER_BITS = 0x0700; + // static final short T_POINTER32 = 0x0400; /* 32 bit pointer */ + // static final short T_POINTER64 = 0x0600; /* 64 bit pointer */ - static final short LF_MODIFIER = 0x1001; - static final short LF_POINTER = 0x1002; - static final short LF_PROCEDURE = 0x1008; - static final short LF_ARGLIST = 0x1201; - //static final short LF_FIELDLIST = 0x1203; - static final short LF_BITFIELD = 0x1205; - static final short LF_BCLASS = 0x1400; - static final short LF_ARRAY = 0x1503; - static final short LF_CLASS = 0x1504; - static final short LF_STRUCTURE = 0x1505; - //static final short LF_UNION = 0x1506; - //static final short LF_ENUM = 0x1507; - static final short LF_MEMBER = 0x150d; + static final short LF_MODIFIER = 0x1001; + static final short LF_POINTER = 0x1002; + static final short LF_PROCEDURE = 0x1008; + static final short LF_ARGLIST = 0x1201; + // static final short LF_FIELDLIST = 0x1203; + static final short LF_BITFIELD = 0x1205; + static final short LF_BCLASS = 0x1400; + static final short LF_ARRAY = 0x1503; + static final short LF_CLASS = 0x1504; + static final short LF_STRUCTURE = 0x1505; + // static final short LF_UNION = 0x1506; + // static final short LF_ENUM = 0x1507; + static final short LF_MEMBER = 0x150d; static final short LF_TYPESERVER2 = 0x1515; - static final short LF_INTERFACE = 0x1519; - static final short LF_BINTERFACE = 0x151a; + static final short LF_INTERFACE = 0x1519; + static final short LF_BINTERFACE = 0x151a; -/* + /*- static final short LF_CHAR = (short) 0x8000; static final short LF_SHORT = (short) 0x8001; static final short LF_USHORT = (short) 0x8002; @@ -77,13 +77,14 @@ abstract class CVTypeConstants { static final short LF_UQUADWORD = (short) 0x800a; static final short LF_OCTWORD = (short) 0x8017; static final short LF_UOCTWORD = (short) 0x8018; -*/ + */ - //static final byte LF_PAD0 = (byte) 0xf0; - static final byte LF_PAD1 = (byte) 0xf1; - static final byte LF_PAD2 = (byte) 0xf2; - static final byte LF_PAD3 = (byte) 0xf3; - /*static final byte LF_PAD4 = (byte) 0xf4; + // static final byte LF_PAD0 = (byte) 0xf0; + static final byte LF_PAD1 = (byte) 0xf1; + static final byte LF_PAD2 = (byte) 0xf2; + static final byte LF_PAD3 = (byte) 0xf3; + /*- + static final byte LF_PAD4 = (byte) 0xf4; static final byte LF_PAD5 = (byte) 0xf5; static final byte LF_PAD6 = (byte) 0xf6; static final byte LF_PAD7 = (byte) 0xf7; @@ -94,5 +95,6 @@ abstract class CVTypeConstants { static final byte LF_PAD12 = (byte) 0xfc; static final byte LF_PAD13 = (byte) 0xfd; static final byte LF_PAD14 = (byte) 0xfe; - static final byte LF_PAD15 = (byte) 0xff;*/ + static final byte LF_PAD15 = (byte) 0xff; + */ } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java index fc9162797007..19a2d30ef81b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecord.java @@ -83,7 +83,7 @@ int computeFullSize(int initialPos) { } int computeFullContents(byte[] buffer, int initialPos) { - int lenPos = initialPos; /* save position of length short */ + int lenPos = initialPos; /* save position of length short */ int pos = initialPos + Short.BYTES; /* save room for length short */ pos = CVUtil.putShort(type, buffer, pos); pos = computeContents(buffer, pos); @@ -95,6 +95,7 @@ int computeFullContents(byte[] buffer, int initialPos) { } protected abstract int computeSize(int initialPos); + protected abstract int computeContents(byte[] buffer, int initialPos); @Override @@ -110,7 +111,7 @@ private static int alignPadded4(byte[] buffer, int originalpos) { int pos = originalpos; int align = pos & 3; if (align == 1) { - byte[] p3 = {LF_PAD3, LF_PAD2, LF_PAD1 }; + byte[] p3 = {LF_PAD3, LF_PAD2, LF_PAD1}; pos = CVUtil.putBytes(p3, buffer, pos); } else if (align == 2) { pos = CVUtil.putByte(LF_PAD2, buffer, pos); @@ -156,6 +157,7 @@ CVTypeModifierRecord addUnaligned() { private short computeFlags() { return (short) ((addConst ? 0x01 : 0x00) | (addVolatile ? 0x02 : 0x00) | (addUnaligned ? 0x04 : 0)); } + @Override public int computeSize(int initialPos) { return initialPos + Integer.BYTES + Short.BYTES; @@ -201,7 +203,8 @@ static final class CVTypePointerRecord extends CVTypeRecord { int modifiers = 0; int size = 4; int flags = 0; -/* + + /*- int kind = attributes & 0x00001f; int mode = (attributes & 0x0000e0) >> 5; int modifiers = (attributes & 0x001f00) >> 8; @@ -209,7 +212,8 @@ static final class CVTypePointerRecord extends CVTypeRecord { int flags = (attributes & 0x380000) >> 19; out.printf("LF_POINTER len=%d leaf=0x%04x refType=0x%06x attrib=0x%06x\n", len, leaf, referentType, attributes); out.printf(" kind=%d mode=%d modifiers=%d size=%d flags=%d\n", kind, mode, modifiers, size, flags); -*/ + */ + CVTypePointerRecord(int originalLeaf) { super(LF_POINTER); this.originalLeaf = originalLeaf; @@ -363,8 +367,8 @@ public int hashCode() { static final class CVMemberRecord extends CVTypeRecord { - short propertyAttributes; /* property attribute field (prop_t) */ - int fieldIndex; /* type index of member type */ + short propertyAttributes; /* property attribute field (prop_t) */ + int fieldIndex; /* type index of member type */ /* TODO data */ CVMemberRecord(short attrs, int fieldIndex) { @@ -402,8 +406,8 @@ public int hashCode() { static class CVBaseClassRecord extends CVTypeRecord { - short propertyAttributes; /* property attribute field (prop_t) */ - int fieldIndex; /* type index of member type */ + short propertyAttributes; /* property attribute field (prop_t) */ + int fieldIndex; /* type index of member type */ /* TODO data */ CVBaseClassRecord(short ltype, short attrs, int fieldIndex) { @@ -462,11 +466,11 @@ public String toString() { static class CVClassRecord extends CVTypeRecord { - short count; /* count of number of elements in class */ - short propertyAttributes; /* property attribute field (prop_t) */ - int fieldIndex; /* type index of LF_FIELDLIST descriptor list */ - int derivedFromIndex; /* type index of derived from list if not zero */ - int vshapeIndex; /* type index of vshape table for this class */ + short count; /* count of number of elements in class */ + short propertyAttributes; /* property attribute field (prop_t) */ + int fieldIndex; /* type index of LF_FIELDLIST descriptor list */ + int derivedFromIndex; /* type index of derived from list if not zero */ + int vshapeIndex; /* type index of vshape table for this class */ /* TODO data */ CVClassRecord(short recType, short count, short attrs, int fieldIndex, int derivedFromIndex, int vshapeIndex) { @@ -484,7 +488,8 @@ static class CVClassRecord extends CVTypeRecord { @Override public int computeSize(int initialPos) { - return initialPos + Short.BYTES + Short.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES; // + TODO + return initialPos + Short.BYTES + Short.BYTES + Integer.BYTES + Integer.BYTES + Integer.BYTES; // + + // TODO } @Override @@ -499,7 +504,8 @@ public int computeContents(byte[] buffer, int initialPos) { } protected String toString(String lfTypeStr) { - return String.format("%s(0x%04x count=%d attr=0x%04x fld=0x%x super=0x%x vshape=0x%x)", lfTypeStr, getSequenceNumber(), count, propertyAttributes, fieldIndex, derivedFromIndex, vshapeIndex); + return String.format("%s(0x%04x count=%d attr=0x%04x fld=0x%x super=0x%x vshape=0x%x)", lfTypeStr, getSequenceNumber(), count, propertyAttributes, fieldIndex, derivedFromIndex, + vshapeIndex); } @Override @@ -650,12 +656,13 @@ static final class CVTypeServer2Record extends CVTypeRecord { this.age = age; this.fileName = fileName; - /* for some very odd reason GUID is stored like this: + /*- + for some very odd reason GUID is stored like this: int guid1 = in.getInt(); int guid2 = in.getShort(); int guid3 = in.getShort(); byte[] guid5[10] - */ + */ swap(this.guid, 0, 3); swap(this.guid, 1, 2); swap(this.guid, 4, 5); diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java index 2a376502495c..9244c11c0cf8 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeRecordBuilder.java @@ -40,9 +40,13 @@ class CVTypeRecordBuilder { } /* - * convenience method - return either the caller-created instance or a matching existing instance. + * convenience method - return either the caller-created instance or a matching existing + * instance. + */ + /* + * we know every entry in typeMap is a T, because it is ONLY this function which inserts entries + * (of type T) */ - /* we know every entry in typeMap is a T, because it is ONLY this function which inserts entries (of type T) */ @SuppressWarnings("unchecked") T buildFrom(T newRecord) { final T record; diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java index 4e183761d6be..c811b374d3bf 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVTypeSectionImpl.java @@ -92,20 +92,22 @@ void addUniqueRecord(CVTypeRecord r) { } T addRecord(T newRecord) { - //CVUtil.debug("adding type record: %s hash=%d\n", newRecord, newRecord.hashCode()); + // CVUtil.debug("adding type record: %s hash=%d\n", newRecord, newRecord.hashCode()); T actual = builder.buildFrom(newRecord); return actual; } private void addClassRecords() { /* we may have done this already when emiting globals in debug$S section */ - //for (DebugInfoBase.ClassEntry classEntry : cvDebugInfo.getPrimaryClasses()) { - // TODO - emit all members, all types, etc - //} + // for (DebugInfoBase.ClassEntry classEntry : cvDebugInfo.getPrimaryClasses()) { + // TODO - emit all members, all types, etc + // } } private void addRecords() { - //final CVTypeRecord r0 = addRecord(new CVTypeRecord.CVTypeServer2Record("0123456789abcdef".getBytes(UTF_8), 1, "c:\\tmp\\graal-8\\vc100.pdb")); + // final CVTypeRecord r0 = addRecord(new + // CVTypeRecord.CVTypeServer2Record("0123456789abcdef".getBytes(UTF_8), 1, + // "c:\\tmp\\graal-8\\vc100.pdb")); addClassRecords(); } @@ -117,8 +119,8 @@ private static int computeHeaderSize() { public Set getDependencies(Map decisions) { Set deps = super.getDependencies(decisions); PECoffObjectFile.PECoffSection targetSection = (PECoffObjectFile.PECoffSection) getElement().getOwner().elementForName(CV_SYMBOL_SECTION_NAME); - LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); - LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); + LayoutDecision ourContent = decisions.get(getElement()).getDecision(LayoutDecision.Kind.CONTENT); + LayoutDecision ourSize = decisions.get(getElement()).getDecision(LayoutDecision.Kind.SIZE); /* make our content depend on the codeview symbol section */ deps.add(BuildDependency.createOrGet(ourContent, decisions.get(targetSection).getDecision(LayoutDecision.Kind.CONTENT))); /* make our size depend on our content */ diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java index f5e322ab50f4..49266b354e16 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVUtil.java @@ -125,7 +125,7 @@ static short getShort(byte[] buffer, int initialPos) { return i; } - /* + /*- static void dump(String msg, byte[] buffer, int initialPos, int len) { if (buffer == null) { return; @@ -144,10 +144,12 @@ static void dump(byte[] buffer, int len) { for (int i = 0; i < len; i++) { System.out.format("%02x", buffer[i]); } - }*/ + } + */ /** * align on 4 byte boundary. + * * @param initialPos initial unaligned position * @return pos aligned on 4 byte boundary */ From 8f1ffd657ba8420636d1f6824a7f48363d77453b Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 14 Apr 2020 09:27:51 -0400 Subject: [PATCH 121/130] fix syntax error from merge --- .../com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 40e21efed4b2..a4396acaa838 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -205,7 +205,7 @@ private static boolean unused_wantNewRange(@SuppressWarnings("unused") Range ran debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previousRange.getLine() != range.getLine()) + " fndiffer:" + (previousRange.getFilePath() != range.getFilePath()) + " contig:" + (previousRange.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); } - }* + } if (previousRange == null) return true; if (previousRange.getLine() != range.getLine()) From c5c82d9dba93184308865c8f98e18cab2056b334 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 14 Apr 2020 09:38:43 -0400 Subject: [PATCH 122/130] fix syntax error from merge --- .../com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java | 2 +- .../src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index a4396acaa838..4fc841e1c63f 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -196,7 +196,7 @@ private static boolean wantNewRange(@SuppressWarnings("unused") Range range, @Su * @param range current range * @return true if the current range is on a different line or file from the previous one */ - @SupressWarnings("unused") + @SuppressWarnings("unused") private static boolean unused_wantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { if (debug) { if (previousRange == null) { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java index df4d0bb54cf4..98368acb6e29 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVRootPackages.java @@ -209,7 +209,7 @@ static boolean isJavaPackage(String pn) { return pn.startsWith("java.") || pn.startsWith("javax.") || pn.startsWith("sun."); } - @SupressWarnings("unused") + @SuppressWarnings("unused") private static boolean isJavaFile(String pn) { /* TODO : make more accurate */ return pn.startsWith("java/") || pn.startsWith("javax/") || pn.startsWith("sun/"); From 77291945815d3543f91770867e24bbeb2a7293d0 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 14 Apr 2020 09:41:22 -0400 Subject: [PATCH 123/130] remove unused logging code --- .../oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 4fc841e1c63f..1fbc9a6553fa 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -198,14 +198,6 @@ private static boolean wantNewRange(@SuppressWarnings("unused") Range range, @Su */ @SuppressWarnings("unused") private static boolean unused_wantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { - if (debug) { - if (previousRange == null) { - debug("wantNewRange() prevnull:true"); - } else { - debug("wantNewRange() prevnull:false" + " linesdiffer:" + (previousRange.getLine() != range.getLine()) - + " fndiffer:" + (previousRange.getFilePath() != range.getFilePath()) + " contig:" + (previousRange.getHi() < range.getLo()) + " delta:" + (range.getHi() - previousRange.getLo())); - } - } if (previousRange == null) return true; if (previousRange.getLine() != range.getLine()) From 971f396d1dde9b3dc75d198f8fbe1fbd1e415730 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 14 Apr 2020 11:24:06 -0400 Subject: [PATCH 124/130] latest travis fixes --- .../oracle/objectfile/pecoff/cv/CVConstants.java | 15 +++++++-------- .../objectfile/pecoff/cv/CVDebugConstants.java | 2 +- .../objectfile/pecoff/cv/CVLineRecordBuilder.java | 2 +- .../pecoff/cv/CVSymbolRecordBuilder.java | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java index 23ac27af784c..5e1cd4d571a5 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVConstants.java @@ -76,14 +76,13 @@ public abstract class CVConstants { static final boolean skipJDKInternals = false; /* - * if true, Graal inlined code treated as user generated code. - * (less complicated for user-level debugging) + * if true, Graal inlined code treated as user generated code. (less complicated for user-level + * debugging) */ static final boolean skipGraalIntrinsics = false; /* - * if a line record is the same line in the same file as the previous record, - * merge them. + * if a line record is the same line in the same file as the previous record, merge them. */ static final boolean mergeAdjacentLineRecords = true; @@ -93,8 +92,8 @@ public abstract class CVConstants { static final boolean emitUnadornedMain = true; /* - * if true, first main() becomes this name (with no class name or arg list at all) (set null - * to disable). + * if true, first main() becomes this name (with no class name or arg list at all) (set null to + * disable). */ static final String replaceMainFunctionName = null; @@ -104,8 +103,8 @@ public abstract class CVConstants { * "Foo.function(String[] args)" becomes "Foo.function_617849326". If functionNamesHashArgs is * false, currently the linker will fail. * - * if true, arg lists become obscure integers (and link.exe will work properly) - * TODO: strip illegal characters from arg lists instead + * if true, arg lists become obscure integers (and link.exe will work properly) TODO: strip + * illegal characters from arg lists instead */ static final boolean functionNamesHashArgs = true; } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java index 7b2b8a555c80..ebf3f51a49ec 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVDebugConstants.java @@ -94,7 +94,7 @@ enum DEBUG_S { final short cmd; DEBUG_S(int cmd) { - this.cmd = (short)cmd; + this.cmd = (short) cmd; } public short command() { diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index 1fbc9a6553fa..a98e2f27f7dd 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -206,7 +206,7 @@ private static boolean unused_wantNewRange(@SuppressWarnings("unused") Range ran return true; /* it might actually be fine to merge if there's a gap between ranges */ // if (previousRange.getHi() < range.getLo()) - // return true; + // return true; return false; } } diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 2beeb7ddbaa8..20992697760a 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -81,8 +81,8 @@ private void build(ClassEntry classEntry) { } /** - * emit records for each function: PROC32 S_FRAMEPROC S_END and line number records. - * (later: type records as required) + * emit records for each function: PROC32 S_FRAMEPROC S_END and line number records. (later: + * type records as required) * * @param primaryEntry primary entry for this function * @param methodName method name alias as it will be seen by the user From ea3d68dc8ae65af55c730d755e554860aa02ebf0 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Tue, 14 Apr 2020 12:16:35 -0400 Subject: [PATCH 125/130] latest travice checkstyle fixes --- .../objectfile/pecoff/cv/CVLineRecordBuilder.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java index a98e2f27f7dd..c9b3b40c9abc 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVLineRecordBuilder.java @@ -197,16 +197,20 @@ private static boolean wantNewRange(@SuppressWarnings("unused") Range range, @Su * @return true if the current range is on a different line or file from the previous one */ @SuppressWarnings("unused") - private static boolean unused_wantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { - if (previousRange == null) + private static boolean unusedWantNewRange(@SuppressWarnings("unused") Range range, @SuppressWarnings("unused") Range previousRange) { + if (previousRange == null) { return true; - if (previousRange.getLine() != range.getLine()) + } + if (previousRange.getLine() != range.getLine()) { return true; - if (previousRange.getFilePath() != range.getFilePath()) + } + if (previousRange.getFilePath() != range.getFilePath()) { return true; + } /* it might actually be fine to merge if there's a gap between ranges */ - // if (previousRange.getHi() < range.getLo()) + // if (previousRange.getHi() < range.getLo()) { // return true; + // } return false; } } From 4406cf4b2913fa9dbcdc68d2f7071e35a17f4006 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Thu, 16 Apr 2020 09:21:10 -0400 Subject: [PATCH 126/130] fix issue while linking with windows debug info on --- .../com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java index a3092937e412..3d958a2627a4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/sources/GraalVMSourceCache.java @@ -128,7 +128,7 @@ private static boolean filterSrcRoot(Path root) { /* if any of the graal paths exist accept this root */ for (String prefix : GRAALVM_SRC_PACKAGE_PREFIXES) { - String subDir = prefix.replaceAll("\\.", separator); + String subDir = prefix.replace(".", separator); if (Files.isDirectory(root.resolve(subDir))) { return true; } From acb9292c4658a6c5aa5451d623290dec286c59c5 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 17 Apr 2020 14:54:08 -0400 Subject: [PATCH 127/130] fix comment alignment --- .../objectfile/pecoff/cv/CVSymbolSubrecord.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java index d829c2737c74..3d10a0ef3f6e 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolSubrecord.java @@ -190,15 +190,14 @@ public static final class CVEnvBlockRecord extends CVSymbolSubrecord { private Map map = new HashMap<>(ENVMAP_INITIAL_CAPACITY); - /* - * Example: cwd = C:\tmp\graal-8 cl = - * C:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\Bin\x86_amd64\cl.exe cmd = -Zi -MT - * -IC:\tmp\graal-8\tools\toolchain\vs2010e\VC\INCLUDE - * -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE - * -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE\gl -TC -X src = helloworld.c pdb = - * C:\tmp\graal-8\vc100.pdb + /*- + * Example contents of the environment block: + * cwd = C:\tmp\graal-8 + * cl = C:\tmp\graal-8\ojdkbuild\tools\toolchain\vs2010e\VC\Bin\x86_amd64\cl.exe + * cmd = -Zi -MT -IC:\tmp\graal-8\tools\toolchain\vs2010e\VC\INCLUDE -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE -IC:\tmp\graal-8\tools\toolchain\sdk71\INCLUDE\gl -TC -X + * src = helloworld.c + * pdb = C:\tmp\graal-8\vc100.pdb */ - CVEnvBlockRecord(CVDebugInfo cvDebugInfo) { super(cvDebugInfo, CVDebugConstants.S_ENVBLOCK); From 145f9733461ddc2a4bb1be3f60a43d44e7b830e0 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 17 Apr 2020 14:55:01 -0400 Subject: [PATCH 128/130] correctly assign base pointer flags to SP --- .../objectfile/pecoff/cv/CVSymbolRecordBuilder.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 20992697760a..558b60cc5956 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -91,14 +91,25 @@ private void build(PrimaryEntry primaryEntry, String methodName) { final Range primaryRange = primaryEntry.getPrimary(); // debug("addfunc(" + methodName + ") numtypes = %d\n", // cvDebugInfo.getCVTypeSection().getRecords().size()); + + /* S_PROC32 add function definition */ int functionTypeIndex = addTypeRecords(primaryEntry); byte funcFlags = 0; CVSymbolSubrecord.CVSymbolGProc32Record proc32 = new CVSymbolSubrecord.CVSymbolGProc32Record(cvDebugInfo, methodName, 0, 0, 0, primaryRange.getHi() - primaryRange.getLo(), 0, 0, functionTypeIndex, primaryRange.getLo(), (short) 0, funcFlags); addToSymbolRecord(proc32); - int frameFlags = 0; /* LLVM uses 0x14000; */ + + /* S_FRAMEPROC add frame definitions */ + int asynceh = 1 << 9; /* aync eh (msc uses 1, clang uses 0) */ + int localBP = 1 << 14; /* local base pointer = SP (0=none, 1=sp, 2=bp 3=r13) */ + int paramBP = 1 << 16; /* param base pointer = SP */ + int frameFlags = asynceh + localBP + paramBP; /* LLVM uses 0x14000; */ addToSymbolRecord(new CVSymbolSubrecord.CVSymbolFrameProcRecord(cvDebugInfo, primaryRange.getHi() - primaryRange.getLo(), frameFlags)); + /* TODO: add local variables, and their types */ + /* TODO: add block definitions */ + + /* S_END add end record */ addToSymbolRecord(new CVSymbolSubrecord.CVSymbolEndRecord(cvDebugInfo)); addLineNumberRecords(primaryEntry, methodName); } From 489345fd23081b3263689adaa4f99573e343020b Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 17 Apr 2020 15:57:14 -0400 Subject: [PATCH 129/130] make travis happy again --- .../com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 558b60cc5956..26f3d422d1a0 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -100,7 +100,7 @@ private void build(PrimaryEntry primaryEntry, String methodName) { addToSymbolRecord(proc32); /* S_FRAMEPROC add frame definitions */ - int asynceh = 1 << 9; /* aync eh (msc uses 1, clang uses 0) */ + int asynceh = 1 << 9; /* aync eh (msc uses 1, clang uses 0) */ int localBP = 1 << 14; /* local base pointer = SP (0=none, 1=sp, 2=bp 3=r13) */ int paramBP = 1 << 16; /* param base pointer = SP */ int frameFlags = asynceh + localBP + paramBP; /* LLVM uses 0x14000; */ From 84ff0abe9b1c383bfa344929d1c0cc56c3aba472 Mon Sep 17 00:00:00 2001 From: Simon Tooke Date: Fri, 17 Apr 2020 16:26:24 -0400 Subject: [PATCH 130/130] make travis really happy again --- .../com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java index 26f3d422d1a0..955a2d9fb59b 100644 --- a/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java +++ b/substratevm/src/com.oracle.objectfile/src/com/oracle/objectfile/pecoff/cv/CVSymbolRecordBuilder.java @@ -100,7 +100,7 @@ private void build(PrimaryEntry primaryEntry, String methodName) { addToSymbolRecord(proc32); /* S_FRAMEPROC add frame definitions */ - int asynceh = 1 << 9; /* aync eh (msc uses 1, clang uses 0) */ + int asynceh = 1 << 9; /* aync eh (msc uses 1, clang uses 0) */ int localBP = 1 << 14; /* local base pointer = SP (0=none, 1=sp, 2=bp 3=r13) */ int paramBP = 1 << 16; /* param base pointer = SP */ int frameFlags = asynceh + localBP + paramBP; /* LLVM uses 0x14000; */