Bug 903804

Summary: libdwarf Segmentation fault on incomplete location
Product: [Fedora] Fedora Reporter: Josh Stone <jistone>
Component: libdwarfAssignee: Tom Hughes <tom>
Status: CLOSED CURRENTRELEASE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 18CC: mjw, panemade, tom
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2013-02-05 03:16:05 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Patch to pass correct offset_size
none
Patch to decode DW_OP_GNU_const_type correctly none

Description Josh Stone 2013-01-24 21:04:36 UTC
Description of problem:
There's a crash in libdwarf after finding a "hole" in location info.  This can be seen using dwarfdump on libc.so.

Version-Release number of selected component (if applicable):
libdwarf-tools-20121130-1.fc18.x86_64
glibc-debuginfo-2.16-28.fc18.x86_64

How reproducible:
100%

Steps to Reproduce:
1. Install libdwarf-tools and glibc-debuginfo.
2. Run: dwarfdump /usr/lib/debug/lib64/libc-2.16.so.debug
  
Actual results:
Segmentation fault

Expected results:
No crash, but optionally warn about the location gap.

Additional info:

Here's the context from gdb:
> < 3><0x00000358>        DW_TAG_inlined_subroutine
>                           DW_AT_abstract_origin       <0x00000265>
>                           DW_AT_entry_pc              0x00021cd0
>                           DW_AT_ranges                0x000001e0
> 		ranges: 3 at .debug_ranges offset 480 (0x000001e0) (48 bytes)
> 			[ 0] range entry    0x00000080 0x000000a3
> 			[ 1] range entry    0x000000a6 0x000000b2
> 			[ 2] range end      0x00000000 0x00000000
>                           DW_AT_call_file             0x00000001 ../sysdeps/x86_64/multiarch/init-arch.c
>                           DW_AT_call_line             0x0000007c
> < 4><0x0000036b>          DW_TAG_formal_parameter
>                             DW_AT_abstract_origin       <0x0000027c>
> 
> Program received signal SIGSEGV, Segmentation fault.
> _dwarf_error (dbg=dbg@entry=0x85e7e0, error=error@entry=0xc3, errval=errval@entry=230)
>     at dwarf_error.c:372
> 372	        *error = errptr;
> (gdb) bt
> #0  _dwarf_error (dbg=dbg@entry=0x85e7e0, error=error@entry=0xc3, errval=errval@entry=230)
>     at dwarf_error.c:372
> #1  0x000000311d217734 in _dwarf_get_locdesc (dbg=0x85e7e0, loc_block=0x7fffffffc8c0, 
>     address_size=8, offset_size=<optimized out>, version_stamp=<optimized out>, lowpc=128, 
>     highpc=5764608622545862656, error=0xc3) at dwarf_loc.c:605
> #2  0x0000c30000000000 in ?? ()
> #3  0x5000010000000000 in ?? ()
> #4  0x00000000000000c3 in ?? ()
> #5  0x0000000000000101 in ?? ()
> #6  0x00003b6c28030009 in ?? ()
> #7  0x0000000000000000 in ?? ()

... not a good backtrace, so the stack may be corrupt.

Binutils' readelf complains too, but doesn't crash:
> $ readelf -w /usr/lib/debug/lib64/libc-2.16.so.debug >/dev/null
> readelf: Warning: There is a hole [0x1b5ddc - 0x1b5e04] in .debug_loc section.

Elfutils' eu-readelf doesn't complain or crash.  I haven't compared yet to see if it figured out other data there, or just was silent about it.

Comment 1 Josh Stone 2013-01-24 22:18:44 UTC
> $ readelf -w /usr/lib/debug/lib64/libc-2.16.so.debug >/dev/null
> readelf: Warning: There is a hole [0x1b5ddc - 0x1b5e04] in .debug_loc section.

As far as I can tell, the hole reported by readelf has nothing to do with the DIE locations where dwarfdump actually crashed.  With the way that backtrace looks, memory may have been corrupted much before that.

