How to receive debug events ?

15 posts / 0 new
Last post
corto's picture
Last seen: 7 years 5 months ago
Joined: 2011-09-09 11:43
How to receive debug events ?


At least on Sam440, I want to program debug registers and receive interrupts. The first point is done but I need help for the second one, if it is possible.

1/ My first approach is to call AddIntServer(). I see there is a trap TRAPNUM_INST_BREAKPOINT that is certainly what I want. In the include "exec/interrupts.h", it is said "These are used with AddIntServer/SetIntVector to install global trap handler". But this trapnum is rejected by AddIntServer.
In the include, an interrupt INTB_NMI is declared as a "fake INT definition, used only for AddIntServer and the like" but with no more information, I don't know what to do except register it with AddIntServer but I can't get interrupts and specify the wanted type of interrupts.
In addition to that, INT_NMI has the same value than INT_SETCLR in "hardware/intbits.h", I don't know if that hurts.

Should I use TRAPNUM_INST_BREAKPOINT with SetIntVector only, and not AddIntServer ?

2/ The second approach would be to use AddDebugHook, thinking I will be notified with the DBHMT_EXCEPTION case. It seems to be more high-level but do I still have to program the debug registers myself ?
It is maybe the best option.

3/ On PowerPC G3 and G4, all that should rely on the performance monitor. There is an API for that but I've never obtained the minimal result. There is a function called SetInterruptVector that seems to work by itself but again, I can't get the performance monitor working.

4/ Still in the performance monitor resource, there is a function called SetBreakpoint, on instruction or data. That sounds like the TRAPNUM_[INST|DATA]_BREAKPOINT and it is said that a handler can be set via SetTaskTrap ... But about TrapNums in "exec/interrupts.h", it was written that SetTaskTrap was "to install local task traps".

There are many questions but several points must be clarified, some parts in autodocs and includes are really confusing.

Thanks !

Belxjander's picture
Last seen: 8 years 7 months ago
Joined: 2011-02-25 11:53
Are you setting an

Are you setting an "exclusive" Interrupt Handler which is the only routine on that interrupt
or setting a "chained" interrupt handler ?

as to me it reads that you are setting a one-owner handler for that interrupt across the entire
system for your performance usage.

Can you clarify this?

corto's picture
Last seen: 7 years 5 months ago
Joined: 2011-09-09 11:43
I don't know what makes an

I don't know what makes an "exclusive" interrupt handler or not. If I understand well, SetIntVector is to take the exclusive control of the interrupt source and AddIntServer allows to register a handler to a chain.

Looking at the nature of what I do, I think I should use an exclusive handler.

This morning, I successfully registered an interrupt vector with TRAPNUM_INST_BREAKPOINT. I correctly programmed the debug registers of the PPC440, so I obtained (in the status register) the notification that an interrupt event happened and it was confirmed by the update of the register SRR0.
But I didn't enter my interrupt handler.

hypex's picture
Last seen: 1 day 9 hours ago
Joined: 2011-09-09 16:20
@corto I have experience


I have experience with this from programming CIAgent. With that I wanted to catch a DSI that registered in the CIA memory space. I had to use SetIntVector() and a TRAP number like you want to. Like you I found AddIntServer() doesn't work, unfortunately, as it would be a cleaner approach. IIRC I allocated an Interrupt using AllocSysObject() using the NATIVE interrupt type. That is the type for a PPC interrupt. They changed the type number for OS4 code and kept the old one for 68K code. I then set up the Interrupt and passed it to SetIntVector(). Watch though as AllocSysObject() never used to clear the memory it returned and it used to result in crashes from corrupt node data. Also when using SetIntVector() you will be exclusive. So if you need to "pass the buck" then use a return with the parameters you get from the Exec interrupt and the routine returned from SetIntVector() when you loaded your one in.

This is from the top if my head so if you need a more clearer example I will post from my sources. :-)

Belxjander's picture
Last seen: 8 years 7 months ago
Joined: 2011-02-25 11:53
I'm also going to need to

I'm also going to need to know things like this...
is the CIAgent sources going to become available?

can you post an example?

Thanks in advance,

hypex's picture
Last seen: 1 day 9 hours ago
Joined: 2011-09-09 16:20
I hadn't planned to give out

