[lldb-dev] Setting breakpoint on file and function name doesn't work as expected.

Konrad Kleine via lldb-dev lldb-dev at lists.llvm.org
Mon Nov 4 07:16:30 PST 2019


I read the LLDB troubleshooting page [1] and found interesting quotes:

> When setting breakpoints in implementation source files (.c, cpp, cxx,
.m, .mm, etc), LLDB by
> default will only search for compile units whose filename matches.
> [...]
>   % echo "settings set target.inline-breakpoint-strategy always" >>
~/.lldbinit
> This tells LLDB to always look in all compile units and search for
breakpoint locations
> by file and line even if the implementation file doesn’t match. Setting
breakpoints in header
> files always searches all compile units because inline functions are
commonly defined in
> header files and often cause multiple breakpoints to have source line
information that matches
> many header file paths.

In my email before I did this

$ lldb -x -b -o "breakpoint set --file foo.h --name foo" ./a.out

I now added the breakpoint strategy and ran the above command without the
-x in order to pick up
the LLDB init code. Still no luck.

[1]: https://lldb.llvm.org/use/troubleshooting.html#troubleshooting

Am Mo., 4. Nov. 2019 um 13:56 Uhr schrieb Konrad Kleine <kkleine at redhat.com
>:

> Hello,
>
> I noticed this behavior for LLDB under Linux when setting a breakpoint on
> a file and a function name:
>
> When doing "breakpoint set --file <filename> --name <function-name>", the
> <filename> is that of the compile unit (CU) and not necessarily where the
> function is defined. This is not what an end-user expects.
>
> Take this simple example program:
>
> $ cat foo.h
> int foo(){ return 42; }
>
> $ cat main.c
> #include "foo.h"
> int main(){return foo();}
>
> $ clang -g main.c
>
> As you can see, the function foo is defined in foo.h so it seems natural
> to set a breakpoint on foo.h, doesn't it?
>
> $ lldb -x -b -o "breakpoint set --file foo.h --name foo" ./a.out
> (lldb) target create "./a.out"
> Current executable set to './a.out' (x86_64).
> (lldb) breakpoint set --file foo.h --name foo
> Breakpoint 1: no locations (pending).
> WARNING:  Unable to resolve breakpoint to any actual locations.
>
> Apparently, LLDB cannot find the symbol like this. Let's try the only
> other file that we have in the project:
>
> $ lldb -x -b -o "breakpoint set --file main.c --name foo" ./a.out
> (lldb) target create "./a.out"
> Current executable set to './a.out' (x86_64).
> (lldb) breakpoint set --file main.c --name foo
> Breakpoint 1: where = a.out`foo + 4 at foo.h:1:12, address =
> 0x0000000000401114
>
> Isn't that remarkable? LLDB uses main.c as the file to search in but then
> finds it in foo.h.
>
> Let's recall what the parameters --file and --name mean:
>
>        -n <function-name> ( --name <function-name> )
>             Set the breakpoint by function name.  Can be repeated multiple
> times to make one breakpoint for multiple names
>
>        -f <filename> ( --file <filename> )
>             Specifies the source file in which to set this breakpoint.
> Note, by default lldb only looks for files that are #included if they use
> the standard include file extensions.  To
>             set breakpoints on .c/.cpp/.m/.mm files that are #included,
> set target.inline-breakpoint-strategy to "always".
>
> Let's check if setting the target.inline-breakpoint strategy to "always"
> changes something:
>
> $ lldb -x -b  -o "settings set target.inline-breakpoint-strategy always"
> -o "breakpoint set --file foo.h --name foo" ./a.out
> (lldb) target create "./a.out"
> Current executable set to './a.out' (x86_64).
> (lldb) settings set target.inline-breakpoint-strategy always
> (lldb) breakpoint set --file foo.h --name foo
> Breakpoint 1: no locations (pending).
> WARNING:  Unable to resolve breakpoint to any actual locations.
>
> No, it didn't change anything.
>
> The only evidence for my assumption that LLDB uses the CU's name for
> --file is the DWARF dump:
>
> $ llvm-dwarfdump a.out
> a.out: file format ELF64-x86-64
>
> .debug_info contents:
> 0x00000000: Compile Unit: length = 0x00000060 version = 0x0004 abbr_offset
> = 0x0000 addr_size = 0x08 (next unit at 0x00000064)
>
> 0x0000000b: DW_TAG_compile_unit
>               DW_AT_producer ("clang version 8.0.0 (Fedora 8.0.0-3.fc30)")
>               DW_AT_language (DW_LANG_C99)
>               DW_AT_name ("main.c")
>               DW_AT_stmt_list (0x00000000)
>               DW_AT_comp_dir ("/home/kkleine")
>               DW_AT_low_pc (0x0000000000401110)
>               DW_AT_high_pc (0x000000000040113a)
>
> 0x0000002a:   DW_TAG_subprogram
>                 DW_AT_low_pc (0x0000000000401110)
>                 DW_AT_high_pc (0x000000000040111b)
>                 DW_AT_frame_base (DW_OP_reg6 RBP)
>                 DW_AT_name ("foo")
>                 DW_AT_decl_file ("/home/kkleine/./foo.h")
>                 DW_AT_decl_line (1)
>                 DW_AT_type (0x0000005c "int")
>                 DW_AT_external (true)
>
> 0x00000043:   DW_TAG_subprogram
>                 DW_AT_low_pc (0x0000000000401120)
>                 DW_AT_high_pc (0x000000000040113a)
>                 DW_AT_frame_base (DW_OP_reg6 RBP)
>                 DW_AT_name ("main")
>                 DW_AT_decl_file ("/home/kkleine/main.c")
>                 DW_AT_decl_line (2)
>                 DW_AT_type (0x0000005c "int")
>                 DW_AT_external (true)
>
> 0x0000005c:   DW_TAG_base_type
>                 DW_AT_name ("int")
>                 DW_AT_encoding (DW_ATE_signed)
>                 DW_AT_byte_size (0x04)
>
> As you can see, the DWARF is very small and simply. The function foo has a
> DW_AT_decl_file which is probably used to report the breakpoint location
> but for the actual filtering, it seems as if the CU is crucial for the
> --file argument.
>
> The only reasonable implementation for --file to me seems to be when
> combined with the line number:
>
> $ lldb -x -b  -o "breakpoint set --file foo.h --line 1" ./a.out
> (lldb) target create "./a.out"
> Current executable set to './a.out' (x86_64).
> (lldb) breakpoint set --file foo.h --line 1
> Breakpoint 1: where = a.out`foo + 4 at foo.h:1:12, address =
> 0x0000000000401114
>
> This works as expected.
>
> For myself I think that the --file --name combination works not like an
> end-user expects because in bigger projects you typically look at the
> definition of foo and want to pause, when execution reaches this. You don't
> care if a function is inlined or in which CU the function is located.
> Moreover I think the DWARF actually supports more than enough information
> with the DW_TAG_subprogram DIE's attributes for the file and line number.
> Enough to filter by file and line number.
>
> IMHO we should come up with a very strong argument to justify that --file
> limits by a CU's DW_AT_name. To me the only reasonable argument is speed.
> But speed doesn't justify such a drastic limitation. Shouldn't we rather
> change what --file currently does and keep the old behavior when using --cu
> instead of --file?
>
> - Konrad
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20191104/940520c3/attachment-0001.html>


More information about the lldb-dev mailing list