So FWIW, readelf's loc dump in that region is:
>     001b5d93 00000000000f3bb0 00000000000f3bfb (DW_OP_reg5 (rdi))
>     001b5d93 00000000000f3bfb 00000000000f3c4c (DW_OP_GNU_entry_value: (DW_OP_reg5 (rdi)); DW_OP_stack_value)
>     001b5d93 <End of list>
>     001b5dcc <End of list>
>     001b5e04 00000000000f3bb0 00000000000f3bd8 (DW_OP_reg1 (rdx))
>     001b5e04 00000000000f3bd8 00000000000f3be2 (DW_OP_GNU_entry_value: (DW_OP_reg1 (rdx)); DW_OP_stack_value)
>     001b5e04 00000000000f3be2 00000000000f3bfb (DW_OP_reg1 (rdx))
>     001b5e04 00000000000f3bfb 00000000000f3c4c (DW_OP_GNU_entry_value: (DW_OP_reg1 (rdx)); DW_OP_stack_value)
>     001b5e04 <End of list>

And eu-readelf on the same:
>  [1b5d93]  +000000000000000000..+0x000000000000004b [   0] reg5
>            +0x000000000000004b..+0x000000000000009c [   0] GNU_entry_value:
>        [   0] reg5
>                                                   [   3] stack_value
>  [1b5dcc]  empty list
>  [1b5ddc]  <UNUSED GARBAGE> ... 40 bytes ...
>  [1b5e04]  +000000000000000000..+0x0000000000000028 [   0] reg1
>            +0x0000000000000028..+0x0000000000000032 [   0] GNU_entry_value:
>        [   0] reg1
>                                                   [   3] stack_value
>            +0x0000000000000032..+0x000000000000004b [   0] reg1
>            +0x000000000000004b..+0x000000000000009c [   0] GNU_entry_value:
>        [   0] reg1
>                                                   [   3] stack_value

I can't find any DIE that references location 1b5ddc, but there is one that references the empty 1b5dcc before it.  So my guess is that's the location which is actually corrupt.

In case anyone is crazy and/or knows enough to manually decode debug_loc, here's the hexdump around that offset:
>   0x001b5d90 00000000 00000000 0000004b 00000000 ...........K....
>   0x001b5da0 00000001 00554b00 00000000 00009c00 .....UK.........
>   0x001b5db0 00000000 00000400 f301559f 00000000 ..........U.....
>   0x001b5dc0 00000000 00000000 00000000 00000000 ................
>   0x001b5dd0 00000000 00000000 00000000 01005400 ..............T.
>   0x001b5de0 00000000 0000004b 00000000 00000003 .......K........
>   0x001b5df0 00549308 00000000 00000000 00000000 .T..............
>   0x001b5e00 00000000 00000000 00000000 28000000 ............(...

Comment 2 Mark Wielaard 2013-01-24 23:35:11 UTC
eu-readelf might be right. This is most likely garbage data if no DIE references those indexes (.loc_debug entries only really make sense if you know the CU from which they are referenced to get the base address, and eu-readelf prints that warning if it cannot find any DIE attribute referencing an index range).

What is the DIE/attribute referencing 1b5dcc?
That might also not be an error. Quoting the DWARF4 spec:
"A location list containing only an end of list entry describes an object that exists in the source code but not in the executable program."

Comment 3 Josh Stone 2013-01-25 00:18:44 UTC
With -fstack-protector-all, dwarfdump is caught only slightly earlier:

> < 4><0x0000036b>          DW_TAG_formal_parameter
>                             DW_AT_abstract_origin       <0x0000027c>
> *** stack smashing detected ***: /home/jistone/fedora-dist/libdwarf/dwarf-20121130/dwarfdump2/dwarfdump terminated
> 
> Program received signal SIGSEGV, Segmentation fault.
> x86_64_fallback_frame_state (context=0x7fffffffb8f0, context=0x7fffffffb8f0, fs=0x7fffffffb9e0)
>     at ./md-unwind-support.h:53
> 53	  if (*(unsigned char *)(pc+0) == 0x48
> (gdb) bt
> #0  x86_64_fallback_frame_state (context=0x7fffffffb8f0, context=0x7fffffffb8f0, fs=0x7fffffffb9e0)
>     at ./md-unwind-support.h:53
> #1  uw_frame_state_for (context=context@entry=0x7fffffffb8f0, fs=fs@entry=0x7fffffffb9e0)
>     at ../../../libgcc/unwind-dw2.c:1187
> #2  0x000000311ee0ff6c in _Unwind_Backtrace (trace=0x311d706a80 <backtrace_helper>, 
>     trace_argument=0x7fffffffbba0) at ../../../libgcc/unwind.inc:290
> #3  0x000000311d706c16 in __GI___backtrace (array=array@entry=0x7fffffffbd80, size=size@entry=64)
>     at ../sysdeps/x86_64/backtrace.c:109
> #4  0x000000311d6755b5 in __libc_message (do_abort=do_abort@entry=2, 
>     fmt=fmt@entry=0x311d7787ff "*** %s ***: %s terminated\n")
>     at ../sysdeps/unix/sysv/linux/libc_fatal.c:177
> #5  0x000000311d70a697 in __GI___fortify_fail (
>     msg=msg@entry=0x311d7787e7 "stack smashing detected") at fortify_fail.c:31
> #6  0x000000311d70a660 in __stack_chk_fail () at stack_chk_fail.c:28
> #7  0x00007ffff7dd7698 in _dwarf_get_locdesc (dbg=0x661800, loc_block=0x7fffffffc5e0, 
>     address_size=8, offset_size=<optimized out>, version_stamp=<optimized out>, lowpc=128, 
>     highpc=195, error=0x101) at dwarf_loc.c:655
> #8  0x5000010000000000 in ?? ()
> #9  0x00000000000000c3 in ?? ()
> #10 0x0000000000000101 in ?? ()
> #11 0x00003b6c28030009 in ?? ()
> #12 0x0000000000000000 in ?? ()

