| Edit | Rename | Changes | History | Upload | Download | Back to Top |
Occasionally it may be necessary to debug at the virtual machine level. If your virtual machine suddenly crashes finding out why either requires figuring it out or using a lower-level debugger. The reasons your VM might crash include holes in the VM, bugs in external C code and VM bugs. This page exists to tell you
7.x VMs have three build variants: fast (production), debug, and assert. The fast variant is compiled using maximal optimization. The debug variant is compiled using minimal optimization and includes significant debugging assertion checking (thus, this variant is the easiest to debug but also exhibits the slowest performance). The assert variant is a compromise between fast and debug: it includes typically useful assertion checks and is compiled with moderate to full optimization.
Furthermore, non-fast engines have two levels of asserts, one that are always on and another that are so time consuming they have to be turned on explicitly. To turn on these so-called dasserts use the -o11s argument. e.g.
vwlinuxdbg -o11s image.im
The VMs report relevant debugging output through the console. On Windows, you will need to use the *console.exe virtual machines to see this output.
The assertFail routine is in stack/assertFail.c, is called whenever an assert fails, and prints the expression that failed, and the file and line number where the expression failed. A common approach to debugging is to put a breakpoint in assertFail, run until a crash causes an assertFail and then start looking around.
The main gotcher on Unix debuggers is the need to turn-off signal catching. By default a Unix debugger will halt execution when a signal is delivered. Given that e.g. mouse movements are communicated to the engine via signals this makes the system unusable unless one turns this off. One can do this with a command, typically the ignore command. But its much less tedious to put the commands in the debugger's initialization file. This file typically resides in a user's home directory, and can contain all sorts of useful stuff.
the init file is called .dbxrc. Here's a sample
ignore io usr1 alrm 36 dalias l list dalias n next dalias ni nexti dalias s step dalias si stepi dalias c cont dalias b1 file assertFail.c\;stop at 54\;assign once=1 dalias sd 'call printStack(currentStack)' dalias tf 'call printTopFrame(currentStack)'
To debug make sure VISUALWORKS is set and then launch dbx with the engine executable. Finally run the image using the run command, along with any other arguments. e.g.
$ VISUALWORKS=/usr/local/vw5i.3 dbx /usr/local/vw5i.3/bin/solaris/vwsun5 > run /usr/local/vw5i.3/image/visual.im
You can get a C stack trace using the where command, e.g.
> where =>[[1] updatePtrs() (optimized), at 0x5ce80 (line ~2853) in "/pps/build/hpsNext/build/sun5/fast/src/mman/mmInit.c" [[2] initMmAfter() (optimized), at 0x5a1d8 (line ~548) in "/pps/build/hpsNext/build/sun5/fast/src/mman/mmInit.c" [[3] startKernel() (optimized), at 0x59ef8 (line ~358) in "/pps/build/hpsNext/build/sun5/fast/src/mman/mmInit.c" [[4] startSupervisor() (optimized), at 0x31f48 (line ~216) in "/pps/build/hpsNext/build/sun5/fast/src/ext/exInit.c" [[5] oeMain(0x3, 0xeffffa44, 0xeffffa54, 0x0, 0x0, 0x0), at 0xb22ec [[6] main(0x3, 0xeffffa44, 0xeffffa54, 0xf9000, 0x1, 0x0), at 0xde8fc
You can call functions in the VM using the call command, e.g.
> call dumpAll(1)
the init file is called .gdbinit. Here's a sample
handle SIGUSR1 nostop noprint noignore handle SIGUSR2 nostop noprint noignore handle SIGALRM nostop noprint noignore handle SIGPOLL nostop noprint noignore
To debug make sure VISUALWORKS is set and then launch dbx with the engine executable. Finally run the image using the run command, along with any other arguments. e.g.
bash$ VISUALWORKS=/usr/local/vw5i.3 gdb /usr/local/vw5i.3/bin/solaris/vwsun5 (gdb) run -=/usr/local/vw5i.3/image/visual.im some other arguments
Just like dbx you can get a C stack trace using the where command, and can call functions in the VM using the call command. See above for examples.
As of VW 7.7, the Windows virtual machines are now compiled to store debug symbols in PDB files. Cincom operates a Windows symbol server as the primary method to access these files. Formerly, COFF debugging symbols were embedded inside the VM binary files. The PDB format is more useful as it includes more debugging information and by using a symbol server it is possible to ensure that the correct symbols are being used for the binaries being debugged.
The Cincom symbol server is located at http://www.cincomsmalltalk.com/downloads/symbols. If you are unfamiliar with using symbol servers, Microsoft provides a good overview at msdn.microsoft.com/en-us/library/ee416588(VS.85).aspx.
WinDBG is a free debugger from Microsoft. You only need to install the debugger, not any of the other SDK components that are offered. You give commands in the line at the bottom of the window, and they and the results are echoed to the terminal display above. You can have all that output logged to a file too.
If you have VM sources, you can set the source path from the File menu to the binsrc directory. WinDBG supports getting debug symbols from Cincom's symbol server. The path for symbols can include multiple servers and a local directory for caching: the following path worked, but there's probably a better way:
.sympath http://www.cincomsmalltalk.com/downloads/symbols;SRV*c:\pdbs*http://msdl.microsoft.com/download/symbols
The VM process has several threads, and if you attach the debugger to a running VW it seems to pick the last thread, which generally isn't interesting. To list all threads, use ~. To switch to thread 0, use ~0s. To list the call stack of the current thread, use kp.
To use the VM debugging functions, switch to a thread that is not doing anything, and call the function with .call, e.g. to dump stacks of all Smalltalk Processes in the image to stack.txt:
~4s .call dumpAllToFile(0, 1)
If you have a VM using 100% CPU, you can find which thread is running. To list all threads in order of how much CPU time they have used, use !runaway 3. You can probably guess from the output, which lists the thread with the most time first. To be sure, choose Debug | Go (which sets VW running again), wait a couple of seconds, choose Debug | Break, reissue the !runaway 3 command, and compare the times for the threads.
If the Threads pane is not visible, choose Choose Debug | Windows | Threads to show it. Generally you want to select the Main Thread, by double-clicking it. The selected thread's stack is shown in the Call Stack pane at the bottom.
You can set the path to the symbol library with Debug | Options and Settings | Debugging | Symbols. Press the yellow 'new folder' button to add http://www.cincomsmalltalk.com/downloads/symbols
You can set the path to the VM source from the Solution Explorer: select the solution and choose Properties from its pop-up menu. Add your VW bin directory to the Debug Source Files.
You can run the VM debugging commands from the Immediate pane (when you have selected a suitable thread):
? dumpAllToFile(0, 1)
The VM is filled with a veritable hoard of debugging functions for
For those with the VM sources these functions live in stack/checks.c. These are useful for findign out the state of the system when it hangs or runs out of memory..
For those with the VM sources these functions live in stack/checks.c
For those with the VM sources these functions live in mman/checks.c
For those with the VM sources these functions live in tran/tmain.c and elsewhere
In our book a reproducible crash is one which can be provoked without user interaction. Anything from moving the mouse to covering a window with another can send events via the engine up into Smalltalk and causes the system to "do stuff". Such "stuff" inevitably results in objects being created. So the slightest change in user interaction will change the number and order of object allocations and can make keeping track of things from run to run a real headache.
Life is much easier if one can cause the system to crash simply by starting up an image and letting it run to destruction. One can then much more easily observe it from run to run building up a complete picture. An easy way to do this is to try to develop a test case as a doit in a workspace and then add a "saveAs:..." expression to the doit, save the image and hope it crashes on start-up without one having to intervene. e.g.
| a b c | ObjectMemory saveAs: 'bug' thenQuit: true. b := (1 to: 100) collect: [:i| Array new: 1]. a := (1 to: 1000000) collect: [:ign| Object new]. a size. c := (1 to: 100) collect: [:i| Array new: 1]. 1 to: b size by: 2 do: [:i| b at: i put: nil]. 1 to: c size by: 2 do: [:i| c at: i put: nil]. a := nil. ObjectMemory garbageCollect. ScheduledControllers restore. ObjectMemory verboseGlobalCompactingGC
or
ObjectMemory saveAs: 'crash' thenQuit: true. 'load.st' asFilename fileIn
Copied from the wayback machine web.archive.org/web/*/http://wiki.cs.uiuc.edu/VisualWorks/debugging+at+the+virtual+machine+level
| Edit | Rename | Changes | History | Upload | Download | Back to Top |