I hadn't planned to give out the CIAgent souces just yet but of course I hadn't planned to stall it so long either.

But here is some code examples, what CIAgent is based on and a full program to test. The first one here installs a local trap handler via SerTaskTrap(). It's like that Abacus divide by zero catch example if you have seen it. It's called Trap.c.

  1. #include <proto/exec.h>
  2. #include <exec/interrupts.h>
  4. uint32 trapCode(struct ExceptionContext *ctx, struct ExecBase *SysBase,
  5. APTR userData)
  6. {
  7. struct ExecIFace *IExec = (struct ExecIFace *)SysBase->MainInterface;
  9. IExec->DebugPrintF("Exception at instruction pointer %p\n",
  10. ctx->ip);
  11. /* To recover from this, we need to skip the offending instruction,
  12. * otherwise, it will re-try the instruciton.
  13. * Note: This depends on the type of instruction. Refer to the
  14. * "PowerPC Programming Environments for 32 bit Microprocessors"
  15. * book for more information.
  16. */
  17. ctx->ip += 4;
  19. return 1;
  20. }
  22. int main(int argc, char **argv)
  23. {
  24. /* This functions sets an exception handler for catching "trap"
  25. * instructions. See <exec/interrupts> for a list of possible
  26. * exceptions
  27. */
  28. IExec->SetTaskTrap(TRAPNUM_TRAP, &trapCode, 0);
  30. /* Generate an exception */
  31. __asm volatile ("trap");
  33. return 0;
  34. }

This next one is called HardHits.c. CIAgent is directly based on it. It catches and displays illegal memory accesses.

  1. #include <dos.h>
  2. #include <stdio.h>
  3. #include <proto/exec.h>
  4. #include <exec/types.h>
  5. #include <exec/nodes.h>
  6. #include <exec/interrupts.h>
  7. #include <exec/tasks.h>
  8. #include <dos/dos.h>
  10. struct TrapData
  11. {
  12. struct Task *MasterTask;
  13. ULONG MasterSignal;
  14. struct Task *TrappedTask;
  15. APTR TrapCode;
  16. ULONG Address;
  17. };
  19. uint32 TrapCode(struct ExceptionContext *ctx, struct ExecBase *SysBase, struct TrapData *TrapData)
  20. {
  21. struct ExecIFace *IExec = (struct ExecIFace *)SysBase->MainInterface;
  22. struct Task *Task;
  24. Task=IExec->FindTask(0);
  25. TrapData->TrappedTask=Task;
  26. TrapData->TrapCode=Task->tc_TrapCode;
  27. TrapData->Address=ctx->dar;
  29. IExec->Signal(TrapData->MasterTask, TrapData->MasterSignal);
  30. ctx->ip += 4;
  32. return 0;
  33. }
  35. int main(int argc, char **argv)
  36. {
  37. __check_abort_enabled=FALSE;
  39. struct Interrupt *TrapInt, *TrapVector;
  40. struct TrapData TrapData;
  41. ULONG signal, mask, except, action=1,received;
  43. signal=IExec->AllocSignal(-1);
  44. if (signal==-1)
  45. {
  46. printf("Unable to allocate signal.\n");
  47. return(0);
  48. }
  49. mask=1<<signal;
  50. TrapData.MasterTask=IExec->FindTask(0);
  51. TrapData.MasterSignal=mask;
  53. TrapInt=IExec->AllocSysObjectTags(ASOT_INTERRUPT, ASOINTR_Code, TrapCode, ASOINTR_Data, TrapData, TAG_END);
  54. if (!TrapInt)
  55. {
  56. printf("Unable to allocate interrupt.\n");
  57. IExec->FreeSignal(signal);
  58. return(0);
  59. }
  61. TrapInt->is_Node.ln_Succ=0;
  62. TrapInt->is_Node.ln_Pred=0;
  63. TrapInt->is_Node.ln_Type=NT_EXTINTERRUPT;
  64. TrapInt->is_Node.ln_Pri=0;
  65. TrapInt->is_Node.ln_Name="TrapIntServer";
  66. TrapInt->is_Data=&TrapData;
  67. TrapInt->is_Code=(APTR)&TrapCode;
  69. TrapVector=IExec->SetIntVector(TRAPNUM_DATA_SEGMENT_VIOLATION, TrapInt);
  71. while (action)
  72. {
  73. received=IExec->Wait(mask|SIGBREAKF_CTRL_C);
  75. if (received & mask) printf("Exception caught! Task: $%lx TrapCode: $%lx Address: $%lx\\n",TrapData.TrappedTask,TrapData.TrapCode,TrapData.Address);
  76. if (received & SIGBREAKF_CTRL_C) action=0;
  77. }
  79. printf("Teminated.\n");
  81. IExec->SetIntVector(TRAPNUM_TRAP,TrapVector);
  82. IExec->FreeSysObject(ASOT_INTERRUPT,TrapInt);
  83. IExec->FreeSignal(signal);
  85. return (0);
  86. }

