Skip to content

Commit

Permalink
Improved DWARF line number handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
GJDuck committed Jun 25, 2024
1 parent e4b67cd commit 2137b6d
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 45 deletions.
92 changes: 49 additions & 43 deletions src/e9tool/e9dwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,13 @@ typedef struct
long int padding__;
} Dwarf_Die;

struct Range
{
intptr_t lb;
intptr_t ub;
};
typedef std::map<intptr_t, Range> Ranges;

typedef Dwarf *(*dwarf_begin_t)(int fildes, int cmd);
typedef int (*dwarf_end_t)(Dwarf *dwarf);
typedef int (*dwarf_nextcu_t)(Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
uint8_t *address_sizep, uint8_t *offset_sizep);
typedef Dwarf_Die *(*dwarf_offdie_t)(Dwarf *dbg, Dwarf_Off offset,
Dwarf_Die *result);
typedef ptrdiff_t (*dwarf_ranges_t)(Dwarf_Die *die,
ptrdiff_t offset, Dwarf_Addr *basep,
Dwarf_Addr *startp, Dwarf_Addr *endp);
typedef int (*dwarf_getsrclines_t)(Dwarf_Die *cudie, Dwarf_Lines **lines,
size_t *nlines);
typedef int (*dwarf_getsrcfiles_t)(Dwarf_Die *cudie, Dwarf_Files **files,
Expand All @@ -84,7 +74,6 @@ static dwarf_begin_t dwarf_begin = nullptr;
static dwarf_end_t dwarf_end = nullptr;
static dwarf_nextcu_t dwarf_nextcu = nullptr;
static dwarf_offdie_t dwarf_offdie = nullptr;
static dwarf_ranges_t dwarf_ranges = nullptr;
static dwarf_getsrclines_t dwarf_getsrclines = nullptr;
static dwarf_getsrcfiles_t dwarf_getsrcfiles = nullptr;
static dwarf_onesrcline_t dwarf_onesrcline = nullptr;
Expand All @@ -95,6 +84,25 @@ static dwarf_linesrc_t dwarf_linesrc = nullptr;
static dwarf_getsrcdirs_t dwarf_getsrcdirs = nullptr;
static dwarf_errmsg_t dwarf_errmsg = nullptr;

/*
* Check if lines are the same.
*/
static bool sameLine(const Line &line_1, const Line &line_2)
{
if (line_1.line != line_2.line)
return false;
if (line_1.dir == nullptr && line_2.dir != nullptr)
return false;
if (line_1.dir != nullptr && line_2.dir == nullptr)
return false;
if (line_1.dir != nullptr && line_2.dir != nullptr &&
strcmp(line_1.dir, line_2.dir) != 0)
return false;
if (strcmp(line_1.file, line_2.file) != 0)
return false;
return true;
}

/*
* Load a symbol from the library.
*/
Expand All @@ -110,7 +118,8 @@ static void *getSym(void *handle, const char *lib, const char *name)
/*
* Build source line information.
*/
extern void e9tool::buildLines(const ELF *elf, Lines &Ls)
extern void e9tool::buildLines(const ELF *elf, const Instr *Is, size_t size,
Lines &Ls)
{
const char *lib = "libdw.so";
void *handle = dlopen(lib, RTLD_LAZY);
Expand All @@ -122,7 +131,6 @@ extern void e9tool::buildLines(const ELF *elf, Lines &Ls)
dwarf_end = (dwarf_end_t) getSym(handle, lib, "dwarf_end");
dwarf_nextcu = (dwarf_nextcu_t) getSym(handle, lib, "dwarf_nextcu");
dwarf_offdie = (dwarf_offdie_t) getSym(handle, lib, "dwarf_offdie");
dwarf_ranges = (dwarf_ranges_t) getSym(handle, lib, "dwarf_ranges");
dwarf_getsrclines = (dwarf_getsrclines_t)getSym(handle, lib, "dwarf_getsrclines");
dwarf_getsrcfiles = (dwarf_getsrcfiles_t)getSym(handle, lib, "dwarf_getsrcfiles");
dwarf_onesrcline = (dwarf_onesrcline_t) getSym(handle, lib, "dwarf_onesrcline");
Expand Down Expand Up @@ -152,6 +160,7 @@ extern void e9tool::buildLines(const ELF *elf, Lines &Ls)

Dwarf_Off offset = 0, last = 0;
size_t hdr_size;
Lines Tmp;
while (dwarf_nextcu(dbg, offset, &offset, &hdr_size, 0, 0, 0) == 0)
{
Dwarf_Die cudie_obj, *cudie;
Expand All @@ -170,15 +179,6 @@ extern void e9tool::buildLines(const ELF *elf, Lines &Ls)
if (dwarf_getsrcdirs(files, &dirs, &ndirs) != 0)
continue;
const char *dir = (dirs[0] != nullptr? strCache(dirs[0]): nullptr);
Ranges Rs;
ptrdiff_t ptr = 0;
Dwarf_Addr base = 0x0, lb, ub;
while ((ptr = dwarf_ranges(cudie, ptr, &base, &lb, &ub)) != 0)
{
Range r = {(intptr_t)lb, (intptr_t)ub};
Rs.insert({(intptr_t)lb, r});
}
Lines Tmp;
for (size_t i = 0; i < nlines; i++)
{
Dwarf_Line *line = dwarf_onesrcline(lines, i);
Expand All @@ -200,30 +200,36 @@ extern void e9tool::buildLines(const ELF *elf, Lines &Ls)
std::forward_as_tuple((intptr_t)addr, INTPTR_MAX, tmp, file,
(unsigned)lineno));
}
for (auto i = Tmp.begin(), iend = Tmp.end(); i != iend; )
}
for (auto i = Tmp.begin(), iend = Tmp.end(); i != iend; )
{
const Line &line = i->second;
for (++i; i != iend && sameLine(i->second, line); ++i)
;
intptr_t lb = line.lb;
intptr_t ub = (i != iend? i->second.lb: INTPTR_MAX);
if (ub == INTPTR_MAX)
{
const Line &line = i->second;
for (++i; i != iend && i->second.line == line.line; ++i)
;
intptr_t lb = line.lb;
intptr_t ub = (i != iend? i->second.lb: INTPTR_MAX);
auto j = Rs.lower_bound(lb);
if (j == Rs.end() && ub == INTPTR_MAX)
{
bad_range:
warning("failed to find line %u in address range for %s",
line.line, line.file);
continue;
}
if (j != Rs.end())
ub = std::min(ub, j->second.ub);
if (lb >= ub)
goto bad_range;
Ls.emplace(std::piecewise_construct,
std::forward_as_tuple(lb),
std::forward_as_tuple(lb, ub, line.dir, line.file, line.line));
// Alternative method for end-case
ub = lb;
for (ssize_t i = findInstr(Is, size, lb);
i >= 0 && (size_t)i < size && Is[i].address == (size_t)ub;
i++)
ub = Is[i].address + Is[i].size;
}
Ls.emplace(std::piecewise_construct,
std::forward_as_tuple(lb),
std::forward_as_tuple(lb, ub, line.dir, line.file, line.line));
}

#if 0
for (const auto &E: Ls)
{
const Line &L = E.second;
fprintf(stderr, "0x%lx..0x%lx [%zu]: %s:%u\n", L.lb, L.ub,
L.ub - L.lb, L.file, L.line);
}
#endif

dwarf_end(dbg);
dlclose(handle);
Expand Down
2 changes: 1 addition & 1 deletion src/e9tool/e9tool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1408,7 +1408,7 @@ int main_2(int argc, char **argv)
if (option_fs)
buildFs(&elf, Is.data(), Is.size(), elf.targets, elf.fs);
if (option_lines)
buildLines(&elf, elf.lines);
buildLines(&elf, Is.data(), Is.size(), elf.lines);
if (option_dump_all)
dumpInfo(option_output, Is.data(), Is.size(), elf.targets,
elf.bbs, elf.fs);
Expand Down
3 changes: 2 additions & 1 deletion src/e9tool/e9tool.h
Original file line number Diff line number Diff line change
Expand Up @@ -2515,7 +2515,8 @@ extern void buildBBs(const ELF *elf, const Instr *Is, size_t size,
const Targets &targets, BBs &bbs);
extern void buildFs(const ELF *elf, const Instr *Is, size_t size,
const Targets &targets, Fs &fs);
extern void buildLines(const ELF *elf, Lines &Ls);
extern void buildLines(const ELF *elf, const Instr *Is, size_t size,
Lines &Ls);
extern intptr_t getSymbol(const ELF *elf, const char *symbol);
extern void NO_RETURN error(const char *msg, ...);
extern void warning(const char *msg, ...);
Expand Down

0 comments on commit 2137b6d

Please sign in to comment.