From 1cab261a783a5aea8c21225d7c9955d5b8135892 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Thu, 24 May 2018 18:00:09 +1200 Subject: rtemstoolkit/dwarf: Fixes for getting source lines. --- rtemstoolkit/rld-dwarf.cpp | 260 +++++++++++++++++++++++++-------------------- rtemstoolkit/rld-dwarf.h | 34 +++--- 2 files changed, 160 insertions(+), 134 deletions(-) diff --git a/rtemstoolkit/rld-dwarf.cpp b/rtemstoolkit/rld-dwarf.cpp index 15cf8e2..674ac8f 100644 --- a/rtemstoolkit/rld-dwarf.cpp +++ b/rtemstoolkit/rld-dwarf.cpp @@ -85,6 +85,28 @@ namespace rld end_sequence = b ? true : false; } + address::address (const address& orig, const sources& source) + : addr (orig.addr), + source (&source), + source_index (orig.source_index), + source_line (orig.source_line), + begin_statement (orig.begin_statement), + block (orig.block), + end_sequence (orig.end_sequence) + { + } + + address::address (const address& orig, dwarf_address addr) + : addr (addr), + source (orig.source), + source_index (orig.source_index), + source_line (orig.source_line), + begin_statement (orig.begin_statement), + block (orig.block), + end_sequence (orig.end_sequence) + { + } + address::address (const address& orig) : addr (orig.addr), source (orig.source), @@ -173,6 +195,12 @@ namespace rld return *this; } + bool + address::operator < (const address& rhs) const + { + return addr < rhs.addr; + } + line_addresses::line_addresses (file& debug, debug_info_entry& die) : debug (debug), @@ -186,15 +214,6 @@ namespace rld } } - line_addresses::line_addresses (line_addresses&& orig) - : debug (orig.debug), - lines (orig.lines), - count_ (orig.count_) - { - orig.lines = nullptr; - orig.count_ = 0; - } - line_addresses::~line_addresses () { if (lines && count_ > 0) @@ -220,12 +239,13 @@ namespace rld return lines[index]; } - sources::sources (file& debug, debug_info_entry& die) + sources::sources (file& debug, dwarf_offset die_offset) : debug (debug), source (nullptr), count (0), - die_offset (die.offset ()) + die_offset (die_offset) { + debug_info_entry die (debug, die_offset); die.source_files (source, count); } @@ -243,16 +263,6 @@ namespace rld die.source_files (source, count); } - sources::sources (sources&& orig) - : debug (orig.debug), - source (orig.source), - count (orig.count), - die_offset (orig.die_offset) - { - orig.source = nullptr; - orig.count = 0; - } - sources::~sources () { dealloc (); @@ -263,7 +273,7 @@ namespace rld { if (index <= 0 || index > count) return "unknown"; - return source[index - 1]; + return std::string (source[index - 1]); } void @@ -274,7 +284,7 @@ namespace rld /* * The elftoolchain cleans the memory up and there is no compatible * call we can put here so adding the required code causes is a double - * free results in a crash. + * free resulting in a crash. */ if (false) { @@ -330,21 +340,8 @@ namespace rld libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de); } - debug_info_entry::debug_info_entry (debug_info_entry&& orig) - : debug (orig.debug), - die (orig.die), - tag_ (orig.tag_), - offset_ (orig.offset_) - { - orig.die = nullptr; - orig.tag_ = 0; - orig.offset_ = 0; - } - debug_info_entry::~debug_info_entry () { - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "dwarf::debug_info_entry::~debug_info_entry" << std::endl; dealloc (); } @@ -492,8 +489,8 @@ namespace rld offset_ (offset), pc_low_ (0), pc_high_ (0), - source_ (debug, die), - die_offset (die.offset ()) + die_offset (die.offset ()), + source_ (debug, die_offset) { die.attribute (DW_AT_name, name_); name_ = name_; @@ -505,6 +502,9 @@ namespace rld if (!die.attribute (DW_AT_high_pc, pc_high_, false)) pc_high_ = ~0U; + if (pc_high_ < pc_low_) + pc_high_ += pc_low_; + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) { std::cout << std::hex << std::setfill ('0') @@ -522,49 +522,85 @@ namespace rld line_addresses lines (debug, die); dwarf_address pc = 0; + bool seq_check = true; + dwarf_address seq_base = 0; for (size_t l = 0; l < lines.count (); ++l) { - address addr (source_, lines[l]); - dwarf_address loc = addr.location (); - if (inside (loc) && loc >= pc) + address daddr (source_, lines[l]); + dwarf_address loc = daddr.location (); + /* + * A CU's line program can have some sequences at the start where the + * address is incorrectly set to 0. Ignore these entries. + */ + if (pc == 0) { - pc = loc; - addr_lines_[addr.location ()] = addr; - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + if (!seq_check) { - std::cout << "dwarf::compilation_unit: " - << std::hex << std::setw (8) << addr.location () << std::dec - << " - " - << (char) (addr.is_a_begin_statement () ? 'B' : '.') - << (char) (addr.is_in_a_block () ? 'I' : '.') - << (char) (addr.is_an_end_sequence () ? 'E' : '.') - << " - " - << rld::path::basename (addr.path ()) - << ':' << addr.line () - << std::endl; + seq_check = daddr.is_an_end_sequence (); + continue; + } + if (loc == 0) + { + seq_check = false; + continue; } } + /* + * A sequence of line program instruction may set the address to 0. Use + * the last location from the previous sequence as the sequence's base + * address. All locations will be offset from the that base until the + * end of this sequence. + */ + if (loc == 0 && seq_base == 0) + seq_base = pc; + if (seq_base != 0) + loc += seq_base; + if (daddr.is_an_end_sequence ()) + seq_base = 0; + address addr (daddr, loc); + if (loc >= pc_low_ && loc < pc_high_) + { + pc = loc; + addr_lines_.push_back (addr); + } } - } - compilation_unit::compilation_unit (compilation_unit&& orig) - : debug (orig.debug), - offset_ (orig.offset_), - name_ (orig.name_), - producer_ (orig.producer_), - pc_low_ (orig.pc_low_), - pc_high_ (orig.pc_high_), - source_ (std::move (orig.source_)), - addr_lines_ (orig.addr_lines_), - die_offset (orig.die_offset) - { - orig.name_.clear (); - orig.producer_.clear (); - orig.offset_ = 0; - orig.die_offset = 0; - orig.pc_low_ = 0; - orig.pc_high_ = 0; + if (!addr_lines_.empty ()) + { + std::stable_sort (addr_lines_.begin (), addr_lines_.end ()); + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + { + auto first = addr_lines_.begin (); + auto last = addr_lines_.end () - 1; + std::cout << "dwarf::compilation_unit: line_low=0x" + << std::hex + << std::setw (8) << first->location () + << ", line_high=0x" + << std::setw (8) << last->location () + << std::dec + << std::endl; + } + } + + if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) + { + int lc = 0; + for (auto& l : addr_lines_) + { + std::cout << "dwarf::compilation_unit: " << std::setw (3) << ++lc + << ": 0x" + << std::hex << std::setw (8) << l.location () << std::dec + << " - " + << (char) (l.is_a_begin_statement () ? 'B' : '.') + << (char) (l.is_in_a_block () ? 'I' : '.') + << (char) (l.is_an_end_sequence () ? 'E' : '.') + << " - " + << rld::path::basename (l.path ()) + << ':' <= RLD_VERBOSE_FULL_DEBUG) - std::cout << "dwarf::compilation_unit::~compilation_unit: " << name_ << std::endl; } std::string @@ -614,39 +650,35 @@ namespace rld compilation_unit::get_source (const dwarf_address addr, address& addr_line) { - if (addr_lines_.find (addr) == addr_lines_.end ()) - return false; - addr_line = addr_lines_[addr]; - return true; + if (!addr_lines_.empty () && inside (addr)) + { + address last_loc; + for (auto& loc : addr_lines_) + { + if (addr <= loc.location ()) + { + if (addr == loc.location ()) + addr_line = loc; + else + addr_line = last_loc; + return addr_line.valid (); + } + last_loc = loc; + } + } + return false; } bool compilation_unit::inside (dwarf_unsigned addr) const { - return addr >= pc_low_ && addr < pc_high_; - } - - compilation_unit& - compilation_unit::operator = (compilation_unit&& rhs) - { - if (this != &rhs) + if (!addr_lines_.empty ()) { - debug = rhs.debug; - offset_ = rhs.offset_; - name_ = rhs.name_; - producer_ = rhs.producer_; - source_ = std::move (rhs.source_); - addr_lines_ = std::move (rhs.addr_lines_), - pc_low_ = rhs.pc_low_; - pc_high_ = rhs.pc_high_; - die_offset = rhs.die_offset; - rhs.offset_ = 0; - rhs.name_.clear (); - rhs.pc_low_ = -1; - rhs.pc_high_ = -1; - rhs.die_offset = 0; + auto first = addr_lines_.begin (); + auto last = addr_lines_.end () - 1; + return first->location () <= addr && addr <= last->location (); } - return *this; + return addr >= pc_low_ && addr < pc_high_; } compilation_unit& @@ -663,9 +695,9 @@ namespace rld offset_ = rhs.offset_; name_ = rhs.name_; producer_ = rhs.producer_; - debug_info_entry die (debug, rhs.offset_); - source_ = sources (debug, die); - addr_lines_ = addresses (rhs.addr_lines_); + source_ = sources (debug, die_offset); + for (auto& line : rhs.addr_lines_) + addr_lines_.push_back (address (line, source_)); pc_low_ = rhs.pc_low_; pc_high_ = rhs.pc_high_; die_offset = rhs.die_offset; @@ -844,16 +876,14 @@ namespace rld r = cu.get_source (addr, line); if (r) { - if (match.valid ()) + if (match.valid () && + (match.is_an_end_sequence () || !!line.is_an_end_sequence ())) + { + match = line; + } + else { - if (match.is_an_end_sequence ()) - { - match = line; - } - else if (!line.is_an_end_sequence ()) - { - match = line; - } + match = line; } } } diff --git a/rtemstoolkit/rld-dwarf.h b/rtemstoolkit/rld-dwarf.h index c69cb9d..1207728 100644 --- a/rtemstoolkit/rld-dwarf.h +++ b/rtemstoolkit/rld-dwarf.h @@ -46,6 +46,8 @@ namespace rld { public: address (const sources& source, dwarf_line& line); + address (const address& orig, const sources& source); + address (const address& orig, dwarf_address addr); address (const address& orig); address (); ~address (); @@ -90,6 +92,11 @@ namespace rld */ address& operator = (const address& rhs); + /** + * Less than operator to allow sorting. + */ + bool operator < (const address& rhs) const; + private: dwarf_address addr; @@ -102,11 +109,9 @@ namespace rld }; /** - * The addresses table is a map of the addresses in a CU to their line - * number. + * The addresses table is a vector sorted from low to high addresses.. */ - typedef std::map < const dwarf_address, address > addresses; - + typedef std::vector < address > addresses; /** * Line addresses. @@ -115,7 +120,6 @@ namespace rld { public: line_addresses (file& debug, debug_info_entry& die); - line_addresses (line_addresses&& orig); ~line_addresses (); /** @@ -144,9 +148,9 @@ namespace rld class sources { public: - sources (file& debug, debug_info_entry& die); + sources (file& debug, dwarf_offset die_offset); sources (const sources& orig); - sources (sources&& orig); + //sources (sources&& orig); ~sources (); /** @@ -186,7 +190,6 @@ namespace rld debug_info_entry (file& debug); debug_info_entry (file& debug, dwarf_die& die); debug_info_entry (file& debug, dwarf_offset offset); - debug_info_entry (debug_info_entry&& orig); /** * Destruct and clean up. @@ -277,7 +280,6 @@ namespace rld debug_info_entry& die, dwarf_offset offset); compilation_unit (const compilation_unit& orig); - compilation_unit (compilation_unit&& orig); ~compilation_unit (); /** @@ -309,17 +311,11 @@ namespace rld address& addr_line); /** - * Is the address inside the CU? Becareful using this because not all CUs - * have these attributes set and the address range will be the entire - * address space. + * Is the address inside the CU? If the PC low and high attributes are + * valid they are used or the lines are checked. */ bool inside (dwarf_unsigned addr) const; - /** - * Move assignment operator. - */ - compilation_unit& operator = (compilation_unit&& rhs); - /** * Copy assignment operator. */ @@ -334,10 +330,10 @@ namespace rld dwarf_unsigned pc_low_; ///< The PC low address dwarf_unsigned pc_high_; ///< The PC high address. + dwarf_offset die_offset; ///< The offset of the DIE in the image. + sources source_; ///< Sources table for this CU. addresses addr_lines_; ///< Address table. - - dwarf_offset die_offset; ///< The offset of the DIE in the image. }; typedef std::list < compilation_unit > compilation_units; -- cgit v1.2.3