11. Debugging AMPS Modules

This chapter includes tips and techniques for debugging AMPS modules. When creating a module, 60East recommends creating a test plan for the module, including testing how the module handles misconfiguration and invalid input.

Logging for Debugging

One of the most important techniques in debugging an AMPS module is to creating and implementing a consistent logging strategy for debugging that allows you to easily trace execution through the module.

As described in the section on logging, Using amps_logger, you can make debugging easier by providing comprehensive tracing through your module, particularly in debug builds of your module. By being able to trace progress through the module, you can quickly isolate the point at which a problem occurs. In many cases, this provides enough information to correct the problem.

Running AMPS Under the Debugger

In some cases, it may be necessary to step through the module to be able to find and correct the problem. For these problems, it’s useful to run AMPS under a debugger, and step through calls to your module. The instructions in this section provide advice for debugging using the gcc compiler and gdb debugger: you may need to adapt this advice for other debuggers.

Before running AMPS under the debugger, create the smallest possible test case to demonstrate the problem that needs to be fixed. This includes creating an AMPS configuration file that has only the features necessary to show the problem. The more you can simplify activity in AMPS while debugging your module, the more efficiently you can find the problem.

Once you have a minimal test case, use the following guidelines to inspect your module within AMPS.

  1. Build the module with debugging enabled. On gcc, this means providing the -g flag to the compiler.

  2. Start the debugger with the AMPS binary as the target. For example, after saving your test configuration to test_config.xml, you might use this command line to start gdb with AMPS as the target:

    gdb --args $AMPS_HOME/bin/ampServer test_config.xml
    

    This starts the debugger, but does not start AMPS or load your module.

  3. Set a breakpoint in the part of your module that you want to step through. For example, if you are debugging the way that an entitlement module processes entitlement checks and the amps_entitlement_check function for the module is in the file my_module.c, you set a breakpoint to stop execution when execution reaches that function

    Because there is no file with that name currently loaded, gdb prompts you to confirm that it will look for the function in a shared library:

    (gdb)
    b my_module.c:amps_entitlement_check
    
    No symbol table is loaded. Use the "file" command.
    Make breakpoint pending on future shared library load?
    (y or [n])
    y
    
    Breakpoint 1 (file_entitlement.c:amps_entitlement_check) pending.
    (gdb)
    

    gdb will set the breakpoint on that function when a shared library is loaded with that filename and that function.

  4. Start the debugger and run the test program.

    (gdb) run

  5. AMPS will run until the test program causes AMPS to call the function where you’ve set the breakpoint. At that point, gdb stops the thread that’s calling the function in the debugger. At this point, normal debugging procedures apply.

Notice that, while you are debugging, AMPS will typically log multiple instances of message 30-0000, indicating a potential stuck thread. These messages are expected. Because you have stopped a thread in the debugger,AMPS has detected that the thread you are debugging on is not making progress as it normally would, and is reporting that warning.