NAME

Devel::DebugInit - Perl extension for creating a debugger initialization files from C header file macros

SYNOPSIS

use Devel::DebugInit::GDB;
my $gdb = new Devel::DebugInit::GDB 'filenames' => ["/my/path/to/library.h"];
$gdb->write("/my/path/to/library/.gdbinit");

DESCRIPTION

Devel::DebugInit is aimed at C/C++ developers who want access to C macro definitions from within a debugger. It provides a simple and automated way of creating debugger initialization files for a specific project. The initialization files created contain user-defined functions built from the macro definitions in the project's header files.

By calling new(), the files specified by the 'filenames' parameter are parsed by the C preprocessor, and all macros #define'd in the file (and if desired, all macros #define'd by all #include'd files as well), will be parsed and expanded. By then calling the write() method, these macros can be written to an output file in the format of user-defined functions specific for your debugger.

By automating the process, a new file can be created whenever the code of a project changes, and that way there will not be antiquated copies lying around to trap the unwary.

NOTES

This module requires the use of one of the debugger-specific backend modules, such as Devel::DebugInit::GDB which is supplied with DebugInit. The backends supply the output routines which are specific for that debugger.

This module also requires both the C::Scan and Data::Flow modules and will not function without them.

WHY CARE?

Debugger initialization files can contain user-defined functions that make doing complicated or repetitive actions easier. Normally, from within the debugger a user can evaluate any C function call. But for a number of reasons, many projects use C preprocessor macros (#define statements) in place of an actual C function call. The use of macros instead of function calls is transparent during compilation, but most debuggers do not allow access to macros, and so the user must type in the code by hand each time s/he wants to use a macro, or must build an initialization file by hand. Retyping is tedious, but hand coding the initialization file may result in antiquated code when the project changes. By automating the process, I hope to alleviate a few headaches for developers.

There are two types of macros: macros with arguments, e.g:

#define min(x,y) ((x) < (y) ? (x) : (y))

and macros without arguments (simple macros), e.g.

#define PI 3.14

Of the two types, macros with arguments are more useful from within a debugger, and so, printing of simple macros is turned off by default (but see INTERNALS for how to turn them on).

INTERNALS

For the casual user the defaults, and the three lines given in the SYNOPSIS should be enough. But for the determined user, a few details of how things happen under the hood might be useful in customizing the output of this module.

How Devel::DebugInit Parses Files

When new() is called to create an instance of a Devel::DebugInit, the following steps occur. The C preprocessor is invoked on the file with the 'macros only' flag set (this flag defaults to '-dM' and if this does not work on your system, change the value of $C::Scan::MACROS_ONLY and let the author know, and he will try and fix it :-). This lists all macros #define'd in the file PLUS all macros #define'd in all files #include'd by that file (both the system files <types.h> and the user files "mystring.h"). This may include many more macros than is desired (not everybody really wants '_LINUX_C_LIB_VERSION_MAJOR' as a user defined function in their debugger...), so there are 3 mode flags defined that allow the user to control which macros are included: MACROS_ALL, MACROS_LOCAL, and MACROS_NONE.

MACROS_ALL, MACROS_LOCAL, and MACROS_NONE

These flags can be used to control what macros go into the print tables that Devel::DebugInit uses to create the output file. The MACROS_ALL flag instructs DebugInit to included all macros of that type in the output table. To avoid printing out all of the system level macros that can get #include'd you can use the MACROS_LOCAL flag. This indicates that only macros actually #define'd in that file should be stored, and macros #define'd in other files which are #include'd into the file should NOT be stored (they are, however, still made available for expansion purposes). The MACROS_LOCAL flag is the default for macros with arguments. Finally, the MACROS_NONE flag indicates that no macros of that type should be put in the output table. The MACROS_NONE flag is the default for the simple macros.

Output Tables and Lookup Tables

Devel::DebugInit has two separate groups of tables that it uses - lookup tables for expanding macro definitions and output tables for printing the fully expanded macros. The lookup tables always include all macros that a given file has access to, but the output tables may have many fewer. Because the user-defined functions of some debuggers can be very limited, Devel::DebugInit fully expands all macros stored in the output tables before writing them to a file. In this way, any macro which utilized other macros in its body will have those expanded in place. So by the end of the expansion process, all macros will be self defined and not rely on any other macro definition. Each macro in the output tables is expanded in this manner using the definitions in the lookup tables. Using separate lookup tables and output tables allows users to print out only those macros they care about while still be able to fully expand all macros.

METHODS

new()

Returns a blessed reference to an instance of a Devel::DebugInit subclass. Each Devel::DebugInit subclass takes a list of option value pairs as optional arguments to new. Currently there are three recognized options 'filenames', 'macros_args', and 'macros_no_args'. The 'filenames' option controls which file is used for creating the output. The 'macros_args' option controls the level of output support for macros with arguments. The 'macro_no_args' option controls the level of output support for simple macros. For example, to make a .gdbinit file useful for debugging perl or perl XSUBs try the following:

$gdb = new Devel::DebugInit::GDB 
    'filenames' => ["$Config{'archlib'}/CORE/perl.h"], 
    'macros_args'    => $Devel::DebugInit::MACROS_ALL,
    'macros_no_args' => $Devel::DebugInit::MACROS_ALL;

$gdb->write();

When written, this will create a file that is about 110k in size and have about 1750 user-defined functions. So it may be useful to limit it in scope somewhat. It is not clear that simple macros are useful from within a debugger, so the default value for 'macros_no_args' is MACROS_NONE, and to avoid printing all system level macros, the default for 'macros_args' is MACROS_LOCAL. NOTE that by using MACROS_LOCAL, you will inhibit printing of all macros not #define'd in the file listed, both from local header files and system headers alike. To get around this multiple files can be included in the array ref for the 'filenames' option. Each files macros are added to a common lookup table, but only the macros #defined in each file are printed. So could do the following:

   $gdb = new Devel::DebugInit::GDB 
       'filenames' => ["$Config{'archlib'}/CORE/perl.h",
		       "$Config{'archlib'}/CORE/sv.h", 
		       "$Config{'archlib'}/CORE/XSUB.h"], 
       'macros_args'    => $Devel::DebugInit::MACROS_LOCAL,
       'macros_no_args' => $Devel::DebugInit::MACROS_NONE;

   $gdb->write();

This reduces the output file to only 21k and 250 or so macros.

write() =head2 write($filename)

This function is overloaded by each of the debugger specific subclasses to produce output recognized by that debugger. If $filename is not given, it defaults to something reasonable for that debugger. All macros in the output table for each macro type (macros with arguments and simple macros) will be printed if it passes scrutiny by the scan() method. See the INTERNALS section for more details on controlling what macros are stored in the print tables.

scan()

The only other method of interest to users of this module is the scan() method which is also overloaded by each backend subclass. This method is called by write() to ascertain whether or not a given macro should be written out to the output file. By default, scan() stops undefined macros, blank macros (e.g. macros such as <#define VMS> which are usually just conditional compiler flags and of no use in a debugger), and macros with names that conflict with built-in debugger commands. Users desiring a very fine grained control over the output can override the builtin scan() with their own on a per need basis. For example:

package myGDB;
use Devel::DebugInit::GDB;
@myGDB::ISA = (Devel::DebugInit::GDB);

sub scan {
  my ($gdb,$key,$macro) = @_;

  #first give the superclass scan a chance 
  return 0 unless $gdb->SUPER::scan(@_);

  # dont' print out any macros with a leading '_'
  return 0 if $macro =~ /^_/;

  # print the rest
  return 1;
}

AUTHOR

Jason E. Stewart, jasons@cs.unm.edu

SEE ALSO

perl(1), Devel::DebugInit::GDB(3), C::Scan(3), and Data::Flow(3).