How do i use the lldb '-s' flag (command source) properly - lldb

I can successfully launch and debug a program such as octave using lldb in a terminal as follows:
$ lldb octave
(lldb) target create "octave"
Current executable set to 'octave' (x86_64).
(lldb) r --no-gui
Process 76986 launched: '/opt/local/bin/octave' (x86_64)
Process 76986 stopped
* thread #1: tid = 0x13465f, 0x00007fff5fc01000 dyld`_dyld_start, stop reason = exec
frame #0: 0x00007fff5fc01000 dyld`_dyld_start
dyld`_dyld_start:
-> 0x7fff5fc01000 <+0>: popq %rdi
...
(lldb) c
Process 76986 resuming
GNU Octave, version 4.2.0
...
octave:1>
Now I can enter octave commands at the octave prompt. For instance:
octave:1> version
ans = 4.2.0
I want to execute an lldb script and therefore start lldb like this instead:
$ lldb octave -s ~/path/to/lldb_script
where the lldb_script file contains for instance:
r --no-gui
When I actually run
$ lldb octave -s ~/path/to/lldb_script
I get
(lldb) target create "octave"
Current executable set to 'octave' (x86_64).
(lldb) command source -s 0 '/Users/cyril/trunk/python/lldb_startup'
Executing commands in '/Users/cyril/trunk/python/lldb_startup'.
(lldb) process launch -- --no-gui
Process 77138 stopped
* thread #1: tid = 0x14b1fb, 0x00007fff5fc01000 dyld`_dyld_start, stop reason = exec
frame #0: 0x00007fff5fc01000 dyld`_dyld_start
dyld`_dyld_start:
-> 0x7fff5fc01000 <+0>: popq %rdi
...
Process 77138 launched: '/opt/local/bin/octave' (x86_64)
Now when I do 'continue' like this
(lldb) c
I get
Process 77138 resuming
GNU Octave, version 4.2.0
...
(lldb)
lldb actually returns to (lldb) prompt and not octave> promt. And I cannot run octave commands.
(lldb) version
returns
lldb-350.0.21.9
and
(lld) c
gives
error: Process is running. Use 'process interrupt' to pause execution.
The script scheme was working fine and was actually giving me octave prompt as expected until recently. I may have upgraded lldb inadvertently.
How do i use the lldb '-s' flag (command source) properly so the launched program gets launched properly and does not return to (lldb) prompt?

Related

Cortex-M remote target with LLDB script

I'm currently able to connect, load and debugg a Nucleo-G0B1 board with LLDB and pyOCD (also with OpenOCD) using the following sequence of commands:
$ lldb Build/temp.elf
(lldb) gdb-remote 127.0.0.1:3333
(lldb) target modules load --load .text 0x08000000
(lldb) process plugin packet monitor reset halt
But i'm not able to do the same thing with the LLDB python interface, currently
I'm trying to use the following mehods, prints for testing purposes
import lldb
debugger = lldb.SBDebugger.Create()
print(debugger.GetInstanceName())
error = lldb.SBError()
target = debugger.CreateTarget('Build/temp.elf', 'armv6m-*-none-eabi', 'remote-gdb-server', False, error)
print(error.GetCString())
print(target)
But so far no target is created. if I change the platform parameter to 'host' the target is created but I'm looking for a remote target not local
script output for remote-gdb-server
$ python lldbinit.py
debugger_1
platform 'remote-gdb-server' doesn't support 'armv6m-*-none-eabi'
No value
script output for host
$ python lldbinit.py
debugger_1
None
temp.elf

Why is LLDB generating EXC_BAD_INSTRUCTION with user compiled library on MacOS?

I want to debug OpenSSL on MacOS to see how it creates an elliptic curve point. So, I compiled OpenSSL with debug symbols and no optimizations. However, when I run with lldb, it doesn't work
$ cat ec.c
#include <crypto/ec.h>
#include <stdio.h>
int main() {
EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp384r1);
EC_POINT *point = EC_POINT_new(group);
printf("done!\n");
return 0;
}
Here is how I compiled and ran the program:
$ gcc ec.c -o ec -I../openssl/include ../openssl/libcrypto.dylib -ggdb3 -O0
$ DYLD_INSERT_LIBRARIES=../openssl/libcrypto.dylib ./ec
done!
Here is what happens when I run lldb and try to break at main:
$ lldb ./ec
(lldb) process launch --environment DYLD_INSERT_LIBRARIES=../openssl/libcrypto.dylib ./ec
Process 3948 launched: '/Users/seanthomas/repos/ec/ec' (arm64)
Process 3948 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=1, subcode=0x4a03000)
frame #0: 0x00000001009651a8 libcrypto.3.dylib`_armv8_sve_probe
libcrypto.3.dylib`:
-> 0x1009651a8 <+0>: eor z0.d, z0.d, z0.d
0x1009651ac <+4>: ret
libcrypto.3.dylib`:
0x1009651b0 <+0>: xar z0.d, z0.d, z0.d, #0x20
0x1009651b4 <+4>: ret
Target 0: (ec) stopped.
(lldb)
Does anyone know how to fix this?
I'm not sure whether this can help you or not. But perhaps, there're bugs in libcrypto.3.dylib on Arm arch.
I met this problem also. It works when I run the program by cmd line in shell. But it meets this problem when I want to debug this program in VSCode using lldb.
How ever, when I delete the libcrypto.3.dylib and libssl.3.dylib, build the openssl using tag OpenSSL_1_1_1m, and rebuild the program. It works!
Yes, confirm the issue on Mac M1/M2. Reverted back to the old version of openssl and the problem got fixed. I use openssl lib in MacOs app of mine and on app launch in Debug mode it gets crashing right away.

