summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Kulaychuk <igor.kulaychuk@gmail.com>2017-09-27 16:32:39 +0300
committerJan Vorlicek <janvorli@microsoft.com>2017-09-27 15:32:39 +0200
commit9509fc86a50ad107ee4d601e917cf072f135aa5e (patch)
treeed61d7ff53cf086920dd586eace8d575ba930e4b
parent863625426be65b96f2a3c085fc049cfcd2f1a82a (diff)
downloadcoreclr-9509fc86a50ad107ee4d601e917cf072f135aa5e.tar.gz
coreclr-9509fc86a50ad107ee4d601e917cf072f135aa5e.tar.bz2
coreclr-9509fc86a50ad107ee4d601e917cf072f135aa5e.zip
[GDBJIT] Provide full file names in generated DWARF (#14172)
* Fix compile unit info Provide full path to source in SequencePoints for GDBJIT Use source file and directory path for compile unit info in DWARF instead of module name. * Add a class for building Directory Table and File Table * Fix code inconsistencies and add comments
-rw-r--r--src/ToolBox/SOS/NETCore/SymbolReader.cs2
-rw-r--r--src/vm/gdbjit.cpp265
-rw-r--r--src/vm/gdbjit.h10
3 files changed, 200 insertions, 77 deletions
diff --git a/src/ToolBox/SOS/NETCore/SymbolReader.cs b/src/ToolBox/SOS/NETCore/SymbolReader.cs
index e0fcdb517d..7a4bb52102 100644
--- a/src/ToolBox/SOS/NETCore/SymbolReader.cs
+++ b/src/ToolBox/SOS/NETCore/SymbolReader.cs
@@ -539,7 +539,7 @@ namespace SOS
DebugInfo debugInfo = new DebugInfo();
debugInfo.lineNumber = point.StartLine;
- debugInfo.fileName = GetFileName(openedReader.Reader.GetString(openedReader.Reader.GetDocument(point.Document).Name));
+ debugInfo.fileName = openedReader.Reader.GetString(openedReader.Reader.GetDocument(point.Document).Name);
debugInfo.ilOffset = point.Offset;
points.Add(debugInfo);
}
diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp
index 9557b0bf3e..9dbf9df1a2 100644
--- a/src/vm/gdbjit.cpp
+++ b/src/vm/gdbjit.cpp
@@ -674,7 +674,7 @@ const int DebugStringCount = sizeof(DebugStrings) / sizeof(DebugStrings[0]);
/* Static data for .debug_abbrev */
const unsigned char AbbrevTable[] = {
1, DW_TAG_compile_unit, DW_CHILDREN_yes,
- DW_AT_producer, DW_FORM_strp, DW_AT_language, DW_FORM_data2, DW_AT_name, DW_FORM_strp,
+ DW_AT_producer, DW_FORM_strp, DW_AT_language, DW_FORM_data2, DW_AT_name, DW_FORM_strp, DW_AT_comp_dir, DW_FORM_strp,
DW_AT_stmt_list, DW_FORM_sec_offset, 0, 0,
2, DW_TAG_base_type, DW_CHILDREN_no,
@@ -772,6 +772,7 @@ struct __attribute__((packed)) DebugInfoCU
uint32_t m_prod_off;
uint16_t m_lang;
uint32_t m_cu_name;
+ uint32_t m_cu_dir;
uint32_t m_line_num;
} debugInfoCU = {
#ifdef FEATURE_GDBJIT_LANGID_CS
@@ -2479,9 +2480,7 @@ void NotifyGdb::OnMethodPrepared(MethodDesc* methodDescPtr)
SString modName = mod->GetFile()->GetPath();
StackScratchBuffer scratch;
const char* szModName = modName.GetUTF8(scratch);
- const char *szModulePath, *szModuleFile;
- SplitPathname(szModName, szModulePath, szModuleFile);
-
+ const char* szModuleFile = SplitFilename(szModName);
int length = MultiByteToWideChar(CP_UTF8, 0, szModuleFile, -1, NULL, 0);
if (length == 0)
@@ -2508,7 +2507,7 @@ void NotifyGdb::OnMethodPrepared(MethodDesc* methodDescPtr)
if (isListedModule(wszModuleFile))
{
- bool bEmitted = EmitDebugInfo(elfBuilder, methodDescPtr, pCode, codeSize, szModuleFile);
+ bool bEmitted = EmitDebugInfo(elfBuilder, methodDescPtr, pCode, codeSize);
bNotify = bNotify || bEmitted;
}
#ifdef FEATURE_GDBJIT_SYMTAB
@@ -2661,7 +2660,7 @@ bool NotifyGdb::EmitSymtab(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, P
}
#endif // FEATURE_GDBJIT_SYMTAB
-bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize, const char *szModuleFile)
+bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize)
{
unsigned int thunkIndexBase = elfBuilder.GetSectionCount();
@@ -2750,13 +2749,26 @@ bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr
return false;
}
+ const char *cuPath = "";
+
/* Build .debug_line section */
- if (!BuildLineTable(dbgLine, pCode, codeSize, symInfo, symInfoLen))
+ if (!BuildLineTable(dbgLine, pCode, codeSize, symInfo, symInfoLen, cuPath))
{
return false;
}
- DebugStrings[1] = szModuleFile;
+ // Split full path to compile unit into file name and directory path
+ const char *fileName = SplitFilename(cuPath);
+ int dirLen = fileName - cuPath;
+ NewArrayHolder<char> dirPath;
+ if (dirLen != 0)
+ {
+ dirPath = new char[dirLen];
+ memcpy(dirPath, DebugStrings[1], dirLen - 1);
+ dirPath[dirLen - 1] = '\0';
+ }
+ DebugStrings[1] = fileName;
+ DebugStrings[2] = dirPath ? (const char *)dirPath : "";
/* Build .debug_str section */
if (!BuildDebugStrings(dbgStr, pTypeMap, method))
@@ -2770,6 +2782,9 @@ bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr
return false;
}
+ DebugStrings[1] = "";
+ DebugStrings[2] = "";
+
for (int i = 0; i < method.GetCount(); ++i)
{
method[i]->lines = nullptr;
@@ -2893,12 +2908,13 @@ void NotifyGdb::MethodPitched(MethodDesc* methodDescPtr)
}
/* Build the DWARF .debug_line section */
-bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines)
+bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines,
+ const char * &cuPath)
{
MemBuf fileTable, lineProg;
/* Build file table */
- if (!BuildFileTable(fileTable, lines, nlines))
+ if (!BuildFileTable(fileTable, lines, nlines, cuPath))
return false;
/* Build line info program */
if (!BuildLineProg(lineProg, startAddr, codeSize, lines, nlines))
@@ -2906,85 +2922,193 @@ bool NotifyGdb::BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, Sym
return false;
}
- buf.MemSize = sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize + lineProg.MemSize;
+ buf.MemSize = sizeof(DwarfLineNumHeader) + fileTable.MemSize + lineProg.MemSize;
buf.MemPtr = new char[buf.MemSize];
/* Fill the line info header */
DwarfLineNumHeader* header = reinterpret_cast<DwarfLineNumHeader*>(buf.MemPtr.GetValue());
memcpy(buf.MemPtr, &LineNumHeader, sizeof(DwarfLineNumHeader));
- header->m_length = buf.MemSize - sizeof(uint32_t);
- header->m_hdr_length = sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize - 2 * sizeof(uint32_t) - sizeof(uint16_t);
- buf.MemPtr[sizeof(DwarfLineNumHeader)] = 0; // this is for missing directory table
+ header->m_length = buf.MemSize - sizeof(header->m_length);
+
+ // Set m_hdr_field to the number of bytes following the m_hdr_field field to the beginning of the first byte of
+ // the line number program itself.
+ header->m_hdr_length = sizeof(DwarfLineNumHeader)
+ - sizeof(header->m_length)
+ - sizeof(header->m_version)
+ - sizeof(header->m_hdr_length)
+ + fileTable.MemSize;
+
/* copy file table */
- memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + 1, fileTable.MemPtr, fileTable.MemSize);
+ memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader), fileTable.MemPtr, fileTable.MemSize);
/* copy line program */
- memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + 1 + fileTable.MemSize, lineProg.MemPtr, lineProg.MemSize);
+ memcpy(buf.MemPtr + sizeof(DwarfLineNumHeader) + fileTable.MemSize, lineProg.MemPtr, lineProg.MemSize);
return true;
}
-/* Buid the source files table for DWARF source line info */
-bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines)
+// A class for building Directory Table and File Table (in .debug_line section) from a list of files
+class NotifyGdb::FileTableBuilder
{
- NewArrayHolder<const char*> files = nullptr;
- unsigned nfiles = 0;
+ int m_capacity;
- /* GetValue file names and replace them with indices in file table */
- files = new const char*[nlines];
- if (files == nullptr)
- return false;
- for (unsigned i = 0; i < nlines; ++i)
- {
- if (lines[i].fileName[0] == 0)
- continue;
- const char *filePath, *fileName;
- SplitPathname(lines[i].fileName, filePath, fileName);
+ NewArrayHolder< NewArrayHolder<char> > m_dirs;
+ int m_dirs_count;
- /* if this isn't first then we already added file, so adjust index */
- lines[i].fileIndex = (nfiles) ? (nfiles - 1) : (nfiles);
+ struct FileEntry
+ {
+ const char* path;
+ const char* name;
+ int dir;
+ };
+ NewArrayHolder<FileEntry> m_files;
+ int m_files_count;
- bool found = false;
- for (int j = 0; j < nfiles; ++j)
+ int FindDir(const char *name) const
+ {
+ for (int i = 0; i < m_dirs_count; ++i)
{
- if (strcmp(fileName, files[j]) == 0)
- {
- found = true;
- break;
- }
+ if (strcmp(m_dirs[i], name) == 0)
+ return i;
}
+ return -1;
+ }
- /* add new source file */
- if (!found)
+ int FindFile(const char *path) const
+ {
+ for (int i = 0; i < m_files_count; ++i)
{
- files[nfiles++] = fileName;
+ if (strcmp(m_files[i].path, path) == 0)
+ return i;
}
+ return -1;
}
- /* build file table */
- unsigned totalSize = 0;
+public:
- for (unsigned i = 0; i < nfiles; ++i)
+ FileTableBuilder(int capacity) :
+ m_capacity(capacity),
+ m_dirs(new NewArrayHolder<char>[capacity]),
+ m_dirs_count(0),
+ m_files(new FileEntry[capacity]),
+ m_files_count(0)
{
- totalSize += strlen(files[i]) + 1 + 3;
}
- totalSize += 1;
- buf.MemSize = totalSize;
- buf.MemPtr = new char[buf.MemSize];
+ int Add(const char *path)
+ {
+ // Already exists?
+ int i = FindFile(path);
+ if (i != -1)
+ return i;
+
+ if (m_files_count >= m_capacity)
+ return -1;
+
+ // Add new file entry
+ m_files[m_files_count].path = path;
+ const char *filename = SplitFilename(path);
+ m_files[m_files_count].name = filename;
+ int dirLen = filename - path;
+ if (dirLen == 0)
+ {
+ m_files[m_files_count].dir = 0;
+ return m_files_count++;
+ }
+
+ // Construct directory path
+ NewArrayHolder<char> dirName = new char[dirLen + 1];
+ int delimiterDelta = dirLen == 1 ? 0 : 1; // Avoid empty dir entry when file is at Unix root /
+ memcpy(dirName, path, dirLen - delimiterDelta);
+ dirName[dirLen - delimiterDelta] = '\0';
+
+ // Try to find existing directory entry
+ i = FindDir(dirName);
+ if (i != -1)
+ {
+ m_files[m_files_count].dir = i + 1;
+ return m_files_count++;
+ }
+
+ // Create new directory entry
+ if (m_dirs_count >= m_capacity)
+ return -1;
+
+ m_dirs[m_dirs_count++] = dirName.Extract();
+
+ m_files[m_files_count].dir = m_dirs_count;
+ return m_files_count++;
+ }
- /* copy collected file names */
- char *ptr = buf.MemPtr;
- for (unsigned i = 0; i < nfiles; ++i)
+ void Build(MemBuf& buf)
{
- strcpy(ptr, files[i]);
- ptr += strlen(files[i]) + 1;
- // three LEB128 entries which we don't care
- *ptr++ = 0;
- *ptr++ = 0;
+ unsigned totalSize = 0;
+
+ // Compute buffer size
+ for (unsigned i = 0; i < m_dirs_count; ++i)
+ totalSize += strlen(m_dirs[i]) + 1;
+ totalSize += 1;
+
+ char cnv_buf[16];
+ for (unsigned i = 0; i < m_files_count; ++i)
+ {
+ int len = Leb128Encode(static_cast<uint32_t>(m_files[i].dir), cnv_buf, sizeof(cnv_buf));
+ totalSize += strlen(m_files[i].name) + 1 + len + 2;
+ }
+ totalSize += 1;
+
+ // Fill the buffer
+ buf.MemSize = totalSize;
+ buf.MemPtr = new char[buf.MemSize];
+
+ char *ptr = buf.MemPtr;
+
+ for (unsigned i = 0; i < m_dirs_count; ++i)
+ {
+ strcpy(ptr, m_dirs[i]);
+ ptr += strlen(m_dirs[i]) + 1;
+ }
+ // final zero byte for directory table
*ptr++ = 0;
+
+ for (unsigned i = 0; i < m_files_count; ++i)
+ {
+ strcpy(ptr, m_files[i].name);
+ ptr += strlen(m_files[i].name) + 1;
+
+ // Index in directory table
+ int len = Leb128Encode(static_cast<uint32_t>(m_files[i].dir), cnv_buf, sizeof(cnv_buf));
+ memcpy(ptr, cnv_buf, len);
+ ptr += len;
+
+ // Two LEB128 entries which we don't care
+ *ptr++ = 0;
+ *ptr++ = 0;
+ }
+ // final zero byte
+ *ptr = 0;
}
- // final zero byte
- *ptr = 0;
+};
+
+/* Buid the source files table for DWARF source line info */
+bool NotifyGdb::BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines, const char * &cuPath)
+{
+ FileTableBuilder fileTable(nlines);
+
+ cuPath = "";
+ for (unsigned i = 0; i < nlines; ++i)
+ {
+ const char* fileName = lines[i].fileName;
+
+ if (fileName[0] == '\0')
+ continue;
+
+ if (*cuPath == '\0') // Use first non-empty filename as compile unit
+ cuPath = fileName;
+
+ lines[i].fileIndex = fileTable.Add(fileName);
+ }
+
+ fileTable.Build(buf);
return true;
}
@@ -3244,6 +3368,7 @@ bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMe
offset += sizeof(DebugInfoCU);
diCU->m_prod_off = 0;
diCU->m_cu_name = strlen(DebugStrings[0]) + 1;
+ diCU->m_cu_dir = diCU->m_cu_name + strlen(DebugStrings[1]) + 1;
{
auto iter = pTypeMap->Begin();
while (iter != pTypeMap->End())
@@ -3404,22 +3529,18 @@ bool NotifyGdb::BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize,
return true;
}
-/* Split full path name into directory & file names */
-void NotifyGdb::SplitPathname(const char* path, const char*& pathName, const char*& fileName)
+/* Split file name part from the full path */
+const char * NotifyGdb::SplitFilename(const char* path)
{
- char* pSlash = strrchr(path, '/');
-
- if (pSlash != nullptr)
+ // Search for the last directory delimiter (Windows or Unix)
+ const char *pSlash = nullptr;
+ for (const char *p = path; *p != '\0'; p++)
{
- *pSlash = 0;
- fileName = ++pSlash;
- pathName = path;
- }
- else
- {
- fileName = path;
- pathName = nullptr;
+ if (*p == '/' || *p == '\\')
+ pSlash = p;
}
+
+ return pSlash ? pSlash + 1 : path;
}
/* ELF 32bit header */
diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h
index f7267ad2a1..6cfe52c36d 100644
--- a/src/vm/gdbjit.h
+++ b/src/vm/gdbjit.h
@@ -340,6 +340,7 @@ class Elf_Builder;
class NotifyGdb
{
public:
+ class FileTableBuilder;
static void MethodPrepared(MethodDesc* methodDescPtr);
static void MethodPitched(MethodDesc* methodDescPtr);
template <typename PARENT_TRAITS>
@@ -422,7 +423,7 @@ private:
#ifdef FEATURE_GDBJIT_SYMTAB
static bool EmitSymtab(Elf_Builder &, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize);
#endif // FEATURE_GDBJIT_SYMTAB
- static bool EmitDebugInfo(Elf_Builder &, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize, const char *szModuleFile);
+ static bool EmitDebugInfo(Elf_Builder &, MethodDesc* methodDescPtr, PCODE pCode, TADDR codeSize);
static bool BuildSymbolTableSection(MemBuf& buf, PCODE addr, TADDR codeSize, int methodCount,
NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount,
@@ -432,14 +433,15 @@ private:
static bool BuildDebugAbbrev(MemBuf& buf);
static bool BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method);
static bool BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t dieOffset);
- static bool BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines);
- static bool BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines);
+ static bool BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines,
+ const char * &cuPath);
+ static bool BuildFileTable(MemBuf& buf, SymbolsInfo* lines, unsigned nlines, const char * &cuPath);
static bool BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines);
static void IssueSetAddress(char*& ptr, PCODE addr);
static void IssueEndOfSequence(char*& ptr);
static void IssueSimpleCommand(char*& ptr, uint8_t command);
static void IssueParamCommand(char*& ptr, uint8_t command, char* param, int param_len);
- static void SplitPathname(const char* path, const char*& pathName, const char*& fileName);
+ static const char* SplitFilename(const char* path);
static bool CollectCalledMethods(CalledMethod* pCM, TADDR nativeCode, FunctionMemberPtrArrayHolder &method,
NewArrayHolder<Elf_Symbol> &symbolNames, int &symbolCount);
};