[llvm-dev] lldb subprogram ranges support

David Blaikie via llvm-dev llvm-dev at lists.llvm.org
Tue Jan 5 12:43:11 PST 2021


Thanks Sri.

I've sent out

https://reviews.llvm.org/D94063 and https://reviews.llvm.org/D94064 for
review, which include fixes for the lldb+ranges-on-subprograms issues I
could find so far.

On Wed, Dec 30, 2020 at 6:53 PM Sriraman Tallam <tmsriram at google.com> wrote:

>
>
> On Tue, Dec 29, 2020 at 4:44 PM Sriraman Tallam <tmsriram at google.com>
> wrote:
>
>>
>>
>> On Tue, Dec 29, 2020 at 2:06 PM David Blaikie <dblaikie at gmail.com> wrote:
>>
>>>
>>>
>>> On Wed, Dec 23, 2020 at 7:02 PM Sriraman Tallam <tmsriram at google.com>
>>> wrote:
>>>
>>>>
>>>>
>>>> On Wed, Dec 23, 2020 at 4:46 PM David Blaikie <dblaikie at gmail.com>
>>>> wrote:
>>>>
>>>>> Hey folks,
>>>>>
>>>>> So I've been doing some more testing/implementation work on various
>>>>> address pool reduction strategies previously discussed back in January (
>>>>> http://lists.llvm.org/pipermail/llvm-dev/2020-January/thread.html#138029
>>>>> ).
>>>>>
>>>>> I've committed a -mllvm flag to allow experimenting with the first of
>>>>> these strategies: Always using ranges in DWARFv5 (the flag has no effect
>>>>> pre-v5). Since ranges can use address pool entries, this allows significant
>>>>> address reuse (clang opt split-dwarf 13% reduction in object file size,
>>>>> specifically a reduction in aggregate .rela.debug_addr size from 78MB to
>>>>> 16MB - the lowest this could go is approximately 8MB (this is the size of
>>>>> .rela.debug_line)).
>>>>>
>>>>> It causes one lldb test to
>>>>> fail lldb/test/SymbolFile/DWARF/Output/debug-types-expressions.test which
>>>>> reveals that lldb has some trouble with ranges on DW_TAG_subprograms.
>>>>>
>>>>> Anyone happen to have ideas about what the problem might be? Anyone
>>>>> interested in fixing this? (Jordan, maybe?)
>>>>>
>>>>> Sri: Sounded like you folks had done some testing of Propeller with
>>>>> lldb - and I'd expect it to trip over this same problem, since it'll cause
>>>>> ranges to be used for DW_TAG_subprograms to an even greater degree. Have
>>>>> you come across anything like this?
>>>>>
>>>>
>>>> Not sure David.  I think you tested basic block sections for v5 a while
>>>> back.
>>>>
>>>
>>> I'd looked at the DWARF being well-formed & for the most part efficient
>>> as it can be, given the nature of Basic Block Sections - but I haven't done
>>> any debugger testing with it.
>>>
>>> You mentioned gdb might already be pretty well setup for functions that
>>> are split into multiple chunks because GCC does this under some
>>> circumstances?
>>>
>>> But it looks like lldb might not be so well situated.
>>>
>>>
>>>>   How do I test if this breaks with bbsections?
>>>>
>>>
>>> Test printing out the value of a variable in a function with more than
>>> one section, eg:
>>>
>>> $ ~/dev/llvm/build/default/bin/lldb ./b
>>>
>>> (lldb) target create "./b"
>>>
>>> Current executable set to '/usr/local/google/home/blaikie/dev/scratch/b'
>>> (x86_64).
>>>
>>> (lldb) b main
>>>
>>> Breakpoint 1: where = b`main + 15, address = 0x000000000040112f
>>>
>>> (lldb) start
>>>
>>> *error: *'start' is not a valid command.
>>>
>>> (lldb) r
>>>
>>> Process 1827628 launched: '/usr/local/google/home/blaikie/dev/scratch/b'
>>> (x86_64)
>>>
>>> Process 1827628 stopped
>>>
>>> * thread #1, name = 'b', stop reason = breakpoint 1.1
>>>
>>>     frame #0: 0x000000000040112f b`main at test.cpp:5:7
>>>
>>>    2      int j = 12;
>>>
>>>    3    }
>>>
>>>    4    int main() {
>>>
>>> -> 5      int i = 7;
>>>
>>>    6      if (i)
>>>
>>>    7        f1();
>>>
>>>    8    }
>>>
>>> (lldb) p i
>>>
>>> error: <user expression 0>:1:1: use of undeclared identifier 'i'
>>>
>>> i
>>>
>>> ^
>>>
>>> (lldb) ^D
>>>
>>> $ clang++-tot test.cpp -g -o b
>>>
>>> $ ~/dev/llvm/build/default/bin/lldb ./b
>>>
>>> (lldb) target create "./b"
>>>
>>> Current executable set to '/usr/local/google/home/blaikie/dev/scratch/b'
>>> (x86_64).
>>>
>>> (lldb) b main
>>>
>>> Breakpoint 1: where = b`main + 15 at test.cpp:5:7, address =
>>> 0x000000000040112f
>>>
>>> (lldb) r
>>>
>>> Process 1828108 launched: '/usr/local/google/home/blaikie/dev/scratch/b'
>>> (x86_64)
>>>
>>> p i
>>>
>>> Process 1828108 stopped
>>>
>>> * thread #1, name = 'b', stop reason = breakpoint 1.1
>>>
>>>     frame #0: 0x000000000040112f b`main at test.cpp:5:7
>>>
>>>    2      int j = 12;
>>>
>>>    3    }
>>>
>>>    4    int main() {
>>>
>>> -> 5      int i = 7;
>>>
>>>    6      if (i)
>>>
>>>    7        f1();
>>>
>>>    8    }
>>>
>>> (lldb) p i
>>>
>>> (int) $0 = 0
>>>
>>> (lldb) ^D
>>>
>>> $ cat test.cpp
>>>
>>> void f1() {
>>>
>>>   int j = 12;
>>>
>>> }
>>>
>>> int main() {
>>>
>>>   int i = 7;
>>>
>>>   if (i)
>>>
>>>     f1();
>>>
>>> }
>>>
>>> So, yeah, seems like DW_AT_ranges on a DW_TAG_subprogram is a bit buggy
>>> with lldb & that'll need to be fixed for Propeller to be usable with lldb.
>>> For my "ranges everywhere" feature - nice to fix, but given we/Google/my
>>> use case uses -ffunction-sections, subprogram ranges don't actually ever
>>> get used in that situation (since every function starts at a new relocated
>>> address - subprogram address ranges can't share address pool entries anyway
>>> - so they never get DW_AT_ranges in this case), so I could tweak
>>> ranges-everywhere to not apply to subprogram ranges for now to keep it more
>>> usable/unsurprising.
>>>
>>>
>>>> I can give you a simple program with bb sections that would create a
>>>> lot of ranges. Any pointers? My understanding of DWARF v5 is near zero so
>>>> please bear with me. Thanks.
>>>>
>>>
>>> This applies to DWARFv4 as well, as shown above - sorry for the
>>> confusion there. I happened to be experimenting with DWARFv5 range features
>>> - but it shows lldb has some problems with ranges on subprograms in general
>>> (& even if the ranges only contains a single range (expressed with a range
>>> list, rather than with low/high pc) it still breaks)
>>>
>>
>
> Just one more data point regarding gcc which uses DW_AT_ranges even with
> DW_TAG_subprogram as it independently implements the function splitting
> feature we did in LLVM.  Here is how to generate this with gcc:
>
> #include <stdio.h>
> const int LOOP_BOUND = 200000000;
> __attribute__((noinline))
> static int work(bool b) {
>   if (b) {
>     for (int i=0; i<LOOP_BOUND; ++i) {
>       printf("Hot\n");
>     }
>   } else {
>     for (int i=0; i<LOOP_BOUND; ++i) {
>       printf("Cold\n");
>     }
>   }
>   return 0;
> }
> int main(int argc, char* argv[]) {
>     int result = work((argc > 3));
>     return result;
> }
>
> $ g++ -O2 gccsplit.cc -fprofile-generate
> $ ./a.out > /dev/null
> $ ls *.gcda
> $ g++ -O2 gccsplit.cc -freorder-blocks-and-partition -g -fprofile-use -c
> $ llvm-dwarfdump gccsplit.o
>
> 0x000000ff:   DW_TAG_subprogram
>                 DW_AT_name      ("work")
>                 DW_AT_decl_file ("gccsplit.cc")
>                 DW_AT_decl_line (5)
>                 DW_AT_decl_column       (0x0c)
>                 DW_AT_type      (0x00000053 "int")
>                 DW_AT_ranges    (0x00000000
>                    [0x0000000000000000, 0x000000000000006b)
>                    [0x0000000000000000, 0x000000000000001e))
>                 DW_AT_frame_base        (DW_OP_call_frame_cfa)
>                 DW_AT_GNU_all_call_sites        (true)
>                 DW_AT_sibling   (0x00000234)
>
>
> This is also exactly how LLVM splits functions and generates debug info.
> Probably explains why gdb is able to work with this example.
>
> Thanks
> Sri
>
>
>
>>
>> Thanks David, so I tried this slightly more complicated program with
>> bbsections on LLDB and GDB.  TLDR;  This seems like a LLDB bug and seems
>> fine with GDB.
>>
>> I used a slightly modified example and split the bb sections to be
>> discontiguous FWIW.
>>
>> inline __attribute__((noinline)) void f1(int j) {}
>> int main() {
>>   int i = 7;
>>   if (i) {
>>      int j = 8;
>>      f1(j);
>>   }
>> }
>>
>> $ cat syms.txt
>> main.__part.1
>> _start
>> main
>> _Z2f1i
>> main.__part.2
>>
>> $ /g/tmsriram/Projects_2019/llvm_trunk_upstream/release_build/bin/clang++
>> -fbasic-block-sections=all -g test.cc -O0
>> -Wl,--symbol-ordering-file=syms.txt -fuse-ld=lld
>> $ nm -n a.out
>> 0000000000201640 t main.__part.1
>> 0000000000201660 T _start
>> 0000000000201690 t _dl_relocate_static_pie
>> 00000000002016a0 T main
>> 00000000002016d0 W _Z2f1i
>> 00000000002016d9 t main.__part.2
>>
>> $ gdb ./a.out
>>
>> (gdb) b main
>> Breakpoint 1 at 0x201647: main. (2 locations)
>> (gdb) r
>> Starting program:
>> /g/tmsriram/Projects_2019/github_repo/Examples/bbsections_bug/a.out
>>
>> Breakpoint 1, main () at test.cc:2
>> 2 int main() {
>> ...
>> (gdb) n
>> 4  if (i) {
>> (gdb) p i
>> $3 = 7
>> (gdb) n
>> 5     int j = 8;
>> (gdb) p j
>> $4 = 32767
>> (gdb) n
>> Breakpoint 1, main () at test.cc:6
>> 6     f1(j);
>> (gdb) p j
>> $5 = 8
>>
>> lldb fails like how you said.
>>
>> Thanks
>> Sri
>>
>>
>>
>>
>>
>>>
>>>
>>>>
>>>>
>>>>>
>>>>> Here's a small example:
>>>>>
>>>>> (the test has an inline function to force the output file to have more
>>>>> than one section (otherwise it'll all be in the text section, the CU's
>>>>> low_pc will be relocatable and all the other addresses will be relative to
>>>>> that - so there won't be any benefit to using ranges) and 'main' is the
>>>>> second function, so it starts at an offset relative to the address in the
>>>>> address pool (which will be f2's starting address) and benefit from using
>>>>> ranges to share that address)
>>>>>
>>>>> $ cat test.cpp
>>>>>
>>>>> inline __attribute__((noinline)) void f1() { }
>>>>>
>>>>> void f2() {
>>>>>
>>>>> }
>>>>>
>>>>> int main() {
>>>>>
>>>>>   int i = 7;
>>>>>
>>>>>   f1();
>>>>>
>>>>> }
>>>>> $ ~/dev/llvm/build/default/bin/lldb ./a
>>>>>
>>>>> (lldb) target create "./a"
>>>>>
>>>>> Current executable set to
>>>>> '/usr/local/google/home/blaikie/dev/scratch/always_ranges/a' (x86_64).
>>>>>
>>>>> (lldb) b main
>>>>>
>>>>> Breakpoint 1: where = a`main + 8 at test.cpp:5:7, address =
>>>>> 0x0000000000401128
>>>>>
>>>>> (lldb) r
>>>>>
>>>>> Process 2271305 launched:
>>>>> '/usr/local/google/home/blaikie/dev/scratch/always_ranges/a' (x86_64)
>>>>>
>>>>> p iProcess 2271305 stopped
>>>>>
>>>>> * thread #1, name = 'a', stop reason = breakpoint 1.1
>>>>>
>>>>>     frame #0: 0x0000000000401128 a`main at test.cpp:5:7
>>>>>
>>>>>    2    void f2() {
>>>>>
>>>>>    3    }
>>>>>
>>>>>    4    int main() {
>>>>>
>>>>> -> 5      int i = 7;
>>>>>
>>>>>    6      f1();
>>>>>
>>>>>    7    }
>>>>>
>>>>> (lldb) p i
>>>>>
>>>>> (int) $0 = 0
>>>>>
>>>>> $ ~/dev/llvm/build/default/bin/lldb ./b
>>>>>
>>>>> (lldb) target create "./b"
>>>>>
>>>>> Current executable set to
>>>>> '/usr/local/google/home/blaikie/dev/scratch/always_ranges/b' (x86_64).
>>>>>
>>>>> (lldb) b main
>>>>>
>>>>> Breakpoint 1: where = b`main + 8, address = 0x0000000000401128
>>>>>
>>>>> (lldb) r
>>>>>
>>>>> Process 2271759 launched:
>>>>> '/usr/local/google/home/blaikie/dev/scratch/always_ranges/b' (x86_64)
>>>>>
>>>>> Process 2271759 stopped
>>>>>
>>>>> * thread #1, name = 'b', stop reason = breakpoint 1.1
>>>>>
>>>>>     frame #0: 0x0000000000401128 b`main at test.cpp:5:7
>>>>>
>>>>>    2    void f2() {
>>>>>
>>>>>    3    }
>>>>>
>>>>>    4    int main() {
>>>>>
>>>>> -> 5      int i = 7;
>>>>>
>>>>>    6      f1();
>>>>>
>>>>>    7    }
>>>>>
>>>>> (lldb) p i
>>>>>
>>>>> error: <user expression 0>:1:1: use of undeclared identifier 'i'
>>>>>
>>>>> i
>>>>>
>>>>> ^
>>>>>
>>>>> $ diff <(llvm-dwarfdump-tot a | sed -e "s/0x[0-9a-f]\{8\}//g")
>>>>> <(llvm-dwarfdump-tot b | sed -e "s/0x[0-9a-f]\{8\}//g")
>>>>>
>>>>> 1c1
>>>>>
>>>>> < a:    file format elf64-x86-64
>>>>>
>>>>> ---
>>>>>
>>>>> > b:    file format elf64-x86-64
>>>>>
>>>>> 14c14
>>>>>
>>>>> <               DW_AT_ranges    (indexed (0x0) rangelist =
>>>>>
>>>>> ---
>>>>>
>>>>> >               DW_AT_ranges    (indexed (0x1) rangelist =
>>>>>
>>>>> 31,32c31,32
>>>>>
>>>>> <                 DW_AT_low_pc  (00401120)
>>>>>
>>>>> <                 DW_AT_high_pc (0040113c)
>>>>>
>>>>> ---
>>>>>
>>>>> >                 DW_AT_ranges  (indexed (0x0) rangelist =
>>>>>
>>>>> >                    [00401120, 0040113c))
>>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20210105/688bf2be/attachment.html>


More information about the llvm-dev mailing list