2 Processor specific parts of the GDB stub
4 Copyright (c) 2008-2009, Apple Inc. All rights reserved.
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 Copyright (c) 2008, Apple, Inc
18 All rights reserved. This program and the accompanying materials
19 are licensed and made available under the terms and conditions of the BSD License
20 which accompanies this distribution. The full text of the license may be found at
21 http://opensource.org/licenses/bsd-license.php
23 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
24 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
28 #include <GdbStubInternal.h>
29 #include <Library/CacheMaintenanceLib.h>
30 #include <Library/PrintLib.h>
33 // Array of exception types that need to be hooked by the debugger
34 // (efi, gdb) //efi number
36 EFI_EXCEPTION_TYPE_ENTRY gExceptionType
[] = {
37 { EXCEPT_ARM_SOFTWARE_INTERRUPT
, GDB_SIGTRAP
}
38 // { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
39 // { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
40 // { EXCEPT_ARM_DATA_ABORT, GDB_SIGEMT },
41 // { EXCEPT_ARM_RESERVED, GDB_SIGILL }
44 // Shut up some annoying RVCT warnings
46 #pragma diag_suppress 1296
49 UINTN gRegisterOffsets
[] = {
50 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R0
),
51 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R1
),
52 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R2
),
53 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R3
),
54 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R4
),
55 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R5
),
56 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R6
),
57 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R7
),
58 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R8
),
59 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R9
),
60 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R10
),
61 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R11
),
62 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, R12
),
63 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, SP
),
64 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, LR
),
65 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, PC
),
93 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, CPSR
)
96 // restore warnings for RVCT
98 #pragma diag_default 1296
102 Return the number of entries in the gExceptionType[]
104 @retval UINTN, the number of entries in the gExceptionType[] array.
111 return sizeof (gExceptionType
)/sizeof (EFI_EXCEPTION_TYPE_ENTRY
);
116 Return the number of entries in the gRegisters[]
118 @retval UINTN, the number of entries (registers) in the gRegisters[] array.
125 return sizeof (gRegisterOffsets
)/sizeof (UINTN
);
130 Check to see if the ISA is supported.
131 ISA = Instruction Set Architecture
133 @retval TRUE if Isa is supported
138 IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
150 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
151 It is, by default, set to find the register pointer of the ARM member
152 @param SystemContext Register content at time of the exception
153 @param RegNumber The register to which we want to find a pointer
154 @retval the pointer to the RegNumber-th pointer
157 FindPointerToRegister(
158 IN EFI_SYSTEM_CONTEXT SystemContext
,
163 ASSERT(gRegisterOffsets
[RegNumber
] < 0xF00);
164 TempPtr
= ((UINT8
*)SystemContext
.SystemContextArm
) + gRegisterOffsets
[RegNumber
];
165 return (UINT32
*)TempPtr
;
170 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
171 @param SystemContext Register content at time of the exception
172 @param RegNumber the number of the register that we want to read
173 @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
174 @retval the pointer to the next character of the output buffer that is available to be written on.
178 IN EFI_SYSTEM_CONTEXT SystemContext
,
186 if (gRegisterOffsets
[RegNumber
] > 0xF00) {
187 AsciiSPrint(OutBufPtr
, 9, "00000000");
193 while (RegSize
< 32) {
194 Char
= mHexToStr
[(UINT8
)((*FindPointerToRegister(SystemContext
, RegNumber
) >> (RegSize
+4)) & 0xf)];
195 if ((Char
>= 'A') && (Char
<= 'F')) {
196 Char
= Char
- 'A' + 'a';
200 Char
= mHexToStr
[(UINT8
)((*FindPointerToRegister(SystemContext
, RegNumber
) >> RegSize
) & 0xf)];
201 if ((Char
>= 'A') && (Char
<= 'F')) {
202 Char
= Char
- 'A' + 'a';
206 RegSize
= RegSize
+ 8;
213 Reads the n-th register's value into an output buffer and sends it as a packet
214 @param SystemContext Register content at time of the exception
215 @param InBuffer Pointer to the input buffer received from gdb server
219 IN EFI_SYSTEM_CONTEXT SystemContext
,
224 CHAR8 OutBuffer
[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
225 CHAR8
*OutBufPtr
; // pointer to the output buffer
227 RegNumber
= AsciiStrHexToUintn (&InBuffer
[1]);
229 if (RegNumber
>= MaxRegisterCount()) {
230 SendError (GDB_EINVALIDREGNUM
);
234 OutBufPtr
= OutBuffer
;
235 OutBufPtr
= BasicReadRegister (SystemContext
, RegNumber
, OutBufPtr
);
237 *OutBufPtr
= '\0'; // the end of the buffer
238 SendPacket(OutBuffer
);
243 Reads the general registers into an output buffer and sends it as a packet
244 @param SystemContext Register content at time of the exception
248 ReadGeneralRegisters (
249 IN EFI_SYSTEM_CONTEXT SystemContext
255 UINTN RegisterCount
= MaxRegisterCount();
257 // It is not safe to allocate pool here....
258 OutBuffer
= AllocatePool((RegisterCount
* 8) + 1); // 8 bytes per register in string format plus a null to terminate
259 OutBufPtr
= OutBuffer
;
260 for (Index
= 0; Index
< RegisterCount
; Index
++) {
261 OutBufPtr
= BasicReadRegister (SystemContext
, Index
, OutBufPtr
);
265 SendPacket(OutBuffer
);
271 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
272 @param SystemContext Register content at time of the exception
273 @param RegNumber the number of the register that we want to write
274 @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
275 @retval the pointer to the next character of the input buffer that can be used
278 *BasicWriteRegister (
279 IN EFI_SYSTEM_CONTEXT SystemContext
,
285 UINTN TempValue
; // the value transferred from a hex char
286 UINT32 NewValue
; // the new value of the RegNumber-th Register
288 if (gRegisterOffsets
[RegNumber
] > 0xF00) {
294 while (RegSize
< 32) {
295 TempValue
= HexCharToInt(*InBufPtr
++);
297 if ((INTN
)TempValue
< 0) {
298 SendError (GDB_EBADMEMDATA
);
302 NewValue
+= (TempValue
<< (RegSize
+4));
303 TempValue
= HexCharToInt(*InBufPtr
++);
305 if ((INTN
)TempValue
< 0) {
306 SendError (GDB_EBADMEMDATA
);
310 NewValue
+= (TempValue
<< RegSize
);
311 RegSize
= RegSize
+ 8;
313 *(FindPointerToRegister(SystemContext
, RegNumber
)) = NewValue
;
318 /** ‘P n...=r...’
319 Writes the new value of n-th register received into the input buffer to the n-th register
320 @param SystemContext Register content at time of the exception
321 @param InBuffer Ponter to the input buffer received from gdb server
325 IN EFI_SYSTEM_CONTEXT SystemContext
,
330 CHAR8 RegNumBuffer
[MAX_REG_NUM_BUF_SIZE
]; // put the 'n..' part of the message into this array
332 CHAR8
*InBufPtr
; // pointer to the input buffer
334 // find the register number to write
335 InBufPtr
= &InBuffer
[1];
336 RegNumBufPtr
= RegNumBuffer
;
337 while (*InBufPtr
!= '=') {
338 *RegNumBufPtr
++ = *InBufPtr
++;
340 *RegNumBufPtr
= '\0';
341 RegNumber
= AsciiStrHexToUintn (RegNumBuffer
);
343 // check if this is a valid Register Number
344 if (RegNumber
>= MaxRegisterCount()) {
345 SendError (GDB_EINVALIDREGNUM
);
348 InBufPtr
++; // skips the '=' character
349 BasicWriteRegister (SystemContext
, RegNumber
, InBufPtr
);
355 Writes the new values received into the input buffer to the general registers
356 @param SystemContext Register content at time of the exception
357 @param InBuffer Pointer to the input buffer received from gdb server
362 WriteGeneralRegisters (
363 IN EFI_SYSTEM_CONTEXT SystemContext
,
368 CHAR8
*InBufPtr
; /// pointer to the input buffer
370 UINTN RegisterCount
= MaxRegisterCount();
372 MinLength
= (RegisterCount
* 8) + 1; // 'G' plus the registers in ASCII format
374 if (AsciiStrLen(InBuffer
) < MinLength
) {
375 //Bad message. Message is not the right length
376 SendError (GDB_EBADBUFSIZE
);
380 InBufPtr
= &InBuffer
[1];
382 // Read the new values for the registers from the input buffer to an array, NewValueArray.
383 // The values in the array are in the gdb ordering
384 for(i
= 0; i
< RegisterCount
; i
++) {
385 InBufPtr
= BasicWriteRegister (SystemContext
, i
, InBufPtr
);
392 // Use SWI 0xdbdbdb as the debug instruction
393 #define GDB_ARM_BKPT 0xefdbdbdb
395 BOOLEAN mSingleStepActive
= FALSE
;
396 UINT32 mSingleStepPC
;
397 UINT32 mSingleStepData
;
398 UINTN mSingleStepDataSize
;
405 } ARM_SOFTWARE_BREAKPOINT
;
407 #define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
408 #define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
410 LIST_ENTRY BreakpointList
;
413 Insert Single Step in the SystemContext
415 @param SystemContext Register content at time of the exception
419 IN EFI_SYSTEM_CONTEXT SystemContext
422 if (mSingleStepActive
) {
423 // Currently don't support nesting
426 mSingleStepActive
= TRUE
;
428 mSingleStepPC
= SystemContext
.SystemContextArm
->PC
;
430 mSingleStepDataSize
= sizeof (UINT32
);
431 mSingleStepData
= (*(UINT32
*)mSingleStepPC
);
432 *(UINT32
*)mSingleStepPC
= GDB_ARM_BKPT
;
433 if (*(UINT32
*)mSingleStepPC
!= GDB_ARM_BKPT
) {
434 // For some reason our breakpoint did not take
435 mSingleStepActive
= FALSE
;
438 InvalidateInstructionCacheRange((VOID
*)mSingleStepPC
, mSingleStepDataSize
);
439 //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
444 Remove Single Step in the SystemContext
446 @param SystemContext Register content at time of the exception
450 IN EFI_SYSTEM_CONTEXT SystemContext
453 if (!mSingleStepActive
) {
457 if (mSingleStepDataSize
== sizeof (UINT16
)) {
458 *(UINT16
*)mSingleStepPC
= (UINT16
)mSingleStepData
;
460 //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
461 *(UINT32
*)mSingleStepPC
= mSingleStepData
;
463 InvalidateInstructionCacheRange((VOID
*)mSingleStepPC
, mSingleStepDataSize
);
464 mSingleStepActive
= FALSE
;
470 Continue. addr is Address to resume. If addr is omitted, resume at current
473 @param SystemContext Register content at time of the exception
478 IN EFI_SYSTEM_CONTEXT SystemContext
,
482 if (PacketData
[1] != '\0') {
483 SystemContext
.SystemContextArm
->PC
= AsciiStrHexToUintn(&PacketData
[1]);
489 Single step. addr is the Address at which to resume. If addr is omitted, resume
492 @param SystemContext Register content at time of the exception
497 IN EFI_SYSTEM_CONTEXT SystemContext
,
505 GetBreakpointDataAddress (
506 IN EFI_SYSTEM_CONTEXT SystemContext
,
507 IN UINTN BreakpointNumber
514 GetBreakpointDetected (
515 IN EFI_SYSTEM_CONTEXT SystemContext
523 IN EFI_SYSTEM_CONTEXT SystemContext
,
524 IN UINTN BreakpointNumber
530 ARM_SOFTWARE_BREAKPOINT
*
531 SearchBreakpointList (
536 ARM_SOFTWARE_BREAKPOINT
*Breakpoint
;
538 Current
= GetFirstNode(&BreakpointList
);
539 while (!IsNull(&BreakpointList
, Current
)) {
540 Breakpoint
= ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current
);
542 if (Address
== Breakpoint
->Address
) {
546 Current
= GetNextNode(&BreakpointList
, Current
);
557 ARM_SOFTWARE_BREAKPOINT
*Breakpoint
;
559 Breakpoint
= SearchBreakpointList(Address
);
561 if (Breakpoint
!= NULL
) {
565 // create and fill breakpoint structure
566 Breakpoint
= AllocatePool(sizeof(ARM_SOFTWARE_BREAKPOINT
));
568 Breakpoint
->Signature
= ARM_SOFTWARE_BREAKPOINT_SIGNATURE
;
569 Breakpoint
->Address
= Address
;
570 Breakpoint
->Instruction
= *(UINT32
*)Address
;
572 // Add it to the list
573 InsertTailList(&BreakpointList
, &Breakpoint
->Link
);
575 // Insert the software breakpoint
576 *(UINT32
*)Address
= GDB_ARM_BKPT
;
577 InvalidateInstructionCacheRange((VOID
*)Address
, 4);
579 //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
587 ARM_SOFTWARE_BREAKPOINT
*Breakpoint
;
589 Breakpoint
= SearchBreakpointList(Address
);
591 if (Breakpoint
== NULL
) {
595 // Add it to the list
596 RemoveEntryList(&Breakpoint
->Link
);
598 // Restore the original instruction
599 *(UINT32
*)Address
= Breakpoint
->Instruction
;
600 InvalidateInstructionCacheRange((VOID
*)Address
, 4);
602 //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
604 FreePool(Breakpoint
);
610 IN EFI_SYSTEM_CONTEXT SystemContext
,
619 ErrorCode
= ParseBreakpointPacket(PacketData
, &Type
, &Address
, &Length
);
621 SendError ((UINT8
)ErrorCode
);
626 case 0: //Software breakpoint
630 DEBUG((EFI_D_ERROR
, "Insert breakpoint default: %x\n", Type
));
631 SendError (GDB_EINVALIDBRKPOINTTYPE
);
635 SetBreakpoint(Address
);
643 IN EFI_SYSTEM_CONTEXT SystemContext
,
652 //Parse breakpoint packet data
653 ErrorCode
= ParseBreakpointPacket (PacketData
, &Type
, &Address
, &Length
);
655 SendError ((UINT8
)ErrorCode
);
660 case 0: //Software breakpoint
664 SendError (GDB_EINVALIDBRKPOINTTYPE
);
668 ClearBreakpoint(Address
);
674 InitializeProcessor (
678 // Initialize breakpoint list
679 InitializeListHead(&BreakpointList
);
687 if ((UINT32
)Address
< 0x80000000) {
696 IN EFI_EXCEPTION_TYPE ExceptionType
,
697 IN OUT EFI_SYSTEM_CONTEXT SystemContext
700 UINT32 ExceptionAddress
;
703 // Is it a debugger SWI?
704 ExceptionAddress
= SystemContext
.SystemContextArm
->PC
-= 4;
705 Instruction
= *(UINT32
*)ExceptionAddress
;
706 if (Instruction
!= GDB_ARM_BKPT
) {
710 // Special for SWI-based exception handling. SWI sets up the context
711 // to return to the instruction following the SWI instruction - NOT what we want
713 SystemContext
.SystemContextArm
->PC
= ExceptionAddress
;