Thanks for the link to `call_function_by_hand`, that's super helpful! In retrospect, I could have found this file by grepping for 'When the function is done executing, GDB will silently stop' (the very useful "grep for UI text" trick!)
the choice between whether to try to understand something by running or by reading the code is a super interesting one (though if I'm seriously interested in understanding exactly what some software does of course I'll do both!).
I think experimentation/stracing a program to understand it has a lot of advantages:
* It can be helpful to look at the system calls as a way to maybe see the big picture before diving into the code.("ok, it's setting some registers somehow, it's putting in some int3 instructions, then it does PTRACE_CONT, then it undoes all the changes it made").
* it lets me focus on what the program actually does instead of understanding how the code is organized (figuring out how the code in a large project I've never looked at before is organized can be time consuming!)
* It's easy to make incorrect conclusions when reading the source. This happens to me a lot when reading distributed systems code -- often I'll think "ok, if I do X, then Y will happen" but that turns out not to be true in practice. So I think even when you are reading code, doing experimentation as you go is a key part of making sure that your understanding of the code is actually correct.
* I find exploring programs interactively fun!
In this specific example -- I think it's really interesting that gdb modifies the `longjmp` function in libc when running a function. The string `longjmp` doesn't appear anywhere in infcall.c. So even though reading infcall.c seems like a great overview, it just has different information that I get from using strace!