Comment 4 Josh Stone 2013-01-25 00:29:14 UTC
(In reply to comment #2)
> eu-readelf might be right. This is most likely garbage data if no DIE
> references those indexes (.loc_debug entries only really make sense if you
> know the CU from which they are referenced to get the base address, and
> eu-readelf prints that warning if it cannot find any DIE attribute
> referencing an index range).
> 
> What is the DIE/attribute referencing 1b5dcc?

 [2a4554]    subprogram
             external             (flag_present) Yes
             name                 (strp) "accept4"
             decl_file            (data1) 1
             decl_line            (data1) 30
             prototyped           (flag_present) Yes
             type                 (ref4) [2a4161]
             low_pc               (addr) +0x00000000000f3bb0
             high_pc              (addr) +0x00000000000f3c4c
             frame_base           (exprloc) 
              [   0] call_frame_cfa
             GNU_all_call_sites   (flag_present) Yes
             sibling              (ref4) [2a473d]
 [2a4575]      formal_parameter
               name                 (string) "fd"
               decl_file            (data1) 1
               decl_line            (data1) 30
               type                 (ref4) [2a4161]
               location             (sec_offset) location list [1b5d93]
 [2a4583]      formal_parameter
               name                 (strp) "addr"
               decl_file            (data1) 1
               decl_line            (data1) 30
               type                 (ref4) [2a43da]
               location             (sec_offset) location list [1b5dcc]

> That might also not be an error. Quoting the DWARF4 spec:
> "A location list containing only an end of list entry describes an object
> that exists in the source code but not in the executable program."

Maybe so, but an empty entry followed by unused data sounds like it got truncated somehow.

Comment 5 Mark Wielaard 2013-01-25 04:48:44 UTC
For reference that describes the argument "addr" in this function:

int
accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
{
  if (SINGLE_THREAD_P)
    return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);

  int oldtype = LIBC_CANCEL_ASYNC ();

  int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
                               flags);

  LIBC_CANCEL_RESET (oldtype);

  return result;
}

Note how addr on itself is never used in the function, only addr.__sockaddr__ is.

