DwarfReader: fixed linetable mapping

This change alters/corrects DwarfReader's way of determining the size of
linetable entries (i.e. their "range size"); the interface (e.g. to
ElfReader) stays the same. Prior to this, it was assumed that static
instructions within "the linetable" were sorted in ascending order. This
assumption turned out to be false, as every compilation unit's  header has
its own linetable and the compilation unit headers are not sorted by their
static instructions.
Furthermore this change implements normalization of file names.

Change-Id: Ia4beb7bf9cfb6f1a499aeebd01228335b70ab52d
This commit is contained in:
Michael Lenz
2014-11-19 18:04:54 +01:00
parent bfd6a55f58
commit e83e87ecc7
2 changed files with 39 additions and 15 deletions

View File

@ -2,6 +2,7 @@
#include <limits> #include <limits>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <map>
#include "DwarfReader.hpp" #include "DwarfReader.hpp"
#include "libdwarf.h" #include "libdwarf.h"
@ -180,6 +181,10 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list<std::s
} }
bool DwarfReader::read_mapping(std::string fileName, std::list<DwarfLineMapping>& lineMapping) { bool DwarfReader::read_mapping(std::string fileName, std::list<DwarfLineMapping>& lineMapping) {
// temporary mapping of instruction address to (file, line)
// => static instruction addresses are sorted ascendingly for the whole binary
// (i.e. all instructions from all CUs!)
std::map<unsigned, SourceLine> instr_to_sourceline;
// Open The file // Open The file
int fd=open(fileName.c_str(),O_RDONLY); int fd=open(fileName.c_str(),O_RDONLY);
@ -237,21 +242,10 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<DwarfLineMapping>
} }
if (lineNo&&isCode) { if (lineNo&&isCode) {
/* default the linetable's address range (->size) to the maximum // wrap line_number and source_file into an object
* possible range. this results in the last linetable entry having SourceLine tmp_sl(normalize(lineSource), lineNo);
* maximum range. as this always (?) is a function epilogue, its // store SourceLine object with static instr in the map
* irrelevant for our use-case. */ instr_to_sourceline.insert(std::make_pair(addr, tmp_sl));
// TODO: properly determine the last interval's range, e.g. via __TEXT_END
DwarfLineMapping mapping(addr, (std::numeric_limits<unsigned>::max() - addr),
lineNo, lineSource);
// the address range for the previous line ends with the current line's address
if (!lineMapping.empty()) {
DwarfLineMapping& back = lineMapping.back();
// update the previous lineRangeSize appropriately
back.line_range_size = (addr - back.absolute_addr);
}
lineMapping.push_back(mapping);
} }
dwarf_dealloc(dbg,lineSource,DW_DLA_STRING); dwarf_dealloc(dbg,lineSource,DW_DLA_STRING);
@ -269,6 +263,26 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<DwarfLineMapping>
return false; return false;
} }
// iterate instr_to_sourceline to determine the "line_range_size" for mapping
std::map<unsigned, SourceLine>::iterator it;
for (it = instr_to_sourceline.begin(); it != instr_to_sourceline.end(); it++) {
unsigned addr = it->first;
SourceLine sl = it->second;
/* Default the linetable's address range (->"size") to the maximum
* possible value. This results in the last linetable entry having
* maximum range. This entry will either be a dummy or a function's
* epilogue, both of which are irrelevant for our (current) use cases.
* All other entries' sizes are set properly. */
DwarfLineMapping mapping(addr, (std::numeric_limits<unsigned>::max() - addr),
sl.line_number, sl.source_file);
if (!lineMapping.empty()) {
DwarfLineMapping& back = lineMapping.back();
back.line_range_size = addr - back.absolute_addr;
}
lineMapping.push_back(mapping);
}
close(fd); close(fd);
return true; return true;
} }

View File

@ -7,6 +7,16 @@
namespace fail { namespace fail {
// temporary wrapper object for (file, linenumber)
class SourceLine {
public:
std::string source_file;
unsigned line_number;
SourceLine(std::string source, unsigned line) : source_file(source), line_number(line) {}
};
// wrapper object for insertion into DB
class DwarfLineMapping { class DwarfLineMapping {
public: public:
unsigned absolute_addr; unsigned absolute_addr;