How to setup LLDB with "openocd and JTAG board"

I'm trying to use lldb with openocd/jtag board but I'm in trouble.
I already use openocd with gdb to develop on L0 STMicroelectronics board and it works perfectly.
Now I want the same with lldb.
I do that on LLDB host side
$ lldb bin/token.elf
(lldb) target create "bin/token.elf"
Current executable set to 'bin/token.elf' (arm).
(lldb) platform select remote-gdb-server
Platform: remote-gdb-server
Connected: no
(lldb) platform connect connect://localhost:5557
Platform: remote-gdb-server
Hostname: (null)
Connected: yes
(lldb) target list
Current targets:
* target #0: /home/cme/Projects/Tacos/ledger/trunk/se/build/st31_bolos/bin/token.elf ( arch=arm-unknown-unknown, platform=host )
On the openocd/GDB server side I correctly see the "Info : accepting 'gdb' connection on tcp/5557"
But now I don't found how to continue:
(lldb) process launch
error: process launch failed: Child exec failed.
I also tried "process continue", but lldb complains there is no process
With gdb, the process is considered as already running and I use reset/continue commands, never the 'run' command.
Does anybody know how to use lldb with openocd/jtag gdb-server?
Thanks for your help
C/M.
from what we were researching, it is not possible to debug remote (bare-metal!) targets with lldb without writing extra code.
for basic functionality, lldb needs to recognize at least one thread context.
the same is true for gdb. But there in gdb there is some sort of stub implemented faking an existing thread on the remote system. [1]
from an conversation on the lldb mailing list [2] the answer compiles to:
we have to write some (python) code to get a remote bare metal working with lldb.
[1] https://github.com/bminor/binutils-gdb/blob/28170b88cc8b40fdea2b065dafe6e1872a47ee4e/gdb/remote.c#L1808
[2] http://comments.gmane.org/gmane.comp.debugging.lldb.devel/3405
So far this works for me on my stm32g0b1 nucleo board and pyOCD but I also tested with OpenOCD
$ lldb --local-lldbinit Build/temp.elf
(lldb) target create "Build/temp.elf"
Current executable set to '/home/diego/Workspace/genesis/Buil /temp.elf' (arm).
(lldb) gdb-remote 127.0.0.1:3333
Process 1 stopped
(lldb) target modules load --load .text 0x08000000
section '.text' loaded at 0x8000000
(lldb) process plugin packet monitor reset halt
packet: qRcmd,72657365742068616c74
response: 526573657474696e672074617267657420776974682068616c740a5375636365737366756c6c792068616c74656420646576696365206f6e2072657365740a

