High Performance Computing

 

[Cygwin Tips] [Floppy Disks] [NAG Toolpack 2.5] [Web PNG images] [Controlling symbol scope in C]

 

Cygwin Tips

vim

By default, the vim editor comes up in an old-fashioned and unhelpful vi-compatible mode. Simply creating an empty .vimrc file in your $HOME directory puts it into a more modern mode but I like to include a few other simple settings in my $HOME/.vimrc file:

:set autoindent
:set backspace=indent,eol,start
:set expandtab

Sometimes programs fail. If we are lucky, the error may be detected by internal run-time tests (eg a failed assert()) or by the operating system (eg a Segmentation fault). Of course, it would be best if we had used modern software design tools to ensure our program was error-free or special error-detecting build strategies (eg a bounds checking compiler); we might also have made our initial runs under the (gdb) debugger which gives us complete control to breakpoint our code and to inspect the stack and other memory at breakpoints and after exceptions. Eventually, however, our program goes out into the wild and we would like some meaningful way of recording the program state when an error is detected.

There are three traditional approaches:

  1. Register dumps simply print the current processor state, including the stack and frame pointers. For most programs written in high level languages, this is not very illuminating.

  2. Stack traces use the frame (or base) pointer to walk up the stack through the frames associated with each calling function; they typically give the return address of the calling function and the first few parameters passed to the called function. You can later translate the calling return address back into a source file and line number; this along with the parameters usually gives a good indication of the program state when an error occurred. Note that most software that produces stack traces depends on all functions using the normal C-style calling sequence (not stdcall or fastcall) and requires the presence of a valid frame pointer on the stack (don't pass -fomit-frame-pointer to gcc). Some compilers (eg Microsoft cl) also omit frame pointers at high levels of optimisation. 

  3. Core dumps capture the complete memory state of a dead process; they have for years been the traditional debug tool of the hard-core programmer who would carefully mark up a hex (or octal) core dump printed on a big stack of fan-fold paper using information from the load map. Times have now changed; modern debuggers such as gdb will accept core dumps and give full symbolic access to memory and to the stack. Under Linux, it's easy to get a core dump; just issue the command ulimit -c 50000. For more fine-grained control, you can write to the file /proc/sys/kernel/core_pattern. See man proc for details. Under Cygwin, there are various "gotcha"s which make postmortem core debugging rather more problematic. Read on.

It is quite easy to generate your own stack traces; we'll try this out first before looking at Cygwin's default stack traces and core dumps. Here is a simple recursive C program:
  #include <stdlib.h>
  #include <stdio.h>
 
  int fac(int i) {
    return
      i<=1 ? 1 :
             i * fac (i-1); }
 
  int main(int argc, char* argv[]) {
    int i;
    if (argc!=2 || (i=atoi(argv[1]))<1) {
      fprintf(stderr,"Bad args\n");
      return 1; }
    printf("%d\n",fac(i));
    return 0; }

We will modify it to produce a stack trace