[lldb-dev] Breakpoint + callback performance ... Can it be faster?

Roman Popov via lldb-dev lldb-dev at lists.llvm.org
Mon Feb 13 11:50:14 PST 2017


Thank you very much Greg and Pavel for help!

I will probably need another months or so to work on my variable tracing
stuff. I don't see any additional roadblocks yet.

2017-02-13 22:11 GMT+03:00 Greg Clayton <gclayton at apple.com>:

> Clang just doesn't currently know where to look for the standard headers.
> Not sure if this is a top level code only bug or not. I know the expression
> parser can include common C headers on Darwin. Not sure if any includes
> work on linux. Try importing <stdio.h> and see how that goes?
>
> The better way to do what you want is to write a shared library, save it
> to "/tmp/liba.so" and then load it at runtime:
>
> (lldb) process load /tmp/liba.so
>
> This will load a shared library with all of the top level code you want
> into your current program, then you can call any functions in that shared
> library as well using expressions that you need.
>
> If you feel you still need to use the expression parser, then a few tips
> on the expression parser when not in top level code mode:
> - C++ lambda functions that don't capture anything can be cast to function
> pointer types and used as static callbacks.
> - Any variable you define that is prefixed with a '$' will become a global
> variable and persist beyond your expression (assign a function callback
> from C++ lambda, and you have a callback you can now use.
> - Any type you declare that is prefixed with a '$' will persist beyond
> that expression and be available for future expressions.
> - Any type returned as the result type of an expression will have its type
> available
>
> Greg
>
> On Feb 13, 2017, at 6:00 AM, Roman Popov via lldb-dev <
> lldb-dev at lists.llvm.org> wrote:
>
> Thats nice! But how to enable C++?:
>
> (lldb) expr --top-level --
> Enter expressions, then terminate with an empty line to evaluate:
> 1 #include <iostream>
> 2 void HOOK() { std::cout << "in hook\n"; }
> 3
>
> error: 'iostream' file not found
>
>
> 2017-02-13 16:46 GMT+03:00 Pavel Labath <labath at google.com>:
>
>> Try this for size:
>>
>>
>> $ bin/lldb /tmp/a.out
>> (lldb) target create "/tmp/a.out"
>> Current executable set to '/tmp/a.out' (x86_64).
>> (lldb) b main
>> Breakpoint 1: where = a.out`main + 4 at a.cc:6, address =
>> 0x0000000000400531
>> (lldb) pr la
>> Process 22550 launched: '/tmp/a.out' (x86_64)
>> Process 22550 stopped
>> * thread #1, name = 'a.out', stop reason = breakpoint 1.1
>>     frame #0: 0x0000000000400531 a.out`main at a.cc:6
>>    3   void (* volatile hook)();
>>    4
>>    5   int main() {
>> -> 6    printf("before\n");
>>    7    if(hook) hook();
>>    8    printf("after\n");
>>    9   }
>> (lldb) expr --top-level -- void HOOK() { (int)printf("in hook\n"); }
>> (lldb) expr hook = &HOOK
>> (void (*volatile)()) $0 = 0x00007ffff7ff5030
>> (lldb) c
>> Process 22550 resuming
>> before
>> in hook
>> after
>> Process 22550 exited with status = 0 (0x00000000)
>> (lldb)
>>
>>
>> On 13 February 2017 at 13:38, Roman Popov <ripopov at gmail.com> wrote:
>> > Yes, it would fit. I can even insert hooks manually, like:
>> >
>> >  std::function<void()> instrumentation_hook = []{ /*dear lldb script,
>> please
>> > insert your code here*/ }
>> >
>> > instrumentation_hook(); // run instrumentation, by default does nothing.
>> >
>> >
>> > Is there an easy way to compile some code in lldb and assign to
>> > instrumentation_hook ?
>> >
>> >
>> > 2017-02-13 16:33 GMT+03:00 Pavel Labath <labath at google.com>:
>> >>
>> >> Making the code persist is easy - that's sort of what expr --top-level
>> >> does.
>> >>
>> >> The tricky part is getting your code to execute. When you evaluate
>> >> expressions interactively, we manually modify the registers (PC being
>> >> the most important one) to point to the code you want to execute. If
>> >> you want it to happen automatically at runtime, you would have to
>> >> insert a jump instruction somewhere. The problem is, that can't
>> >> usually be done without overwriting a couple of instructions of
>> >> original code, which means you then have to somehow simulate the
>> >> effects of the overwritten instructions. And there's always a danger
>> >> that you will overwrite a jump target and things will blow up when
>> >> someone tries to jump there. The way this is normally done is that you
>> >> have the compiler insert hooks into your code during compilation, that
>> >> you can then intercept if necessary. I am not sure if that would fit
>> >> your use case.
>> >>
>> >> pl
>> >>
>> >>
>> >>
>> >> On 13 February 2017 at 13:13, Roman Popov <ripopov at gmail.com> wrote:
>> >> > Thanks Pavel, you are correct. This was the direction I thought to
>> >> > investigate, but I didnt done my homework yet.
>> >> >
>> >> > Yes, dynamic instrumentation is what I want. Looks like both lldb and
>> >> > gdb do
>> >> > not allow this directly.
>> >> >
>> >> > As GDB doc says "After execution, the compiled code is removed from
>> gdb
>> >> > and
>> >> > any new types or variables you have defined will be deleted."
>> >> >
>> >> > Do you know why it is the case? Why cannot my generated code persist?
>> >> >
>> >> >
>> >> > Looks like technically it is possible. For example you can allocate
>> >> > memory
>> >> > for generated code on heap.
>> >> >
>> >> > GDB does not even allow me to define a new function. But for data
>> >> > dynamic
>> >> > allocation works perfectly fine:
>> >> >
>> >> >
>> >> > Example:
>> >> >
>> >> > #include <stdio.h>
>> >> >
>> >> > char message[1000] = "test message\n";
>> >> >
>> >> > int main() {
>> >> >     char *msg = message;
>> >> >
>> >> >     for (int i = 0; i < 5; i++)
>> >> >         printf("%s\n", msg);
>> >> >
>> >> >     return 0;
>> >> > }
>> >> >
>> >> >
>> >> >
>> >> > gdb session:
>> >> >
>> >> > (gdb) break main.c:8
>> >> > Breakpoint 1 at 0x400536: file main.c, line 8.
>> >> > (gdb) run
>> >> > Starting program: /home/ripopov/work/test_c_inject/a.out
>> >> >
>> >> > Breakpoint 1, main () at main.c:8
>> >> > 8           for (int i = 0; i < 5; i++)
>> >> > (gdb) compile code
>> >> >>char *str;
>> >> >>str = (char *) malloc(3);
>> >> >>str[0] = 'T';
>> >> >>str[1] = '\n';
>> >> >>str[2] = 0;
>> >> >>msg = str;
>> >> >>end
>> >> > (gdb) c
>> >> > Continuing.
>> >> > T
>> >> >
>> >> > T
>> >> >
>> >> > T
>> >> >
>> >> > T
>> >> >
>> >> > T
>> >> >
>> >> > [Inferior 1 (process 96445) exited normally]
>> >> > (gdb)
>> >> >
>> >> >
>> >> >
>> >> >
>> >> > 2017-02-13 13:56 GMT+03:00 Pavel Labath <labath at google.com>:
>> >> >>
>> >> >> Every time you use the "expr" command, we compile a tiny c++ code
>> >> >> snippet inject it into the target process and execute it. If you
>> type
>> >> >> "log enable lldb expr" you should be able to follow how exactly that
>> >> >> works. You can use pretty much any c++ construct in the expression
>> >> >> including declaring variables/types:
>> >> >> (lldb) expr -- char s[]="qwerty"; for(int i=0; i < sizeof s; ++i)
>> >> >> printf("%d: %c\n", i, s[i]);
>> >> >> 0: q
>> >> >> 1: w
>> >> >> 2: e
>> >> >> 3: r
>> >> >> 4: t
>> >> >> 5: y
>> >> >> 6:
>> >> >>
>> >> >>
>> >> >> So, if your question is "do we support compiling code and running it
>> >> >> in the debugged process", then the answer is yes. If you want
>> >> >> something that would automatically intercept some function to
>> execute
>> >> >> your code while the process is running (some kind of dynamic
>> >> >> instrumentation), then the answer is no. (But I don't see any
>> mention
>> >> >> of that on the gdb page you quoted either).
>> >> >>
>> >> >> cheers,
>> >> >> pavel
>> >> >>
>> >> >> On 12 February 2017 at 18:34, Roman Popov via lldb-dev
>> >> >> <lldb-dev at lists.llvm.org> wrote:
>> >> >> > Hello Benjamin , all
>> >> >> >
>> >> >> >>>I recently started using lldb to write a basic instrumentation
>> tool
>> >> >> >>> for
>> >> >> >>>tracking the values of variables at various code-points in a
>> >> >> >>> program.
>> >> >> >
>> >> >> > I have the same problem of tracing some variables and debugging
>> >> >> > application
>> >> >> > post-mortem. Without knowing about your experience I've started
>> >> >> > walking
>> >> >> > same
>> >> >> > path and encountered same problem. In my case inserting an empty
>> >> >> > callback
>> >> >> > slows-down application by 100x. This is not acceptable for me,
>> >> >> > because
>> >> >> > instead of minutes I got hours of runtime.
>> >> >> >
>> >> >> > Did you found any faster solution?
>> >> >> >
>> >> >> > My current plan is to solve it with code injection: I plan to find
>> >> >> > pointers
>> >> >> > to interesting values using debugger scripting and then inject
>> code
>> >> >> > to
>> >> >> > trace
>> >> >> > them.
>> >> >> >
>> >> >> > Does LLDB supports code injection ? I've found information only
>> about
>> >> >> > gdb
>> >> >> >
>> >> >> >
>> >> >> > https://sourceware.org/gdb/onlinedocs/gdb/Compiling-and-Inje
>> cting-Code.html
>> >> >> > but not about lldb
>> >> >> >
>> >> >> >
>> >> >> > -Roman
>> >> >> >
>> >> >> >
>> >> >> > _______________________________________________
>> >> >> > lldb-dev mailing list
>> >> >> > lldb-dev at lists.llvm.org
>> >> >> > http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>> >> >> >
>> >> >
>> >> >
>> >
>> >
>>
>
> _______________________________________________
> lldb-dev mailing list
> lldb-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20170213/b5650c56/attachment.html>


More information about the lldb-dev mailing list