Why doesn't lldb forward my environment variable anymore?

I'm working on a patch for FFmpeg and need to debug my code. I'm loading an external library, and in order to test different library versions, I have them in different folders. To select which one I want to use, I've been using DYLD_LIBRARY_PATH=/path/to/lib/dir ./ffmpeg and that works okay. But when I try it within lldb, it crashes saying dyld: Library not loaded and Reason: image not found. This used to work pre-Xcode 7.1, but I just recently upgraded and it stopped working.
Here's my MVCE:
#include <stdio.h>
#include <stdlib.h>
int main() {
char* str = getenv("DYLD_LIBRARY_PATH");
if (str) puts(str);
else puts("(null)");
return 0;
}
Running this program as follows produces the output:
$ ./a.out
(null)
$ DYLD_LIBRARY_PATH=/tmp ./a.out
/tmp
That looks okay. But when I try to use lldb it fails:
$ DYLD_LIBRARY_PATH=/tmp lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) run
Process 54255 launched: './a.out' (x86_64)
(null)
Process 54255 exited with status = 0 (0x00000000)
Trying to set the environment variable inside lldb works:
lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) env DYLD_LIBRARY_PATH=/tmp
(lldb) run
Process 54331 launched: './a.out' (x86_64)
/tmp
Process 54331 exited with status = 0 (0x00000000)
lldb version (it's from Xcode 7.1):
$ lldb --version
lldb-340.4.110
Question: Is this an intended new "feature," or is this a new bug in lldb (or am I totally crazy and this never used to work)? I'm quite positive lldb used to forward the DYLD_LIBRARY_PATH environment variable, so how come it isn't anymore?
Edit: This is on OS X 10.11.1.
If this is on El Capitan (OS X 10.11), then it's almost certainly a side effect of System Integrity Protection. From the System Integrity Protection Guide: Runtime Protections article:
When a process is started, the kernel checks to see whether the main
executable is protected on disk or is signed with an special system
entitlement. If either is true, then a flag is set to denote that it
is protected against modification. …
… Any dynamic linker (dyld)
environment variables, such as DYLD_LIBRARY_PATH, are purged when
launching protected processes.
Everything in /usr/bin is protected in this fashion. Therefore, when you invoke /usr/bin/lldb, all DYLD_* environment variables are purged.
It should work to run lldb from within Xcode.app or the Command Line Tools, like so:
DYLD_LIBRARY_PATH=whatever /Applications/Xcode.app/Contents/Developer/usr/bin/lldb <whatever else>
I don't believe that copy of lldb is protected. /usr/bin/lldb is actually just a trampoline that executes the version in Xcode or the Command Line Tools, so you're ultimately running the same thing. But /usr/bin/lldb is protected so the DYLD_* environment variables are purged when running that.
Otherwise, you will have to set the environment variable inside lldb as shown in this thread:
(lldb) process launch --environment DYLD_LIBRARY_PATH=<mydylibpath> -- arg1 arg2 arg3
or using the short -v option:
(lldb) process launch -v DYLD_LIBRARY_PATH=<mydylibpath> -- arg1 arg2 arg3
Or, you can disable System Integrity Protection, although it serves a good purpose.
You can set an environment variable inside lldb once it is started.
$ lldb
(lldb) help env
Shorthand for viewing and setting environment variables. Expects 'raw' input (see 'help raw-input'.)
Syntax:
_regexp-env // Show environment
_regexp-env <name>=<value> // Set an environment variable
'env' is an abbreviation for '_regexp-env'
(lldb)
So that
lldb ./a.out
(lldb) env DYLD_LIBRARY_PATH=/path/to/lib/dir
(lldb) r
should work.
Tested with
$ lldb --version
lldb-1400.0.38.17
Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)