The type is described as:

 [2a43da]    typedef
             name                 (strp) "__SOCKADDR_ARG"
             decl_file            (data1) 9
             decl_line            (data1) 92
             type                 (ref4) [2a43e5]

 [2a43e5]    union_type
             byte_size            (data1) 8
             decl_file            (data1) 9
             decl_line            (data1) 91
             sibling              (ref4) [2a447d]
 [2a43ed]      member
               name                 (strp) "__sockaddr__"
               decl_file            (data1) 9
               decl_line            (data1) 91
               type                 (ref4) [2a42d4]
[...]

So what is used in the function is just the first member of the union with type, a pointer type:

 [2a42d4]    pointer_type
             byte_size            (data1) 8
             type                 (ref4) [2a429f]

 [2a429f]    structure_type
             name                 (strp) "sockaddr"
             byte_size            (data1) 16
             decl_file            (data1) 6
             decl_line            (data1) 148
             sibling              (ref4) [2a42c4]
 [2a42ab]      member
               name                 (strp) "sa_family"
               decl_file            (data1) 6
               decl_line            (data1) 150
               type                 (ref4) [2a4294]
               data_member_location (data1) 0
 [2a42b7]      member
               name                 (strp) "sa_data"
               decl_file            (data1) 6
               decl_line            (data1) 151
               type                 (ref4) [2a42c4]
               data_member_location (data1) 2

Comment 6 Mark Wielaard 2013-01-25 09:02:00 UTC
This compiled with gcc -Wall -g -O2 -c foo.c will produce the same:

# define __SOCKADDR_ALLTYPES \
  __SOCKADDR_ONETYPE (sockaddr) \
  __SOCKADDR_ONETYPE (sockaddr_at) \
  __SOCKADDR_ONETYPE (sockaddr_ax25) \
  __SOCKADDR_ONETYPE (sockaddr_dl) \
  __SOCKADDR_ONETYPE (sockaddr_eon) \
  __SOCKADDR_ONETYPE (sockaddr_in) \
  __SOCKADDR_ONETYPE (sockaddr_in6) \
  __SOCKADDR_ONETYPE (sockaddr_inarp) \
  __SOCKADDR_ONETYPE (sockaddr_ipx) \
  __SOCKADDR_ONETYPE (sockaddr_iso) \
  __SOCKADDR_ONETYPE (sockaddr_ns) \
  __SOCKADDR_ONETYPE (sockaddr_un) \
  __SOCKADDR_ONETYPE (sockaddr_x25)

# define __SOCKADDR_ONETYPE(type) struct type *__restrict __##type##__;
typedef union { __SOCKADDR_ALLTYPES
              } __SOCKADDR_ARG __attribute__ ((__transparent_union__));
# undef __SOCKADDR_ONETYPE
# define __SOCKADDR_ONETYPE(type) const struct type *__restrict __##type##__;
typedef union { __SOCKADDR_ALLTYPES
              } __CONST_SOCKADDR_ARG __attribute__ ((__transparent_union__));
# undef __SOCKADDR_ONETYPE

int
accept4 (int fd, __SOCKADDR_ARG addr)
{
  int result = addr.__sockaddr__ != 0;

  if (fd != 0)
    result = addr.__sockaddr__ == 0;

  return result;
}

$ gcc -Wall -g -O2 -c foo.c

$ eu-readelf --debug-dump=loc foo.o


DWARF section [ 7] '.debug_loc' at offset 0x2b0:
 [     0]  empty list
 [    10]  <UNUSED GARBAGE> ... 40 bytes ...
 [    38]  .text+000000000000000000 <accept4>...text+0x000000000000000c <accept4+0xc> [   0] breg4 0
                                                  [   2] lit0
                                                  [   3] ne
                                                  [   4] const1u 255
                                                  [   6] and
                                                  [   7] stack_value
           .text+0x000000000000000c <accept4+0xc>...text+0x000000000000000e <accept4+0xe> [   0] reg0
           .text+0x000000000000000e <accept4+0xe>...text+0x0000000000000018 <accept4+0x18> [   0] breg4 0
                                                  [   2] lit0
                                                  [   3] ne
                                                  [   4] const1u 255
                                                  [   6] and
                                                  [   7] stack_value
           .text+0x0000000000000018 <accept4+0x18>...text+0x0000000000000019 [   0] reg0

