Copyright (c) Hyperion Entertainment and contributors.

How to open and use the exec debug interface

From AmigaOS Documentation Wiki
Revision as of 16:30, 18 February 2013 by Alexandre Balaban (talk | contribs) (→‎Tutorial: Added link to GDB article)
Jump to navigation Jump to search

Author

Alfkil Wennermark
Copyright (c) 2010 Alfkil Wennermark
Used by permission.

Tutorial

Next step in my small series concerns itself with how to open and use the "secret" (but very useful) debug interface. Thanks to Steven Solie and Thomas Frieden.

Probably the best way to trap exceptions from within your code is to use the debug interface, that is "hidden" inside exec.library. The main problem with this interface is, that it is not very well documented. My main source of documentation on this issue is the amigaos-nat.c file from Thomas Friedens GDB sources. These can be found inside the adtools project on sourceforge.net.

The following code just plainly opens the interface, attaches a debug hook to itself, causes an exception and tells you what has happened. Normally you wouldn't attach the hook to your own process. Rather you would open whatever code you want to debug with fx. LoadSeg(), run it with CreateNewProc() (or some other way) and attach the debug hook to it. To keep things simple, though, this code just attaches the hook to itself.

/* debugtrap.cExample of use of the exec debug interface
by Alfkil Wennermark 2010
 
Thanks to Steven Solie, Thomas Frieden and others
 
This code is partially copied from Thomas' GDB source
*/
 
 
#include <proto/exec.h>
#include <proto/dos.h>
 
#include <exec/types.h>
#include <exec/interrupts.h>
#include <exec/tasks.h>
 
#include <dos/dos.h>
 
#include <stdio.h>
 
 
struct DebugIFace *IDebug = 0;
 
struct KernelDebugMessage
{
  uint32 type;
  union
  {
    struct ExceptionContext *context;
    struct Library *library;
  } message;
};
 
static ULONG amigaos_debug_callback(struct Hook *, struct Task *, struct KernelDebugMessage *);
 
struct Hook debug_hook;
struct Task *amiga_task;
 
BPTR exec_seglist;
ULONG debug_data = 1234;
 
void init()
{
  IDebug = (struct DebugIFace *)IExec->GetInterface((struct Library *)SysBase, "debug", 1, 0);
  if (!IDebug)
  {
    printf("Can't get DEBUG accessn");
    exit(RETURN_FAIL);
  }
 
  debug_hook.h_Entry = (ULONG (*)())amigaos_debug_callback;
  debug_hook.h_Data =(APTR)&debug_data;
 
  /* NB: Ideally we would start up another task, that
  we want to debug, and attach ourselves to that
  task using the debug hook, but for simplicity
  we just use our own task here */
  amiga_task = IExec->FindTask(NULL);
  IDebug->AddDebugHook(amiga_task, &debug_hook);
}
 
void end()
{
  IDebug->AddDebugHook(amiga_task, 0);
 
  if (IDebug)IExec->DropInterface((struct Interface *)IDebug);
  IDebug = NULL;
}
 
 
 
ULONG
amigaos_debug_callback(struct Hook *hook, struct Task *currentTask,
struct KernelDebugMessage *dbgmsg)
{
  struct ExecIFace *IExec = (struct ExecIFace *)((struct ExecBase *)SysBase)->MainInterface;
 
  uint32 *data = (uint32 *)hook->h_Data;
 
  /* these are the 4 types of debug msgs: */
  switch (dbgmsg->type)
  {
    case DBHMT_REMTASK:
    *data = 9;
    break;
 
    case DBHMT_EXCEPTION:
    *data = 11;
    break;
 
    case DBHMT_OPENLIB:
    *data = 13;
    break;
 
    case DBHMT_CLOSELIB:
    *data = 15;
    break;
 
    default:
    *data = 0;
    break;
  }
  /* returning 1 will suspend the task ! */
  return 0;
}
 
 
int main()
{
  init();
 
  /* Cause an exception on purpose: */
  uint32 *beef = 0;
  *beef = 0L;
 
  printf("We received a");
  switch (debug_data)
  {
  case 9:
    printf(" REMTASK");
    break;
  case 11:
    printf("n EXCEPTION");
    break;
  case 13:
    printf("n OPENLIB");
    break;
  case 15:
    printf(" CLOSELIB");
    break;
 
  default:
    printf("n unknown");
  break;
  }
  printf(" signal!n");
 
  end();
 
  return RETURN_OK;
}