Found by John Mellor-Crummey.

The reason this bug wasn't found earlier is because gcc fixes
minimum_instr_len and max_ops_per_instr to 1 for all architectures
(in theory max_ops_per_instr could be overridden, but I didn't find
any architecture that does). And op_index always seems zero (it looks
like it is really only for special VLWI architectures).

So in all cases I saw it means that:

op_addr_advance = minimum_instr_len * ((op_index + op_advance)
                                       / max_ops_per_instr)
                = 1 * ((0 + op_advance) / 1)
                = op_advance

Completely masking the bug.

The libdw dwarf_getsrclines.c implementation does get this right.
Because it doesn't care about the data representation and so does
the calculation directly.

Signed-off-by: Mark Wielaard <m...@klomp.org>
---
 src/ChangeLog | 5 +++++
 src/readelf.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 068c87b..2d525e6 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2018-04-16  Mark Wielaard  <m...@klomp.org>
+
+       * readelf.c (print_debug_line_section). In advance_pc, advance
+       using op_addr_advance, not op_advance.
+
 2018-04-14  Mark Wielaard  <m...@klomp.org>
 
        * readelf.c (attr_callback): Only show errors when not silent.
diff --git a/src/readelf.c b/src/readelf.c
index 8c0ef6c..45fc826 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -6971,7 +6971,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, 
GElf_Ehdr *ehdr,
       {
        op_addr_advance = minimum_instr_len * ((op_index + op_advance)
                                               / max_ops_per_instr);
-       address += op_advance;
+       address += op_addr_advance;
        show_op_index = (op_index > 0 ||
                         (op_index + op_advance) % max_ops_per_instr > 0);
        op_index = (op_index + op_advance) % max_ops_per_instr;
-- 
1.8.3.1

Reply via email to