util/DwarfReader, ElfImporter: import address ranges

This change implements the following:
-DwarfReader now exports the address range of linetable-entries instead of
	only the first address
-ElfImporter saves this range alongside the mapping

Change-Id: I7fe6361178f761a8f605a44bb0183c56a236cc95
This commit is contained in:
Michael Lenz
2014-10-15 17:41:08 +02:00
parent d94b005be2
commit 5378573b1d
3 changed files with 43 additions and 23 deletions

View File

@ -1,4 +1,5 @@
#include <fstream> #include <fstream>
#include <limits>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
@ -178,7 +179,7 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list<std::s
return true; return true;
} }
bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addrToLineList) { bool DwarfReader::read_mapping(std::string fileName, std::list<DwarfLineMapping>& lineMapping) {
// Open The file // Open The file
int fd=open(fileName.c_str(),O_RDONLY); int fd=open(fileName.c_str(),O_RDONLY);
@ -200,9 +201,11 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addr
// Iterator over the headers // Iterator over the headers
Dwarf_Unsigned header; Dwarf_Unsigned header;
// iterate compilation unit headers
while (dwarf_next_cu_header(dbg,0,0,0,0,&header,0)==DW_DLV_OK) { while (dwarf_next_cu_header(dbg,0,0,0,0,&header,0)==DW_DLV_OK) {
// Access the die // Access the die
Dwarf_Die die; Dwarf_Die die;
// XXX: "if there are no sibling headers, die" | semantics unclear!
if (dwarf_siblingof(dbg,0,&die,0)!=DW_DLV_OK) { if (dwarf_siblingof(dbg,0,&die,0)!=DW_DLV_OK) {
return false; return false;
} }
@ -234,8 +237,21 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addr
} }
if (lineNo&&isCode) { if (lineNo&&isCode) {
struct addrToLine newLine = { addr, lineNo, normalize(lineSource) }; /* default the linetable's address range (->size) to the maximum
addrToLineList.push_back(newLine); * possible range. this results in the last linetable entry having
* maximum range. as this always (?) is a function epilogue, its
* irrelevant for our use-case. */
// 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);

View File

@ -7,6 +7,16 @@
namespace fail { namespace fail {
class DwarfLineMapping {
public:
unsigned absolute_addr;
unsigned line_range_size;
unsigned line_number;
std::string line_source;
DwarfLineMapping(unsigned addr, unsigned size, unsigned number, std::string src)
: absolute_addr(addr), line_range_size(size), line_number(number), line_source(src){}
};
/** /**
* This source code is based on bcov 0.2. * This source code is based on bcov 0.2.
@ -15,23 +25,16 @@ namespace fail {
* GNU GENERAL PUBLIC LICENSE * GNU GENERAL PUBLIC LICENSE
*/ */
struct addrToLine { /**
unsigned absoluteAddr; * \class DwarfReader
unsigned lineNumber; * ToDO
std::string lineSource; */
}; class DwarfReader {
/**
* \class DwarfReader
* ToDO
*/
class DwarfReader {
public: public:
bool read_source_files(const std::string& fileName, std::list<std::string>& lines); bool read_source_files(const std::string& fileName, std::list<std::string>& lines);
bool read_mapping(std::string fileName, std::list<addrToLine>& addrToLineList); bool read_mapping(std::string fileName, std::list<DwarfLineMapping>& lineMapping);
}; };
} // end-of-namespace fail } // end-of-namespace fail

View File

@ -78,6 +78,7 @@ bool ElfImporter::create_database()
create_statement << "CREATE TABLE IF NOT EXISTS dbg_mapping (" create_statement << "CREATE TABLE IF NOT EXISTS dbg_mapping ("
" variant_id int(11) NOT NULL," " variant_id int(11) NOT NULL,"
" instr_absolute int(11) UNSIGNED NOT NULL," " instr_absolute int(11) UNSIGNED NOT NULL,"
" line_range_size int(11) UNSIGNED NOT NULL,"
" linenumber int(11) UNSIGNED NOT NULL," " linenumber int(11) UNSIGNED NOT NULL,"
" file_id int(11) NOT NULL," " file_id int(11) NOT NULL,"
" PRIMARY KEY (variant_id, instr_absolute ,linenumber)" " PRIMARY KEY (variant_id, instr_absolute ,linenumber)"
@ -356,19 +357,18 @@ bool ElfImporter::import_source_files(const std::string& elf_filename, std::list
bool ElfImporter::import_mapping(std::string fileName) bool ElfImporter::import_mapping(std::string fileName)
{ {
std::list<addrToLine> mapping; std::list<DwarfLineMapping> mapping;
if (!dwReader.read_mapping(fileName, mapping)) { if (!dwReader.read_mapping(fileName, mapping)) {
return false; return false;
} }
while (!mapping.empty()) { while (!mapping.empty()) {
struct addrToLine temp_addrToLine; DwarfLineMapping tmp_mapping = mapping.front();
temp_addrToLine = mapping.front();
// FIXME reuse file_id from previous iteration if file name stays constant // FIXME reuse file_id from previous iteration if file name stays constant
std::stringstream ss; std::stringstream ss;
ss << "SELECT file_id FROM dbg_filename " ss << "SELECT file_id FROM dbg_filename "
<< "WHERE path = '" << temp_addrToLine.lineSource << "' " << "WHERE path = '" << tmp_mapping.line_source << "' "
<< "AND variant_id = " << m_variant_id; << "AND variant_id = " << m_variant_id;
MYSQL_RES *res = db->query(ss.str().c_str(), true); MYSQL_RES *res = db->query(ss.str().c_str(), true);
@ -380,17 +380,18 @@ bool ElfImporter::import_mapping(std::string fileName)
// INSERT group entry // INSERT group entry
std::stringstream sql; std::stringstream sql;
sql << "(" << m_variant_id << "," << temp_addrToLine.absoluteAddr << "," << temp_addrToLine.lineNumber << ","; sql << "(" << m_variant_id << "," << tmp_mapping.absolute_addr << ","
<< tmp_mapping.line_range_size << "," << tmp_mapping.line_number << ",";
if (row != NULL) { if (row != NULL) {
sql << row[0] << ")"; sql << row[0] << ")";
} else { } else {
// this should not happen // this should not happen
LOG << "error: no entry for '" << temp_addrToLine.lineSource << "' in dbg_filename, aborting" << std::endl; LOG << "error: no entry for '" << tmp_mapping.line_source << "' in dbg_filename, aborting" << std::endl;
return false; return false;
} }
// TODO: Skip duplicated entries with ON DUPLICATE KEY UPDATE (?) // TODO: Skip duplicated entries with ON DUPLICATE KEY UPDATE (?)
if (!db->insert_multiple("INSERT IGNORE INTO dbg_mapping (variant_id, instr_absolute, linenumber, file_id) VALUES ", if (!db->insert_multiple("INSERT IGNORE INTO dbg_mapping (variant_id, instr_absolute, line_range_size, linenumber, file_id) VALUES ",
sql.str().c_str())) { sql.str().c_str())) {
return false; return false;
} }