Make gdb quit automatically on successful termination?

I use a debugging script that runs several related processes in succession with the debugger. I'm currently using -x to execute several commands automatically (such as run). How can I make gdb quit automatically when the debugged process successfully terminates? Adding a quit command to the command file will cause that command to be handled not just on successful termination, but when errors occur also (when I'd rather take over at that point).
Here's an extract of what's going on:
+ gdb -return-child-result -x gdbbatch --args ./mkfs.cpfs /dev/loop0
GNU gdb (GDB) 7.1-ubuntu
Reading symbols from /home/matt/cpfs/mkfs.cpfs...done.
Program exited normally.
Breakpoint 2 at 0x805224f: file log.c, line 32.
(gdb)
Contents of gdbbatch:
start
b cpfs_log if level >= WARNING
I think I have found a complete solution to your question in connection to looking for something similar in How to make gdb send an external notification on receiving a signal?. None of the other guys here seem to have mentioned or discovered gdb hooks.
Based on Matthew's tip about $_exitcode, this is now my app/.gdbinit that achieves exactly the behavior wanted; normal quit on successful termination and drop to gdb prompt, send email, whatnot on everything else:
set $_exitcode = -999
set height 0
handle SIGTERM nostop print pass
handle SIGPIPE nostop
define hook-stop
if $_exitcode != -999
quit
else
shell echo | mail -s "NOTICE: app has stopped on unhandled signal" root
end
end
echo .gdbinit: running app\n
run
gdb sets $_exitcode when the program successfully terminates. You can make use of that - set it to an unlikely value at the start of your script, and only quit at the end if it has changed:
set $_exitcode = -999
# ...
run
# ...
if $_exitcode != -999
quit
end
(Setting $_exitcode to an unlikely value is a bit ugly, but it will otherwise not be defined at all if the program doesn't terminate, and there doesn't seem to be any obvious way of asking "is this variable defined?" in a conditional.)
GDB has a different "language" for interacting with automated programs called GDB/MI (detailed here), but unfortunately, it doesn't look like it supports conditionals, and is expected to run from other programs with parsing and branching. So, it looks like Expect is the easiest (or at least a working) solution:
$ cat gdbrunner
#!/usr/bin/expect -f
#spawn gdb -return-child-result --args ./mkfs.cpfs /dev/loop0
spawn gdb -return-child-result --args [lindex $argv 0]
#send "start\n"
#send "b cpfs_log if level >= WARNING"
send "run\n"
expect {
normally\. { send "quit\n" }
"exited with code" { interact -nobuffer }
}
I tested this with the simple programs:
$ cat prog1.c
int main(void) { return 0; }
$ cat prog2.c
int main(void) { return 1; }
With the following results:
$ ./gdbrunner ./prog1
spawn gdb -return-child-result --args ./prog1
run
(gdb) run
Starting program: /home/foo/prog1
Program exited normally.
(gdb) quit
$ ./gdbrunner ./prog2
spawn gdb -return-child-result --args ./prog2
run
(gdb) run
Starting program: /home/foo/prog2
Program exited with code 01.
(gdb)
Essentially, you have to parse the output and branch using something else. This would of course work with any other program capable of handling input/output of another process, but the above expect script should get you started, if you don't mind Tcl. It should be a little better, and expect the first (gdb) prompt, but works due to stdin buffering.
You can also modify it to use that GDB/MI interface with the -i command-line argument to GDB; its commands and output are a bit more readily parsable, if you will expand to need more advanced features, as you can see in the previously linked documentation.

Resources