diff options
Diffstat (limited to 'src/common/dwarf/dwarf2reader.h')
-rw-r--r-- | src/common/dwarf/dwarf2reader.h | 603 |
1 files changed, 442 insertions, 161 deletions
diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 8824bf90..0b194c17 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -40,39 +40,44 @@ #ifndef COMMON_DWARF_DWARF2READER_H__ #define COMMON_DWARF_DWARF2READER_H__ +#include <stdint.h> + #include <list> #include <map> #include <string> #include <utility> #include <vector> +#include <memory> #include "common/dwarf/bytereader.h" #include "common/dwarf/dwarf2enums.h" #include "common/dwarf/types.h" #include "common/using_std_string.h" +#include "common/dwarf/elf_reader.h" namespace dwarf2reader { struct LineStateMachine; class Dwarf2Handler; class LineInfoHandler; +class DwpReader; // This maps from a string naming a section to a pair containing a // the data for the section, and the size of the section. -typedef std::map<string, std::pair<const char*, uint64> > SectionMap; +typedef std::map<string, std::pair<const uint8_t *, uint64_t> > SectionMap; typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> > AttributeList; typedef AttributeList::iterator AttributeIterator; typedef AttributeList::const_iterator ConstAttributeIterator; struct LineInfoHeader { - uint64 total_length; - uint16 version; - uint64 prologue_length; - uint8 min_insn_length; // insn stands for instructin + uint64_t total_length; + uint16_t version; + uint64_t prologue_length; + uint8_t min_insn_length; // insn stands for instructin bool default_is_stmt; // stmt stands for statement - int8 line_base; - uint8 line_range; - uint8 opcode_base; + int8_t line_base; + uint8_t line_range; + uint8_t opcode_base; // Use a pointer so that signalsafe_addr2line is able to use this structure // without heap allocation problem. std::vector<unsigned char> *std_opcode_lengths; @@ -85,7 +90,7 @@ class LineInfo { // to the beginning and length of the line information to read. // Reader is a ByteReader class that has the endianness set // properly. - LineInfo(const char* buffer_, uint64 buffer_length, + LineInfo(const uint8_t *buffer_, uint64_t buffer_length, ByteReader* reader, LineInfoHandler* handler); virtual ~LineInfo() { @@ -97,7 +102,7 @@ class LineInfo { // Start processing line info, and calling callbacks in the handler. // Consumes the line number information for a single compilation unit. // Returns the number of bytes processed. - uint64 Start(); + uint64_t Start(); // Process a single line info opcode at START using the state // machine at LSM. Return true if we should define a line using the @@ -111,7 +116,7 @@ class LineInfo { static bool ProcessOneOpcode(ByteReader* reader, LineInfoHandler* handler, const struct LineInfoHeader &header, - const char* start, + const uint8_t *start, struct LineStateMachine* lsm, size_t* len, uintptr pc, @@ -139,9 +144,11 @@ class LineInfo { // buffer is the buffer for our line info, starting at exactly where // the line info to read is. after_header is the place right after // the end of the line information header. - const char* buffer_; - uint64 buffer_length_; - const char* after_header_; + const uint8_t *buffer_; +#ifndef NDEBUG + uint64_t buffer_length_; +#endif + const uint8_t *after_header_; }; // This class is the main interface between the line info reader and @@ -157,7 +164,7 @@ class LineInfoHandler { // Called when we define a directory. NAME is the directory name, // DIR_NUM is the directory number - virtual void DefineDir(const string& name, uint32 dir_num) { } + virtual void DefineDir(const string& name, uint32_t dir_num) { } // Called when we define a filename. NAME is the filename, FILE_NUM // is the file number which is -1 if the file index is the next @@ -166,9 +173,9 @@ class LineInfoHandler { // directory index for the directory name of this file, MOD_TIME is // the modification time of the file, and LENGTH is the length of // the file - virtual void DefineFile(const string& name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 length) { } + virtual void DefineFile(const string& name, int32_t file_num, + uint32_t dir_num, uint64_t mod_time, + uint64_t length) { } // Called when the line info reader has a new line, address pair // ready for us. ADDRESS is the address of the code, LENGTH is the @@ -176,8 +183,138 @@ class LineInfoHandler { // containing the code, LINE_NUM is the line number in that file for // the code, and COLUMN_NUM is the column number the code starts at, // if we know it (0 otherwise). - virtual void AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 column_num) { } + virtual void AddLine(uint64_t address, uint64_t length, + uint32_t file_num, uint32_t line_num, uint32_t column_num) { } +}; + +class RangeListHandler { + public: + RangeListHandler() { } + + virtual ~RangeListHandler() { } + + // Add a range. + virtual void AddRange(uint64_t begin, uint64_t end) { }; + + // A new base address must be set for computing the ranges' addresses. + virtual void SetBaseAddress(uint64_t base_address) { }; + + // Finish processing the range list. + virtual void Finish() { }; +}; + +class RangeListReader { + public: + RangeListReader(const uint8_t *buffer, uint64_t size, ByteReader *reader, + RangeListHandler *handler); + + bool ReadRangeList(uint64_t offset); + + private: + const uint8_t *buffer_; + uint64_t size_; + ByteReader* reader_; + RangeListHandler *handler_; +}; + +// This class is the main interface between the reader and the +// client. The virtual functions inside this get called for +// interesting events that happen during DWARF2 reading. +// The default implementation skips everything. +class Dwarf2Handler { + public: + Dwarf2Handler() { } + + virtual ~Dwarf2Handler() { } + + // Start to process a compilation unit at OFFSET from the beginning of the + // .debug_info section. Return false if you would like to skip this + // compilation unit. + virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size, + uint8_t offset_size, uint64_t cu_length, + uint8_t dwarf_version) { return false; } + + // When processing a skeleton compilation unit, resulting from a split + // DWARF compilation, once the skeleton debug info has been read, + // the reader will call this function to ask the client if it needs + // the full debug info from the .dwo or .dwp file. Return true if + // you need it, or false to skip processing the split debug info. + virtual bool NeedSplitDebugInfo() { return true; } + + // Start to process a split compilation unit at OFFSET from the beginning of + // the debug_info section in the .dwp/.dwo file. Return false if you would + // like to skip this compilation unit. + virtual bool StartSplitCompilationUnit(uint64_t offset, + uint64_t cu_length) { return false; } + + // Start to process a DIE at OFFSET from the beginning of the .debug_info + // section. Return false if you would like to skip this DIE. + virtual bool StartDIE(uint64_t offset, enum DwarfTag tag) { return false; } + + // Called when we have an attribute with unsigned data to give to our + // handler. The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, and its value is + // DATA. + virtual void ProcessAttributeUnsigned(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t data) { } + + // Called when we have an attribute with signed data to give to our handler. + // The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, and its value is + // DATA. + virtual void ProcessAttributeSigned(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64_t data) { } + + // Called when we have an attribute whose value is a reference to + // another DIE. The attribute belongs to the DIE at OFFSET from the + // beginning of the .debug_info section. Its name is ATTR, its form + // is FORM, and the offset of the DIE being referred to from the + // beginning of the .debug_info section is DATA. + virtual void ProcessAttributeReference(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t data) { } + + // Called when we have an attribute with a buffer of data to give to our + // handler. The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, DATA points to + // the buffer's contents, and its length in bytes is LENGTH. The buffer is + // owned by the caller, not the callee, and may not persist for very long. + // If you want the data to be available later, it needs to be copied. + virtual void ProcessAttributeBuffer(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t *data, + uint64_t len) { } + + // Called when we have an attribute with string data to give to our handler. + // The attribute is for the DIE at OFFSET from the beginning of the + // .debug_info section. Its name is ATTR, its form is FORM, and its value is + // DATA. + virtual void ProcessAttributeString(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const string& data) { } + + // Called when we have an attribute whose value is the 64-bit signature + // of a type unit in the .debug_types section. OFFSET is the offset of + // the DIE whose attribute we're reporting. ATTR and FORM are the + // attribute's name and form. SIGNATURE is the type unit's signature. + virtual void ProcessAttributeSignature(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t signature) { } + + // Called when finished processing the DIE at OFFSET. + // Because DWARF2/3 specifies a tree of DIEs, you may get starts + // before ends of the previous DIE, as we process children before + // ending the parent. + virtual void EndDIE(uint64_t offset) { } + }; // The base of DWARF2/3 debug info is a DIE (Debugging Information @@ -221,12 +358,21 @@ class CompilationUnit { // Initialize a compilation unit. This requires a map of sections, // the offset of this compilation unit in the .debug_info section, a // ByteReader, and a Dwarf2Handler class to call callbacks in. - CompilationUnit(const SectionMap& sections, uint64 offset, - ByteReader* reader, Dwarf2Handler* handler); + CompilationUnit(const string& path, const SectionMap& sections, + uint64_t offset, ByteReader* reader, Dwarf2Handler* handler); virtual ~CompilationUnit() { if (abbrevs_) delete abbrevs_; } + // Initialize a compilation unit from a .dwo or .dwp file. + // In this case, we need the .debug_addr section from the + // executable file that contains the corresponding skeleton + // compilation unit. We also inherit the Dwarf2Handler from + // the executable file, and call it as if we were still + // processing the original compilation unit. + void SetSplitDwarf(const uint8_t* addr_buffer, uint64_t addr_buffer_length, + uint64_t addr_base, uint64_t ranges_base, uint64_t dwo_id); + // Begin reading a Dwarf2 compilation unit, and calling the // callbacks in the Dwarf2Handler @@ -234,7 +380,7 @@ class CompilationUnit { // headers. This plus the starting offset passed to the constructor // is the offset of the end of the compilation unit --- and the // start of the next compilation unit, if there is one. - uint64 Start(); + uint64_t Start(); private: @@ -242,7 +388,7 @@ class CompilationUnit { // The abbreviation tells how to read a DWARF2/3 DIE, and consist of a // tag and a list of attributes, as well as the data form of each attribute. struct Abbrev { - uint64 number; + uint64_t number; enum DwarfTag tag; bool has_children; AttributeList attributes; @@ -252,10 +398,10 @@ class CompilationUnit { // in the actual file, as the one in the file may have a 32 bit or // 64 bit length. struct CompilationUnitHeader { - uint64 length; - uint16 version; - uint64 abbrev_offset; - uint8 address_size; + uint64_t length; + uint16_t version; + uint64_t abbrev_offset; + uint8_t address_size; } header_; // Reads the DWARF2/3 header for this compilation unit. @@ -266,40 +412,115 @@ class CompilationUnit { // Processes a single DIE for this compilation unit and return a new // pointer just past the end of it - const char* ProcessDIE(uint64 dieoffset, - const char* start, - const Abbrev& abbrev); + const uint8_t *ProcessDIE(uint64_t dieoffset, + const uint8_t *start, + const Abbrev& abbrev); // Processes a single attribute and return a new pointer just past the // end of it - const char* ProcessAttribute(uint64 dieoffset, - const char* start, - enum DwarfAttribute attr, - enum DwarfForm form); + const uint8_t *ProcessAttribute(uint64_t dieoffset, + const uint8_t *start, + enum DwarfAttribute attr, + enum DwarfForm form); + + // Called when we have an attribute with unsigned data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + // If we see a DW_AT_GNU_dwo_id attribute, save the value so that + // we can find the debug info in a .dwo or .dwp file. + void ProcessAttributeUnsigned(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + uint64_t data) { + if (attr == DW_AT_GNU_dwo_id) { + dwo_id_ = data; + } + else if (attr == DW_AT_GNU_addr_base) { + addr_base_ = data; + } + else if (attr == DW_AT_GNU_ranges_base) { + ranges_base_ = data; + } + // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, + // that base will apply to DW_AT_ranges attributes in the + // skeleton CU as well as in the .dwo/.dwp files. + else if (attr == DW_AT_ranges && is_split_dwarf_) { + data += ranges_base_; + } + handler_->ProcessAttributeUnsigned(offset, attr, form, data); + } + + // Called when we have an attribute with signed data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + void ProcessAttributeSigned(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + int64_t data) { + handler_->ProcessAttributeSigned(offset, attr, form, data); + } + + // Called when we have an attribute with a buffer of data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA, and the + // length of the buffer is LENGTH. + void ProcessAttributeBuffer(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const uint8_t* data, + uint64_t len) { + handler_->ProcessAttributeBuffer(offset, attr, form, data, len); + } + + // Called when we have an attribute with string data to give to + // our handler. The attribute is for the DIE at OFFSET from the + // beginning of compilation unit, has a name of ATTR, a form of + // FORM, and the actual data of the attribute is in DATA. + // If we see a DW_AT_GNU_dwo_name attribute, save the value so + // that we can find the debug info in a .dwo or .dwp file. + void ProcessAttributeString(uint64_t offset, + enum DwarfAttribute attr, + enum DwarfForm form, + const char* data) { + if (attr == DW_AT_GNU_dwo_name) + dwo_name_ = data; + handler_->ProcessAttributeString(offset, attr, form, data); + } // Processes all DIEs for this compilation unit void ProcessDIEs(); // Skips the die with attributes specified in ABBREV starting at // START, and return the new place to position the stream to. - const char* SkipDIE(const char* start, - const Abbrev& abbrev); + const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev); // Skips the attribute starting at START, with FORM, and return the // new place to position the stream to. - const char* SkipAttribute(const char* start, - enum DwarfForm form); + const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form); + + // Process the actual debug information in a split DWARF file. + void ProcessSplitDwarf(); + + // Read the debug sections from a .dwo file. + void ReadDebugSectionsFromDwo(ElfReader* elf_reader, + SectionMap* sections); + + // Path of the file containing the debug information. + const string path_; // Offset from section start is the offset of this compilation unit // from the beginning of the .debug_info section. - uint64 offset_from_section_start_; + uint64_t offset_from_section_start_; // buffer is the buffer for our CU, starting at .debug_info + offset // passed in from constructor. // after_header points to right after the compilation unit header. - const char* buffer_; - uint64 buffer_length_; - const char* after_header_; + const uint8_t *buffer_; + uint64_t buffer_length_; + const uint8_t *after_header_; // The associated ByteReader that handles endianness issues for us ByteReader* reader_; @@ -318,96 +539,143 @@ class CompilationUnit { // String section buffer and length, if we have a string section. // This is here to avoid doing a section lookup for strings in // ProcessAttribute, which is in the hot path for DWARF2 reading. - const char* string_buffer_; - uint64 string_buffer_length_; -}; + const uint8_t *string_buffer_; + uint64_t string_buffer_length_; -// This class is the main interface between the reader and the -// client. The virtual functions inside this get called for -// interesting events that happen during DWARF2 reading. -// The default implementation skips everything. + // String offsets section buffer and length, if we have a string offsets + // section (.debug_str_offsets or .debug_str_offsets.dwo). + const uint8_t* str_offsets_buffer_; + uint64_t str_offsets_buffer_length_; -class Dwarf2Handler { + // Address section buffer and length, if we have an address section + // (.debug_addr). + const uint8_t* addr_buffer_; + uint64_t addr_buffer_length_; + + // Flag indicating whether this compilation unit is part of a .dwo + // or .dwp file. If true, we are reading this unit because a + // skeleton compilation unit in an executable file had a + // DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute. + // In a .dwo file, we expect the string offsets section to + // have a ".dwo" suffix, and we will use the ".debug_addr" section + // associated with the skeleton compilation unit. + bool is_split_dwarf_; + + // The value of the DW_AT_GNU_dwo_id attribute, if any. + uint64_t dwo_id_; + + // The value of the DW_AT_GNU_dwo_name attribute, if any. + const char* dwo_name_; + + // If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute + // from the skeleton CU. + uint64_t skeleton_dwo_id_; + + // The value of the DW_AT_GNU_ranges_base attribute, if any. + uint64_t ranges_base_; + + // The value of the DW_AT_GNU_addr_base attribute, if any. + uint64_t addr_base_; + + // True if we have already looked for a .dwp file. + bool have_checked_for_dwp_; + + // Path to the .dwp file. + string dwp_path_; + + // ByteReader for the DWP file. + std::unique_ptr<ByteReader> dwp_byte_reader_; + + // DWP reader. + std::unique_ptr<DwpReader> dwp_reader_; +}; + +// A Reader for a .dwp file. Supports the fetching of DWARF debug +// info for a given dwo_id. +// +// There are two versions of .dwp files. In both versions, the +// .dwp file is an ELF file containing only debug sections. +// In Version 1, the file contains many copies of each debug +// section, one for each .dwo file that is packaged in the .dwp +// file, and the .debug_cu_index section maps from the dwo_id +// to a set of section indexes. In Version 2, the file contains +// one of each debug section, and the .debug_cu_index section +// maps from the dwo_id to a set of offsets and lengths that +// identify each .dwo file's contribution to the larger sections. + +class DwpReader { public: - Dwarf2Handler() { } + DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); - virtual ~Dwarf2Handler() { } + ~DwpReader(); - // Start to process a compilation unit at OFFSET from the beginning of the - // .debug_info section. Return false if you would like to skip this - // compilation unit. - virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version) { return false; } + // Read the CU index and initialize data members. + void Initialize(); - // Start to process a DIE at OFFSET from the beginning of the .debug_info - // section. Return false if you would like to skip this DIE. - virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; } + // Read the debug sections for the given dwo_id. + void ReadDebugSectionsForCU(uint64_t dwo_id, SectionMap* sections); - // Called when we have an attribute with unsigned data to give to our - // handler. The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } + private: + // Search a v1 hash table for "dwo_id". Returns the slot index + // where the dwo_id was found, or -1 if it was not found. + int LookupCU(uint64_t dwo_id); - // Called when we have an attribute with signed data to give to our handler. - // The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { } + // Search a v2 hash table for "dwo_id". Returns the row index + // in the offsets and sizes tables, or 0 if it was not found. + uint32_t LookupCUv2(uint64_t dwo_id); - // Called when we have an attribute whose value is a reference to - // another DIE. The attribute belongs to the DIE at OFFSET from the - // beginning of the .debug_info section. Its name is ATTR, its form - // is FORM, and the offset of the DIE being referred to from the - // beginning of the .debug_info section is DATA. - virtual void ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } + // The ELF reader for the .dwp file. + ElfReader* elf_reader_; - // Called when we have an attribute with a buffer of data to give to our - // handler. The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, DATA points to - // the buffer's contents, and its length in bytes is LENGTH. The buffer is - // owned by the caller, not the callee, and may not persist for very long. - // If you want the data to be available later, it needs to be copied. - virtual void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const char* data, - uint64 len) { } + // The ByteReader for the .dwp file. + const ByteReader& byte_reader_; - // Called when we have an attribute with string data to give to our handler. - // The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { } + // Pointer to the .debug_cu_index section. + const char* cu_index_; - // Called when we have an attribute whose value is the 64-bit signature - // of a type unit in the .debug_types section. OFFSET is the offset of - // the DIE whose attribute we're reporting. ATTR and FORM are the - // attribute's name and form. SIGNATURE is the type unit's signature. - virtual void ProcessAttributeSignature(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature) { } + // Size of the .debug_cu_index section. + size_t cu_index_size_; - // Called when finished processing the DIE at OFFSET. - // Because DWARF2/3 specifies a tree of DIEs, you may get starts - // before ends of the previous DIE, as we process children before - // ending the parent. - virtual void EndDIE(uint64 offset) { } + // Pointer to the .debug_str.dwo section. + const char* string_buffer_; + + // Size of the .debug_str.dwo section. + size_t string_buffer_size_; + + // Version of the .dwp file. We support versions 1 and 2 currently. + int version_; + // Number of columns in the section tables (version 2). + unsigned int ncolumns_; + + // Number of units in the section tables (version 2). + unsigned int nunits_; + + // Number of slots in the hash table. + unsigned int nslots_; + + // Pointer to the beginning of the hash table. + const char* phash_; + + // Pointer to the beginning of the index table. + const char* pindex_; + + // Pointer to the beginning of the section index pool (version 1). + const char* shndx_pool_; + + // Pointer to the beginning of the section offset table (version 2). + const char* offset_table_; + + // Pointer to the beginning of the section size table (version 2). + const char* size_table_; + + // Contents of the sections of interest (version 2). + const char* abbrev_data_; + size_t abbrev_size_; + const char* info_data_; + size_t info_size_; + const char* str_offsets_data_; + size_t str_offsets_size_; }; // This class is a reader for DWARF's Call Frame Information. CFI @@ -637,7 +905,7 @@ class CallFrameInfo { // The mechanics of C++ exception handling, personality routines, // and language-specific data areas are described here, rather nicely: // http://www.codesourcery.com/public/cxx-abi/abi-eh.html - CallFrameInfo(const char *buffer, size_t buffer_length, + CallFrameInfo(const uint8_t *buffer, size_t buffer_length, ByteReader *reader, Handler *handler, Reporter *reporter, bool eh_frame = false) : buffer_(buffer), buffer_length_(buffer_length), @@ -665,7 +933,7 @@ class CallFrameInfo { size_t offset; // The start of this entry in the buffer. - const char *start; + const uint8_t *start; // Which kind of entry this is. // @@ -676,20 +944,20 @@ class CallFrameInfo { // The end of this entry's common prologue (initial length and id), and // the start of this entry's kind-specific fields. - const char *fields; + const uint8_t *fields; // The start of this entry's instructions. - const char *instructions; + const uint8_t *instructions; // The address past the entry's last byte in the buffer. (Note that // since offset points to the entry's initial length field, and the // length field is the number of bytes after that field, this is not // simply buffer_ + offset + length.) - const char *end; + const uint8_t *end; // For both DWARF CFI and .eh_frame sections, this is the CIE id in a // CIE, and the offset of the associated CIE in an FDE. - uint64 id; + uint64_t id; // The CIE that applies to this entry, if we've parsed it. If this is a // CIE, then this field points to this structure. @@ -698,9 +966,9 @@ class CallFrameInfo { // A common information entry (CIE). struct CIE: public Entry { - uint8 version; // CFI data version number + uint8_t version; // CFI data version number string augmentation; // vendor format extension markers - uint64 code_alignment_factor; // scale for code address adjustments + uint64_t code_alignment_factor; // scale for code address adjustments int data_alignment_factor; // scale for stack pointer adjustments unsigned return_address_register; // which register holds the return addr @@ -724,24 +992,29 @@ class CallFrameInfo { // If has_z_personality is true, this is the address of the personality // routine --- or, if personality_encoding & DW_EH_PE_indirect, the // address where the personality routine's address is stored. - uint64 personality_address; + uint64_t personality_address; // This is the encoding used for addresses in the FDE header and // in DW_CFA_set_loc instructions. This is always valid, whether // or not we saw a 'z' augmentation string; its default value is // DW_EH_PE_absptr, which is what normal DWARF CFI uses. DwarfPointerEncoding pointer_encoding; + + // These were only introduced in DWARF4, so will not be set in older + // versions. + uint8_t address_size; + uint8_t segment_size; }; // A frame description entry (FDE). struct FDE: public Entry { - uint64 address; // start address of described code - uint64 size; // size of described code, in bytes + uint64_t address; // start address of described code + uint64_t size; // size of described code, in bytes // If cie->has_z_lsda is true, then this is the language-specific data // area's address --- or its address's address, if cie->lsda_encoding // has the DW_EH_PE_indirect bit set. - uint64 lsda_address; + uint64_t lsda_address; }; // Internal use. @@ -762,7 +1035,7 @@ class CallFrameInfo { // true. On failure, report the problem, and return false. Even if we // return false, set ENTRY->end to the first byte after the entry if we // were able to figure that out, or NULL if we weren't. - bool ReadEntryPrologue(const char *cursor, Entry *entry); + bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry); // Parse the fields of a CIE after the entry prologue, including any 'z' // augmentation data. Assume that the 'Entry' fields of CIE are @@ -790,7 +1063,7 @@ class CallFrameInfo { } // The contents of the DWARF .debug_info section we're parsing. - const char *buffer_; + const uint8_t *buffer_; size_t buffer_length_; // For reading multi-byte values with the appropriate endianness. @@ -832,8 +1105,8 @@ class CallFrameInfo::Handler { // to the handler explicitly; instead, if the handler elects to // process a given FDE, the parser reiterates the appropriate CIE's // contents at the beginning of the FDE's rules. - virtual bool Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, + virtual bool Entry(size_t offset, uint64_t address, uint64_t length, + uint8_t version, const string &augmentation, unsigned return_address) = 0; // When the Entry function returns true, the parser calls these @@ -855,21 +1128,21 @@ class CallFrameInfo::Handler { // computation. All other REG values will be positive. // At ADDRESS, register REG's value is not recoverable. - virtual bool UndefinedRule(uint64 address, int reg) = 0; + virtual bool UndefinedRule(uint64_t address, int reg) = 0; // At ADDRESS, register REG's value is the same as that it had in // the caller. - virtual bool SameValueRule(uint64 address, int reg) = 0; + virtual bool SameValueRule(uint64_t address, int reg) = 0; // At ADDRESS, register REG has been saved at offset OFFSET from // BASE_REGISTER. - virtual bool OffsetRule(uint64 address, int reg, + virtual bool OffsetRule(uint64_t address, int reg, int base_register, long offset) = 0; // At ADDRESS, the caller's value of register REG is the current // value of BASE_REGISTER plus OFFSET. (This rule doesn't provide an // address at which the register's value is saved.) - virtual bool ValOffsetRule(uint64 address, int reg, + virtual bool ValOffsetRule(uint64_t address, int reg, int base_register, long offset) = 0; // At ADDRESS, register REG has been saved in BASE_REGISTER. This differs @@ -877,17 +1150,17 @@ class CallFrameInfo::Handler { // BASE_REGISTER is the "home" for REG's saved value: if you want to // assign to a variable whose home is REG in the calling frame, you // should put the value in BASE_REGISTER. - virtual bool RegisterRule(uint64 address, int reg, int base_register) = 0; + virtual bool RegisterRule(uint64_t address, int reg, int base_register) = 0; // At ADDRESS, the DWARF expression EXPRESSION yields the address at // which REG was saved. - virtual bool ExpressionRule(uint64 address, int reg, + virtual bool ExpressionRule(uint64_t address, int reg, const string &expression) = 0; // At ADDRESS, the DWARF expression EXPRESSION yields the caller's // value for REG. (This rule doesn't provide an address at which the // register's value is saved.) - virtual bool ValExpressionRule(uint64 address, int reg, + virtual bool ValExpressionRule(uint64_t address, int reg, const string &expression) = 0; // Indicate that the rules for the address range reported by the @@ -928,7 +1201,7 @@ class CallFrameInfo::Handler { // which the routine's address is stored. The default definition for // this handler function simply returns true, allowing parsing of // the entry to continue. - virtual bool PersonalityRoutine(uint64 address, bool indirect) { + virtual bool PersonalityRoutine(uint64_t address, bool indirect) { return true; } @@ -937,7 +1210,7 @@ class CallFrameInfo::Handler { // which the area's address is stored. The default definition for // this handler function simply returns true, allowing parsing of // the entry to continue. - virtual bool LanguageSpecificDataArea(uint64 address, bool indirect) { + virtual bool LanguageSpecificDataArea(uint64_t address, bool indirect) { return true; } @@ -973,69 +1246,77 @@ class CallFrameInfo::Reporter { // The CFI entry at OFFSET ends too early to be well-formed. KIND // indicates what kind of entry it is; KIND can be kUnknown if we // haven't parsed enough of the entry to tell yet. - virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind); + virtual void Incomplete(uint64_t offset, CallFrameInfo::EntryKind kind); // The .eh_frame data has a four-byte zero at OFFSET where the next // entry's length would be; this is a terminator. However, the buffer // length as given to the CallFrameInfo constructor says there should be // more data. - virtual void EarlyEHTerminator(uint64 offset); + virtual void EarlyEHTerminator(uint64_t offset); // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the // section is not that large. - virtual void CIEPointerOutOfRange(uint64 offset, uint64 cie_offset); + virtual void CIEPointerOutOfRange(uint64_t offset, uint64_t cie_offset); // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the entry // there is not a CIE. - virtual void BadCIEId(uint64 offset, uint64 cie_offset); + virtual void BadCIEId(uint64_t offset, uint64_t cie_offset); + + // The FDE at OFFSET refers to a CIE with an address size we don't know how + // to handle. + virtual void UnexpectedAddressSize(uint64_t offset, uint8_t address_size); + + // The FDE at OFFSET refers to a CIE with an segment descriptor size we + // don't know how to handle. + virtual void UnexpectedSegmentSize(uint64_t offset, uint8_t segment_size); // The FDE at OFFSET refers to a CIE with version number VERSION, // which we don't recognize. We cannot parse DWARF CFI if it uses // a version number we don't recognize. - virtual void UnrecognizedVersion(uint64 offset, int version); + virtual void UnrecognizedVersion(uint64_t offset, int version); // The FDE at OFFSET refers to a CIE with augmentation AUGMENTATION, // which we don't recognize. We cannot parse DWARF CFI if it uses // augmentations we don't recognize. - virtual void UnrecognizedAugmentation(uint64 offset, + virtual void UnrecognizedAugmentation(uint64_t offset, const string &augmentation); // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not // a valid encoding. - virtual void InvalidPointerEncoding(uint64 offset, uint8 encoding); + virtual void InvalidPointerEncoding(uint64_t offset, uint8_t encoding); // The pointer encoding ENCODING, specified by the CIE at OFFSET, depends // on a base address which has not been supplied. - virtual void UnusablePointerEncoding(uint64 offset, uint8 encoding); + virtual void UnusablePointerEncoding(uint64_t offset, uint8_t encoding); // The CIE at OFFSET contains a DW_CFA_restore instruction at // INSN_OFFSET, which may not appear in a CIE. - virtual void RestoreInCIE(uint64 offset, uint64 insn_offset); + virtual void RestoreInCIE(uint64_t offset, uint64_t insn_offset); // The entry at OFFSET, of kind KIND, has an unrecognized // instruction at INSN_OFFSET. - virtual void BadInstruction(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); + virtual void BadInstruction(uint64_t offset, CallFrameInfo::EntryKind kind, + uint64_t insn_offset); // The instruction at INSN_OFFSET in the entry at OFFSET, of kind // KIND, establishes a rule that cites the CFA, but we have not // established a CFA rule yet. - virtual void NoCFARule(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); + virtual void NoCFARule(uint64_t offset, CallFrameInfo::EntryKind kind, + uint64_t insn_offset); // The instruction at INSN_OFFSET in the entry at OFFSET, of kind // KIND, is a DW_CFA_restore_state instruction, but the stack of // saved states is empty. - virtual void EmptyStateStack(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); + virtual void EmptyStateStack(uint64_t offset, CallFrameInfo::EntryKind kind, + uint64_t insn_offset); // The DW_CFA_remember_state instruction at INSN_OFFSET in the entry // at OFFSET, of kind KIND, would restore a state that has no CFA // rule, whereas the current state does have a CFA rule. This is // bogus input, which the CallFrameInfo::Handler interface doesn't // (and shouldn't) have any way to report. - virtual void ClearingCFARule(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); + virtual void ClearingCFARule(uint64_t offset, CallFrameInfo::EntryKind kind, + uint64_t insn_offset); protected: // The name of the file whose CFI we're reading. |