4. Determining Program Behavior

There are a couple of tools that allow us to look into program behavior at a more closer level. Lets look at some of these:

4.1. strace/truss(Solaris)

These programs trace system calls a program makes as it makes them.

Useful options:

  1. -f (follow fork)

  2. -ffo filename (output trace to filename.pid for forking)

  3. -i (Print instruction pointer for each system call)

4.2. ltrace

This utility is extremely useful. It traces ALL library calls made by a program.

Useful options:

  1. -S (display syscalls too)

  2. -f (follow fork)

  3. -o filename (output trace to filename)

  4. -C (demangle C++ function call names)

  5. -n 2 (indent each nested call 2 spaces)

  6. -i (prints instruction pointer of caller)

  7. -p pid (attaches to specified pid)

4.3. LD_PRELOAD

This is an environment variable that allows us to add a library to the execution of a particular program. Any functions in this library automatically override standard library functions. Sorry, you can't use this with suid programs.

Example:

% gcc -o preload.so -shared preload.c -ldl

% LD_PRELOAD=preload.so ssh students.uiuc.edu

4.4. gdb

gdb is the GNU debugger. It is very intimidating to most people, but there really is no reason for it to be. It is very well done for a command line debugger. There is a nice GUI front end to it known as DDD, but our purposes will require a closer relationship with the command line.

gdb has a nice built-in help system organized by topic. typing help will show you the catagories. The main commands we will be interested in are run, break, cont, stepi, finish, disassemble, bt, info [registers/frame], and x. Every command in gdb can be followed by a number N, which means repeat N times. For example, stepi 1000 will step over 1000 assembly instructions.

-> Example using gdb to set breakpoints in functions with and without debugging symbols.