$ eu-readelf --debug-dump=info foo.o

[...]
 [   15f]    subprogram
             external             (flag_present) Yes
             name                 (strp) "accept4"
             decl_file            (data1) 1
             decl_line            (data1) 26
             prototyped           (flag_present) Yes
             type                 (ref4) [   1ab]
             low_pc               (addr) .text+000000000000000000 <accept4>
             high_pc              (addr) .text+0x0000000000000019
             frame_base           (exprloc) 
              [   0] call_frame_cfa
             GNU_all_call_sites   (flag_present) Yes
             sibling              (ref4) [   1ab]
 [   180]      formal_parameter
               name                 (string) "fd"
               decl_file            (data1) 1
               decl_line            (data1) 26
               type                 (ref4) [   1ab]
               location             (exprloc) 
                [   0] reg5
 [   18c]      formal_parameter
               name                 (strp) "addr"
               decl_file            (data1) 1
               decl_line            (data1) 26
               type                 (ref4) [    bc]
               location             (sec_offset) location list [     0]
 [   19b]      variable
               name                 (strp) "result"
               decl_file            (data1) 1
               decl_line            (data1) 28
               type                 (ref4) [   1ab]
               location             (sec_offset) location list [    38]
[...]

Comment 7 Tom Hughes 2013-01-25 09:20:47 UTC
Using an unoptimised build from git (which has only minimal changes over the RPM version) the reported crash is a bit more sane:

#0  0x000000000046900a in _dwarf_decode_s_leb128 (leb128=
    0xc0 <Address 0xc0 out of bounds>, leb128_length=0x7fffffffb8e8)
    at dwarf_leb.c:120
#1  0x0000000000463da5 in _dwarf_get_locdesc (dbg=0x6a1960, loc_block=
    0x7fffffffba10, address_size=8, offset_size=1216, version_stamp=4 '\004', 
    lowpc=128, highpc=257, error=0x7fffffffbb50) at dwarf_loc.c:567
#2  0x0000000000000000 in ?? ()

Stack gives out at that point, so does look trashed.

Comment 8 Tom Hughes 2013-01-25 09:49:38 UTC
The problem is with the handling of DW_OP_GNU_implicit_pointer which seems to be new code in the latest release.

Specifically offset_size (and hence iplen) is 192 bytes, which is insane, and means we wind up reading 192 bytes into a Dwarf_Unsigned variable, overrunning it and trashing the stack.

Comment 9 Tom Hughes 2013-01-25 10:15:41 UTC
The full trace just before we do the read which trashes the stack is:

#0  _dwarf_get_locdesc (dbg=0x6a1960, loc_block=0x7fffffffba10, address_size=
    8, offset_size=1216, version_stamp=4 '\004', lowpc=128, highpc=257, error=
    0x7fffffffbb50) at dwarf_loc.c:558
#1  0x0000000000464ac8 in dwarf_loclist_n (attr=0x6b2600, llbuf_out=
    0x7fffffffbb40, listlen_out=0x7fffffffbb48, error=0x7fffffffbb50)
    at dwarf_loc.c:969
#2  0x000000000042c7df in get_location_list (dbg=0x6a1960, die=0x6a8df0, attr=
    0x6b2600, locstr="") at print_die.cc:2513
#3  0x000000000042934b in print_attribute (dbg=0x6a1960, die=0x6a8df0, attr=2, 
    attr_in=0x6b2600, print_information=true, die_indent_level=4, hsrcfiles=
    ...) at print_die.cc:1795
#4  0x0000000000424d8d in print_one_die (hdie=..., print_information=true, 
    die_indent_level=4, hsrcfiles=..., ignore_die_printed_flag=false)
    at print_die.cc:900
#5  0x0000000000423119 in print_die_and_children_internal (hin_die_in=..., 
    is_info=1, dieVec=std::vector of length 5, capacity 8 = {...}, 
    indent_level=@0x7fffffffcedc: 4, hsrcfiles=...) at print_die.cc:594
#6  0x00000000004233c4 in print_die_and_children_internal (hin_die_in=..., 
    is_info=1, dieVec=std::vector of length 5, capacity 8 = {...}, 
    indent_level=@0x7fffffffcedc: 4, hsrcfiles=...) at print_die.cc:654
#7  0x00000000004233c4 in print_die_and_children_internal (hin_die_in=..., 
    is_info=1, dieVec=std::vector of length 5, capacity 8 = {...}, 
    indent_level=@0x7fffffffcedc: 4, hsrcfiles=...) at print_die.cc:654
#8  0x00000000004233c4 in print_die_and_children_internal (hin_die_in=..., 
    is_info=1, dieVec=std::vector of length 5, capacity 8 = {...}, 
    indent_level=@0x7fffffffcedc: 4, hsrcfiles=...) at print_die.cc:654
#9  0x00000000004233c4 in print_die_and_children_internal (hin_die_in=..., 
    is_info=1, dieVec=std::vector of length 5, capacity 8 = {...}, 
    indent_level=@0x7fffffffcedc: 4, hsrcfiles=...) at print_die.cc:654
#10 0x0000000000422a90 in print_die_and_children (in_die_in=..., is_info=1, 
    hsrcfiles=...) at print_die.cc:483
#11 0x0000000000422730 in print_one_die_section (dbg=0x6a1960, is_info=true)
    at print_die.cc:441
#12 0x00000000004214b4 in print_infos (dbg=0x6a1960, is_info=true)
    at print_die.cc:224
#13 0x00000000004078c3 in process_one_file (elf=0x69f680, file_name=
    "/usr/lib/debug/lib64/libc-2.16.so.debug", archive=0, config_file_data=
    0x69cb20 <config_file_data>) at dwarfdump.cc:973
#14 0x0000000000405614 in main (argc=2, argv=0x7fffffffd308)
    at dwarfdump.cc:373

Comment 10 Tom Hughes 2013-01-25 10:17:11 UTC
So offset_size is coming from cucontext->cc_length in the parent routine (dwarf_loclist_n) and seems to vary from run to run.

Comment 11 Tom Hughes 2013-01-25 10:56:20 UTC
Looks like the problem is just that the caller should be passing cc_length_size not cc_length which is a latent bug that DW_OP_GNU_implicit_pointer support has exposed as there is only one other case in _dwarf_get_locdesc which uses the offset_size value.

I have a patch which I'll run by upstream...

Comment 12 Josh Stone 2013-01-25 16:55:39 UTC
So Tom, the issue you've found and possibly fixed is completely unrelated to the garbage loc data?  Interesting... I'd still like to figure that out too, but it's easier if the actual crash here is something fixed independently.  Thanks for tracking it down so quickly!

Comment 13 Tom Hughes 2013-01-25 17:01:02 UTC
Looks like it, yes. With my patch the dump still doesn't finish - it terminates with this error:

< 2><0x000000cd>      DW_TAG_formal_parameter
                        DW_AT_name                  x
                        DW_AT_decl_file             0x00000001 ../sysdeps/ieee754/dbl-64/wordsize-64/s_frexp.c
                        DW_AT_decl_line             0x00000023
                        DW_AT_type                  <0x0000002d>
                        
./dwarfdump ERROR:  dwarf_loclist:  DW_DLE_LOC_EXPR_BAD (128)

CU Name = ../sysdeps/ieee754/dbl-64/wordsize-64/s_frexp.c
CU Producer = GNU C 4.7.2 20121109 (Red Hat 4.7.2-8) -mtune=generic -march=x86-64 -g -O3 -std=gnu99 -fgnu89-inline -fasynchronous-unwind-tables -fmerge-all-constants -frounding-math -fPIC
DIE OFF = 0x000000cd GOFF = 0x000531a0, Low PC = 0x000351f0, High PC = 0x00035266

