import-trace: ElfImporter cleanups

-  added several insert_multiple() flushes (which completely broke
    the import before)
 -  import_source_code() refactored
 -  parameter naming improved
 -  better error handling
 -  whitespace/coding-style cleanups
 -  documentation added + cleanups

Change-Id: I70ac95391b9678e0dcce8adfa7df69a4f91ca30d
This commit is contained in:
Horst Schirmeier
2014-10-08 13:06:12 +02:00
parent 31166f990e
commit 8fcbc7eeae
2 changed files with 125 additions and 113 deletions

View File

@ -21,7 +21,8 @@ static Logger LOG("ElfImporter");
* Callback function that can be used to add command line options
* to the campaign
*/
bool ElfImporter::cb_commandline_init() {
bool ElfImporter::cb_commandline_init()
{
CommandLine &cmd = CommandLine::Inst();
OBJDUMP = cmd.addOption("", "objdump", Arg::Required,
@ -31,7 +32,8 @@ bool ElfImporter::cb_commandline_init() {
return true;
}
bool ElfImporter::create_database() {
bool ElfImporter::create_database()
{
CommandLine &cmd = CommandLine::Inst();
std::stringstream create_statement;
@ -88,7 +90,8 @@ bool ElfImporter::create_database() {
return true;
}
bool ElfImporter::copy_to_database(ProtoIStream &ps) {
bool ElfImporter::copy_to_database(ProtoIStream &ps)
{
if (!m_elf) {
LOG << "please give an elf binary as parameter (-e/--elf)" << std::endl;
return false;
@ -131,7 +134,8 @@ bool ElfImporter::copy_to_database(ProtoIStream &ps) {
return true;
}
bool ElfImporter::import_with_objdump(const std::string &binary) {
bool ElfImporter::import_with_objdump(const std::string &binary)
{
#ifndef __puma
LOG << "importing with " << binary << std::endl;
@ -162,7 +166,8 @@ bool ElfImporter::import_with_objdump(const std::string &binary) {
return true;
}
bool ElfImporter::evaluate_objdump_line(const std::string& line){
bool ElfImporter::evaluate_objdump_line(const std::string& line)
{
#ifndef __puma
// Only read in real code lines:
// Code lines start with a leading whitespace! (hopefully in each objdump implementation!)
@ -209,7 +214,8 @@ bool ElfImporter::evaluate_objdump_line(const std::string& line){
bool ElfImporter::import_instruction(fail::address_t addr, char *opcode, int opcode_length,
const std::string &instruction, const std::string &comment) {
const std::string &instruction, const std::string &comment)
{
/* Prepare a mysql statement if it was not done before */
static MYSQL_STMT *stmt = 0;
if (!stmt) {
@ -263,98 +269,112 @@ bool ElfImporter::import_instruction(fail::address_t addr, char *opcode, int opc
return true;
}
bool ElfImporter::import_source_code(std::string fileName) {
static inline std::string rtrim(std::string str)
{
std::string whitespaces(" \t\f\v\n\r");
std::size_t found = str.find_last_not_of(whitespaces);
if (found != std::string::npos) {
str.erase(found+1);
} else {
str.clear();
}
return str;
}
bool ElfImporter::import_source_code(std::string fileName)
{
LOG << "Importing Sourcefile: " << fileName << endl;
ifstream in(fileName.c_str());
if (!in.is_open()) {
LOG << "Sourcefile not found: " << fileName << endl;
} else {
unsigned lineNo=0;
while (!in.eof()) {
++lineNo;
// Read and strip the current line
string currentLine;
getline(in,currentLine);
if ((!currentLine.length())&&(in.eof())) break;
while (true) {
unsigned l=currentLine.length();
if (!l) break;
char c=currentLine[l-1];
if ((c!='\n')&&(c!='\r')&&(c!=' ')&&(c!='\t')) break;
currentLine=currentLine.substr(0,l-1);
return true; // we can live with this
}
//Sonderzeichen
currentLine = db->escape_string(currentLine);
// retrieve file_id
std::stringstream ss;
ss << "SELECT file_id FROM dbg_filename "
<< "WHERE path = '" << fileName.c_str() << "' "
<< "AND variant_id = " << m_variant_id;
MYSQL_RES *res = db->query(ss.str().c_str(), true);
MYSQL_ROW row;
row = mysql_fetch_row(res);
// INSERT group entry
std::stringstream sql;
sql << "(" << m_variant_id << "," << lineNo << ",";
if (row != NULL) {
sql << row[0];
} else {
sql << -1;
if (!res) {
return false;
}
sql << "," << "\"" << currentLine << "\"" << ")";
MYSQL_ROW row;
if (!(row = mysql_fetch_row(res))) {
// this should not happen
LOG << "error: no entry for '" << fileName.c_str() << "' in dbg_filename, aborting" << std::endl;
return false;
}
std::string file_id = row[0];
if (!db->insert_multiple("INSERT INTO dbg_source (variant_id, linenumber, file_id, line) VALUES ", sql.str().c_str())){
LOG << "Can not import sourcelines!" << endl;;
// import lines from this file
for (unsigned lineNo = 1; !in.eof(); ++lineNo) {
// read and strip a line
string currentLine;
getline(in, currentLine);
if (!currentLine.length() && in.eof()) {
break;
}
currentLine = rtrim(currentLine);
// escape special characters for use in SQL
currentLine = db->escape_string(currentLine);
// insert line into dbg_source
std::stringstream sql;
sql << "(" << m_variant_id << "," << lineNo
<< "," << file_id << ",'" << currentLine << "')";
if (!db->insert_multiple("INSERT INTO dbg_source (variant_id, linenumber, file_id, line) VALUES ",
sql.str().c_str())) {
return false;
}
}
db->insert_multiple();
}
return true;
}
bool ElfImporter::import_source_files(const std::string& fileName,std::list<std::string>& lines) {
//std::list<addrToLine> lines;
if (!dwReader.read_source_files(fileName, lines)) {
bool ElfImporter::import_source_files(const std::string& elf_filename, std::list<std::string>& filenames)
{
if (!dwReader.read_source_files(elf_filename, filenames)) {
return false;
}
for (std::list<std::string>::iterator it = lines.begin(); it != lines.end(); ++it) {
for (std::list<std::string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
// INSERT group entry
std::stringstream sql;
sql << "(" << m_variant_id << "," << "\"" << (*it).c_str() << "\"" << ")";
sql << "(" << m_variant_id << ",'" << it->c_str() << "')";
if(!db->insert_multiple("INSERT INTO dbg_filename (variant_id, path) VALUES ", sql.str().c_str())){
LOG << "Can not import filename!"<< endl;
if (!db->insert_multiple("INSERT INTO dbg_filename (variant_id, path) VALUES ",
sql.str().c_str())) {
return false;
}
}
db->insert_multiple();
return true;
}
bool ElfImporter::import_mapping(std::string fileName) {
bool ElfImporter::import_mapping(std::string fileName)
{
std::list<addrToLine> mapping;
if (!dwReader.read_mapping(fileName, mapping)) {
return false;
}
while (!mapping.empty())
{
while (!mapping.empty()) {
struct addrToLine temp_addrToLine;
temp_addrToLine = mapping.front();
// FIXME reuse file_id from previous iteration if file name stays constant
std::stringstream ss;
ss << "SELECT file_id FROM dbg_filename "
<< "WHERE path = '" << temp_addrToLine.lineSource << "' "
<< "AND variant_id = " << m_variant_id;
MYSQL_RES *res = db->query(ss.str().c_str(), true);
if (!res) {
return false;
}
MYSQL_ROW row;
row = mysql_fetch_row(res);
@ -364,62 +384,57 @@ bool ElfImporter::import_mapping(std::string fileName) {
if (row != NULL) {
sql << row[0] << ")";
} else {
sql << -1 << ")";
// this should not happen
LOG << "error: no entry for '" << temp_addrToLine.lineSource << "' in dbg_filename, aborting" << std::endl;
return false;
}
//ToDo: Skip duplicated entrys with ON DUPLICATE KEY UPDATE
if(!db->insert_multiple("INSERT IGNORE INTO dbg_mapping (variant_id, instr_absolute, linenumber, file_id) VALUES ", sql.str().c_str())){
LOG << "Can not import line number information!" << endl;;
// 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 ",
sql.str().c_str())) {
return false;
}
mapping.pop_front();
}
db->insert_multiple();
return true;
}
bool ElfImporter::clear_database() {
bool ElfImporter::clear_database()
{
CommandLine &cmd = CommandLine::Inst();
std::stringstream ss;
bool ret = true;
bool ret = true, result;
ss.str("");
ss << "DELETE FROM objdump WHERE variant_id = " << m_variant_id;
if (ret) {
ret = db->query(ss.str().c_str()) == 0 ? false : true;
}
result = db->query(ss.str().c_str());
ret = ret && result;
LOG << "deleted " << db->affected_rows() << " rows from objdump table" << std::endl;
//ToDo: Reset auto increment value to 1
if (cmd[SOURCECODE]) {
ss.str("");
ss << "DELETE FROM dbg_source WHERE variant_id = " << m_variant_id;
if (ret) {
ret = db->query(ss.str().c_str()) == 0 ? false : true;
}
result = db->query(ss.str().c_str());
ret = ret && result;
LOG << "deleted " << db->affected_rows() << " rows from dbg_source table" << std::endl;
ss.str("");
ss << "DELETE FROM dbg_filename WHERE variant_id = " << m_variant_id;
if (ret) {
ret = db->query(ss.str().c_str()) == 0 ? false : true;
}
LOG << "deleted " << db->affected_rows() << " rows from dbg_source table" << std::endl;
result = db->query(ss.str().c_str());
ret = ret && result;
LOG << "deleted " << db->affected_rows() << " rows from dbg_filename table" << std::endl;
//ToDo: Reset auto increment value to 1
ss.str("");
ss << "DELETE FROM dbg_mapping WHERE variant_id = " << m_variant_id;
if (ret) {
ret = db->query(ss.str().c_str()) == 0 ? false : true;
}
result = db->query(ss.str().c_str());
ret = ret && result;
LOG << "deleted " << db->affected_rows() << " rows from source table" << std::endl;
}
return ret;
}

View File

@ -14,21 +14,18 @@
/**
The ElfImporter is not a real trace importer, but we locate it
into the import-trace utility, since here the infrastructure is
already in place to import things related to an elf binary into
already in place to import things related to an ELF binary into
the database.
The ElfImporter calls objdump and dissassembles an elf binary
The ElfImporter calls objdump and dissassembles an ELF binary
and imports the results into the database
In addition, debugging information can be imported:
If the --sources option is set, the source files will be imported
into the database. Only the files that were actually used in the
elf binary will be imported.
If the --debug option is set, the line number table of the elf binary will
be imported into the database. The information will be stored in the
"mapping" table.
ELF binary will be imported. Additionally, the line number table of the
ELF binary will be imported into the database.
*/
class ElfImporter : public Importer {
llvm::OwningPtr<llvm::object::Binary> binary;
@ -46,7 +43,7 @@ class ElfImporter : public Importer {
bool import_instruction(fail::address_t addr, char opcode[16], int opcode_length,
const std::string &instruction, const std::string &comment);
bool import_source_files(const std::string& fileName,std::list<std::string>& lines);
bool import_source_files(const std::string& elf_filename, std::list<std::string>& filenames);
bool import_source_code(std::string fileName);
bool import_mapping(std::string fileName);
@ -61,7 +58,7 @@ protected:
}
public:
ElfImporter() : Importer() {};
ElfImporter() : Importer() {}
/**
* Callback function that can be used to add command line options