# Modula-3 Debugging

A Modula-3 aware version of gdb may be used to debug Modula-3 code. It understands Modula-3 types, declarations, and expressions. It also supports threads. The usual gdb commands may be used. This document discusses three areas where special care is required: garbage collection, threads, and calling non standard procedures. While gdb tries to determine automatically the language for the current frame (procedure), you may sometimes want to explicitely set the current language:

        (m3gdb) set language m3
        (m3gdb) set language c

## Garbage collection

On some platforms, a VM synchronized version of the garbage collector uses SIGSEGV signals. By default, gdb stops and prints a message each time SIGSEGV is received. This behavior may be changed with the `handle` command. The simplest way to avoid these signals is to disable the VM synchronized garbage collector, using the `@M3novm` command line option:

    cassis> m3gdb myprog
    (m3gdb) run @M3novm ...other arguments...

If you prefer to keep the VM synchronized collector while debugging, you may use:

        (m3gdb) handle SIGSEGV noprint pass

However, you will then not be able to examine the protected memory regions. You may unprotect the memory with:

        (m3gdb) call RTCollectorSRC.FinishVM()

You may disable the memory protection for the rest of the execution with:

        (m3gdb) call RTCollectorSRC.DisableVM()

## Threads

On platforms where Modula-3 uses native threads (NT), the gdb thread commands may be used (`info thread`, and `thread`) to list the threads and switch to another thread.

On other platforms, `m3gdb` provides `threads` to list the threads, and `switch id` to switch to another thread indicated by `id`. You must switch back to the thread where the program stopped before continuing the execution (i.e. the first thread listed by the `threads`). If the `switch` command is interrupted, the state of `m3gdb` is essentially random and it will most likely crash. The current language must be `m3` for the `threads` and `switch` commands to work.

## Calling procedures from m3gdb

Modula-3 procedures are mapped as closely as possible into C procedures and may be called by gdb using `call`. Two differences exist: "large" results and nested procedures.

First, procedures that return structured values (i.e. records, arrays or sets) take an extra parameter. The last parameter is a pointer to the memory that will receive the returned result. This parameter was necessary because some C compilers return structured results by momentarily copying them into global memory. The global memory scheme works fine until it's preempted by the Modula-3 thread scheduler.

Second, nested procedures are passed an extra parameter, the ``static link''. The exact details of how that parameter are passed are system dependent. When a nested procedure is passed as a parameter, the address of the corresponding C procedure and its extra parameter are packaged into a small closure record. The address of this record is actually passed. Any call through a formal procedure parameter first checks to see whether the parameter is a closure or not and then makes the appropriate call. Likewise, assignments of formal procedure parameters to variables perform runtime checks for closures.

`<*EXTERNAL*>` procedures have no extra parameters. except if they return large results??