Upstream have just confirmed my diagnosis of the crash and will probably be doing a new release to fix this.

Comment 14 Josh Stone 2013-01-25 17:57:25 UTC
Hmm, that's yet another different location.  eu-readelf gives that as:

>  [ 5317f]    subprogram
>              external             (flag_present) Yes
>              name                 (strp) "__frexp"
>              decl_file            (data1) 1
>              decl_line            (data1) 35
>              prototyped           (flag_present) Yes
>              type                 (ref4) [ 53100]
>              low_pc               (addr) +0x00000000000351f0
>              high_pc              (addr) +0x0000000000035266
>              frame_base           (exprloc) 
>               [   0] call_frame_cfa
>              GNU_all_call_sites   (flag_present) Yes
>              sibling              (ref4) [ 53255]
>  [ 531a0]      formal_parameter
>                name                 (string) "x"
>                decl_file            (data1) 1
>                decl_line            (data1) 35
>                type                 (ref4) [ 53100]
>                location             (sec_offset) location list [ 30ccd]

And that location list:
>  [ 30ccd]  +000000000000000000..+0x0000000000000048 [   0] reg17
>            +0x000000000000004d..+0x0000000000000054 [   0] reg17
>            +0x0000000000000054..+0x000000000000005c [   0] GNU_regval_type 17 0x2d
>                                                   [   3] GNU_const_type [    2d] 8 byte block: 00 00 00 00 00 00 50 43
>                                                   [  14] mul
>                                                   [  15] stack_value
>            +0x000000000000005c..+0x0000000000000076 [   0] reg17

Is there something in that which libdwarf doesn't understand?  At least grepping the source, it appears that it's supposed to handle those GNU forms ok.

Comment 15 Tom Hughes 2013-01-25 20:15:09 UTC
Yes - the problem is DW_OP_GNU_const_type which is only processing the first of it's three arguments, so the it tries to decode the others as ops.

Comment 16 Josh Stone 2013-01-25 21:05:12 UTC
FYI, I filed bug 904252 for the empty+garbage loc at 0x1b5dcc.

That particular loc seems to have been a red herring to libdwarf's issues, but it would still be nice to make sure libdwarf and dwarfdump don't barf too badly when they get to that point.

Comment 17 Tom Hughes 2013-01-25 22:38:58 UTC
Yes I've already got a patch for the second problem, which I've sent to upstream, and with that applied dwarfdump runs to completion.

I'll attach the patches here as well.

Comment 18 Tom Hughes 2013-01-25 22:39:47 UTC
Created attachment 687737 [details]
Patch to pass correct offset_size

Comment 19 Tom Hughes 2013-01-25 22:40:55 UTC
Created attachment 687738 [details]
Patch to decode DW_OP_GNU_const_type correctly

Comment 20 Josh Stone 2013-01-26 00:44:31 UTC
Oh, now I see that DW_OP_GNU_const_type actually wasn't in 20121130 at all. :(  But I tried your patches on libdwarf's git master, and indeed it passes through libc now.

For "fun", I also tried a survey of all the other debug files on my system using this script:

find /usr/lib/debug -type f -name \*.debug | while read file; do 
  ./dwarfdump "$file" >/dev/null || echo exit $? on "$file"
done

This got pretty far, but it's not entirely successful.  Let me know if you'd rather have new bug reports instead of working in this bug.

There were a lot like this "dwarf_whatform unexpected value":
> $ ./dwarfdump /usr/lib/debug/bin/rpm.debug
> 
> .debug_info
> 
> COMPILE_UNIT<header overall offset = 0x00000000>:
> < 0><0x0000000b>  DW_TAG_partial_unit
>                     DW_AT_stmt_list             0x00000000
>                     
> ./dwarfdump:  dwarf_whatform unexpected value
> 
> CU Name = <unknown>
> CU Producer = "<CU-missing-DW_AT_producer>"
> DIE OFF = 0x0000000b GOFF = 0x0000000b, Low PC = 0x00000000, High PC = 0x00000000

