| 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
As of 5i.2 each platform comes with more than one engine:
Why both? The stripped engine is significantly smaller and some customers think its neat to be able to fit a VM on to a floppy, so Cincom has to provide it. But in this age of cheap gigabyte drives the saving in space is insignificant. You need to use the production engine *with* debug symbols to be able to call debugging functions, or to get a meaningful stack trace. So we recommend and urge you to use the unstripped production engine, as when crashes happen you'll be in a much better position to debug.
All platforms provide a "debug" engine. This is an unoptimized engine that also includes many assertion checks. This is the vw
As of vw7 all platforms provide an "assert" engine. This is an optimized engine that also includes many assertion checks. This is the vw
Oh yes, those other three Windows engines, vwntconsole.exe et al, are engines that stay connected to their command prompt, so they can read and write to standard input. This distinction isn't necessary on Unix because there are decent shells which allow you to start things in the background.
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, like setting the debugger's prompt to ugh>, which makes it seem so much cleverer.
the init file is called .dbxrc. Here's a sample
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.
You can get a C stack trace using the where command, e.g.
You can call functions in the VM using the call command, e.g.
the init file is called .gdbinit. Here's a sample
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.
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:
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:
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.
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
...is primarily for VM debugging as opposed to application debugging. It is slow but its assertion checks tend to catch errors early. It also includes more debugging functions which are compiled in only in an engine with ASSERTs. 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.
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.
or
Copied from the wayback machine web.archive.org/web/*/http://wiki.cs.uiuc.edu/VisualWorks/debugging+at+the+virtual+machine+level
vwlinuxdbg -o11s image.im
vwlinuxdbg -o11s image.im
Debugging on Unixes
- with dbx (e.g. Solaris)
setenv PS1 "ugh> "
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)'
$ VISUALWORKS=/usr/local/vw5i.3
dbx /usr/local/vw5i.3/bin/solaris/vwsun5
ugh> run /usr/local/vw5i.3/image/visual.im
ugh> 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
ugh> call dumpAll(1)
- with gdb (e.g. linux)
handle SIGUSR1 nostop noprint noignore
handle SIGUSR2 nostop noprint noignore
handle SIGALRM nostop noprint noignore
handle SIGPOLL nostop noprint noignore
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
Debugging on Windows: VW 7.7 and later
- with WinDBG
.sympath http://www.cincomsmalltalk.com/downloads/symbols;SRV*c:\pdbs*http://msdl.microsoft.com/download/symbols
~4s
.call dumpAllToFile(0, 1)
Debugging Facilities in the VM
These functions sometimes get added to or modified as the VM implementors desire, so the folowing list is only guaranteed to apply to vw5i.3, but is likely to be the same thereafter. What follows is a subset of the full functions. If these don't fit the bill you'll probably need the VM source anyway, and you can get the functions by browsing the source. miscellaneous but useful
dumping the stacks of all Smalltalk processes
examining the Smalltalk stack
examining Smalltalk objects
examining native code
The Debug Engine
Why and How to Create Reproducible Crashes
| 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
ObjectMemory saveAs: 'crash' thenQuit: true.
'load.st' asFilename fileIn
Edit
Rename
Changes
History
Upload
Download
Back to Top