Now that libdw's srclines use a stable sort, we can reliably choose the *last* matching line record for a given address, which should be the innermost where inlines are concerned.
Signed-off-by: Josh Stone <[email protected]> --- libdwfl/ChangeLog | 5 +++++ libdwfl/dwfl_module_getsrc.c | 51 +++++++++++++++++++++++--------------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index b882f2049ca0..7b0ea15f013f 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,8 @@ +2014-12-11 Josh Stone <[email protected]> + + * dwfl_module_getsrc.c (dwfl_module_getsrc): Return the *last* line + record <= addr, rather than returning immediately on matches. + 2014-12-07 Mark Wielaard <[email protected]> * relocate.c (relocate_section): Sanity check section overlap against diff --git a/libdwfl/dwfl_module_getsrc.c b/libdwfl/dwfl_module_getsrc.c index cf8dc0fc2d0a..41cf9753313e 100644 --- a/libdwfl/dwfl_module_getsrc.c +++ b/libdwfl/dwfl_module_getsrc.c @@ -1,5 +1,5 @@ /* Find source location for PC address in module. - Copyright (C) 2005, 2008 Red Hat, Inc. + Copyright (C) 2005, 2008, 2014 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -42,32 +42,35 @@ dwfl_module_getsrc (Dwfl_Module *mod, Dwarf_Addr addr) error = __libdwfl_cu_getsrclines (cu); if (likely (error == DWFL_E_NOERROR)) { - /* Now we look at the module-relative address. */ - addr -= bias; - - /* The lines are sorted by address, so we can use binary search. */ - size_t l = 0, u = cu->die.cu->lines->nlines; - while (l < u) + Dwarf_Lines *lines = cu->die.cu->lines; + size_t nlines = lines->nlines; + if (nlines > 0) { - size_t idx = (l + u) / 2; - if (addr < cu->die.cu->lines->info[idx].addr) - u = idx; - else if (addr > cu->die.cu->lines->info[idx].addr) - l = idx + 1; - else - return &cu->lines->idx[idx]; - } + /* This is guaranteed for us by libdw read_srclines. */ + assert(lines->info[nlines - 1].end_sequence); - if (cu->die.cu->lines->nlines > 0) - assert (cu->die.cu->lines->info - [cu->die.cu->lines->nlines - 1].end_sequence); + /* Now we look at the module-relative address. */ + addr -= bias; - /* If none were equal, the closest one below is what we want. - We never want the last one, because it's the end-sequence - marker with an address at the high bound of the CU's code. */ - if (u > 0 && u < cu->die.cu->lines->nlines - && addr > cu->die.cu->lines->info[u - 1].addr) - return &cu->lines->idx[u - 1]; + /* The lines are sorted by address, so we can use binary search. */ + size_t l = 0, u = nlines - 1; + while (l < u) + { + size_t idx = u - (u - l) / 2; + Dwarf_Line *line = &lines->info[idx]; + if (addr < line->addr) + u = idx - 1; + else if (addr >= line->addr) + l = idx; + } + + /* The last line which is less than or equal to addr is what we want, + except with an end_sequence which can only be strictly equal. */ + Dwarf_Line *line = &lines->info[l]; + if (line->addr == addr + || (! line->end_sequence && line->addr < addr)) + return &cu->lines->idx[l]; + } error = DWFL_E_ADDR_OUTOFRANGE; } -- 2.1.0