A few "DW_DLE_NOT_REF_FORM" like:
> $ ./dwarfdump /usr/lib/debug/usr/lib64/libdwarf.so.0.0.debug
...
> < 1><0x00000045>    DW_TAG_base_type
>                       DW_AT_byte_size             0x00000008
>                       DW_AT_encoding              DW_ATE_signed
>                       DW_AT_name                  long long int
> 
> .debug_line: line number info for a single cu
> 
> ./dwarfdump ERROR:  dwarf_srclines:  DW_DLE_NOT_REF_FORM(226) (226)
> 
> CU Name = <unknown>
> CU Producer = "<CU-missing-DW_AT_producer>"
> DIE OFF = 0x00000045 GOFF = 0x00000045, Low PC = 0x00000000, High PC = 0x00000000

The rest of the errors looked similar, so hopefully these are representative.  And of course this only checked the debuginfo that I happen to have installed already.

Comment 21 Josh Stone 2013-01-26 00:46:32 UTC
Oh, also vmlinux since that wasn't picked up by my "find" above.

> $ ./dwarfdump /usr/lib/debug/lib/modules/3.7.2-204.fc18.x86_64/vmlinux
...
> COMPILE_UNIT<header overall offset = 0x05462d83>:
> < 0><0x0000000b>  DW_TAG_compile_unit
>                     DW_AT_stmt_list             0x0054b712
>                     DW_AT_low_pc                0xffffffff81611ad0
>                     DW_AT_high_pc               0xffffffff81611c3c
>                     DW_AT_name                  arch/x86/lib/csum-copy_64.S
>                     DW_AT_comp_dir              /usr/src/debug////////kernel-3.7.fc18/linux-3.7.2-204.fc18.x86_64
>                     DW_AT_producer              GNU AS 2.23.51.0.1
>                     DW_AT_language              DW_LANG_Mips_Assembler
> 
> 
> arange starts at 0xffffffff81611ad0, length of 0x0000016c, cu_die_offset = 0x05462d8e
> arange end
> .debug_frame
> 
> ./dwarfdump ERROR:  dwarf_get_fde_list:  DW_DLE_FRAME_AUGMENTATION_UNKNOWN(195) (195)

Comment 22 Fedora Update System 2013-01-26 14:33:24 UTC
libdwarf-20121130-2.fc18 has been submitted as an update for Fedora 18.
https://admin.fedoraproject.org/updates/libdwarf-20121130-2.fc18

Comment 23 Tom Hughes 2013-01-26 14:52:15 UTC
I've pushed libdwarf-20121130-2.fc18 to fix the first two issues - this is a combination of backported patches and my fixes because the new upstream release involves an ABI change so I will only put that in rawhide and will need to coordinate with the dependent packages. There is a scratch build of the new release here:

http://koji.fedoraproject.org/koji/taskinfo?taskID=4904418

If you could open new bugs for the other three issues then that would be very helpful...

Comment 24 Fedora Update System 2013-01-27 10:26:27 UTC
libdwarf-20130126-1.fc18 has been submitted as an update for Fedora 18.
https://admin.fedoraproject.org/updates/libdwarf-20130126-1.fc18

Comment 25 Tom Hughes 2013-01-27 10:37:43 UTC
Upstream found a way to avoid the ABI break and did another release, so I have pushed that release for F18 now.

Comment 26 Fedora Update System 2013-01-28 14:55:18 UTC
Package libdwarf-20130126-1.fc18:
* should fix your issue,
* was pushed to the Fedora 18 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing libdwarf-20130126-1.fc18'
as soon as you are able to.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2013-1572/libdwarf-20130126-1.fc18
then log in and leave karma (feedback).

Comment 27 Josh Stone 2013-01-28 21:55:37 UTC
Looks good - karma given.

I'll file separate bugs for the other errors.

Comment 28 Fedora Update System 2013-02-05 03:16:09 UTC
libdwarf-20130126-1.fc18 has been pushed to the Fedora 18 stable repository.  If problems still persist, please make note of it in this bug report.