Sunday, July 8, 2012

Gathering stacktraces of crashed test cases

One major feature that will be part of Kyua 0.5 — just landed onto HEAD — is the automatic collection of stacktraces for any crashing test case. This feature was originally implemented in ATF 0.13 and it had to make its way to Kyua as part of the ATF tools deprecation. As the linked commit message well mentions, the implementation of this functionality in ATF was a non-portable hack. So, while rewriting this feature for Kyua, I have attempted to come up with a more portable and, specially, testable solution.

Collecting stacktraces is a tricky business. Attempting to do it "by hand" — i.e. by reading a core file and walking the stack manually while resolving symbols possibly in shared libraries and dealing with all sorts of platforms/architecture differences — is just crazy talk. Fortunately, GDB has the ability to do this and, even better, comes with a batch mode that allows the unattended collection of a stacktrace.

Here is how, given a binary and a core dump, you generate a stacktrace:

$ gdb -batch -q -ex bt binary-name core-dump

And this is how the new stacktrace module goes by collecting stacktraces: it just calls out to GDB (if present) to gather the stacktrace and append it to the test case's stderr output.

Easy enough, huh? Well, yes, but you still need to determine what the name of the core file is! And that is, of course, platform specific and (even worse) user-customizable. Here are some examples:

  • NetBSD places the core files in the current directory and names them after the binary that generated them, with a .core suffix. The names have a maximum length of MAXCOMLEN. To make things trickier, this is all customizable through the kern.defcorename sysctl setting.
  • Mac OS X places core files in /cores/ using a naming scheme of the form core.PID. This is also customizable through the kern.corefile sysctl setting.
  • Fedora places core files in the current directory with a naming scheme of core.PID. I guess this is also customizable, but I haven't investigated how.
In the current implementation, I have special-cased all these default values in the find_core() function, which has been tested to work on all the operating systems above mentioned. I could go one step further and attempt to cope with the user customizations, but haven't done so at this point.  (Why? Because I wasn't aware that this was all tunable until I wrote this post!)

Lastly, and as mentioned earlier, the new code comes with unit and integration tests to ensure that the gathering of stacktraces works. This is something that the ATF codebase did not have, and thus is why nobody spotted that this did not work in any other system than NetBSD.

No comments:

Post a Comment