[lldb-dev] Setting breakpoint on file and function name doesn't work as expected.
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 --name ", the 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 = 0x00401114 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 ( --name ) Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names -f ( --file ) 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: 0x: Compile Unit: length = 0x0060 version = 0x0004 abbr_offset = 0x addr_size = 0x08 (next unit at 0x0064) 0x000b: 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 (0x) DW_AT_comp_dir ("/home/kkleine") DW_AT_low_pc (0x00401110) DW_AT_high_pc (0x0040113a) 0x002a: DW_TAG_subprogram DW_AT_low_pc (0x00401110) DW_AT_high_pc (0x0040111b) 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 (0x005c "int") DW_AT_external (true) 0x0043: DW_TAG_subprogram DW_AT_low_pc (0x00401120) DW_AT_high_pc (0x0040113a) 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 (0x005c "int") DW_AT_external (true) 0x005c: 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 = 0x00401114 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 inform
Re: [lldb-dev] Setting breakpoint on file and function name doesn't work as expected.
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 : > 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 --name ", the > 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 = > 0x00401114 > > 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 ( --name ) > Set the breakpoint by function name. Can be repeated multiple > times to make one breakpoint for multiple names > >-f ( --file ) > 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: > 0x: Compile Unit: length = 0x0060 version = 0x0004 abbr_offset > = 0x addr_size = 0x08 (next unit at 0x0064) > > 0x000b: 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 (0x) > DW_AT_comp_dir ("/home/kkleine") > DW_AT_low_pc (0x00401110) > DW_AT_high_pc (0x0040113a) > > 0x002a: DW_TAG_subprogram > DW_AT_low_pc (0x00401110) > DW_AT_high_pc (0x0040111b) > 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 (0x005c "int") > DW_AT_external (true) > > 0x0043: DW_TAG_subprogram > DW_AT_low_pc (0x00401120) > DW_AT_high_pc (0x0040113a) > DW_AT_frame_base (DW_OP_reg6 RBP) > DW_AT_name ("main") > DW_AT_decl_file ("/home/kkl
Re: [lldb-dev] https://reviews.llvm.org/D69273
On 31/10/2019 20:51, Jim Ingham via lldb-dev wrote: It looks like this change is causing problems with swift. I was talking a little bit with Davide about this and it seems like it wasn't obvious how this was designed to work. So here's what this was intended to do (apologies if this is at too basic a level and the issue was something deeper I missed, but anyway this might get us started...) The lldb ValueObject system supports two fairly different kinds of values, live and frozen. The classic example of a live ValueObject is ValueObjectVariable. That ValueObject is backed by an entity in the target, and knows when that entity is valid and not. So it can always try to do "UpdateValueIfNeeded" and that will always return good values. However, there's on complication with this, which is that we also want ValueObjectVariable to be able to answer "IsChanged". That's so in a UI you can mark values that change over a step in red, which is very helpful for following along in a debugging session. So you have to copy the values into host memory, in order to have something to compare against when you stop again. That's why there's this slightly complex dance between host and target memory for the live ValueObjects. The example of a frozen object is the ValueObjectConstResult that is returned from expression evaluation. That value is fixed to a StopID, so the backing entity is only known to be good at that stop id. This is implemented by copying the value into Host memory and fetching it from there when requested. The use case for this is for people like me who have a bad memory. So I can stop somewhere and do: (lldb) expr foo struct baz $1 = { bar = 20 } Then later on when I forget what foo.bar was at that time, I can do: (lldb) expr $1.bar bar = 20 At a first approximation, this leads to the statement that ConstValues should fetch what they fetch when made, and then not offer any information that wasn't gathered when the variable was fetched, and you certainly don't ever want these values to be updated. A little complication arises because I might do: (lldb) expr foo_which_has_a_pointer $1 = ... (lldb) expr *$1->the_pointer If the StopID is the same between the first and second evaluation, then you should follow the pointer into target memory and fetch the value. But if the StopID has changed, then trying to dereference a pointer should be an error. After all, you are now accessing an incoherent object, and if you try to do anything fancier with it than just print some memory (like asking the Swift Language Runtime what this value happens to be) you are very likely to get into trouble. So it's clear we need two different behaviors w.r.t. how we treat live or frozen values. Pavel's change was addressing a failure in ValueObjectChild, and the solution was to move the ValueObjectVariable behavior up to the ValueObject level. But then that means that ValueObjectConstResults are no longer obeying the ConstResult rules. But it seems like the problem really is that we have only one ValueObjectChild class, but child value objects can either be live or frozen, depending on the nature of their Root ValueObject. And this is made a little more complicated by the fact that frozen values only freeze when the stop ID changes. Thanks for the writeup Jim. I haven't managed to dive into the source code yet, but the thing that's not clear to me from this otherwise detailed an understandable explanation is what is the interaction between this ConstResult stuff and the above patch. Superficially, it doesn't sound like that patch should do anything bad here. As the ValueObjectConstResult's data is located in host memory, the patch will compute that its pointer children will be of "load address" type, which sounds like precisely what's needed here. Of course, under the surface, there are plenty of ways this can go wrong, but precisely because of that, it's hard to say what's the right thing to do. Is it that ValueObjectConstResult uses the "address type" field to implement the "are the children valid at this stop ID" logic, and so this patch interferes with that? What's exactly the nature of the crash/misbehavior you were witnessing? pl ___ lldb-dev mailing list lldb-dev@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
Re: [lldb-dev] Setting breakpoint on file and function name doesn't work as expected.
On Mon, 04 Nov 2019 16:16:30 +0100, Konrad Kleine via lldb-dev wrote: > 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 ... > 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. That doc is obsolete, LLDB has this setting by default: (lldb) settings show target.inline-breakpoint-strategy target.inline-breakpoint-strategy (enum) = always It has been changed: https://github.com/llvm/llvm-project/commit/ad6eee639952090684aa84c35218ec327a017ca1 This setting does work but only for the --line option: ==> inc.C <== #include "inc2.C" int main() { func(); } ==> inc2.C <== static volatile int i; static void func() { i++; } $ clang++ -o inc inc.C -Wall -g;lldb ./inc (lldb) target create "./inc" Current executable set to './inc' (x86_64). (lldb) settings set target.inline-breakpoint-strategy headers (lldb) breakpoint set --file inc2.C --line 3 Breakpoint 1: no locations (pending). WARNING: Unable to resolve breakpoint to any actual locations. (lldb) settings set target.inline-breakpoint-strategy always (lldb) breakpoint set --file inc2.C --line 3 Breakpoint 2: where = inc`func() + 4 at inc2.C:3:4, address = 0x00401124 (lldb) _ To make it working also for the -n option will require some fix, maybe some code around lldb/source/Commands/CommandObjectBreakpoint.cpp line 500, dunno. Jan ___ lldb-dev mailing list lldb-dev@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
Re: [lldb-dev] https://reviews.llvm.org/D69273
Sorry, my brain is not working this morning, I answered your question in the review comments… Jim > On Nov 4, 2019, at 7:28 AM, Pavel Labath wrote: > > On 31/10/2019 20:51, Jim Ingham via lldb-dev wrote: >> It looks like this change is causing problems with swift. I was talking a >> little bit with Davide about this and it seems like it wasn't obvious how >> this was designed to work. So here's what this was intended to do >> (apologies if this is at too basic a level and the issue was something >> deeper I missed, but anyway this might get us started...) >> The lldb ValueObject system supports two fairly different kinds of values, >> live and frozen. >> The classic example of a live ValueObject is ValueObjectVariable. That >> ValueObject is backed by an entity in the target, and knows when that entity >> is valid and not. So it can always try to do "UpdateValueIfNeeded" and that >> will always return good values. However, there's on complication with this, >> which is that we also want ValueObjectVariable to be able to answer >> "IsChanged". That's so in a UI you can mark values that change over a step >> in red, which is very helpful for following along in a debugging session. >> So you have to copy the values into host memory, in order to have something >> to compare against when you stop again. That's why there's this slightly >> complex dance between host and target memory for the live ValueObjects. >> The example of a frozen object is the ValueObjectConstResult that is >> returned from expression evaluation. That value is fixed to a StopID, so >> the backing entity is only known to be good at that stop id. This is >> implemented by copying the value into Host memory and fetching it from there >> when requested. >> The use case for this is for people like me who have a bad memory. So I can >> stop somewhere and do: >> (lldb) expr foo >> struct baz $1 = { >> bar = 20 >> } >> Then later on when I forget what foo.bar was at that time, I can do: >> (lldb) expr $1.bar >> bar = 20 >> At a first approximation, this leads to the statement that ConstValues >> should fetch what they fetch when made, and then not offer any information >> that wasn't gathered when the variable was fetched, and you certainly don't >> ever want these values to be updated. >> A little complication arises because I might do: >> (lldb) expr foo_which_has_a_pointer >> $1 = ... >> (lldb) expr *$1->the_pointer >> If the StopID is the same between the first and second evaluation, then you >> should follow the pointer into target memory and fetch the value. But if >> the StopID has changed, then trying to dereference a pointer should be an >> error. After all, you are now accessing an incoherent object, and if you >> try to do anything fancier with it than just print some memory (like asking >> the Swift Language Runtime what this value happens to be) you are very >> likely to get into trouble. >> So it's clear we need two different behaviors w.r.t. how we treat live or >> frozen values. Pavel's change was addressing a failure in ValueObjectChild, >> and the solution was to move the ValueObjectVariable behavior up to the >> ValueObject level. But then that means that ValueObjectConstResults are no >> longer obeying the ConstResult rules. >> But it seems like the problem really is that we have only one >> ValueObjectChild class, but child value objects can either be live or >> frozen, depending on the nature of their Root ValueObject. And this is made >> a little more complicated by the fact that frozen values only freeze when >> the stop ID changes. > > Thanks for the writeup Jim. I haven't managed to dive into the source code > yet, but the thing that's not clear to me from this otherwise detailed an > understandable explanation is what is the interaction between this > ConstResult stuff and the above patch. > > Superficially, it doesn't sound like that patch should do anything bad here. > As the ValueObjectConstResult's data is located in host memory, the patch > will compute that its pointer children will be of "load address" type, which > sounds like precisely what's needed here. > > Of course, under the surface, there are plenty of ways this can go wrong, but > precisely because of that, it's hard to say what's the right thing to do. Is > it that ValueObjectConstResult uses the "address type" field to implement the > "are the children valid at this stop ID" logic, and so this patch interferes > with that? What's exactly the nature of the crash/misbehavior you were > witnessing? > > pl ___ lldb-dev mailing list lldb-dev@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
Re: [lldb-dev] https://reviews.llvm.org/D69273
On 04/11/2019 18:19, Jim Ingham wrote: Sorry, my brain is not working this morning, I answered your question in the review comments… Jim NP, maybe let's continue the discussion there? I find it useful to have the actual code change around.. ___ lldb-dev mailing list lldb-dev@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev