wip post
This commit is contained in:
parent
c8a2913172
commit
5a1c98d8a4
8 changed files with 170 additions and 0 deletions
2
content/posts/debugging-rr-children/.gitignore
vendored
Normal file
2
content/posts/debugging-rr-children/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
/crasher
|
||||
/caller
|
||||
5
content/posts/debugging-rr-children/Makefile
Normal file
5
content/posts/debugging-rr-children/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
CFLAGS = -g
|
||||
all: caller crasher
|
||||
.PHONY: all
|
||||
caller: caller.o
|
||||
crasher: crasher.o
|
||||
21
content/posts/debugging-rr-children/caller.c
Normal file
21
content/posts/debugging-rr-children/caller.c
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
int main(void) {
|
||||
int pid = fork();
|
||||
if (pid == -1) {
|
||||
perror("fork");
|
||||
return 1;
|
||||
} else if (pid == 0) {
|
||||
execl("./crasher", "./crasher", NULL);
|
||||
return 1;
|
||||
} else {
|
||||
// parent
|
||||
int status;
|
||||
printf("[caller] spawned pid %d\n", pid);
|
||||
int ret = waitpid(pid, &status, 0);
|
||||
printf("[caller] waitpid: %d, exited? %d status %d, signaled? %d signal %d\n", ret, WIFEXITED(status), WEXITSTATUS(status), WIFSIGNALED(status), WTERMSIG(status));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
7
content/posts/debugging-rr-children/crasher.c
Normal file
7
content/posts/debugging-rr-children/crasher.c
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(void) {
|
||||
printf("[crasher] about to crash\n");
|
||||
abort();
|
||||
}
|
||||
80
content/posts/debugging-rr-children/index.md
Normal file
80
content/posts/debugging-rr-children/index.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
+++
|
||||
date = "2022-02-24"
|
||||
draft = false
|
||||
path = "/blog/debugging-rr-children"
|
||||
tags = []
|
||||
title = "Debugging: using rr to deal with unruly children (processes)"
|
||||
+++
|
||||
|
||||
I have done multiple rounds of debugging blobs of processes that start together
|
||||
and then something bad happens in one of the children several forks down.
|
||||
Although gdb claims to support child processes with `set follow-fork-mode`
|
||||
([docs][gdb-follow-fork-mode]), in practice, this is extremely painful since
|
||||
you may have to set it to multiple different things in one reproduction.
|
||||
|
||||
To deal with these, I've done such hacks as writing wrapper scripts for the
|
||||
executable at fault that run it in a gdbserver. However, by far the worst one
|
||||
I've done is printing out the PID of the misbehaving process then waiting, to
|
||||
give me time to attach the debugger ([this is even suggested in the gdb
|
||||
documentation][gdb-sleep]).
|
||||
|
||||
[gdb-follow-fork-mode]: https://docs.jade.fyi/gnu/gdb/gdb.html#index-set-follow_002dfork_002dmode
|
||||
[gdb-sleep]: https://docs.jade.fyi/gnu/gdb/gdb.html#Forks
|
||||
|
||||
## Using rr to do it the easy way
|
||||
|
||||
For this demo, I am using two programs I wrote:
|
||||
|
||||
- `crasher` just prints out that it's about to crash, then aborts.
|
||||
- `caller` forks and executes `crasher`, then prints its return value once it
|
||||
exits.
|
||||
|
||||
These are written in C but their source is not super interesting. Nevertheless,
|
||||
you can find their source code [at the bottom of the post](#source).
|
||||
|
||||
Here they are in action:
|
||||
|
||||
```
|
||||
» ./caller
|
||||
[caller] spawned pid 158938
|
||||
[crasher] about to crash
|
||||
[caller] waitpid: 158938, exited? 0 status 0, signaled? 1 signal 6
|
||||
```
|
||||
|
||||
Signal 6, if you consult the table in `man 'signal(7)'`, is `SIGABRT` as
|
||||
expected.
|
||||
|
||||
We want to figure out why the crasher is crashing. It's possible to do with
|
||||
gdb, but that's unnecessarily hard because of gdb, even moreso if it forks
|
||||
multiple times.
|
||||
|
||||
Let's use `rr` to do this more easily. First, record a run:
|
||||
|
||||
```
|
||||
» rr record ./caller
|
||||
rr: Saving execution to trace directory `/home/lf/.local/share/rr/caller-0'.
|
||||
[caller] spawned pid 159146
|
||||
[crasher] about to crash
|
||||
[caller] waitpid: 159146, exited? 0 status 0, signaled? 1 signal 6
|
||||
```
|
||||
|
||||
Then find the process ID of the crashing process:
|
||||
|
||||
```
|
||||
» rr ps
|
||||
PID PPID EXIT CMD
|
||||
159145 -- 0 ./caller
|
||||
159146 159145 -6 ./crasher
|
||||
```
|
||||
|
||||
Next, use either `--onfork=<PID>` or `--onprocess=<PID>` to get a debugger on
|
||||
the problem process:
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Demo source {#source}
|
||||
|
||||
{{ codefile(path="caller.c", code_lang="c", colocated=true, hide=true) }}
|
||||
{{ codefile(path="crasher.c", code_lang="c", colocated=true, hide=true) }}
|
||||
{{ codefile(path="Makefile", code_lang="make", colocated=true, hide=true) }}
|
||||
36
templates/macros/code.html
Normal file
36
templates/macros/code.html
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{%- import "macros/colocated_asset.html" as colocated_asset -%}
|
||||
|
||||
<!-- Load a file and dump it in a code block. -->
|
||||
{%- macro file(path, code_lang=false, colocated=false,
|
||||
hide=false, show_path_with_prefix=false) -%}
|
||||
|
||||
{%- set newline = "
|
||||
" -%}
|
||||
{%- set mypath = path -%}
|
||||
|
||||
{%- if show_path_with_prefix == false -%}
|
||||
{%- set header = "" -%}
|
||||
{%- else -%}
|
||||
{%- set header = show_path_with_prefix ~ " " ~ path ~ newline -%}
|
||||
{%- endif -%}
|
||||
{%- if colocated == true -%}
|
||||
{%- set path = colocated_asset::colocated_asset(path=path) | trim -%}
|
||||
{%- endif -%}
|
||||
{%- if code_lang == true -%}
|
||||
{%- set code_lang = '' -%}
|
||||
{%- endif -%}
|
||||
{%- set data = load_data(path=path, format="plain") -%}
|
||||
{%- set source = "```" ~ code_lang ~ newline ~ header ~ data ~ newline ~ "```" | safe -%}
|
||||
|
||||
|
||||
{%- if hide == true -%}
|
||||
<details>
|
||||
<summary>
|
||||
<code>{{ mypath }}</code>
|
||||
</summary>
|
||||
{%- endif -%}
|
||||
{{ source | markdown(inline=true) | safe }}
|
||||
{%- if hide == true -%}
|
||||
</details>
|
||||
{%- endif -%}
|
||||
{%- endmacro file -%}
|
||||
10
templates/macros/colocated_asset.html
Normal file
10
templates/macros/colocated_asset.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!--
|
||||
Returns the file path of the colocated asset.
|
||||
When Zola uses `resize_image` it looks relative to the `content` folder.
|
||||
This means you have to reference the full page asset colocation path.
|
||||
-->
|
||||
{%- macro colocated_asset(path) -%}
|
||||
{%- set page_url_components = page.relative_path | default(value=section.relative_path) | split(pat='/') -%}
|
||||
{%- set page_base = page_url_components | slice(end=page_url_components | length - 1) | join(sep='/') -%}
|
||||
{{ page_base ~ '/' ~ path }}
|
||||
{%- endmacro colocated_asset -%}
|
||||
9
templates/shortcodes/codefile.html
Normal file
9
templates/shortcodes/codefile.html
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{%- import "macros/code.html" as code -%}
|
||||
|
||||
{{ code::file(
|
||||
path=path,
|
||||
code_lang=code_lang | default(value=''),
|
||||
colocated=colocated | default(value=false),
|
||||
hide=hide | default(value=false),
|
||||
show_path_with_prefix=show_path_with_prefix | default(value=false)
|
||||
) }}
|
||||
Loading…
Add table
Add a link
Reference in a new issue