Get the code
bzr branch http://www.visophyte.org/rev_control/bzr/chroniquery/trunk/ chroniquery
bzr branch http://www.visophyte.org/rev_control/bzr/chronicle-recorder/visbrero-integration/ chronicle-recorder
mv valgrind old-valgrind
bzr branch http://www.visophyte.org/rev_control/bzr/valgrind-chronicle/valgrind-chronicle/ valgrind
in chronicle-recorder, make
Set up your scripts/paths
You want the chronicle-recorder/chronicle/chronicle-query binary to be on your path; symlinking is fine.
You may want to put chroniquery/python/chronisole.py on your path too, so that you can invoke it from anywhere.
You probably also want to create a “chronicle” script that allows you to easily run a program under chronicle. For example, you might use the following as a basis:
#!/bin/sh CHRONBASE=/path/to/chronicle-recorder/chronicle/ appname=$1 shift PATH=$CHRONBASE:$PATH CHRONICLE_DB=`basename $appname`.db VALGRIND_LIB=$CHRONBASE/valgrind/.in_place $CHRONBASE/valgrind/coregrind/valgrind --tool=chronicle $appname "$@"
(You can also find the script in chroniquery/scripts, but you’ll still need to modify it.)
Run something under chronicle
Let’s try an example program from chroniquery/examples:
g++ fancy.cc -g -o fancy
This should result in chronicle leaving a ‘fancy.db’ file in the directory.
Now, let’s use the “trace” mechanism:
chronisole.py trace fancy -f main
This tells chronisole to run the “trace” command against the “fancy” program. fancy.db is implied, but you could also have done chronisole.py trace fancy fancy.db -f main. The “-f main” indicates that you want to start tracing from the ‘main’ function.
First, it’s a good idea to tell chronisole how to ignore the stuff we don’t care about. For now, this is done via the ~/.chroniquery.cfg file. Here are the contents of mine:
[default] interesting=false recurse=false [templates] boring=true [dir@mail] interesting=true depth=2 [dir@mailnews] interesting=true depth=3 [dir@mozilla/db/mork] interesting=true # Blanket boring mozilla [dir@mozilla] boring=true # Now opt-in things that are perhaps not actually boring... [dir@mozilla/modules/libpref] boring=false depth=0 # Inline things are jerks and need to be banned until our logic improves # (can it? I'm not sure DWARF is on our side here...) [func@getter_Copies] boring=true [class@nsCGetterCopies] boring=true [class@nsID] boring=true [class@nsIJSID] boring=true [class@nsAutoRefCnt] boring=true [func@Substring] boring=true [class@nsCString] boring=true [class@nsString] boring=true [class@nsCAutoString] boring=true [class@nsAutoString] boring=True [class@nsDependentCString] boring=true [class@nsDependentString] boring=true [class@nsDependentSubstring] boring=true [class@nsFixedCString] boring=true [class@nsFixedString] boring=true [class@nsACstring] boring=true [class@nsAString] boring=true [class@nsACString_internal] boring=true [class@nsAString_internal] boring=true [class@nsSubstring_base] boring=true [class@nsXPIDLCString] boring=true [class@NS_ConvertUTF8toUTF16] boring=true
Without this, chronicle would want to trace into everything.
BEWARE OF HACKS
So, you may note in the above configuration file, we have some paths. If you grep for “evil” in the code, you may also note that there is a Chronifer._evilNormalizePath method in chronifer.py. That evil method assumes that you are using comm-central and the top of the repository is also named that way; if this turns out to be true, it strips the path up through comm-central/. It now also falls back to the possibility that your repository is named mozilla-central, stripping up through mozilla-central/ and replacing it with just “mozilla/”. It assumes that if you have objdirs for your builds, that the objdir starts with “obj-” and that it is found under comm-central or mozilla-central.
This should clearly either not be hardcoded or not stupid.
END BEWARE OF HACKS
Let’s assume you want to trace an xpcshell run. First, you probably want something like this patch against comm-central chroni-test and this wrapper script chronicle-xpcshell (rather like the above helper script, but targetting /tmp) that you would place in dist/bin. You also need debug symbols, so your .mozconfig should have –enable-debugger-info-modules=yes in it. You don’t have to –enable-debug or –disable-optimize, in fact you may not want to (as the DEBUG hit and lack of optimization will get even worse with chronicle), but you may want to ramp down the optimization using –enable-optimize=-O1 if you are leaving optimization on. Then you can do:
USECHRONICLE=1 SOLO_FILE=”test_name.js” check-one
chronisole.py jstrace path/to/xpcshell path/to/logfile -d 5
(-d controls the default maximum recurse depth, you can leave this off if you want, as the configuration file’s interesting logic can accomplish this more specifically)
Using some incorrect logic, we attempt to figure out what’s going on with the stack. (Because of the save frame/restore frame stuff, the logic can get confused.) What we should be doing is tracing the fp->down chain until we hit null each time, most likely. But what we do is try and perform only 2 memory reads and figure out if we’re pushing or popping the stack. If we are pushing, we look for calls made from the current point.
If the call is to the XPC call or getter/setter function, we do note the interface the call is going through and do some magic to go directly to the actual dispatch, avoiding the intermediary XPConnect stuff we could care less about.
Once we are in general trace space, we use the configuration file previously noted to figure out whether we want to display the current function (we do if it’s not boring), whether we want to recurse (we do if it’s interesting), and how deep we want to recurse.
Pingback: visophyte: data made shiny :: understanding libmime using chroniquery and unit tests