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
),
91 OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM
, CPSR
)
94 // restore warnings for RVCT
96 #pragma diag_default 1296
100 Return the number of entries in the gExceptionType[]
102 @retval UINTN, the number of entries in the gExceptionType[] array.
109 return sizeof (gExceptionType
)/sizeof (EFI_EXCEPTION_TYPE_ENTRY
);
114 Return the number of entries in the gRegisters[]
116 @retval UINTN, the number of entries (registers) in the gRegisters[] array.
123 return sizeof (gRegisterOffsets
)/sizeof (UINTN
);
128 Check to see if the ISA is supported.
129 ISA = Instruction Set Architecture
131 @retval TRUE if Isa is supported
136 IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
148 This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
149 It is, by default, set to find the register pointer of the ARM member
150 @param SystemContext Register content at time of the exception
151 @param RegNumber The register to which we want to find a pointer
152 @retval the pointer to the RegNumber-th pointer
155 FindPointerToRegister(
156 IN EFI_SYSTEM_CONTEXT SystemContext
,
161 ASSERT(gRegisterOffsets
[RegNumber
] < 0xF00);
162 TempPtr
= ((UINT8
*)SystemContext
.SystemContextArm
) + gRegisterOffsets
[RegNumber
];
163 return (UINT32
*)TempPtr
;
168 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
169 @param SystemContext Register content at time of the exception
170 @param RegNumber the number of the register that we want to read
171 @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
172 @retval the pointer to the next character of the output buffer that is available to be written on.
176 IN EFI_SYSTEM_CONTEXT SystemContext
,
184 if (gRegisterOffsets
[RegNumber
] > 0xF00) {
185 AsciiSPrint(OutBufPtr
, 9, "00000000");
191 while (RegSize
< 32) {
192 Char
= mHexToStr
[(UINT8
)((*FindPointerToRegister(SystemContext
, RegNumber
) >> (RegSize
+4)) & 0xf)];
193 if ((Char
>= 'A') && (Char
<= 'F')) {
194 Char
= Char
- 'A' + 'a';
198 Char
= mHexToStr
[(UINT8
)((*FindPointerToRegister(SystemContext
, RegNumber
) >> RegSize
) & 0xf)];
199 if ((Char
>= 'A') && (Char
<= 'F')) {
200 Char
= Char
- 'A' + 'a';
204 RegSize
= RegSize
+ 8;
211 Reads the n-th register's value into an output buffer and sends it as a packet
212 @param SystemContext Register content at time of the exception
213 @param InBuffer Pointer to the input buffer received from gdb server
217 IN EFI_SYSTEM_CONTEXT SystemContext
,
222 CHAR8 OutBuffer
[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
223 CHAR8
*OutBufPtr
; // pointer to the output buffer
225 RegNumber
= AsciiStrHexToUintn (&InBuffer
[1]);
227 if (RegNumber
>= MaxRegisterCount()) {
228 SendError (GDB_EINVALIDREGNUM
);
232 OutBufPtr
= OutBuffer
;
233 OutBufPtr
= BasicReadRegister (SystemContext
, RegNumber
, OutBufPtr
);
235 *OutBufPtr
= '\0'; // the end of the buffer
236 SendPacket(OutBuffer
);
241 Reads the general registers into an output buffer and sends it as a packet
242 @param SystemContext Register content at time of the exception
246 ReadGeneralRegisters (
247 IN EFI_SYSTEM_CONTEXT SystemContext
253 UINTN RegisterCount
= MaxRegisterCount();
255 // It is not safe to allocate pool here....
256 OutBuffer
= AllocatePool((RegisterCount
* 8) + 1); // 8 bytes per register in string format plus a null to terminate
257 OutBufPtr
= OutBuffer
;
258 for (Index
= 0; Index
< RegisterCount
; Index
++) {
259 OutBufPtr
= BasicReadRegister (SystemContext
, Index
, OutBufPtr
);
263 SendPacket(OutBuffer
);
269 Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
270 @param SystemContext Register content at time of the exception
271 @param RegNumber the number of the register that we want to write
272 @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
273 @retval the pointer to the next character of the input buffer that can be used
276 *BasicWriteRegister (
277 IN EFI_SYSTEM_CONTEXT SystemContext
,
283 UINTN TempValue
; // the value transferred from a hex char
284 UINT32 NewValue
; // the new value of the RegNumber-th Register
286 if (gRegisterOffsets
[RegNumber
] > 0xF00) {
292 while (RegSize
< 32) {
293 TempValue
= HexCharToInt(*InBufPtr
++);
295 if ((INTN
)TempValue
< 0) {
296 SendError (GDB_EBADMEMDATA
);
300 NewValue
+= (TempValue
<< (RegSize
+4));
301 TempValue
= HexCharToInt(*InBufPtr
++);
303 if ((INTN
)TempValue
< 0) {
304 SendError (GDB_EBADMEMDATA
);
308 NewValue
+= (TempValue
<< RegSize
);
309 RegSize
= RegSize
+ 8;
311 *(FindPointerToRegister(SystemContext
, RegNumber
)) = NewValue
;
316 /** ‘P n...=r...’
317 Writes the new value of n-th register received into the input buffer to the n-th register
318 @param SystemContext Register content at time of the exception
319 @param InBuffer Ponter to the input buffer received from gdb server
323 IN EFI_SYSTEM_CONTEXT SystemContext
,
328 CHAR8 RegNumBuffer
[MAX_REG_NUM_BUF_SIZE
]; // put the 'n..' part of the message into this array
330 CHAR8
*InBufPtr
; // pointer to the input buffer
332 // find the register number to write
333 InBufPtr
= &InBuffer
[1];
334 RegNumBufPtr
= RegNumBuffer
;
335 while (*InBufPtr
!= '=') {
336 *RegNumBufPtr
++ = *InBufPtr
++;
338 *RegNumBufPtr
= '\0';
339 RegNumber
= AsciiStrHexToUintn (RegNumBuffer
);
341 // check if this is a valid Register Number
342 if (RegNumber
>= MaxRegisterCount()) {
343 SendError (GDB_EINVALIDREGNUM
);
346 InBufPtr
++; // skips the '=' character
347 BasicWriteRegister (SystemContext
, RegNumber
, InBufPtr
);
353 Writes the new values received into the input buffer to the general registers
354 @param SystemContext Register content at time of the exception
355 @param InBuffer Pointer to the input buffer received from gdb server
360 WriteGeneralRegisters (
361 IN EFI_SYSTEM_CONTEXT SystemContext
,
366 CHAR8
*InBufPtr
; /// pointer to the input buffer
368 UINTN RegisterCount
= MaxRegisterCount();
370 MinLength
= (RegisterCount
* 8) + 1; // 'G' plus the registers in ASCII format
372 if (AsciiStrLen(InBuffer
) < MinLength
) {
373 //Bad message. Message is not the right length
374 SendError (GDB_EBADBUFSIZE
);
378 InBufPtr
= &InBuffer
[1];
380 // Read the new values for the registers from the input buffer to an array, NewValueArray.
381 // The values in the array are in the gdb ordering
382 for(i
= 0; i
< RegisterCount
; i
++) {
383 InBufPtr
= BasicWriteRegister (SystemContext
, i
, InBufPtr
);
390 // Use SWI 0xdbdbdb as the debug instruction
391 #define GDB_ARM_BKPT 0xefdbdbdb
393 BOOLEAN mSingleStepActive
= FALSE
;
394 UINT32 mSingleStepPC
;
395 UINT32 mSingleStepData
;
396 UINTN mSingleStepDataSize
;
403 } ARM_SOFTWARE_BREAKPOINT
;
405 #define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
406 #define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
408 LIST_ENTRY BreakpointList
;
411 Insert Single Step in the SystemContext
413 @param SystemContext Register content at time of the exception
417 IN EFI_SYSTEM_CONTEXT SystemContext
420 if (mSingleStepActive
) {
421 // Currently don't support nesting
424 mSingleStepActive
= TRUE
;
426 mSingleStepPC
= SystemContext
.SystemContextArm
->PC
;
428 mSingleStepDataSize
= sizeof (UINT32
);
429 mSingleStepData
= (*(UINT32
*)mSingleStepPC
);
430 *(UINT32
*)mSingleStepPC
= GDB_ARM_BKPT
;
431 if (*(UINT32
*)mSingleStepPC
!= GDB_ARM_BKPT
) {
432 // For some reason our breakpoint did not take
433 mSingleStepActive
= FALSE
;
436 InvalidateInstructionCacheRange((VOID
*)mSingleStepPC
, mSingleStepDataSize
);
437 //DEBUG((EFI_D_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
442 Remove Single Step in the SystemContext
444 @param SystemContext Register content at time of the exception
448 IN EFI_SYSTEM_CONTEXT SystemContext
451 if (!mSingleStepActive
) {
455 if (mSingleStepDataSize
== sizeof (UINT16
)) {
456 *(UINT16
*)mSingleStepPC
= (UINT16
)mSingleStepData
;
458 //DEBUG((EFI_D_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
459 *(UINT32
*)mSingleStepPC
= mSingleStepData
;
461 InvalidateInstructionCacheRange((VOID
*)mSingleStepPC
, mSingleStepDataSize
);
462 mSingleStepActive
= FALSE
;
468 Continue. addr is Address to resume. If addr is omitted, resume at current
471 @param SystemContext Register content at time of the exception
476 IN EFI_SYSTEM_CONTEXT SystemContext
,
480 if (PacketData
[1] != '\0') {
481 SystemContext
.SystemContextArm
->PC
= AsciiStrHexToUintn(&PacketData
[1]);
487 Single step. addr is the Address at which to resume. If addr is omitted, resume
490 @param SystemContext Register content at time of the exception
495 IN EFI_SYSTEM_CONTEXT SystemContext
,
503 GetBreakpointDataAddress (
504 IN EFI_SYSTEM_CONTEXT SystemContext
,
505 IN UINTN BreakpointNumber
512 GetBreakpointDetected (
513 IN EFI_SYSTEM_CONTEXT SystemContext
521 IN EFI_SYSTEM_CONTEXT SystemContext
,
522 IN UINTN BreakpointNumber
528 ARM_SOFTWARE_BREAKPOINT
*
529 SearchBreakpointList (
534 ARM_SOFTWARE_BREAKPOINT
*Breakpoint
;
536 Current
= GetFirstNode(&BreakpointList
);
537 while (!IsNull(&BreakpointList
, Current
)) {
538 Breakpoint
= ARM_SOFTWARE_BREAKPOINT_FROM_LINK(Current
);
540 if (Address
== Breakpoint
->Address
) {
544 Current
= GetNextNode(&BreakpointList
, Current
);
555 ARM_SOFTWARE_BREAKPOINT
*Breakpoint
;
557 Breakpoint
= SearchBreakpointList(Address
);
559 if (Breakpoint
!= NULL
) {
563 // create and fill breakpoint structure
564 Breakpoint
= AllocatePool(sizeof(ARM_SOFTWARE_BREAKPOINT
));
566 Breakpoint
->Signature
= ARM_SOFTWARE_BREAKPOINT_SIGNATURE
;
567 Breakpoint
->Address
= Address
;
568 Breakpoint
->Instruction
= *(UINT32
*)Address
;
570 // Add it to the list
571 InsertTailList(&BreakpointList
, &Breakpoint
->Link
);
573 // Insert the software breakpoint
574 *(UINT32
*)Address
= GDB_ARM_BKPT
;
575 InvalidateInstructionCacheRange((VOID
*)Address
, 4);
577 //DEBUG((EFI_D_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
585 ARM_SOFTWARE_BREAKPOINT
*Breakpoint
;
587 Breakpoint
= SearchBreakpointList(Address
);
589 if (Breakpoint
== NULL
) {
593 // Add it to the list
594 RemoveEntryList(&Breakpoint
->Link
);
596 // Restore the original instruction
597 *(UINT32
*)Address
= Breakpoint
->Instruction
;
598 InvalidateInstructionCacheRange((VOID
*)Address
, 4);
600 //DEBUG((EFI_D_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
602 FreePool(Breakpoint
);
608 IN EFI_SYSTEM_CONTEXT SystemContext
,
617 ErrorCode
= ParseBreakpointPacket(PacketData
, &Type
, &Address
, &Length
);
619 SendError ((UINT8
)ErrorCode
);
624 case 0: //Software breakpoint
628 DEBUG((EFI_D_ERROR
, "Insert breakpoint default: %x\n", Type
));
629 SendError (GDB_EINVALIDBRKPOINTTYPE
);
633 SetBreakpoint(Address
);
641 IN EFI_SYSTEM_CONTEXT SystemContext
,
650 //Parse breakpoint packet data
651 ErrorCode
= ParseBreakpointPacket (PacketData
, &Type
, &Address
, &Length
);
653 SendError ((UINT8
)ErrorCode
);
658 case 0: //Software breakpoint
662 SendError (GDB_EINVALIDBRKPOINTTYPE
);
666 ClearBreakpoint(Address
);
672 InitializeProcessor (
676 // Initialize breakpoint list
677 InitializeListHead(&BreakpointList
);
685 if ((UINT32
)Address
< 0x80000000) {
694 IN EFI_EXCEPTION_TYPE ExceptionType
,
695 IN OUT EFI_SYSTEM_CONTEXT SystemContext
698 UINT32 ExceptionAddress
;
701 // Is it a debugger SWI?
702 ExceptionAddress
= SystemContext
.SystemContextArm
->PC
-= 4;
703 Instruction
= *(UINT32
*)ExceptionAddress
;
704 if (Instruction
!= GDB_ARM_BKPT
) {
708 // Special for SWI-based exception handling. SWI sets up the context
709 // to return to the instruction following the SWI instruction - NOT what we want
711 SystemContext
.SystemContextArm
->PC
= ExceptionAddress
;