Skip to content

Instantly share code, notes, and snippets.

@dbolser
Forked from fjahr/debugging_workshop.md
Created February 7, 2020 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dbolser/80fbca5f3ba7d3d01a1949744edac0e6 to your computer and use it in GitHub Desktop.
Save dbolser/80fbca5f3ba7d3d01a1949744edac0e6 to your computer and use it in GitHub Desktop.
Debugging Bitcoin Core Workshop - Advancing Bitcoin 2020

Debugging Bitcoin Core Workshop

Short link: http://bit.ly/2H2rKjp

Goals of this workshop

  • Learn to use GDB/LLDB when you need it
  • Practice basic commands
  • Drills / Wax on, wax off.
  • We stay high level

Why debugging with LLDB and GDB?

  • What is a debugger?
    • App to debug other apps
      • Breakpoints
      • Stepping
      • Expression/Variable evaluation
      • Backtrace inspection
  • Growing up with pry and pdb
  • My primary use cases
    • Getting confused from reading the code
    • Getting different results than expected

Why use the plain CLI interface?

  • I like CLI
  • Portability
  • I did not find "the" great alternative
  • You can explore gui mode

Preparations

  • ./configure --enable-debug which is the same as -O0 -ggdb3

Useful commands

Command LLDB GDB
Loading a program $ lldb /path/to/foo.app $ gdb /path/to/foo.app
Listing breakpoints breakpoint list info break
Setting a breakpoint with file/line breakpoint set -f foo.c -l 12 break test.c:12
Setting a breakpoint on a name breakpoint set -n foo break main
Delete breakpoints breakpoint delete 1 delete 1
Setting watchpoints watch set var global watch global_var
Running the program (with arg) run -txindex run -txindex
Attach to program by pid process attach --pid 123 attach 123
Attach to program by name (wait for it) process attach --name bitcoind --waitfor attach -waitfor bitcoind
Continue from breakpoint thread continue continue
Step into function thread step-in or step step
Step over function thread step-over or next next
Step out of function thread step-out or finish finish
List all threads thread list info threads
List stack frame variables frame variable info args and info locals
Print stack frame variable frame variable foo or p foo p foo
Print global variable target variable baz p foo
Set environment variables settings set target.env-vars DEBUG=1 or env DEBUG=1 set env DEBUG 1
Evaluate an expression expr foo() call foo()
Lookup symbol information image lookup -v -s gFoo info symbol 0x1ec4

Full map of commands

Misc tipps

  • Shortest unique string match on command names works too, i.e. br s -n foo
  • Setting a /.gdbinit or /.lldbinit
  • How to get out of a long loop

Using debugging with an RPC manually

  • Usually "standard way" of starting your debugger
    • Load bitcoind into lldb
    • Set your breakpoints
    • run with arguments
    • Use bitcoin-cli if you need to, to hit the breakpoint

Exercise #1 - getblockchaininfo

Where does the RPC getblockchaininfo get values for bestblockhash, difficulty and mediantime from? Find their sources.

Exercise #2 - init

Set a breakpoint in init.cpp that only gets hit when -txindex is set.

Using debugging with unit tests

  • Similar to "standard way" with some adjustments:
    • Load src/test/test_bitcoin instead of bitcoind
    • Probably run with args --log_level=all --run_test=*/lthash_tests

Exercise #3 - multisig_tests

Change one of the (or more) scripts in the test src/test/multisig_tests.cpp during text execution to make the test fail!

Using debugging with functional tests

  1. Change funtional test timeout in test/functional/test_framework/test_framework.py L99 self.rpc_timeout = 60 to avoid timeouts while debugging.
  2. Insert import pdb; pdb.set_trace() at any point in the (python) functional test before the breakpoint you would like to set is going to be hit.
  3. Run the functional test ./test/functional/example_test.py, it should be stopped at the inserted line.
  4. Get the pid of the node you wnat to set the breakpoint in self.nodes[0].process.pid.
  5. Start lldb, attaching to the pid lldb -p 12345 (which causes it to be stopped by lldb)
  6. Set your breakpoints and let the process continue from within lldb
  7. Let the process continue from within pdb
  8. The node should now run into the breakpoint in lldb

Exercise #4 - mempool_limit

Watch the removal of tx from the mempool in TrimToSize using test/functional/mempool_limit.py.

Exercise #5 - wallet_avoidreuse

Use test/functional/wallet_avoidreuse.py to see where the avoid reuse setting is making a difference when getting your balance.

Exercise #6 - p2p_node_network_limited

Watch messages as they come in to a syncing node in test/functional/p2p_node_network_limited.py (hint: ProcessMessage).

Bonus

Explore TxIndex and BaseIndex inheritance relationship.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment