| # Repeat Commands | |
| In LLDB's command line interface, pressing Enter (an empty command) repeats the | |
| previous command. By default, the exact same command is re-executed. However, | |
| several commands customize this behavior to implement paging or progressive | |
| expansion, making it easy to explore data incrementally by pressing Enter | |
| repeatedly. Repeat commands can be learned and discovered by pressing enter and | |
| observing the result. | |
| In some instances, commands disable repeat commands, to prevent | |
| accidentally triggering a destructive operation (e.g. `process launch`). | |
| This page documents the commands with custom repeat behavior. | |
| ## `thread backtrace` (`bt`) | |
| When `thread backtrace` is invoked with the `--count` (`-c`) option, the | |
| repeat command pages through the backtrace by advancing the `--start` (`-s`) | |
| option by the count each time. | |
| For example: | |
| ``` | |
| (lldb) bt 5 | |
| * thread #1, stop reason = breakpoint 1.1 | |
| * frame #0: handle_request at server.cpp:50 | |
| frame #1: parse_headers at http.cpp:12 | |
| frame #2: read_socket at socket.cpp:30 | |
| frame #3: accept_connection at listener.cpp:8 | |
| frame #4: event_loop at reactor.cpp:100 | |
| (lldb) | |
| # repeats as: thread backtrace -c 5 -s 5 | |
| * thread #1, stop reason = breakpoint 1.1 | |
| frame #5: start_server at main.cpp:42 | |
| frame #6: load_config at config.cpp:7 | |
| ... | |
| (lldb) | |
| # repeats as: thread backtrace -c 5 -s 10 | |
| ``` | |
| Each press of Enter shows the next 5 frames. If `--count` is not specified, | |
| the full backtrace is displayed and there is no repeat command. | |
| ## `source list` (`list`) | |
| When `source list` is repeated, it shows the next block of source lines, | |
| continuing from where the previous listing ended. This mimics paging behavior. | |
| If the `--reverse` (`-r`) option was given, the repeat command continues | |
| listing in reverse (showing earlier source lines). | |
| ``` | |
| (lldb) list # shows source around the current location | |
| (lldb) # shows the next block of source lines | |
| (lldb) # shows the next block after that | |
| (lldb) list -r # shows source in reverse | |
| (lldb) # continues listing in reverse | |
| ``` | |
| ## `memory read` | |
| When `memory read` is repeated, it continues reading from where the previous | |
| read ended. The repeat command drops the address arguments and re-uses the same | |
| format, size, and count options from the previous invocation. | |
| ``` | |
| (lldb) memory read 0x1000 -c 32 | |
| 0x1000: 48 8b 05 a9 3b 00 00 48 ... | |
| (lldb) # continues reading the next 32 bytes from 0x1020 | |
| (lldb) # continues reading from 0x1040 | |
| ``` | |
| ## `memory region` | |
| When `memory region` is given an address, it displays the memory region | |
| containing that address. Pressing Enter then shows the next memory region, and | |
| so on, allowing you to walk through the process's entire memory map. | |
| ``` | |
| (lldb) memory region 0x1000 | |
| [0x0000-0x2000) rw- | |
| (lldb) # shows the next region starting at 0x2000 | |
| (lldb) # shows the next region after that | |
| ``` | |
| ## `frame variable` (`v`) | |
| When `frame variable` is repeated, it re-runs the command with an incremented | |
| `--depth` (`-D`) value. This progressively reveals deeper levels of nested | |
| data structures with each press of Enter. | |
| If no `--depth` option was specified in the original command, the next repeat | |
| starts at one level beyond the `target.max-children-depth` default setting. If | |
| `--depth` was specified, it increments the given value by 1 each time. | |
| Consider a deeply nested configuration structure: | |
| ``` | |
| (lldb) v config | |
| (Config) config = { | |
| server = { | |
| network = { | |
| tls = { | |
| certificate = { | |
| issuer = {...} | |
| } | |
| } | |
| } | |
| } | |
| } | |
| (lldb) # repeats as: frame variable --depth 6 config | |
| (Config) config = { | |
| server = { | |
| network = { | |
| tls = { | |
| certificate = { | |
| issuer = { | |
| name = {...} | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| (lldb) # repeats as: frame variable --depth 7 config | |
| ``` | |
| The default `target.max-children-depth` causes the first output to truncate at | |
| `issuer`. Each press of Enter reveals one more level without having to | |
| manually specify `--depth`. | |
| ## `thread trace dump instructions` | |
| When repeated, this command adds the `--continue` flag, which continues | |
| dumping traced instructions from where the previous instruction dump left off. | |
| ``` | |
| (lldb) thread trace dump instructions | |
| ... first batch of instructions ... | |
| (lldb) # continues dumping the next 20 instructions | |
| ``` |