The followng code will set it off. But you could write anything really to do that. This is the source to HardHitter. It's in AmigaE. :-)

  1. -> CIA hardware access test
  3. PROC main()
  4. DEF ciaa=$bfe001:PTR TO CHAR, ciab=$bfd000:PTR TO CHAR, custom=$dff000, i
  6. FOR i:=0 TO 15
  7. ciaa[i*16*16]:=i*16+i
  8. ciab[i*16*16]:=i*16+i
  11. Delay(5)

BTW you can add a native interrupt server for the interrupt blank routine and it also works for 68K code! :-D

alfkil's picture
Last seen: 2 years 11 months ago
Joined: 2011-05-10 22:02
I'm not sure if this is

I'm not sure if this is relevant, but have you looked into the exec "debug" interface?? There is a really easy way of setting up a hook function that catches all interrups from a specific task. Or maybe you want to catch interrups from the whole system?? In any case, if it has your interest, look into the "src/suspend.c" file in the db101 directory in adtools. I also posted some stuff on utilitybase with regards to interrups, but sadly that seems to be unavailable atm.

corto's picture
Last seen: 7 years 5 months ago
Joined: 2011-09-09 11:43
alfkil: I already looked at

alfkil: I already looked at your code that is very helpful ! Using the debug interface of exec was my second approach. I "just" need to try in the context I want. By the way, I still have other ways to investigate before bringing information back here.

The best for me would be to catch a specific interrupt from the whole system, else I will be forced to track only one specific process.

m3x's picture
Last seen: 11 years 10 months ago
Joined: 2012-02-28 14:39
@corto, The PLB Performance


The PLB Performance Monitor generates an interrupt number 26 on the UIC1 (Universal Interrupt Controller)

You may try with AddIntVector(74) where 74 = 16 (legacy) + 32 (UIC0) + 26 (UIC1) and interrupt type set to NT_EXTINTERRUPT (and check if the IRQ is enabled in the UIC registers)

Max Tretene, ACube Systems Srl, Soft3

corto's picture
Last seen: 7 years 5 months ago
Joined: 2011-09-09 11:43
m3x : Thanks, what you say

m3x : Thanks, what you say has a great value !

Debug registers are not related to PLB but for my profiler, I will have to work on this performance monitor in a second step.
I am not so confident at the moment playing with the interrupt controller but I will try what you propose.

About what I obtained with the debug registers. With SetIntVector and programming the debug registers by hand ... that freezes the machine if I set the Debug Enable (DE) bit in MSR (I suppose it is not planned to be hacked like that).

m3x's picture
Last seen: 11 years 10 months ago
Joined: 2012-02-28 14:39
Did you enter in supervisor

Did you enter in supervisor mode before reading / writing the MSR register ?

Max Tretene, ACube Systems Srl, Soft3

hypex's picture
Last seen: 1 day 9 hours ago
Joined: 2011-09-09 16:20
@all It is a bit unclear


It is a bit unclear what interrupts can be used. But I just went trough sone early emails with Thomas Frieden. First, it's "badly documented" as they don't want you touching this system stuff. Second, might as well forget about AddIntServer() in the future. Third, SetTaskTrap() doesn't always work as it only gets what is passed through the system, so if the system catches what you want first you won't see it. Infact it looks like this routine used to crash on my machine when trying to add a DSI. Finally, SetIntVector() and thus taking over the main system interrupt will most lilkely be needed regardless as they consider any exception programming a hack. So one is forced to "hack" that system whether we like it or not.


If that works and I suspect it should not it is at a dispute with the API where the accepted numbers are from 0 to 14. AddIntVector() is not said to take flags, and acccording to Thomas none of the newer PPC interrupts will ever work. So good luck!

But isn't this what you need? ;-)

TRAPNUM_PERFORMANCE = 0x0c000000, /* Performance monitor (System use only) */

corto's picture
Last seen: 7 years 5 months ago
Joined: 2011-09-09 11:43
hypex: Thanks for clarifying

hypex: Thanks for clarifying the situation with the Thomas' input. That confirms we can't really use these functions. About AddIntServer, I tried several sources of interrupts but I suspected some of them were not working ...

But if these functions are not intended to be touched, I wonder why it was added in recent versions of the system.

About TRAPNUM_PERFORMANCE, maybe it is used by the system for the performancemonitor resource, even if it didn't work for me in the past :-(
And the 440 has not really a performance monitor, the 440 core has none.

m3x: Yes, I did.
I found the documentation with the description of UICx and even if I won't touch that, it will be interesting to know more how the 440 works.

hypex's picture
Last seen: 1 day 9 hours ago
Joined: 2011-09-09 16:20
Well for one thing the main

Well for one thing the main functions were in 68K Exec and infact are still used by 68K code. You can add a vertical blanking interupt and your 68K code will executed on each blank! :-)

But, looking at what you want to do, such as reading PPC control registers is going too far. Since you are running as an Exec interupt where such things are hidden. How it works is the interrupt is generated and jumps into the low level code for that vector. This then saves the machine state and calls the Exec server routine. This does soem system stuff and finally calls the higher level Exec interupt code with the context. You are running as the last piece of code.

But, here is an early example I made up for a native vertical blanking interupt in C! :-D

  1. #include <proto/exec.h>
  2. #include <exec/types.h>
  3. #include <exec/nodes.h>
  4. #include <exec/interrupts.h>
  5. #include <exec/tasks.h>
  6. #include <hardware/intbits.h>
  7. #include <dos/dos.h>
  9. struct IntData
  10. {
  11. ULONG Task;
  12. ULONG Data;
  13. };
  15. uint32 TrapCode(struct ExceptionContext *ctx, struct ExecBase *SysBase, struct IntData *Data)
  16. {
  17. struct ExecIFace *IExec = (struct ExecIFace *)SysBase->MainInterface;
  19. Data->Data++;
  20. if (Data->Data==100) IExec->Signal((struct Task *)Data->Task, SIGF_SINGLE);
  22. return 0;
  23. }
  25. int main(int argc, char **argv)
  26. {
  27. struct Interrupt TrapIs;
  28. struct IntData Data;
  29. ULONG flags;
  30. ULONG running=1;
  32. Data.Task=(ULONG) IExec->FindTask(0);
  33. Data.Data=0;
  35. TrapIs.is_Node.ln_Succ=0;
  36. TrapIs.is_Node.ln_Pred=0;
  37. TrapIs.is_Node.ln_Type=NT_EXTINTERRUPT;
  38. TrapIs.is_Node.ln_Pri=11;
  39. TrapIs.is_Node.ln_Name="TrapInt";
  40. TrapIs.is_Code=(APTR)&TrapCode;
  41. TrapIs.is_Data=&Data;
  43. IExec->AddIntServer(INTB_VERTB, &TrapIs);
  45. do
  46. {
  47. flags=IExec->Wait(SIGF_SINGLE|SIGBREAKF_CTRL_C);
  48. if (flags==SIGF_SINGLE) printf("Exception caught!\n");
  49. if (flags==SIGBREAKF_CTRL_C) running=0;
  50. }
  51. while (running);
  52. IExec->RemIntServer(INTB_VERTB, &TrapIs);
  54. return 0;
  55. }
corto's picture
Last seen: 7 years 5 months ago
Joined: 2011-09-09 11:43
I have the same kind of code,

I have the same kind of code, that is used in Hieronymus.

I tried to play with AddDebugHook in order to get exceptions but now ... I don't know how to program debug exceptions that will be notified using this way and ... AddDebugHook relies on a specific process while debug registers are not aware of processes.

Log in or register to post comments