From 35c615b756322f7755a5fbe1846129be8b9fa936 Mon Sep 17 00:00:00 2001 From: Neeraj Singh Date: Wed, 1 Dec 2021 20:55:09 -0800 Subject: Fix file names in dwarf5 line tables --- src/dwarflines.cpp | 90 ++++++++++++++++++++++++++++++++++++++++++------------ src/readDwarf.h | 9 +++--- 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/src/dwarflines.cpp b/src/dwarflines.cpp index 13106e5..11380ae 100644 --- a/src/dwarflines.cpp +++ b/src/dwarflines.cpp @@ -5,6 +5,7 @@ // see file LICENSE for further details // +#include #include "PEImage.h" #include "mspdb.h" #include "dwarf.h" @@ -25,6 +26,13 @@ bool isRelativePath(const std::string& s) return true; } +static void addTrailingSlash(std::string& dir) +{ + // Make sure dirs always end in a trailing slash + if (!dir.size() || (dir.back() != '\\' && dir.back() != '/')) + dir += '\\'; +} + static int cmpAdr(const void* s1, const void* s2) { const mspdb::LineInfoEntry* e1 = (const mspdb::LineInfoEntry*) s1; @@ -63,7 +71,7 @@ bool _flushDWARFLines(const PEImage& img, mspdb::Mod* mod, DWARF_LineState& stat const DWARF_FileName* dfn; if(state.lineInfo_file == 0) - dfn = state.file_ptr; + dfn = &state.cur_file; else if(state.lineInfo_file > 0 && state.lineInfo_file <= state.files.size()) dfn = &state.files[state.lineInfo_file - 1]; else @@ -74,8 +82,6 @@ bool _flushDWARFLines(const PEImage& img, mspdb::Mod* mod, DWARF_LineState& stat dfn->dir_index > 0 && dfn->dir_index <= state.include_dirs.size()) { std::string dir = state.include_dirs[dfn->dir_index - 1]; - if(dir.length() > 0 && dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\') - dir.append("\\"); fname = dir + fname; } for(size_t i = 0; i < fname.length(); i++) @@ -241,7 +247,6 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) DWARF_LineState state; state.seg_offset = img.getImageBase() + img.getSection(img.text.secNo).VirtualAddress; - DWARF_FileName fname; if (hdr->version <= 4) { // dirs @@ -249,16 +254,19 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) { if(*p == 0) break; - state.include_dirs.push_back((const char*) p); - p += strlen((const char*) p) + 1; + state.include_dirs.emplace_back((const char*) p); + auto &dir = state.include_dirs.back(); + p += dir.size() + 1; + addTrailingSlash(dir); } p++; // files while(p < end && *p) { + DWARF_FileName fname; fname.read(p); - state.files.push_back(fname); + state.files.emplace_back(std::move(fname)); } p++; } @@ -278,31 +286,48 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) unsigned int directories_count = LEB128(p); for (int o = 0; o < directories_count; o++) { - for (int i = 0; i < directory_entry_format_count; i++) + for (const auto &typeForm : directory_entry_format) { - switch (directory_entry_format[i].type) + switch (typeForm.type) { case DW_LNCT_path: - switch (directory_entry_format[i].form) + { + switch (typeForm.form) { case DW_FORM_line_strp: { size_t offset = cu.isDWARF64() ? RD8(p) : RD4(p); - state.include_dirs.push_back((const char*)img.debug_line_str.byteAt(offset)); + state.include_dirs.emplace_back((const char*)img.debug_line_str.byteAt(offset)); break; } case DW_FORM_string: - state.include_dirs.push_back((const char*)p); + state.include_dirs.emplace_back((const char*)p); p += strlen((const char*)p) + 1; break; default: + fprintf(stderr, "%s:%d: ERROR: invalid form=%d for path lineHdrOffs=%x\n", __FUNCTION__, __LINE__, + typeForm.form, off); + return false; } + + auto& dir = state.include_dirs.back(); + + // Relative dirs are relative to the first directory + // in the table. + if (state.include_dirs.size() > 1 && isRelativePath(dir)) + dir = state.include_dirs.front() + dir; + + addTrailingSlash(dir); break; + } case DW_LNCT_directory_index: case DW_LNCT_timestamp: case DW_LNCT_size: default: + fprintf(stderr, "%s:%d: ERROR: unexpected type=%d form=%d for directory path lineHdrOffs=%x\n", __FUNCTION__, __LINE__, + typeForm.type, typeForm.form, off); + return false; } } @@ -320,12 +345,14 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) unsigned int file_names_count = LEB128(p); for (int o = 0; o < file_names_count; o++) { - for (int i = 0; i < file_name_entry_format_count; i++) + DWARF_FileName fname; + + for (const auto &typeForm : file_name_entry_format) { - switch (file_name_entry_format[i].type) + switch (typeForm.type) { case DW_LNCT_path: - switch (directory_entry_format[i].form) + switch (typeForm.form) { case DW_FORM_line_strp: { @@ -338,22 +365,41 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) p += strlen((const char*)p) + 1; break; default: + fprintf(stderr, "%s:%d: ERROR: invalid form=%d for path lineHdrOffs=%x\n", __FUNCTION__, __LINE__, + typeForm.form, off); + + + assert(false, "invalid path form"); return false; } break; case DW_LNCT_directory_index: - if (file_name_entry_format[i].form == DW_FORM_udata) - fname.dir_index = LEB128(p); + // bias the directory index by 1 since _flushDWARFLines + // will check for 0 and subtract one (which is + // useful for DWARF4). + if (typeForm.form == DW_FORM_udata) + { + fname.dir_index = LEB128(p) + 1; + } else + { + fprintf(stderr, "%s:%d: ERROR: invalid form=%d for directory index lineHdrOffs=%x\n", __FUNCTION__, __LINE__, + typeForm.form, off); + return false; + } break; case DW_LNCT_timestamp: case DW_LNCT_size: default: + fprintf(stderr, "%s:%d: ERROR: unexpected type=%d form=%d for file path lineHdrOffs=%x\n", __FUNCTION__, __LINE__, + typeForm.type, typeForm.form, off); + return false; } } - state.files.push_back(fname); + + state.files.emplace_back(std::move(fname)); } } @@ -406,8 +452,7 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) break; } case DW_LNE_define_file: - fname.read(p); - state.file_ptr = &fname; + state.cur_file.read(p); state.file = 0; break; case DW_LNE_set_discriminator: @@ -433,6 +478,11 @@ bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod, DebugLevel debug_) break; case DW_LNS_set_file: state.file = LEB128(p); + // DWARF5 numbers all files starting at zero. We will + // subtract one in _flushDWARFLines when indexing the files + // array. + if (hdr->version >= 5) + state.file += 1; break; case DW_LNS_set_column: state.column = LEB128(p); diff --git a/src/readDwarf.h b/src/readDwarf.h index f9593f9..5e1db99 100644 --- a/src/readDwarf.h +++ b/src/readDwarf.h @@ -165,7 +165,7 @@ struct DWARF_CompilationUnitInfo struct DWARF_FileName { - const char* file_name; + std::string file_name; unsigned int dir_index; unsigned long lastModification; unsigned long fileLength; @@ -173,7 +173,7 @@ struct DWARF_FileName void read(byte* &p) { file_name = (const char*)p; - p += strlen((const char*)p) + 1; + p += file_name.size() + 1; dir_index = LEB128(p); lastModification = LEB128(p); fileLength = LEB128(p); @@ -345,7 +345,7 @@ struct DWARF2_LineNumberProgramHeader struct DWARF_LineState { // hdr info - std::vector include_dirs; + std::vector include_dirs; std::vector files; unsigned long address; @@ -362,7 +362,7 @@ struct DWARF_LineState unsigned int discriminator; // not part of the "documented" state - DWARF_FileName* file_ptr; + DWARF_FileName cur_file; unsigned long seg_offset; unsigned long section; unsigned long last_addr; @@ -371,7 +371,6 @@ struct DWARF_LineState DWARF_LineState() { - file_ptr = nullptr; seg_offset = 0x400000; last_addr = 0; lineInfo_file = 0; -- cgit v0.12