EmbeddedPkg: remove GdbDebugAgent library

The GdbDebugAgent library is unused and unmaintained, and now it
turns out it doesn't build with Clang, so let's just get rid of it.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
This commit is contained in:
Ard Biesheuvel 2018-12-12 13:48:42 +01:00
parent 5f0b035f10
commit 3bdc111178
11 changed files with 0 additions and 4738 deletions

View File

@ -155,9 +155,6 @@
# 1/123 faster than Stm or Vstm version
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
# Uncomment to turn on GDB stub in SEC.
#DebugAgentLib|EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.inf
[LibraryClasses.common.PEI_CORE]
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
ReportStatusCodeLib|MdeModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf

View File

@ -237,7 +237,6 @@
EmbeddedPkg/Library/AcpiLib/AcpiLib.inf
EmbeddedPkg/Library/DebugAgentTimerLibNull/DebugAgentTimerLibNull.inf
EmbeddedPkg/Library/FdtLib/FdtLib.inf
EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.inf
EmbeddedPkg/Library/PrePiHobLib/PrePiHobLib.inf
EmbeddedPkg/Library/PrePiMemoryAllocationLib/PrePiMemoryAllocationLib.inf

View File

@ -1,258 +0,0 @@
#------------------------------------------------------------------------------
#
# Use ARMv6 instruction to operate on a single stack
#
# Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
#
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#------------------------------------------------------------------------------
/*
This is the stack constructed by the exception handler (low address to high address)
# R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
Reg Offset
=== ======
R0 0x00 # stmfd SP!,{R0-R12}
R1 0x04
R2 0x08
R3 0x0c
R4 0x10
R5 0x14
R6 0x18
R7 0x1c
R8 0x20
R9 0x24
R10 0x28
R11 0x2c
R12 0x30
SP 0x34 # reserved via adding 0x20 (32) to the SP
LR 0x38
PC 0x3c
CPSR 0x40
DFSR 0x44
DFAR 0x48
IFSR 0x4c
IFAR 0x50
LR 0x54 # SVC Link register (we need to restore it)
LR 0x58 # pushed by srsfd
CPSR 0x5c
*/
GCC_ASM_EXPORT(ExceptionHandlersStart)
GCC_ASM_EXPORT(ExceptionHandlersEnd)
GCC_ASM_EXPORT(CommonExceptionEntry)
GCC_ASM_EXPORT(AsmCommonExceptionEntry)
GCC_ASM_EXPORT(GdbExceptionHandler)
.text
.align 3
//
// This code gets copied to the ARM vector table
// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
//
ASM_PFX(ExceptionHandlersStart):
ASM_PFX(Reset):
b ASM_PFX(Reset)
ASM_PFX(UndefinedInstruction):
b ASM_PFX(UndefinedInstructionEntry)
ASM_PFX(SoftwareInterrupt):
b ASM_PFX(SoftwareInterruptEntry)
ASM_PFX(PrefetchAbort):
b ASM_PFX(PrefetchAbortEntry)
ASM_PFX(DataAbort):
b ASM_PFX(DataAbortEntry)
ASM_PFX(ReservedException):
b ASM_PFX(ReservedExceptionEntry)
ASM_PFX(Irq):
b ASM_PFX(Irq)
ASM_PFX(Fiq):
b ASM_PFX(FiqEntry)
ASM_PFX(UndefinedInstructionEntry):
sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry
srsdb #0x13! @ Store return state on SVC stack
cpsid f,#0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#1 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(SoftwareInterruptEntry):
sub LR, LR, #4 @ Only -2 for Thumb, adjust in CommonExceptionEntry
srsdb #0x13! @ Store return state on SVC stack
cpsid f @ We are already in SVC mode
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#2 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(PrefetchAbortEntry):
sub LR,LR,#4
srsdb #0x13! @ Store return state on SVC stack
cpsid f,#0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#3 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(DataAbortEntry):
sub LR,LR,#8
srsdb #0x13! @ Store return state on SVC stack
cpsid f,#0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#4
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(ReservedExceptionEntry):
srsdb #0x13! @ Store return state on SVC stack
cpsid f,#0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
mov R0,#5
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
ASM_PFX(FiqEntry):
sub LR,LR,#4
srsdb #0x13! @ Store return state on SVC stack
cps #0x13 @ Switch to SVC for common stack
stmfd SP!,{LR} @ Store the link register for the current mode
sub SP,SP,#0x20 @ Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} @ Store the register state
@ Since we have already switch to SVC R8_fiq - R12_fiq
@ never get used or saved
mov R0,#7 @ ExceptionType
ldr R1,ASM_PFX(CommonExceptionEntry)
bx R1
//
// This gets patched by the C code that patches in the vector table
//
ASM_PFX(CommonExceptionEntry):
.byte 0x12
.byte 0x34
.byte 0x56
.byte 0x78
ASM_PFX(ExceptionHandlersEnd):
//
// This code runs from CpuDxe driver loaded address. It is patched into
// CommonExceptionEntry.
//
ASM_PFX(AsmCommonExceptionEntry):
mrc p15, 0, R1, c6, c0, 2 @ Read IFAR
str R1, [SP, #0x50] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
mrc p15, 0, R1, c5, c0, 1 @ Read IFSR
str R1, [SP, #0x4c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
mrc p15, 0, R1, c6, c0, 0 @ Read DFAR
str R1, [SP, #0x48] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
mrc p15, 0, R1, c5, c0, 0 @ Read DFSR
str R1, [SP, #0x44] @ Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
ldr R1, [SP, #0x5c] @ srsdb saved pre-exception CPSR on the stack
str R1, [SP, #0x40] @ Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R3, R1, #0x1f @ Check CPSR to see if User or System Mode
cmp R3, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1df))
cmpne R3, #0x10 @
stmeqed R2, {lr}^ @ save unbanked lr
@ else
stmneed R2, {lr} @ save SVC lr
ldr R5, [SP, #0x58] @ PC is the LR pushed by srsfd
@ Check to see if we have to adjust for Thumb entry
sub r4, r0, #1 @ if (ExceptionType == 1 || ExceptionType ==2)) {
cmp r4, #1 @ // UND & SVC have differnt LR adjust for Thumb
bhi NoAdjustNeeded
tst r1, #0x20 @ if ((CPSR & T)) == T) { // Thumb Mode on entry
addne R5, R5, #2 @ PC += 2@
str R5,[SP,#0x58] @ Update LR value pused by srsfd
NoAdjustNeeded:
str R5, [SP, #0x3c] @ Store it in EFI_SYSTEM_CONTEXT_ARM.PC
sub R1, SP, #0x60 @ We pused 0x60 bytes on the stack
str R1, [SP, #0x34] @ Store it in EFI_SYSTEM_CONTEXT_ARM.SP
@ R0 is ExceptionType
mov R1,SP @ R1 is SystemContext
/*
VOID
EFIAPI
GdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType, R0
IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
)
*/
blx ASM_PFX(GdbExceptionHandler) @ Call exception handler
ldr R1,[SP,#0x3c] @ EFI_SYSTEM_CONTEXT_ARM.PC
str R1,[SP,#0x58] @ Store it back to srsfd stack slot so it can be restored
ldr R1,[SP,#0x40] @ EFI_SYSTEM_CONTEXT_ARM.CPSR
str R1,[SP,#0x5c] @ Store it back to srsfd stack slot so it can be restored
add R3, SP, #0x54 @ Make R3 point to SVC LR saved on entry
add R2, SP, #0x38 @ Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R1, R1, #0x1f @ Check to see if User or System Mode
cmp R1, #0x1f @ if ((CPSR == 0x10) || (CPSR == 0x1f))
cmpne R1, #0x10 @
ldmeqed R2, {lr}^ @ restore unbanked lr
@ else
ldmneed R3, {lr} @ restore SVC lr, via ldmfd SP!, {LR}
ldmfd SP!,{R0-R12} @ Restore general purpose registers
@ Exception handler can not change SP
add SP,SP,#0x20 @ Clear out the remaining stack space
ldmfd SP!,{LR} @ restore the link register for this context
rfefd SP! @ return from exception via srsfd stack slot

View File

@ -1,259 +0,0 @@
//------------------------------------------------------------------------------
//
// Use ARMv6 instruction to operate on a single stack
//
// Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
//
// This program and the accompanying materials
// are licensed and made available under the terms and conditions of the BSD License
// which accompanies this distribution. The full text of the license may be found at
// http://opensource.org/licenses/bsd-license.php
//
// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
//
//------------------------------------------------------------------------------
/*
This is the stack constructed by the exception handler (low address to high address)
# R0 - IFAR is EFI_SYSTEM_CONTEXT for ARM
Reg Offset
=== ======
R0 0x00 # stmfd SP!,{R0-R12}
R1 0x04
R2 0x08
R3 0x0c
R4 0x10
R5 0x14
R6 0x18
R7 0x1c
R8 0x20
R9 0x24
R10 0x28
R11 0x2c
R12 0x30
SP 0x34 # reserved via adding 0x20 (32) to the SP
LR 0x38
PC 0x3c
CPSR 0x40
DFSR 0x44
DFAR 0x48
IFSR 0x4c
IFAR 0x50
LR 0x54 # SVC Link register (we need to restore it)
LR 0x58 # pushed by srsfd
CPSR 0x5c
*/
EXPORT ExceptionHandlersStart
EXPORT ExceptionHandlersEnd
EXPORT CommonExceptionEntry
EXPORT AsmCommonExceptionEntry
IMPORT GdbExceptionHandler
PRESERVE8
AREA DxeExceptionHandlers, CODE, READONLY
//
// This code gets copied to the ARM vector table
// ExceptionHandlersStart - ExceptionHandlersEnd gets copied
//
ExceptionHandlersStart
Reset
b Reset
UndefinedInstruction
b UndefinedInstructionEntry
SoftwareInterrupt
b SoftwareInterruptEntry
PrefetchAbort
b PrefetchAbortEntry
DataAbort
b DataAbortEntry
ReservedException
b ReservedExceptionEntry
Irq
b Irq
Fiq
b FiqEntry
UndefinedInstructionEntry
sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry
srsfd #0x13! ; Store return state on SVC stack
cpsid f, #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#1 ; ExceptionType
ldr R1,CommonExceptionEntry;
bx R1
SoftwareInterruptEntry
sub LR, LR, #4 ; Only -2 for Thumb, adjust in CommonExceptionEntry
srsfd #0x13! ; Store return state on SVC stack
cpsid f ; We are already in SVC mode
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#2 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
PrefetchAbortEntry
sub LR,LR,#4
srsfd #0x13! ; Store return state on SVC stack
cpsid f, #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#3 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
DataAbortEntry
sub LR,LR,#8
srsfd #0x13! ; Store return state on SVC stack
cpsid f, #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#4 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
ReservedExceptionEntry
srsfd #0x13! ; Store return state on SVC stack
cpsid f, #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
mov R0,#5 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
FiqEntry
sub LR,LR,#4
srsfd #0x13! ; Store return state on SVC stack
cps #0x13 ; Switch to SVC for common stack
stmfd SP!,{LR} ; Store the link register for the current mode
sub SP,SP,#0x20 ; Save space for SP, LR, PC, IFAR - CPSR
stmfd SP!,{R0-R12} ; Store the register state
; Since we have already switch to SVC R8_fiq - R12_fiq
; never get used or saved
mov R0,#7 ; ExceptionType
ldr R1,CommonExceptionEntry
bx R1
//
// This gets patched by the C code that patches in the vector table
//
CommonExceptionEntry
dcd 0x12345678
ExceptionHandlersEnd
//
// This code runs from CpuDxe driver loaded address. It is patched into
// CommonExceptionEntry.
//
AsmCommonExceptionEntry
mrc p15, 0, R1, c6, c0, 2 ; Read IFAR
str R1, [SP, #0x50] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFAR
mrc p15, 0, R1, c5, c0, 1 ; Read IFSR
str R1, [SP, #0x4c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.IFSR
mrc p15, 0, R1, c6, c0, 0 ; Read DFAR
str R1, [SP, #0x48] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFAR
mrc p15, 0, R1, c5, c0, 0 ; Read DFSR
str R1, [SP, #0x44] ; Store it in EFI_SYSTEM_CONTEXT_ARM.DFSR
ldr R1, [SP, #0x5c] ; srsfd saved pre-exception CPSR on the stack
str R1, [SP, #0x40] ; Store it in EFI_SYSTEM_CONTEXT_ARM.CPSR
add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R3, R1, #0x1f ; Check CPSR to see if User or System Mode
cmp R3, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1df))
cmpne R3, #0x10 ;
stmeqed R2, {lr}^ ; save unbanked lr
; else
stmneed R2, {lr} ; save SVC lr
ldr R5, [SP, #0x58] ; PC is the LR pushed by srsfd
; Check to see if we have to adjust for Thumb entry
sub r4, r0, #1 ; if (ExceptionType == 1 || ExceptionType ==2)) {
cmp r4, #1 ; // UND & SVC have differnt LR adjust for Thumb
bhi NoAdjustNeeded
tst r1, #0x20 ; if ((CPSR & T)) == T) { // Thumb Mode on entry
addne R5, R5, #2 ; PC += 2;
str R5,[SP,#0x58] ; Update LR value pused by srsfd
NoAdjustNeeded
str R5, [SP, #0x3c] ; Store it in EFI_SYSTEM_CONTEXT_ARM.PC
sub R1, SP, #0x60 ; We pused 0x60 bytes on the stack
str R1, [SP, #0x34] ; Store it in EFI_SYSTEM_CONTEXT_ARM.SP
; R0 is ExceptionType
mov R1,SP ; R1 is SystemContext
/*
VOID
EFIAPI
GdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType, R0
IN OUT EFI_SYSTEM_CONTEXT SystemContext R1
)
*/
blx GdbExceptionHandler ; Call exception handler
ldr R1,[SP,#0x3c] ; EFI_SYSTEM_CONTEXT_ARM.PC
str R1,[SP,#0x58] ; Store it back to srsfd stack slot so it can be restored
ldr R1,[SP,#0x40] ; EFI_SYSTEM_CONTEXT_ARM.CPSR
str R1,[SP,#0x5c] ; Store it back to srsfd stack slot so it can be restored
add R3, SP, #0x54 ; Make R3 point to SVC LR saved on entry
add R2, SP, #0x38 ; Make R2 point to EFI_SYSTEM_CONTEXT_ARM.LR
and R1, R1, #0x1f ; Check to see if User or System Mode
cmp R1, #0x1f ; if ((CPSR == 0x10) || (CPSR == 0x1f))
cmpne R1, #0x10 ;
ldmeqed R2, {lr}^ ; restore unbanked lr
; else
ldmneed R3, {lr} ; restore SVC lr, via ldmfd SP!, {LR}
ldmfd SP!,{R0-R12} ; Restore general purpose registers
; Exception handler can not change SP
add SP,SP,#0x20 ; Clear out the remaining stack space
ldmfd SP!,{LR} ; restore the link register for this context
rfefd SP! ; return from exception via srsfd stack slot
END

View File

@ -1,675 +0,0 @@
/** @file
Processor specific parts of the GDB stub
Copyright (c) 2008 - 2010, Apple Inc. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <GdbDebugAgent.h>
#include <Library/PrintLib.h>
#include <Library/ArmLib.h>
//
// Externs from the exception handler assembly file
//
VOID
ExceptionHandlersStart (
VOID
);
VOID
ExceptionHandlersEnd (
VOID
);
VOID
CommonExceptionEntry (
VOID
);
VOID
AsmCommonExceptionEntry (
VOID
);
//
// Array of exception types that need to be hooked by the debugger
// (efi, gdb) //efi number
//
EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
{ EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP },
{ EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
{ EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
{ EXCEPT_ARM_DATA_ABORT, GDB_SIGTRAP }, // GDB_SIGEMT
{ EXCEPT_ARM_RESERVED, GDB_SIGTRAP }, // GDB_SIGILL
{ EXCEPT_ARM_FIQ, GDB_SIGINT } // Used for ctrl-c
};
// Shut up some annoying RVCT warnings
#ifdef __CC_ARM
#pragma diag_suppress 1296
#endif
UINTN gRegisterOffsets[] = {
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R0),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R1),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R2),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R3),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R4),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R5),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R6),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R7),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R8),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R9),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R10),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R11),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, R12),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, SP),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, LR),
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, PC),
0x00000F01, // f0
0x00000F02,
0x00000F03,
0x00000F11, // f1
0x00000F12,
0x00000F13,
0x00000F21, // f2
0x00000F22,
0x00000F23,
0x00000F31, // f3
0x00000F32,
0x00000F33,
0x00000F41, // f4
0x00000F42,
0x00000F43,
0x00000F51, // f5
0x00000F52,
0x00000F53,
0x00000F61, // f6
0x00000F62,
0x00000F63,
0x00000F71, // f7
0x00000F72,
0x00000F73,
0x00000FFF, // fps
OFFSET_OF(EFI_SYSTEM_CONTEXT_ARM, CPSR)
};
// restore warnings for RVCT
#ifdef __CC_ARM
#pragma diag_default 1296
#endif
/**
Return the number of entries in the gExceptionType[]
@retval UINTN, the number of entries in the gExceptionType[] array.
**/
UINTN
MaxEfiException (
VOID
)
{
return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
}
/**
Check to see if the ISA is supported.
ISA = Instruction Set Architecture
@retval TRUE if Isa is supported
**/
BOOLEAN
CheckIsa (
IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
)
{
if (Isa == IsaArm) {
return TRUE;
} else {
return FALSE;
}
}
/**
This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
It is, by default, set to find the register pointer of the ARM member
@param SystemContext Register content at time of the exception
@param RegNumber The register to which we want to find a pointer
@retval the pointer to the RegNumber-th pointer
**/
UINTN *
FindPointerToRegister(
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber
)
{
UINT8 *TempPtr;
ASSERT(gRegisterOffsets[RegNumber] < 0xF00);
TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
return (UINT32 *)TempPtr;
}
/**
Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
@param SystemContext Register content at time of the exception
@param RegNumber the number of the register that we want to read
@param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
@retval the pointer to the next character of the output buffer that is available to be written on.
**/
CHAR8 *
BasicReadRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *OutBufPtr
)
{
UINTN RegSize;
CHAR8 Char;
if (gRegisterOffsets[RegNumber] > 0xF00) {
AsciiSPrint(OutBufPtr, 9, "00000000");
OutBufPtr += 8;
return OutBufPtr;
}
RegSize = 0;
while (RegSize < 32) {
Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
if ((Char >= 'A') && (Char <= 'F')) {
Char = Char - 'A' + 'a';
}
*OutBufPtr++ = Char;
Char = mHexToStr[(UINT8)((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
if ((Char >= 'A') && (Char <= 'F')) {
Char = Char - 'A' + 'a';
}
*OutBufPtr++ = Char;
RegSize = RegSize + 8;
}
return OutBufPtr;
}
/**
Reads the n-th register's value into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
ReadNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN RegNumber;
CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
CHAR8 *OutBufPtr; // pointer to the output buffer
RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {
SendError (GDB_EINVALIDREGNUM);
return;
}
OutBufPtr = OutBuffer;
OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
*OutBufPtr = '\0'; // the end of the buffer
SendPacket(OutBuffer);
}
/**
Reads the general registers into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
ReadGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
UINTN Index;
// a UINT32 takes 8 ascii characters
CHAR8 OutBuffer[(sizeof (gRegisterOffsets) * 2) + 1];
CHAR8 *OutBufPtr;
// It is not safe to allocate pool here....
OutBufPtr = OutBuffer;
for (Index = 0; Index < (sizeof (gRegisterOffsets)/sizeof (UINTN)); Index++) {
OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
}
*OutBufPtr = '\0';
SendPacket(OutBuffer);
}
/**
Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
@param SystemContext Register content at time of the exception
@param RegNumber the number of the register that we want to write
@param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
@retval the pointer to the next character of the input buffer that can be used
**/
CHAR8 *
BasicWriteRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *InBufPtr
)
{
UINTN RegSize;
UINTN TempValue; // the value transferred from a hex char
UINT32 NewValue; // the new value of the RegNumber-th Register
if (gRegisterOffsets[RegNumber] > 0xF00) {
return InBufPtr + 8;
}
NewValue = 0;
RegSize = 0;
while (RegSize < 32) {
TempValue = HexCharToInt(*InBufPtr++);
if ((INTN)TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << (RegSize+4));
TempValue = HexCharToInt(*InBufPtr++);
if ((INTN)TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << RegSize);
RegSize = RegSize + 8;
}
*(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;
return InBufPtr;
}
/** P n...=r...
Writes the new value of n-th register received into the input buffer to the n-th register
@param SystemContext Register content at time of the exception
@param InBuffer Ponter to the input buffer received from gdb server
**/
VOID
WriteNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN RegNumber;
CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
CHAR8 *RegNumBufPtr;
CHAR8 *InBufPtr; // pointer to the input buffer
// find the register number to write
InBufPtr = &InBuffer[1];
RegNumBufPtr = RegNumBuffer;
while (*InBufPtr != '=') {
*RegNumBufPtr++ = *InBufPtr++;
}
*RegNumBufPtr = '\0';
RegNumber = AsciiStrHexToUintn (RegNumBuffer);
// check if this is a valid Register Number
if (RegNumber >= (sizeof (gRegisterOffsets)/sizeof (UINTN))) {
SendError (GDB_EINVALIDREGNUM);
return;
}
InBufPtr++; // skips the '=' character
BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
SendSuccess();
}
/** G XX...
Writes the new values received into the input buffer to the general registers
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
EFIAPI
WriteGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN i;
CHAR8 *InBufPtr; /// pointer to the input buffer
UINTN MinLength;
UINTN RegisterCount = (sizeof (gRegisterOffsets)/sizeof (UINTN));
MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format
if (AsciiStrLen(InBuffer) < MinLength) {
//Bad message. Message is not the right length
SendError (GDB_EBADBUFSIZE);
return;
}
InBufPtr = &InBuffer[1];
// Read the new values for the registers from the input buffer to an array, NewValueArray.
// The values in the array are in the gdb ordering
for(i = 0; i < RegisterCount; i++) {
InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
}
SendSuccess ();
}
/**
Continue. addr is Address to resume. If addr is omitted, resume at current
Address.
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
ContinueAtAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
if (PacketData[1] != '\0') {
SystemContext.SystemContextArm->PC = AsciiStrHexToUintn(&PacketData[1]);
}
}
/** s [addr ]
Single step. addr is the Address at which to resume. If addr is omitted, resume
at same Address.
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
SingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
SendNotSupported();
}
VOID
EFIAPI
InsertBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
SendNotSupported ();
}
VOID
EFIAPI
RemoveBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
SendNotSupported ();
}
/**
Send the T signal with the given exception type (in gdb order) and possibly
with n:r pairs related to the watchpoints
@param SystemContext Register content at time of the exception
@param GdbExceptionType GDB exception type
**/
VOID
ProcessorSendTSignal (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINT8 GdbExceptionType,
IN OUT CHAR8 *TSignalPtr,
IN UINTN SizeOfBuffer
)
{
*TSignalPtr = '\0';
}
/**
FIQ state is only changed by FIQ exception. We don't want to take FIQ
ticks in the GDB stub. The stub disables FIQ on entry, but this is the
third instruction that executes in the execption handler. Thus we have
a crack we need to test for.
@param PC PC of execption
@return TRUE We are in the GDB stub exception preamble
@return FALSE We are not in GDB stub code
**/
BOOLEAN
InFiqCrack (
IN UINT32 PC
)
{
UINT64 VectorBase = PcdGet64 (PcdCpuVectorBaseAddress);
UINT32 Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
if ((PC >= VectorBase) && (PC <= (VectorBase + Length))) {
return TRUE;
}
return FALSE;
}
/**
Check to see if this exception is related to ctrl-c handling.
In this scheme we dedicate FIQ to the ctrl-c handler so it is
independent of the rest of the system.
SaveAndSetDebugTimerInterrupt () can be used to
@param ExceptionType Exception that is being processed
@param SystemContext Register content at time of the exception
@return TRUE This was a ctrl-c check that did not find a ctrl-c
@return FALSE This was not a ctrl-c check or some one hit ctrl-c
**/
BOOLEAN
ProcessorControlC (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
CHAR8 Char;
BOOLEAN Return = TRUE;
if (ExceptionType != EXCEPT_ARM_FIQ) {
// Skip it as it is not related to ctrl-c
return FALSE;
}
if (InFiqCrack (SystemContext.SystemContextArm->PC)) {
// We are in our own interrupt preable, so skip this tick.
// We never want to let gdb see the debug stub running if we can help it
return FALSE;
}
while (TRUE) {
if (!GdbIsCharAvailable ()) {
//
// No characters are pending so exit the loop
//
Return = TRUE;
break;
}
Char = GdbGetChar ();
if (Char == 0x03) {
//
// We have a ctrl-c so exit and process exception for ctrl-c
//
Return = FALSE;
break;
}
}
DebugAgentTimerEndOfInterrupt ();
// Force an exit from the exception handler as we are done
return Return;
}
/**
Enable/Disable the interrupt of debug timer and return the interrupt state
prior to the operation.
If EnableStatus is TRUE, enable the interrupt of debug timer.
If EnableStatus is FALSE, disable the interrupt of debug timer.
@param[in] EnableStatus Enable/Disable.
@retval TRUE Debug timer interrupt were enabled on entry to this call.
@retval FALSE Debug timer interrupt were disabled on entry to this call.
**/
BOOLEAN
EFIAPI
SaveAndSetDebugTimerInterrupt (
IN BOOLEAN EnableStatus
)
{
BOOLEAN FiqEnabled;
FiqEnabled = ArmGetFiqState ();
if (EnableStatus) {
DebugAgentTimerSetPeriod (PcdGet32 (PcdGdbTimerPeriodMilliseconds));
ArmEnableFiq ();
} else {
DebugAgentTimerSetPeriod (0);
ArmDisableFiq ();
}
return FiqEnabled;
}
VOID
GdbFPutString (
IN CHAR8 *String
);
/**
Initialize debug agent.
This function is used to set up debug environment to support source level debugging.
If certain Debug Agent Library instance has to save some private data in the stack,
this function must work on the mode that doesn't return to the caller, then
the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
responsible to invoke the passing-in function at the end of InitializeDebugAgent().
If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
passing in the Context to be its parameter.
If Function() is NULL, Debug Agent Library instance will return after setup debug
environment.
@param[in] InitFlag Init flag is used to decide the initialize process.
@param[in] Context Context needed according to InitFlag; it was optional.
@param[in] Function Continue function called by debug agent library; it was
optional.
**/
VOID
EFIAPI
InitializeDebugAgent (
IN UINT32 InitFlag,
IN VOID *Context, OPTIONAL
IN DEBUG_AGENT_CONTINUE Function OPTIONAL
)
{
UINTN Offset;
UINTN Length;
BOOLEAN IrqEnabled;
UINT64 *VectorBase;
//
// Disable interrupts
//
IrqEnabled = ArmGetInterruptState ();
ArmDisableInterrupts ();
ArmDisableFiq ();
//
// Copy an implementation of the ARM exception vectors to PcdCpuVectorBaseAddress.
//
Length = (UINTN)ExceptionHandlersEnd - (UINTN)ExceptionHandlersStart;
//
// Reserve space for the exception handlers
//
VectorBase = (UINT64 *)(UINTN)PcdGet64 (PcdCpuVectorBaseAddress);
// Copy our assembly code into the page that contains the exception vectors.
CopyMem ((VOID *)VectorBase, (VOID *)ExceptionHandlersStart, Length);
//
// Patch in the common Assembly exception handler
//
Offset = (UINTN)CommonExceptionEntry - (UINTN)ExceptionHandlersStart;
*(UINTN *) (((UINT8 *)VectorBase) + Offset) = (UINTN)AsmCommonExceptionEntry;
// Flush Caches since we updated executable stuff
InvalidateInstructionCacheRange ((VOID *)(UINTN)PcdGet64(PcdCpuVectorBaseAddress), Length);
// setup a timer so gdb can break in via ctrl-c
DebugAgentTimerIntialize ();
if (IrqEnabled) {
ArmEnableInterrupts ();
}
if (Function != NULL) {
Function (Context);
}
return;
}

View File

@ -1,815 +0,0 @@
/** @file
Debug Agent library implementition with empty functions.
Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "GdbDebugAgent.h"
UINTN gMaxProcessorIndex = 0;
//
// Buffers for basic gdb communication
//
CHAR8 gInBuffer[MAX_BUF_SIZE];
CHAR8 gOutBuffer[MAX_BUF_SIZE];
//
// Globals for returning XML from qXfer:libraries:read packet
//
UINTN gPacketqXferLibraryOffset = 0;
UINTN gEfiDebugImageTableEntry = 0;
CHAR8 gXferLibraryBuffer[2000];
GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
// add-symbol-file c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll 0x80008360
CHAR8 *qXferHack = "<library name=\"c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll\"><segment address=\"0x80008360\"/></library>";
UINTN
gXferObjectReadResponse (
IN CHAR8 Type,
IN CHAR8 *Str
)
{
CHAR8 *OutBufPtr; // pointer to the output buffer
CHAR8 Char;
UINTN Count;
// responce starts with 'm' or 'l' if it is the end
OutBufPtr = gOutBuffer;
*OutBufPtr++ = Type;
Count = 1;
// Binary data encoding
OutBufPtr = gOutBuffer;
while (*Str != '\0') {
Char = *Str++;
if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) {
// escape character
*OutBufPtr++ = 0x7d;
Char ^= 0x20;
}
*OutBufPtr++ = Char;
Count++;
}
*OutBufPtr = '\0' ; // the end of the buffer
SendPacket (gOutBuffer);
return Count;
}
/**
Process "qXfer:object:read:annex:offset,length" request.
Returns an XML document that contains loaded libraries. In our case it is
infomration in the EFI Debug Inmage Table converted into an XML document.
GDB will call with an arbitrary length (it can't know the real length and
will reply with chunks of XML that are easy for us to deal with. Gdb will
keep calling until we say we are done. XML doc looks like:
<library-list>
<library name="/a/a/c/d.dSYM"><segment address="0x10000000"/></library>
<library name="/a/m/e/e.pdb"><segment address="0x20000000"/></library>
<library name="/a/l/f/f.dll"><segment address="0x30000000"/></library>
</library-list>
Since we can not allocate memory in interupt context this module has
assumptions about how it will get called:
1) Length will generally be max remote packet size (big enough)
2) First Offset of an XML document read needs to be 0
3) This code will return back small chunks of the XML document on every read.
Each subseqent call will ask for the next available part of the document.
Note: The only variable size element in the XML is:
" <library name=\"%s\"><segment address=\"%p\"/></library>\n" and it is
based on the file path and name of the symbol file. If the symbol file name
is bigger than the max gdb remote packet size we could update this code
to respond back in chunks.
@param Offset offset into special data area
@param Length number of bytes to read starting at Offset
**/
VOID
QxferLibrary (
IN UINTN Offset,
IN UINTN Length
)
{
gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");
gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', qXferHack);
gXferObjectReadResponse ('l', "</library-list>\n");
gPacketqXferLibraryOffset = 0;
}
/**
Transfer length bytes of input buffer, starting at Address, to memory.
@param length the number of the bytes to be transferred/written
@param *address the start address of the transferring/writing the memory
@param *new_data the new data to be written to memory
**/
VOID
TransferFromInBufToMem (
IN UINTN Length,
IN unsigned char *Address,
IN CHAR8 *NewData
)
{
CHAR8 c1;
CHAR8 c2;
while (Length-- > 0) {
c1 = (CHAR8)HexCharToInt (*NewData++);
c2 = (CHAR8)HexCharToInt (*NewData++);
if ((c1 < 0) || (c2 < 0)) {
SendError (GDB_EBADMEMDATA);
return;
}
*Address++ = (UINT8)((c1 << 4) + c2);
}
SendSuccess();
}
/**
Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer
as a packet.
@param Length the number of the bytes to be transferred/read
@param *address pointer to the start address of the transferring/reading the memory
**/
VOID
TransferFromMemToOutBufAndSend (
IN UINTN Length,
IN unsigned char *Address
)
{
// there are Length bytes and every byte is represented as 2 hex chars
CHAR8 OutBuffer[MAX_BUF_SIZE];
CHAR8 *OutBufPtr; // pointer to the output buffer
CHAR8 Char;
OutBufPtr = OutBuffer;
while (Length > 0) {
Char = mHexToStr[*Address >> 4];
if ((Char >= 'A') && (Char <= 'F')) {
Char = Char - 'A' + 'a';
}
*OutBufPtr++ = Char;
Char = mHexToStr[*Address & 0x0f];
if ((Char >= 'A') && (Char <= 'F')) {
Char = Char - 'A' + 'a';
}
*OutBufPtr++ = Char;
Address++;
Length--;
}
*OutBufPtr = '\0' ; // the end of the buffer
SendPacket (OutBuffer);
}
/**
Send a GDB Remote Serial Protocol Packet
$PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
the packet teminating character '#' and the two digit checksum.
If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up
in an infinit loop. This is so if you unplug the debugger code just keeps running
@param PacketData Payload data for the packet
@retval Number of bytes of packet data sent.
**/
UINTN
SendPacket (
IN CHAR8 *PacketData
)
{
UINT8 CheckSum;
UINTN Timeout;
CHAR8 *Ptr;
CHAR8 TestChar;
UINTN Count;
Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount);
Count = 0;
do {
Ptr = PacketData;
if (Timeout-- == 0) {
// Only try a finite number of times so we don't get stuck in the loop
return Count;
}
// Packet prefix
GdbPutChar ('$');
for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) {
GdbPutChar (*Ptr);
CheckSum = CheckSum + *Ptr;
}
// Packet terminating character and checksum
GdbPutChar ('#');
GdbPutChar (mHexToStr[CheckSum >> 4]);
GdbPutChar (mHexToStr[CheckSum & 0x0F]);
TestChar = GdbGetChar ();
} while (TestChar != '+');
return Count;
}
/**
Receive a GDB Remote Serial Protocol Packet
$PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
the packet teminating character '#' and the two digit checksum.
If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.
(In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)
If an ack '+' is not sent resend the packet
@param PacketData Payload data for the packet
@retval Number of bytes of packet data received.
**/
UINTN
ReceivePacket (
OUT CHAR8 *PacketData,
IN UINTN PacketDataSize
)
{
UINT8 CheckSum;
UINTN Index;
CHAR8 Char;
CHAR8 SumString[3];
CHAR8 TestChar;
ZeroMem (PacketData, PacketDataSize);
for (;;) {
// wait for the start of a packet
TestChar = GdbGetChar ();
while (TestChar != '$') {
TestChar = GdbGetChar ();
};
retry:
for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {
Char = GdbGetChar ();
if (Char == '$') {
goto retry;
}
if (Char == '#') {
break;
}
PacketData[Index] = Char;
CheckSum = CheckSum + Char;
}
PacketData[Index] = '\0';
if (Index == PacketDataSize) {
continue;
}
SumString[0] = GdbGetChar ();
SumString[1] = GdbGetChar ();
SumString[2] = '\0';
if (AsciiStrHexToUintn (SumString) == CheckSum) {
// Ack: Success
GdbPutChar ('+');
// Null terminate the callers string
PacketData[Index] = '\0';
return Index;
} else {
// Ack: Failure
GdbPutChar ('-');
}
}
//return 0;
}
/**
Empties the given buffer
@param Buf pointer to the first element in buffer to be emptied
**/
VOID
EmptyBuffer (
IN CHAR8 *Buf
)
{
*Buf = '\0';
}
/**
Converts an 8-bit Hex Char into a INTN.
@param Char the hex character to be converted into UINTN
@retval a INTN, from 0 to 15, that corressponds to Char
-1 if Char is not a hex character
**/
INTN
HexCharToInt (
IN CHAR8 Char
)
{
if ((Char >= 'A') && (Char <= 'F')) {
return Char - 'A' + 10;
} else if ((Char >= 'a') && (Char <= 'f')) {
return Char - 'a' + 10;
} else if ((Char >= '0') && (Char <= '9')) {
return Char - '0';
} else { // if not a hex value, return a negative value
return -1;
}
}
// 'E' + the biggest error number is 255, so its 2 hex digits + buffer end
CHAR8 *gError = "E__";
/** 'E NN'
Send an error with the given error number after converting to hex.
The error number is put into the buffer in hex. '255' is the biggest errno we can send.
ex: 162 will be sent as A2.
@param errno the error number that will be sent
**/
VOID
EFIAPI
SendError (
IN UINT8 ErrorNum
)
{
//
// Replace _, or old data, with current errno
//
gError[1] = mHexToStr [ErrorNum >> 4];
gError[2] = mHexToStr [ErrorNum & 0x0f];
SendPacket (gError); // send buffer
}
/**
Send 'OK' when the function is done executing successfully.
**/
VOID
EFIAPI
SendSuccess (
VOID
)
{
SendPacket ("OK"); // send buffer
}
/**
Send empty packet to specify that particular command/functionality is not supported.
**/
VOID
EFIAPI
SendNotSupported (
VOID
)
{
SendPacket ("");
}
/**
Translates the EFI mapping to GDB mapping
@param EFIExceptionType EFI Exception that is being processed
@retval UINTN that corresponds to EFIExceptionType's GDB exception type number
**/
UINT8
ConvertEFItoGDBtype (
IN EFI_EXCEPTION_TYPE EFIExceptionType
)
{
UINTN i;
for (i=0; i < MaxEfiException() ; i++) {
if (gExceptionType[i].Exception == EFIExceptionType) {
return gExceptionType[i].SignalNo;
}
}
return GDB_SIGTRAP; // this is a GDB trap
}
/** "m addr,length"
Find the Length of the area to read and the start addres. Finally, pass them to
another function, TransferFromMemToOutBufAndSend, that will read from that memory space and
send it as a packet.
**/
VOID
EFIAPI
ReadFromMemory (
CHAR8 *PacketData
)
{
UINTN Address;
UINTN Length;
CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars
CHAR8 *AddrBufPtr; // pointer to the address buffer
CHAR8 *InBufPtr; /// pointer to the input buffer
AddrBufPtr = AddressBuffer;
InBufPtr = &PacketData[1];
while (*InBufPtr != ',') {
*AddrBufPtr++ = *InBufPtr++;
}
*AddrBufPtr = '\0';
InBufPtr++; // this skips ',' in the buffer
/* Error checking */
if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {
SendError (GDB_EBADMEMADDRBUFSIZE);
return;
}
// 2 = 'm' + ','
if (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {
SendError (GDB_EBADMEMLENGTH);
return;
}
Address = AsciiStrHexToUintn (AddressBuffer);
Length = AsciiStrHexToUintn (InBufPtr);
TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);
}
/** "M addr,length :XX..."
Find the Length of the area in bytes to write and the start addres. Finally, pass them to
another function, TransferFromInBufToMem, that will write to that memory space the info in
the input buffer.
**/
VOID
EFIAPI
WriteToMemory (
IN CHAR8 *PacketData
)
{
UINTN Address;
UINTN Length;
UINTN MessageLength;
CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars
CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars
CHAR8 *AddrBufPtr; // pointer to the Address buffer
CHAR8 *LengthBufPtr; // pointer to the Length buffer
CHAR8 *InBufPtr; /// pointer to the input buffer
AddrBufPtr = AddressBuffer;
LengthBufPtr = LengthBuffer;
InBufPtr = &PacketData[1];
while (*InBufPtr != ',') {
*AddrBufPtr++ = *InBufPtr++;
}
*AddrBufPtr = '\0';
InBufPtr++; // this skips ',' in the buffer
while (*InBufPtr != ':') {
*LengthBufPtr++ = *InBufPtr++;
}
*LengthBufPtr = '\0';
InBufPtr++; // this skips ':' in the buffer
Address = AsciiStrHexToUintn (AddressBuffer);
Length = AsciiStrHexToUintn (LengthBuffer);
/* Error checking */
//Check if Address is not too long.
if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {
SendError (GDB_EBADMEMADDRBUFSIZE);
return;
}
//Check if message length is not too long
if (AsciiStrLen(LengthBuffer) >= MAX_LENGTH_SIZE) {
SendError (GDB_EBADMEMLENGBUFSIZE);
return;
}
// Check if Message is not too long/short.
// 3 = 'M' + ',' + ':'
MessageLength = (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - AsciiStrLen(LengthBuffer) - 3);
if (MessageLength != (2*Length)) {
//Message too long/short. New data is not the right size.
SendError (GDB_EBADMEMDATASIZE);
return;
}
TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr);
}
/**
Parses breakpoint packet data and captures Breakpoint type, Address and length.
In case of an error, function returns particular error code. Returning 0 meaning
no error.
@param PacketData Pointer to the payload data for the packet.
@param Type Breakpoint type
@param Address Breakpoint address
@param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
@retval 1 Success
@retval {other} Particular error code
**/
UINTN
ParseBreakpointPacket (
IN CHAR8 *PacketData,
OUT UINTN *Type,
OUT UINTN *Address,
OUT UINTN *Length
)
{
CHAR8 AddressBuffer[MAX_ADDR_SIZE];
CHAR8 *AddressBufferPtr;
CHAR8 *PacketDataPtr;
PacketDataPtr = &PacketData[1];
AddressBufferPtr = AddressBuffer;
*Type = AsciiStrHexToUintn (PacketDataPtr);
//Breakpoint/watchpoint type should be between 0 to 4
if (*Type > 4) {
return 22; //EINVAL: Invalid argument.
}
//Skip ',' in the buffer.
while (*PacketDataPtr++ != ',');
//Parse Address information
while (*PacketDataPtr != ',') {
*AddressBufferPtr++ = *PacketDataPtr++;
}
*AddressBufferPtr = '\0';
//Check if Address is not too long.
if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {
return 40; //EMSGSIZE: Message size too long.
}
*Address = AsciiStrHexToUintn (AddressBuffer);
PacketDataPtr++; //This skips , in the buffer
//Parse Length information
*Length = AsciiStrHexToUintn (PacketDataPtr);
//Length should be 1, 2 or 4 bytes
if (*Length > 4) {
return 22; //EINVAL: Invalid argument
}
return 0; //0 = No error
}
/**
Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
@param SystemContext Register content at time of the exception
@param GdbExceptionType GDB exception type
**/
VOID
GdbSendTSignal (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINT8 GdbExceptionType
)
{
CHAR8 TSignalBuffer[128];
CHAR8 *TSignalPtr;
TSignalPtr = &TSignalBuffer[0];
//Construct TSignal packet
*TSignalPtr++ = 'T';
//
// replace _, or previous value, with Exception type
//
*TSignalPtr++ = mHexToStr [GdbExceptionType >> 4];
*TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];
ProcessorSendTSignal (SystemContext, GdbExceptionType, TSignalPtr, sizeof (TSignalBuffer) - 2);
SendPacket (TSignalBuffer);
}
VOID
GdbFWrite (
IN UINTN Fd,
IN CHAR8 *Data,
IN UINTN DataSize
)
{
CHAR8 Buffer[128];
AsciiSPrint (Buffer, sizeof (Buffer), "Fwrite,%x,%x,%x", Fd, Data, DataSize);
SendPacket (Buffer);
for( ; ; ) {
ReceivePacket (gInBuffer, MAX_BUF_SIZE);
switch (gInBuffer[0]) {
case 'm':
ReadFromMemory (gInBuffer);
break;
case 'M':
WriteToMemory (gInBuffer);
break;
case 'F':
return;
}
}
}
VOID
GdbFPutString (
IN CHAR8 *String
)
{
UINTN Len = AsciiStrSize (String);
GdbFWrite (2, String, Len);
}
/**
Exception Hanldler for GDB. It will be called for all exceptions
registered via the gExceptionType[] array.
@param ExceptionType Exception that is being processed
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
GdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
UINT8 GdbExceptionType;
CHAR8 *Ptr;
if (ProcessorControlC (ExceptionType, SystemContext)) {
// We tried to process a control C handler and there is nothing to do
return;
}
GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);
GdbSendTSignal (SystemContext, GdbExceptionType);
for( ; ; ) {
ReceivePacket (gInBuffer, MAX_BUF_SIZE);
switch (gInBuffer[0]) {
case '?':
GdbSendTSignal (SystemContext, GdbExceptionType);
break;
case 'c':
ContinueAtAddress (SystemContext, gInBuffer);
return;
case 'D':
// gdb wants to disconnect so return "OK" packet since.
SendSuccess ();
return;
case 'g':
ReadGeneralRegisters (SystemContext);
break;
case 'G':
WriteGeneralRegisters (SystemContext, gInBuffer);
break;
case 'H':
//Return "OK" packet since we don't have more than one thread.
SendSuccess ();
break;
case 'm':
ReadFromMemory (gInBuffer);
break;
case 'M':
WriteToMemory (gInBuffer);
break;
case 'P':
WriteNthRegister (SystemContext, gInBuffer);
break;
//
// Still debugging this code. Not used in Darwin
//
case 'q':
// General Query Packets
if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {
// return what we currently support, we don't parse what gdb suports
AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE);
SendPacket (gOutBuffer);
} else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) {
// qXfer:libraries:read::offset,length
// gInBuffer[22] is offset string, ++Ptr is length string
for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++);
// Not sure if multi-radix support is required. Currently only support decimal
QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr));
} else if (AsciiStrnCmp (gInBuffer, "qOffsets", 8) == 0) {
AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000");
SendPacket (gOutBuffer);
} else if (AsciiStrnCmp (gInBuffer, "qAttached", 9) == 0) {
// remote server attached to an existing process
SendPacket ("1");
} else {
//Send empty packet
SendNotSupported ();
}
break;
case 's':
SingleStep (SystemContext, gInBuffer);
return;
case 'z':
RemoveBreakPoint (SystemContext, gInBuffer);
break;
case 'Z':
InsertBreakPoint (SystemContext, gInBuffer);
break;
default:
//Send empty packet
SendNotSupported ();
break;
}
}
}

View File

@ -1,728 +0,0 @@
/** @file
Private include file for GDB stub
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef __GCC_DEBUG_AGENT_INTERNAL__
#define __GCC_DEBUG_AGENT_INTERNAL__
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/PcdLib.h>
#include <Library/GdbSerialLib.h>
#include <Library/PrintLib.h>
#include <Library/CacheMaintenanceLib.h>
#include <Library/DebugAgentTimerLib.h>
#include <Library/DebugAgentLib.h>
#include <IndustryStandard/PeImage.h>
#include <Protocol/DebugSupport.h>
extern CONST CHAR8 mHexToStr[];
// maximum size of input and output buffers
// This value came from the show remote command of the gdb we tested against
#define MAX_BUF_SIZE 2000
// maximum size of address buffer
#define MAX_ADDR_SIZE 32
// maximum size of register number buffer
#define MAX_REG_NUM_BUF_SIZE 32
// maximum size of length buffer
#define MAX_LENGTH_SIZE 32
// maximum size of T signal members
#define MAX_T_SIGNAL_SIZE 64
// the mask used to clear all the cache
#define TF_BIT 0x00000100
//
// GDB Signal definitions - generic names for interrupts
//
#define GDB_SIGINT 2 // Interrupt process via ctrl-c
#define GDB_SIGILL 4 // Illegal instruction
#define GDB_SIGTRAP 5 // Trace Trap (Breakpoint and SingleStep)
#define GDB_SIGEMT 7 // Emulator Trap
#define GDB_SIGFPE 8 // Floating point exception
#define GDB_SIGSEGV 11 // Setgment violation, page fault
//
// GDB File I/O Error values, zero means no error
// Includes all general GDB Unix like error values
//
#define GDB_EBADMEMADDRBUFSIZE 11 // the buffer that stores memory Address to be read from/written to is not the right size
#define GDB_EBADMEMLENGBUFSIZE 12 // the buffer that stores Length is not the right size
#define GDB_EBADMEMLENGTH 13 // Length, the given number of bytes to read or write, is not the right size
#define GDB_EBADMEMDATA 14 // one of the bytes or nibbles of the memory is leess than 0
#define GDB_EBADMEMDATASIZE 15 // the memory data, 'XX..', is too short or too long
#define GDB_EBADBUFSIZE 21 // the buffer created is not the correct size
#define GDB_EINVALIDARG 31 // argument is invalid
#define GDB_ENOSPACE 41 //
#define GDB_EINVALIDBRKPOINTTYPE 51 // the breakpoint type is not recognized
#define GDB_EINVALIDREGNUM 61 // given register number is not valid: either <0 or >=Number of Registers
#define GDB_EUNKNOWN 255 // unknown
//
// These devices are open by GDB so we can just read and write to them
//
#define GDB_STDIN 0x00
#define GDB_STDOUT 0x01
#define GDB_STDERR 0x02
//
//Define Register size for different architectures
//
#if defined (MDE_CPU_IA32)
#define REG_SIZE 32
#elif defined (MDE_CPU_X64)
#define REG_SIZE 64
#elif defined (MDE_CPU_ARM)
#define REG_SIZE 32
#endif
typedef struct {
EFI_EXCEPTION_TYPE Exception;
UINT8 SignalNo;
} EFI_EXCEPTION_TYPE_ENTRY;
#if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64)
//
// Byte packed structure for DR6
// 32-bits on IA-32
// 64-bits on X64. The upper 32-bits on X64 are reserved
//
typedef union {
struct {
UINT32 B0:1; // Breakpoint condition detected
UINT32 B1:1; // Breakpoint condition detected
UINT32 B2:1; // Breakpoint condition detected
UINT32 B3:1; // Breakpoint condition detected
UINT32 Reserved_1:9; // Reserved
UINT32 BD:1; // Debug register access detected
UINT32 BS:1; // Single step
UINT32 BT:1; // Task switch
UINT32 Reserved_2:16; // Reserved
} Bits;
UINTN UintN;
} IA32_DR6;
//
// Byte packed structure for DR7
// 32-bits on IA-32
// 64-bits on X64. The upper 32-bits on X64 are reserved
//
typedef union {
struct {
UINT32 L0:1; // Local breakpoint enable
UINT32 G0:1; // Global breakpoint enable
UINT32 L1:1; // Local breakpoint enable
UINT32 G1:1; // Global breakpoint enable
UINT32 L2:1; // Local breakpoint enable
UINT32 G2:1; // Global breakpoint enable
UINT32 L3:1; // Local breakpoint enable
UINT32 G3:1; // Global breakpoint enable
UINT32 LE:1; // Local exact breakpoint enable
UINT32 GE:1; // Global exact breakpoint enable
UINT32 Reserved_1:3; // Reserved
UINT32 GD:1; // Global detect enable
UINT32 Reserved_2:2; // Reserved
UINT32 RW0:2; // Read/Write field
UINT32 LEN0:2; // Length field
UINT32 RW1:2; // Read/Write field
UINT32 LEN1:2; // Length field
UINT32 RW2:2; // Read/Write field
UINT32 LEN2:2; // Length field
UINT32 RW3:2; // Read/Write field
UINT32 LEN3:2; // Length field
} Bits;
UINTN UintN;
} IA32_DR7;
#endif /* if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) */
typedef enum {
InstructionExecution, //Hardware breakpoint
DataWrite, //watch
DataRead, //rwatch
DataReadWrite, //awatch
SoftwareBreakpoint, //Software breakpoint
NotSupported
} BREAK_TYPE;
//
// Array of exception types that need to be hooked by the debugger
//
extern EFI_EXCEPTION_TYPE_ENTRY gExceptionType[];
//
// If the periodic callback is called while we are processing an F packet we need
// to let the callback know to not read from the serail stream as it could steal
// characters from the F reponse packet
//
extern BOOLEAN gProcessingFPacket;
/**
Return the number of entries in the gExceptionType[]
@retval UINTN, the number of entries in the gExceptionType[] array.
**/
UINTN
MaxEfiException (
VOID
);
/**
Check to see if the ISA is supported.
ISA = Instruction Set Architecture
@retval TRUE if Isa is supported,
FALSE otherwise.
**/
BOOLEAN
CheckIsa (
IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
);
/**
Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
@param SystemContext Register content at time of the exception
@param GdbExceptionType GDB exception type
**/
VOID
GdbSendTSignal (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINT8 GdbExceptionType
);
/**
Translates the EFI mapping to GDB mapping
@param EFIExceptionType EFI Exception that is being processed
@retval UINTN that corresponds to EFIExceptionType's GDB exception type number
**/
UINT8
ConvertEFItoGDBtype (
IN EFI_EXCEPTION_TYPE EFIExceptionType
);
/**
Empties the given buffer
@param *Buf pointer to the first element in buffer to be emptied
**/
VOID
EmptyBuffer (
IN CHAR8 *Buf
);
/**
Converts an 8-bit Hex Char into a INTN.
@param Char - the hex character to be converted into UINTN
@retval a INTN, from 0 to 15, that corressponds to Char
-1 if Char is not a hex character
**/
INTN
HexCharToInt (
IN CHAR8 Char
);
/** 'E NN'
Send an error with the given error number after converting to hex.
The error number is put into the buffer in hex. '255' is the biggest errno we can send.
ex: 162 will be sent as A2.
@param errno the error number that will be sent
**/
VOID
EFIAPI
SendError (
IN UINT8 ErrorNum
);
/**
Send 'OK' when the function is done executing successfully.
**/
VOID
SendSuccess (
VOID
);
/**
Send empty packet to specify that particular command/functionality is not supported.
**/
VOID
SendNotSupported (
VOID
);
/** p n
Reads the n-th register's value into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
@param InBuffer This is the input buffer received from gdb server
**/
VOID
ReadNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
);
/** g
Reads the general registers into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
**/
VOID
ReadGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext
);
/** P n...=r...
Writes the new value of n-th register received into the input buffer to the n-th register
@param SystemContext Register content at time of the exception
@param InBuffer This is the input buffer received from gdb server
**/
VOID
WriteNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
);
/** G XX...
Writes the new values received into the input buffer to the general registers
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
WriteGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
);
/** m addr,length
Find the Length of the area to read and the start addres. Finally, pass them to
another function, TransferFromMemToOutBufAndSend, that will read from that memory space and
send it as a packet.
@param *PacketData Pointer to Payload data for the packet
**/
VOID
ReadFromMemory (
IN CHAR8 *PacketData
);
/** M addr,length :XX...
Find the Length of the area in bytes to write and the start addres. Finally, pass them to
another function, TransferFromInBufToMem, that will write to that memory space the info in
the input buffer.
@param PacketData Pointer to Payload data for the packet
**/
VOID
WriteToMemory (
IN CHAR8 *PacketData
);
/** c [addr ]
Continue. addr is Address to resume. If addr is omitted, resume at current
Address.
@param SystemContext Register content at time of the exception
@param *PacketData Pointer to PacketData
**/
VOID
ContinueAtAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
);
/** s [addr ]
Single step. addr is the Address at which to resume. If addr is omitted, resume
at same Address.
@param SystemContext Register content at time of the exception
@param PacketData Pointer to Payload data for the packet
**/
VOID
SingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
);
/**
Insert Single Step in the SystemContext
@param SystemContext Register content at time of the exception
**/
VOID
AddSingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext
);
/**
Remove Single Step in the SystemContext
@param SystemContext Register content at time of the exception
**/
VOID
RemoveSingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext
);
/**
Z1, [addr], [length]
Z2, [addr], [length]
Z3, [addr], [length]
Z4, [addr], [length]
Insert hardware breakpoint/watchpoint at address addr of size length
@param SystemContext Register content at time of the exception
@param *PacketData Pointer to the Payload data for the packet
**/
VOID
EFIAPI
InsertBreakPoint(
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
);
/**
z1, [addr], [length]
z2, [addr], [length]
z3, [addr], [length]
z4, [addr], [length]
Remove hardware breakpoint/watchpoint at address addr of size length
@param SystemContext Register content at time of the exception
@param *PacketData Pointer to the Payload data for the packet
**/
VOID
EFIAPI
RemoveBreakPoint(
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
);
/**
Exception Hanldler for GDB. It will be called for all exceptions
registered via the gExceptionType[] array.
@param ExceptionType Exception that is being processed
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
GdbExceptionHandler (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
);
/**
Periodic callback for GDB. This function is used to catch a ctrl-c or other
break in type command from GDB.
@param SystemContext Register content at time of the call
**/
VOID
EFIAPI
GdbPeriodicCallBack (
IN OUT EFI_SYSTEM_CONTEXT SystemContext
);
/**
Make two serail consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB.
These console show up on the remote system running GDB
**/
VOID
GdbInitializeSerialConsole (
VOID
);
/**
Send a GDB Remote Serial Protocol Packet
$PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
the packet teminating character '#' and the two digit checksum.
If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up
in an infinit loop. This is so if you unplug the debugger code just keeps running
@param PacketData Payload data for the packet
@retval Number of bytes of packet data sent.
**/
UINTN
SendPacket (
IN CHAR8 *PacketData
);
/**
Receive a GDB Remote Serial Protocol Packet
$PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
the packet teminating character '#' and the two digit checksum.
If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.
(In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)
If an ack '+' is not sent resend the packet
@param PacketData Payload data for the packet
@retval Number of bytes of packet data received.
**/
UINTN
ReceivePacket (
OUT CHAR8 *PacketData,
IN UINTN PacketDataSize
);
/**
Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates
the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero.
@param FileDescriptor Device to talk to.
@param Buffer Buffer to hold Count bytes that were read
@param Count Number of bytes to transfer.
@retval -1 Error
@retval {other} Number of bytes read.
**/
INTN
GdbRead (
IN INTN FileDescriptor,
OUT VOID *Buffer,
IN UINTN Count
);
/**
Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates
nothing was written. On error -1 is returned.
@param FileDescriptor Device to talk to.
@param Buffer Buffer to hold Count bytes that are to be written
@param Count Number of bytes to transfer.
@retval -1 Error
@retval {other} Number of bytes written.
**/
INTN
GdbWrite (
IN INTN FileDescriptor,
OUT CONST VOID *Buffer,
IN UINTN Count
);
UINTN *
FindPointerToRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber
);
CHAR8 *
BasicReadRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *OutBufPtr
);
VOID
TransferFromInBufToMem (
IN UINTN Length,
IN UINT8 *Address,
IN CHAR8 *NewData
);
VOID
TransferFromMemToOutBufAndSend (
IN UINTN Length,
IN UINT8 *Address
);
CHAR8 *
BasicWriteRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *InBufPtr
);
VOID
PrintReg (
EFI_SYSTEM_CONTEXT SystemContext
);
UINTN
ParseBreakpointPacket (
IN CHAR8 *PacketData,
OUT UINTN *Type,
OUT UINTN *Address,
OUT UINTN *Length
);
UINTN
GetBreakpointDataAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN BreakpointNumber
);
UINTN
GetBreakpointDetected (
IN EFI_SYSTEM_CONTEXT SystemContext
);
BREAK_TYPE
GetBreakpointType (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN BreakpointNumber
);
UINTN
ConvertLengthData (
IN UINTN Length
);
EFI_STATUS
FindNextFreeDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
OUT UINTN *Register
);
EFI_STATUS
EnableDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Register,
IN UINTN Address,
IN UINTN Length,
IN UINTN Type
);
EFI_STATUS
FindMatchingDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Address,
IN UINTN Length,
IN UINTN Type,
OUT UINTN *Register
);
EFI_STATUS
DisableDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Register
);
VOID
InitializeProcessor (
VOID
);
/**
Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
@param SystemContext Register content at time of the exception
@param GdbExceptionType GDB exception type
**/
VOID
ProcessorSendTSignal (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINT8 GdbExceptionType,
IN OUT CHAR8 *TSignalPtr,
IN UINTN SizeOfBuffer
);
/**
Check to see if this exception is related to ctrl-c handling.
@param ExceptionType Exception that is being processed
@param SystemContext Register content at time of the exception
@return TRUE This was a ctrl-c check that did not find a ctrl-c
@return FALSE This was not a ctrl-c check or some one hit ctrl-c
**/
BOOLEAN
ProcessorControlC (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
);
/**
Initialize debug agent.
This function is used to set up debug enviroment. It may enable interrupts.
@param[in] InitFlag Init flag is used to decide initialize process.
@param[in] Context Context needed according to InitFlag, it was optional.
**/
VOID
EFIAPI
DebugAgentHookExceptions (
IN UINT32 InitFlag,
IN VOID *Context OPTIONAL
);
#endif

View File

@ -1,70 +0,0 @@
#/** @file
# Null instance of Debug Agent Library with empty functions.
#
# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD License
# which accompanies this distribution. The full text of the license may be found at
# http://opensource.org/licenses/bsd-license.php
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#
#
#**/
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = GdbDebugAgent
FILE_GUID = b9f10c17-6ca0-40b5-9b44-6253cfc7d24b
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = DebugAgentLib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 EBC
#
[Sources.common]
GdbDebugAgent.c
[Sources.arm]
Arm/Processor.c
Arm/ExceptionSupport.ARMv6.S
Arm/ExceptionSupport.ARMv6.asm
[Sources.X64]
Ia32/Processor.c
[Sources.Ia32]
X64/Processor.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
EmbeddedPkg/EmbeddedPkg.dec
[Packages.arm]
ArmPkg/ArmPkg.dec
[LibraryClasses]
BaseLib
DebugLib
BaseMemoryLib
PcdLib
GdbSerialLib
CacheMaintenanceLib
DebugAgentTimerLib
[FeaturePcd.common]
gEmbeddedTokenSpaceGuid.PcdGdbSerial
[FixedPcd.common]
gEmbeddedTokenSpaceGuid.PcdGdbMaxPacketRetryCount
gEmbeddedTokenSpaceGuid.PcdGdbTimerPeriodMilliseconds
[FixedPcd.arm]
gArmTokenSpaceGuid.PcdCpuVectorBaseAddress

View File

@ -1,951 +0,0 @@
/** @file
Processor specific parts of the GDB stub
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <GdbDebugAgent.h>
//
// Array of exception types that need to be hooked by the debugger
// {EFI mapping, GDB mapping}
//
EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
{ EXCEPT_IA32_DIVIDE_ERROR, GDB_SIGFPE },
{ EXCEPT_IA32_DEBUG, GDB_SIGTRAP },
{ EXCEPT_IA32_NMI, GDB_SIGEMT },
{ EXCEPT_IA32_BREAKPOINT, GDB_SIGTRAP },
{ EXCEPT_IA32_OVERFLOW, GDB_SIGSEGV },
{ EXCEPT_IA32_BOUND, GDB_SIGSEGV },
{ EXCEPT_IA32_INVALID_OPCODE, GDB_SIGILL },
{ EXCEPT_IA32_DOUBLE_FAULT, GDB_SIGEMT },
{ EXCEPT_IA32_STACK_FAULT, GDB_SIGSEGV },
{ EXCEPT_IA32_GP_FAULT, GDB_SIGSEGV },
{ EXCEPT_IA32_PAGE_FAULT, GDB_SIGSEGV },
{ EXCEPT_IA32_FP_ERROR, GDB_SIGEMT },
{ EXCEPT_IA32_ALIGNMENT_CHECK, GDB_SIGEMT },
{ EXCEPT_IA32_MACHINE_CHECK, GDB_SIGEMT }
};
// The offsets of registers SystemContext.
// The fields in the array are in the gdb ordering.
//
//16 regs
UINTN gRegisterOffsets[] = {
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eax),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ecx),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Edx),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ebx),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Esp),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ebp),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Esi),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Edi),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eip),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Eflags),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Cs),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ss),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Ds),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Es),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Fs),
OFFSET_OF(EFI_SYSTEM_CONTEXT_IA32, Gs)
};
//Debug only..
VOID
PrintReg (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
Print ((CHAR16 *)L"EAX: %x ", SystemContext.SystemContextIa32->Eax);
Print ((CHAR16 *)L"ECX: %x ", SystemContext.SystemContextIa32->Ecx);
Print ((CHAR16 *)L"EDX: %x ", SystemContext.SystemContextIa32->Edx);
Print ((CHAR16 *)L"EBX: %x ", SystemContext.SystemContextIa32->Ebx);
Print ((CHAR16 *)L"ESP: %x ", SystemContext.SystemContextIa32->Esp);
Print ((CHAR16 *)L"EBP: %x ", SystemContext.SystemContextIa32->Ebp);
Print ((CHAR16 *)L"ESI: %x ", SystemContext.SystemContextIa32->Esi);
Print ((CHAR16 *)L"EDI: %x ", SystemContext.SystemContextIa32->Edi);
Print ((CHAR16 *)L"EIP: %x\n", SystemContext.SystemContextIa32->Eip);
Print ((CHAR16 *)L"EFlags: %x\n", SystemContext.SystemContextIa32->Eflags);
}
//Debug only..
VOID
PrintDRreg (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
Print ((CHAR16 *)L"DR0: %x ", SystemContext.SystemContextIa32->Dr0);
Print ((CHAR16 *)L"DR1: %x ", SystemContext.SystemContextIa32->Dr1);
Print ((CHAR16 *)L"DR2: %x ", SystemContext.SystemContextIa32->Dr2);
Print ((CHAR16 *)L"DR3: %x ", SystemContext.SystemContextIa32->Dr3);
Print ((CHAR16 *)L"DR6: %x ", SystemContext.SystemContextIa32->Dr6);
Print ((CHAR16 *)L"DR7: %x\n", SystemContext.SystemContextIa32->Dr7);
}
/**
Return the number of entries in the gExceptionType[]
@retval UINTN, the number of entries in the gExceptionType[] array.
**/
UINTN
MaxEfiException (
VOID
)
{
return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
}
/**
Check to see if the ISA is supported.
ISA = Instruction Set Architecture
@retval TRUE if Isa is supported,
FALSE otherwise.
**/
BOOLEAN
CheckIsa (
IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
)
{
return (BOOLEAN)(Isa == IsaIa32);
}
/**
This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
It is, by default, set to find the register pointer of the IA32 member
@param SystemContext Register content at time of the exception
@param RegNumber The register to which we want to find a pointer
@retval the pointer to the RegNumber-th pointer
**/
UINTN *
FindPointerToRegister(
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber
)
{
UINT8 *TempPtr;
TempPtr = ((UINT8 *)SystemContext.SystemContextIa32) + gRegisterOffsets[RegNumber];
return (UINTN *)TempPtr;
}
/**
Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
@param SystemContext Register content at time of the exception
@param RegNumber the number of the register that we want to read
@param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
@retval the pointer to the next character of the output buffer that is available to be written on.
**/
CHAR8 *
BasicReadRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *OutBufPtr
)
{
UINTN RegSize;
RegSize = 0;
while (RegSize < REG_SIZE) {
*OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
*OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
RegSize = RegSize + 8;
}
return OutBufPtr;
}
/** p n
Reads the n-th register's value into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
EFIAPI
ReadNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN RegNumber;
CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
CHAR8 *OutBufPtr; // pointer to the output buffer
RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
if ((RegNumber < 0) || (RegNumber >= sizeof (gRegisterOffsets)/sizeof (UINTN))) {
SendError (GDB_EINVALIDREGNUM);
return;
}
OutBufPtr = OutBuffer;
OutBufPtr = BasicReadRegister(SystemContext, RegNumber, OutBufPtr);
*OutBufPtr = '\0'; // the end of the buffer
SendPacket(OutBuffer);
}
/** g
Reads the general registers into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
ReadGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
UINTN i;
CHAR8 OutBuffer[129]; // 16 regs, 8 hex chars each, and the end '\0' (escape seq)
CHAR8 *OutBufPtr; // pointer to the output buffer
OutBufPtr = OutBuffer;
for(i = 0 ; i < sizeof (gRegisterOffsets)/sizeof (UINTN) ; i++) { // there are only 16 registers to read
OutBufPtr = BasicReadRegister(SystemContext, i, OutBufPtr);
}
*OutBufPtr = '\0'; // the end of the buffer
SendPacket(OutBuffer);
}
/**
Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
@param SystemContext Register content at time of the exception
@param RegNumber the number of the register that we want to write
@param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
@retval the pointer to the next character of the input buffer that can be used
**/
CHAR8 *
BasicWriteRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *InBufPtr
)
{
UINTN RegSize;
UINTN TempValue; // the value transferred from a hex char
UINT32 NewValue; // the new value of the RegNumber-th Register
NewValue = 0;
RegSize = 0;
while (RegSize < REG_SIZE) {
TempValue = HexCharToInt(*InBufPtr++);
if (TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << (RegSize+4));
TempValue = HexCharToInt(*InBufPtr++);
if (TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << RegSize);
RegSize = RegSize + 8;
}
*(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;
return InBufPtr;
}
/** P n...=r...
Writes the new value of n-th register received into the input buffer to the n-th register
@param SystemContext Register content at time of the exception
@param InBuffer Ponter to the input buffer received from gdb server
**/
VOID
EFIAPI
WriteNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN RegNumber;
CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
CHAR8 *RegNumBufPtr;
CHAR8 *InBufPtr; // pointer to the input buffer
// find the register number to write
InBufPtr = &InBuffer[1];
RegNumBufPtr = RegNumBuffer;
while (*InBufPtr != '=') {
*RegNumBufPtr++ = *InBufPtr++;
}
*RegNumBufPtr = '\0';
RegNumber = AsciiStrHexToUintn (RegNumBuffer);
// check if this is a valid Register Number
if ((RegNumber < 0) || (RegNumber >= sizeof (gRegisterOffsets)/sizeof (UINTN))) {
SendError (GDB_EINVALIDREGNUM);
return;
}
InBufPtr++; // skips the '=' character
BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
SendSuccess();
}
/** G XX...
Writes the new values received into the input buffer to the general registers
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
EFIAPI
WriteGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN i;
CHAR8 *InBufPtr; /// pointer to the input buffer
// check to see if the buffer is the right size which is
// 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 129
if (AsciiStrLen(InBuffer) != 129) { // 16 regs, 8 hex chars each, and the end '\0' (escape seq)
//Bad message. Message is not the right length
SendError (GDB_EBADBUFSIZE);
return;
}
InBufPtr = &InBuffer[1];
// Read the new values for the registers from the input buffer to an array, NewValueArray.
// The values in the array are in the gdb ordering
for(i=0; i < sizeof (gRegisterOffsets)/sizeof (UINTN); i++) { // there are only 16 registers to write
InBufPtr = BasicWriteRegister(SystemContext, i, InBufPtr);
}
SendSuccess();
}
/** c [addr ]
Continue. addr is Address to resume. If addr is omitted, resume at current
Address.
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
ContinueAtAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
if (PacketData[1] != '\0') {
SystemContext.SystemContextIa32->Eip = AsciiStrHexToUintn (&PacketData[1]);
}
}
/** s [addr ]
Single step. addr is the Address at which to resume. If addr is omitted, resume
at same Address.
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
SingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
SendNotSupported();
}
/**
Returns breakpoint data address from DR0-DR3 based on the input breakpoint number
@param SystemContext Register content at time of the exception
@param BreakpointNumber Breakpoint number
@retval Address Data address from DR0-DR3 based on the breakpoint number.
**/
UINTN
GetBreakpointDataAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN BreakpointNumber
)
{
UINTN Address;
if (BreakpointNumber == 1) {
Address = SystemContext.SystemContextIa32->Dr0;
} else if (BreakpointNumber == 2) {
Address = SystemContext.SystemContextIa32->Dr1;
} else if (BreakpointNumber == 3) {
Address = SystemContext.SystemContextIa32->Dr2;
} else if (BreakpointNumber == 4) {
Address = SystemContext.SystemContextIa32->Dr3;
} else {
Address = 0;
}
return Address;
}
/**
Returns currently detected breakpoint value based on the register DR6 B0-B3 field.
If no breakpoint is detected then it returns 0.
@param SystemContext Register content at time of the exception
@retval {1-4} Currently detected breakpoint value
@retval 0 No breakpoint detected.
**/
UINTN
GetBreakpointDetected (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
IA32_DR6 Dr6;
UINTN BreakpointNumber;
Dr6.UintN = SystemContext.SystemContextIa32->Dr6;
if (Dr6.Bits.B0 == 1) {
BreakpointNumber = 1;
} else if (Dr6.Bits.B1 == 1) {
BreakpointNumber = 2;
} else if (Dr6.Bits.B2 == 1) {
BreakpointNumber = 3;
} else if (Dr6.Bits.B3 == 1) {
BreakpointNumber = 4;
} else {
BreakpointNumber = 0; //No breakpoint detected
}
return BreakpointNumber;
}
/**
Returns Breakpoint type (InstructionExecution, DataWrite, DataRead or DataReadWrite)
based on the Breakpoint number
@param SystemContext Register content at time of the exception
@param BreakpointNumber Breakpoint number
@retval BREAK_TYPE Breakpoint type value read from register DR7 RWn field
For unknown value, it returns NotSupported.
**/
BREAK_TYPE
GetBreakpointType (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN BreakpointNumber
)
{
IA32_DR7 Dr7;
BREAK_TYPE Type = NotSupported; //Default is NotSupported type
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (BreakpointNumber == 1) {
Type = (BREAK_TYPE) Dr7.Bits.RW0;
} else if (BreakpointNumber == 2) {
Type = (BREAK_TYPE) Dr7.Bits.RW1;
} else if (BreakpointNumber == 3) {
Type = (BREAK_TYPE) Dr7.Bits.RW2;
} else if (BreakpointNumber == 4) {
Type = (BREAK_TYPE) Dr7.Bits.RW3;
}
return Type;
}
/**
Parses Length and returns the length which DR7 LENn field accepts.
For example: If we receive 1-Byte length then we should return 0.
Zero gets written to DR7 LENn field.
@param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
@retval Length Appropriate converted values which DR7 LENn field accepts.
**/
UINTN
ConvertLengthData (
IN UINTN Length
)
{
if (Length == 1) { //1-Byte length
return 0;
} else if (Length == 2) { //2-Byte length
return 1;
} else if (Length == 4) { //4-Byte length
return 3;
} else { //Undefined or 8-byte length
return 2;
}
}
/**
Finds the next free debug register. If all the registers are occupied then
EFI_OUT_OF_RESOURCES is returned.
@param SystemContext Register content at time of the exception
@param Register Register value (0 - 3 for the first free debug register)
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
FindNextFreeDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
OUT UINTN *Register
)
{
IA32_DR7 Dr7;
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (Dr7.Bits.G0 == 0) {
*Register = 0;
} else if (Dr7.Bits.G1 == 0) {
*Register = 1;
} else if (Dr7.Bits.G2 == 0) {
*Register = 2;
} else if (Dr7.Bits.G3 == 0) {
*Register = 3;
} else {
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
/**
Enables the debug register. Writes Address value to appropriate DR0-3 register.
Sets LENn, Gn, RWn bits in DR7 register.
@param SystemContext Register content at time of the exception
@param Register Register value (0 - 3)
@param Address Breakpoint address value
@param Type Breakpoint type (Instruction, Data write, Data read
or write etc.)
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
EnableDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Register,
IN UINTN Address,
IN UINTN Length,
IN UINTN Type
)
{
IA32_DR7 Dr7;
//Convert length data
Length = ConvertLengthData (Length);
//For Instruction execution, length should be 0
//(Ref. Intel reference manual 18.2.4)
if ((Type == 0) && (Length != 0)) {
return EFI_INVALID_PARAMETER;
}
//Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
//software breakpoint. We should send empty packet in both these cases.
if ((Type == (BREAK_TYPE)DataRead) ||
(Type == (BREAK_TYPE)SoftwareBreakpoint)) {
return EFI_UNSUPPORTED;
}
//Read DR7 so appropriate Gn, RWn and LENn bits can be modified.
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (Register == 0) {
SystemContext.SystemContextIa32->Dr0 = Address;
Dr7.Bits.G0 = 1;
Dr7.Bits.RW0 = Type;
Dr7.Bits.LEN0 = Length;
} else if (Register == 1) {
SystemContext.SystemContextIa32->Dr1 = Address;
Dr7.Bits.G1 = 1;
Dr7.Bits.RW1 = Type;
Dr7.Bits.LEN1 = Length;
} else if (Register == 2) {
SystemContext.SystemContextIa32->Dr2 = Address;
Dr7.Bits.G2 = 1;
Dr7.Bits.RW2 = Type;
Dr7.Bits.LEN2 = Length;
} else if (Register == 3) {
SystemContext.SystemContextIa32->Dr3 = Address;
Dr7.Bits.G3 = 1;
Dr7.Bits.RW3 = Type;
Dr7.Bits.LEN3 = Length;
} else {
return EFI_INVALID_PARAMETER;
}
//Update Dr7 with appropriate Gn, RWn and LENn bits
SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
return EFI_SUCCESS;
}
/**
Returns register number 0 - 3 for the maching debug register.
This function compares incoming Address, Type, Length and
if there is a match then it returns the appropriate register number.
In case of mismatch, function returns EFI_NOT_FOUND message.
@param SystemContext Register content at time of the exception
@param Address Breakpoint address value
@param Length Breakpoint length value
@param Type Breakpoint type (Instruction, Data write,
Data read or write etc.)
@param Register Register value to be returned
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
FindMatchingDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Address,
IN UINTN Length,
IN UINTN Type,
OUT UINTN *Register
)
{
IA32_DR7 Dr7;
//Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
//software breakpoint. We should send empty packet in both these cases.
if ((Type == (BREAK_TYPE)DataRead) ||
(Type == (BREAK_TYPE)SoftwareBreakpoint)) {
return EFI_UNSUPPORTED;
}
//Convert length data
Length = ConvertLengthData(Length);
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if ((Dr7.Bits.G0 == 1) &&
(Dr7.Bits.LEN0 == Length) &&
(Dr7.Bits.RW0 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr0)) {
*Register = 0;
} else if ((Dr7.Bits.G1 == 1) &&
(Dr7.Bits.LEN1 == Length) &&
(Dr7.Bits.RW1 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr1)) {
*Register = 1;
} else if ((Dr7.Bits.G2 == 1) &&
(Dr7.Bits.LEN2 == Length) &&
(Dr7.Bits.RW2 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr2)) {
*Register = 2;
} else if ((Dr7.Bits.G3 == 1) &&
(Dr7.Bits.LEN3 == Length) &&
(Dr7.Bits.RW3 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr3)) {
*Register = 3;
} else {
Print ((CHAR16 *)L"No match found..\n");
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Disables the particular debug register.
@param SystemContext Register content at time of the exception
@param Register Register to be disabled
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
DisableDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Register
)
{
IA32_DR7 Dr7;
UINTN Address = 0;
//Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (Register == 0) {
SystemContext.SystemContextIa32->Dr0 = Address;
Dr7.Bits.G0 = 0;
Dr7.Bits.RW0 = 0;
Dr7.Bits.LEN0 = 0;
} else if (Register == 1) {
SystemContext.SystemContextIa32->Dr1 = Address;
Dr7.Bits.G1 = 0;
Dr7.Bits.RW1 = 0;
Dr7.Bits.LEN1 = 0;
} else if (Register == 2) {
SystemContext.SystemContextIa32->Dr2 = Address;
Dr7.Bits.G2 = 0;
Dr7.Bits.RW2 = 0;
Dr7.Bits.LEN2 = 0;
} else if (Register == 3) {
SystemContext.SystemContextIa32->Dr3 = Address;
Dr7.Bits.G3 = 0;
Dr7.Bits.RW3 = 0;
Dr7.Bits.LEN3 = 0;
} else {
return EFI_INVALID_PARAMETER;
}
//Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
return EFI_SUCCESS;
}
/**
Z1, [addr], [length]
Z2, [addr], [length]
Z3, [addr], [length]
Z4, [addr], [length]
Insert hardware breakpoint/watchpoint at address addr of size length
@param SystemContext Register content at time of the exception
@param *PacketData Pointer to the Payload data for the packet
**/
VOID
EFIAPI
InsertBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
UINTN Type;
UINTN Address;
UINTN Length;
UINTN Register;
EFI_STATUS Status;
BREAK_TYPE BreakType = NotSupported;
UINTN ErrorCode;
ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
if (ErrorCode > 0) {
SendError ((UINT8)ErrorCode);
return;
}
switch (Type) {
case 0: //Software breakpoint
BreakType = SoftwareBreakpoint;
break;
case 1: //Hardware breakpoint
BreakType = InstructionExecution;
break;
case 2: //Write watchpoint
BreakType = DataWrite;
break;
case 3: //Read watchpoint
BreakType = DataRead;
break;
case 4: //Access watchpoint
BreakType = DataReadWrite;
break;
default :
Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);
SendError (GDB_EINVALIDBRKPOINTTYPE);
return;
}
// Find next free debug register
Status = FindNextFreeDebugRegister (SystemContext, &Register);
if (EFI_ERROR(Status)) {
Print ((CHAR16 *)L"No space left on device\n");
SendError (GDB_ENOSPACE);
return;
}
// Write Address, length data at particular DR register
Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);
if (EFI_ERROR(Status)) {
if (Status == EFI_UNSUPPORTED) {
SendNotSupported();
return;
}
SendError (GDB_EINVALIDARG);
return;
}
SendSuccess ();
}
/**
z1, [addr], [length]
z2, [addr], [length]
z3, [addr], [length]
z4, [addr], [length]
Remove hardware breakpoint/watchpoint at address addr of size length
@param *PacketData Pointer to the Payload data for the packet
**/
VOID
EFIAPI
RemoveBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
UINTN Type;
UINTN Address;
UINTN Length;
UINTN Register;
BREAK_TYPE BreakType = NotSupported;
EFI_STATUS Status;
UINTN ErrorCode;
//Parse breakpoint packet data
ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
if (ErrorCode > 0) {
SendError ((UINT8)ErrorCode);
return;
}
switch (Type) {
case 0: //Software breakpoint
BreakType = SoftwareBreakpoint;
break;
case 1: //Hardware breakpoint
BreakType = InstructionExecution;
break;
case 2: //Write watchpoint
BreakType = DataWrite;
break;
case 3: //Read watchpoint
BreakType = DataRead;
break;
case 4: //Access watchpoint
BreakType = DataReadWrite;
break;
default :
SendError (GDB_EINVALIDBRKPOINTTYPE);
return;
}
//Find matching debug register
Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);
if (EFI_ERROR(Status)) {
if (Status == EFI_UNSUPPORTED) {
SendNotSupported();
return;
}
SendError (GDB_ENOSPACE);
return;
}
//Remove breakpoint
Status = DisableDebugRegister(SystemContext, Register);
if (EFI_ERROR(Status)) {
SendError (GDB_EINVALIDARG);
return;
}
SendSuccess ();
}
/**
Initialize debug agent.
This function is used to set up debug environment to support source level debugging.
If certain Debug Agent Library instance has to save some private data in the stack,
this function must work on the mode that doesn't return to the caller, then
the caller needs to wrap up all rest of logic after InitializeDebugAgent() into one
function and pass it into InitializeDebugAgent(). InitializeDebugAgent() is
responsible to invoke the passing-in function at the end of InitializeDebugAgent().
If the parameter Function is not NULL, Debug Agent Library instance will invoke it by
passing in the Context to be its parameter.
If Function() is NULL, Debug Agent Library instance will return after setup debug
environment.
@param[in] InitFlag Init flag is used to decide the initialize process.
@param[in] Context Context needed according to InitFlag; it was optional.
@param[in] Function Continue function called by debug agent library; it was
optional.
**/
VOID
EFIAPI
InitializeDebugAgent (
IN UINT32 InitFlag,
IN VOID *Context, OPTIONAL
IN DEBUG_AGENT_CONTINUE Function OPTIONAL
)
{
// BugBug: Add the code to build an GDT/IDT
if (Function != NULL) {
Function (Context);
}
}

View File

@ -1,963 +0,0 @@
/** @file
Processor specific parts of the GDB stub
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <GdbStubInternal.h>
//
// Array of exception types that need to be hooked by the debugger
//
EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
{ EXCEPT_X64_DIVIDE_ERROR, GDB_SIGFPE },
{ EXCEPT_X64_DEBUG, GDB_SIGTRAP },
{ EXCEPT_X64_NMI, GDB_SIGEMT },
{ EXCEPT_X64_BREAKPOINT, GDB_SIGTRAP },
{ EXCEPT_X64_OVERFLOW, GDB_SIGSEGV },
{ EXCEPT_X64_BOUND, GDB_SIGSEGV },
{ EXCEPT_X64_INVALID_OPCODE, GDB_SIGILL },
{ EXCEPT_X64_DOUBLE_FAULT, GDB_SIGEMT },
{ EXCEPT_X64_STACK_FAULT, GDB_SIGSEGV },
{ EXCEPT_X64_GP_FAULT, GDB_SIGSEGV },
{ EXCEPT_X64_PAGE_FAULT, GDB_SIGSEGV },
{ EXCEPT_X64_FP_ERROR, GDB_SIGEMT },
{ EXCEPT_X64_ALIGNMENT_CHECK, GDB_SIGEMT },
{ EXCEPT_X64_MACHINE_CHECK, GDB_SIGEMT }
};
// The offsets of registers SystemContextX64.
// The fields in the array are in the gdb ordering.
// HAVE TO DOUBLE-CHECK THE ORDER of the 24 regs
//
UINTN gRegisterOffsets[] = {
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rax),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rcx),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdx),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbx),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsp),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rbp),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rsi),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rdi),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rip),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Rflags),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Cs),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ss),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Ds),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Es),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Fs),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, Gs),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R8),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R9),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R10),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R11),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R12),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R13),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R14),
OFFSET_OF(EFI_SYSTEM_CONTEXT_X64, R15)
};
/**
Return the number of entries in the gExceptionType[]
@retval UINTN, the number of entries in the gExceptionType[] array.
**/
UINTN
MaxEfiException (
VOID
)
{
return sizeof (gExceptionType)/sizeof (EFI_EXCEPTION_TYPE_ENTRY);
}
/**
Return the number of entries in the gRegisters[]
@retval UINTN, the number of entries (registers) in the gRegisters[] array.
**/
UINTN
MaxRegisterCount (
VOID
)
{
return sizeof (gRegisterOffsets)/sizeof (UINTN);
}
/**
Check to see if the ISA is supported.
ISA = Instruction Set Architecture
@retval TRUE if Isa is supported
**/
BOOLEAN
CheckIsa (
IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
)
{
return (BOOLEAN)(Isa == IsaX64);
}
/**
This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
It is, by default, set to find the register pointer of the X64 member
@param SystemContext Register content at time of the exception
@param RegNumber The register to which we want to find a pointer
@retval the pointer to the RegNumber-th pointer
**/
UINTN *
FindPointerToRegister(
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber
)
{
UINT8 *TempPtr;
TempPtr = ((UINT8 *)SystemContext.SystemContextX64) + gRegisterOffsets[RegNumber];
return (UINTN *)TempPtr;
}
/**
Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
@param SystemContext Register content at time of the exception
@param RegNumber the number of the register that we want to read
@param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
@retval the pointer to the next character of the output buffer that is available to be written on.
**/
CHAR8 *
BasicReadRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *OutBufPtr
)
{
UINTN RegSize;
RegSize = 0;
while (RegSize < 64) {
*OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
*OutBufPtr++ = mHexToStr[((*FindPointerToRegister(SystemContext, RegNumber) >> RegSize) & 0xf)];
RegSize = RegSize + 8;
}
return OutBufPtr;
}
/** p n
Reads the n-th register's value into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
ReadNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN RegNumber;
CHAR8 OutBuffer[17]; // 1 reg=16 hex chars, and the end '\0' (escape seq)
CHAR8 *OutBufPtr; // pointer to the output buffer
RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) {
SendError (GDB_EINVALIDREGNUM);
return;
}
OutBufPtr = OutBuffer;
OutBufPtr = BasicReadRegister(SystemContext, RegNumber, OutBufPtr);
*OutBufPtr = '\0'; // the end of the buffer
SendPacket (OutBuffer);
}
/** g
Reads the general registers into an output buffer and sends it as a packet
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
ReadGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
UINTN i;
CHAR8 OutBuffer[385]; // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
CHAR8 *OutBufPtr; // pointer to the output buffer
OutBufPtr = OutBuffer;
for(i = 0 ; i < MaxRegisterCount() ; i++) { // there are only 24 registers to read
OutBufPtr = BasicReadRegister(SystemContext, i, OutBufPtr);
}
*OutBufPtr = '\0'; // the end of the buffer
SendPacket (OutBuffer);
}
/**
Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
@param SystemContext Register content at time of the exception
@param RegNumber the number of the register that we want to write
@param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
@retval the pointer to the next character of the input buffer that can be used
**/
CHAR8 *
BasicWriteRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN RegNumber,
IN CHAR8 *InBufPtr
)
{
UINTN RegSize;
UINTN TempValue; // the value transferred from a hex char
UINT64 NewValue; // the new value of the RegNumber-th Register
NewValue = 0;
RegSize = 0;
while (RegSize < 64) {
TempValue = HexCharToInt(*InBufPtr++);
if (TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << (RegSize+4));
TempValue = HexCharToInt(*InBufPtr++);
if (TempValue < 0) {
SendError (GDB_EBADMEMDATA);
return NULL;
}
NewValue += (TempValue << RegSize);
RegSize = RegSize + 8;
}
*(FindPointerToRegister(SystemContext, RegNumber)) = NewValue;
return InBufPtr;
}
/** P n...=r...
Writes the new value of n-th register received into the input buffer to the n-th register
@param SystemContext Register content at time of the exception
@param InBuffer Ponter to the input buffer received from gdb server
**/
VOID
EFIAPI
WriteNthRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN RegNumber;
CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
CHAR8 *RegNumBufPtr;
CHAR8 *InBufPtr; // pointer to the input buffer
// find the register number to write
InBufPtr = &InBuffer[1];
RegNumBufPtr = RegNumBuffer;
while (*InBufPtr != '=') {
*RegNumBufPtr++ = *InBufPtr++;
}
*RegNumBufPtr = '\0';
RegNumber = AsciiStrHexToUintn (RegNumBuffer);
// check if this is a valid Register Number
if ((RegNumber < 0) || (RegNumber >= MaxRegisterCount())) {
SendError (GDB_EINVALIDREGNUM);
return;
}
InBufPtr++; // skips the '=' character
BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
SendSuccess();
}
/** G XX...
Writes the new values received into the input buffer to the general registers
@param SystemContext Register content at time of the exception
@param InBuffer Pointer to the input buffer received from gdb server
**/
VOID
EFIAPI
WriteGeneralRegisters (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *InBuffer
)
{
UINTN i;
CHAR8 *InBufPtr; /// pointer to the input buffer
// check to see if the buffer is the right size which is
// 1 (for 'G') + 16 (for 16 registers) * 8 ( for 8 hex chars each) = 385
if (AsciiStrLen(InBuffer) != 385) { // 24 regs, 16 hex chars each, and the end '\0' (escape seq)
//Bad message. Message is not the right length
SendError (GDB_EBADBUFSIZE);
return;
}
InBufPtr = &InBuffer[1];
// Read the new values for the registers from the input buffer to an array, NewValueArray.
// The values in the array are in the gdb ordering
for(i=0; i < MaxRegisterCount(); i++) { // there are only 16 registers to write
InBufPtr = BasicWriteRegister(SystemContext, i, InBufPtr);
}
SendSuccess();
}
/**
Insert Single Step in the SystemContext
@param SystemContext Register content at time of the exception
**/
VOID
AddSingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
SystemContext.SystemContextX64->Rflags |= TF_BIT; //Setting the TF bit.
}
/**
Remove Single Step in the SystemContext
@param SystemContext Register content at time of the exception
**/
VOID
RemoveSingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
SystemContext.SystemContextX64->Rflags &= ~TF_BIT; // clearing the TF bit.
}
/** c [addr ]
Continue. addr is Address to resume. If addr is omitted, resume at current
Address.
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
ContinueAtAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
if (PacketData[1] != '\0') {
SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn(&PacketData[1]);
}
}
/** s [addr ]
Single step. addr is the Address at which to resume. If addr is omitted, resume
at same Address.
@param SystemContext Register content at time of the exception
**/
VOID
EFIAPI
SingleStep (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
if (PacketData[1] != '\0') {
SystemContext.SystemContextX64->Rip = AsciiStrHexToUintn (&PacketData[1]);
}
AddSingleStep (SystemContext);
}
/**
Returns breakpoint data address from DR0-DR3 based on the input breakpoint
number
@param SystemContext Register content at time of the exception
@param BreakpointNumber Breakpoint number
@retval Address Data address from DR0-DR3 based on the
breakpoint number.
**/
UINTN
GetBreakpointDataAddress (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN BreakpointNumber
)
{
UINTN Address;
if (BreakpointNumber == 1) {
Address = SystemContext.SystemContextIa32->Dr0;
} else if (BreakpointNumber == 2) {
Address = SystemContext.SystemContextIa32->Dr1;
} else if (BreakpointNumber == 3) {
Address = SystemContext.SystemContextIa32->Dr2;
} else if (BreakpointNumber == 4) {
Address = SystemContext.SystemContextIa32->Dr3;
} else {
Address = 0;
}
return Address;
}
/**
Returns currently detected breakpoint value based on the register
DR6 B0-B3 field.
If no breakpoint is detected then it returns 0.
@param SystemContext Register content at time of the exception
@retval {1-4} Currently detected breakpoint value
@retval 0 No breakpoint detected.
**/
UINTN
GetBreakpointDetected (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
IA32_DR6 Dr6;
UINTN BreakpointNumber;
Dr6.UintN = SystemContext.SystemContextIa32->Dr6;
if (Dr6.Bits.B0 == 1) {
BreakpointNumber = 1;
} else if (Dr6.Bits.B1 == 1) {
BreakpointNumber = 2;
} else if (Dr6.Bits.B2 == 1) {
BreakpointNumber = 3;
} else if (Dr6.Bits.B3 == 1) {
BreakpointNumber = 4;
} else {
BreakpointNumber = 0; //No breakpoint detected
}
return BreakpointNumber;
}
/**
Returns Breakpoint type (InstructionExecution, DataWrite, DataRead
or DataReadWrite) based on the Breakpoint number
@param SystemContext Register content at time of the exception
@param BreakpointNumber Breakpoint number
@retval BREAK_TYPE Breakpoint type value read from register DR7 RWn
field. For unknown value, it returns NotSupported.
**/
BREAK_TYPE
GetBreakpointType (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN BreakpointNumber
)
{
IA32_DR7 Dr7;
BREAK_TYPE Type = NotSupported; //Default is NotSupported type
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (BreakpointNumber == 1) {
Type = (BREAK_TYPE) Dr7.Bits.RW0;
} else if (BreakpointNumber == 2) {
Type = (BREAK_TYPE) Dr7.Bits.RW1;
} else if (BreakpointNumber == 3) {
Type = (BREAK_TYPE) Dr7.Bits.RW2;
} else if (BreakpointNumber == 4) {
Type = (BREAK_TYPE) Dr7.Bits.RW3;
}
return Type;
}
/**
Parses Length and returns the length which DR7 LENn field accepts.
For example: If we receive 1-Byte length then we should return 0.
Zero gets written to DR7 LENn field.
@param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
@retval Length Appropriate converted values which DR7 LENn field accepts.
**/
UINTN
ConvertLengthData (
IN UINTN Length
)
{
if (Length == 1) { //1-Byte length
return 0;
} else if (Length == 2) { //2-Byte length
return 1;
} else if (Length == 4) { //4-Byte length
return 3;
} else { //Undefined or 8-byte length
return 2;
}
}
/**
Finds the next free debug register. If all the registers are occupied then
EFI_OUT_OF_RESOURCES is returned.
@param SystemContext Register content at time of the exception
@param Register Register value (0 - 3 for the first free debug register)
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
FindNextFreeDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
OUT UINTN *Register
)
{
IA32_DR7 Dr7;
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (Dr7.Bits.G0 == 0) {
*Register = 0;
} else if (Dr7.Bits.G1 == 0) {
*Register = 1;
} else if (Dr7.Bits.G2 == 0) {
*Register = 2;
} else if (Dr7.Bits.G3 == 0) {
*Register = 3;
} else {
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
/**
Enables the debug register. Writes Address value to appropriate DR0-3 register.
Sets LENn, Gn, RWn bits in DR7 register.
@param SystemContext Register content at time of the exception
@param Register Register value (0 - 3)
@param Address Breakpoint address value
@param Type Breakpoint type (Instruction, Data write,
Data read or write etc.)
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
EnableDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Register,
IN UINTN Address,
IN UINTN Length,
IN UINTN Type
)
{
IA32_DR7 Dr7;
//Convert length data
Length = ConvertLengthData (Length);
//For Instruction execution, length should be 0
//(Ref. Intel reference manual 18.2.4)
if ((Type == 0) && (Length != 0)) {
return EFI_INVALID_PARAMETER;
}
//Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
//software breakpoint. We should send empty packet in both these cases.
if ((Type == (BREAK_TYPE)DataRead) ||
(Type == (BREAK_TYPE)SoftwareBreakpoint)) {
return EFI_UNSUPPORTED;
}
//Read DR7 so appropriate Gn, RWn and LENn bits can be modified.
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (Register == 0) {
SystemContext.SystemContextIa32->Dr0 = Address;
Dr7.Bits.G0 = 1;
Dr7.Bits.RW0 = Type;
Dr7.Bits.LEN0 = Length;
} else if (Register == 1) {
SystemContext.SystemContextIa32->Dr1 = Address;
Dr7.Bits.G1 = 1;
Dr7.Bits.RW1 = Type;
Dr7.Bits.LEN1 = Length;
} else if (Register == 2) {
SystemContext.SystemContextIa32->Dr2 = Address;
Dr7.Bits.G2 = 1;
Dr7.Bits.RW2 = Type;
Dr7.Bits.LEN2 = Length;
} else if (Register == 3) {
SystemContext.SystemContextIa32->Dr3 = Address;
Dr7.Bits.G3 = 1;
Dr7.Bits.RW3 = Type;
Dr7.Bits.LEN3 = Length;
} else {
return EFI_INVALID_PARAMETER;
}
//Update Dr7 with appropriate Gn, RWn and LENn bits
SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
return EFI_SUCCESS;
}
/**
Returns register number 0 - 3 for the maching debug register.
This function compares incoming Address, Type, Length and
if there is a match then it returns the appropriate register number.
In case of mismatch, function returns EFI_NOT_FOUND message.
@param SystemContext Register content at time of the exception
@param Address Breakpoint address value
@param Length Breakpoint length value
@param Type Breakpoint type (Instruction, Data write, Data read
or write etc.)
@param Register Register value to be returned
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
FindMatchingDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Address,
IN UINTN Length,
IN UINTN Type,
OUT UINTN *Register
)
{
IA32_DR7 Dr7;
//Hardware doesn't support ReadWatch (z3 packet) type. GDB can handle
//software breakpoint. We should send empty packet in both these cases.
if ((Type == (BREAK_TYPE)DataRead) ||
(Type == (BREAK_TYPE)SoftwareBreakpoint)) {
return EFI_UNSUPPORTED;
}
//Convert length data
Length = ConvertLengthData(Length);
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if ((Dr7.Bits.G0 == 1) &&
(Dr7.Bits.LEN0 == Length) &&
(Dr7.Bits.RW0 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr0)) {
*Register = 0;
} else if ((Dr7.Bits.G1 == 1) &&
(Dr7.Bits.LEN1 == Length) &&
(Dr7.Bits.RW1 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr1)) {
*Register = 1;
} else if ((Dr7.Bits.G2 == 1) &&
(Dr7.Bits.LEN2 == Length) &&
(Dr7.Bits.RW2 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr2)) {
*Register = 2;
} else if ((Dr7.Bits.G3 == 1) &&
(Dr7.Bits.LEN3 == Length) &&
(Dr7.Bits.RW3 == Type) &&
(Address == SystemContext.SystemContextIa32->Dr3)) {
*Register = 3;
} else {
Print ((CHAR16 *)L"No match found..\n");
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Disables the particular debug register.
@param SystemContext Register content at time of the exception
@param Register Register to be disabled
@retval EFI_STATUS Appropriate status value.
**/
EFI_STATUS
DisableDebugRegister (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN UINTN Register
)
{
IA32_DR7 Dr7;
UINTN Address = 0;
//Read DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
Dr7.UintN = SystemContext.SystemContextIa32->Dr7;
if (Register == 0) {
SystemContext.SystemContextIa32->Dr0 = Address;
Dr7.Bits.G0 = 0;
Dr7.Bits.RW0 = 0;
Dr7.Bits.LEN0 = 0;
} else if (Register == 1) {
SystemContext.SystemContextIa32->Dr1 = Address;
Dr7.Bits.G1 = 0;
Dr7.Bits.RW1 = 0;
Dr7.Bits.LEN1 = 0;
} else if (Register == 2) {
SystemContext.SystemContextIa32->Dr2 = Address;
Dr7.Bits.G2 = 0;
Dr7.Bits.RW2 = 0;
Dr7.Bits.LEN2 = 0;
} else if (Register == 3) {
SystemContext.SystemContextIa32->Dr3 = Address;
Dr7.Bits.G3 = 0;
Dr7.Bits.RW3 = 0;
Dr7.Bits.LEN3 = 0;
} else {
return EFI_INVALID_PARAMETER;
}
//Update DR7 register so appropriate Gn, RWn and LENn bits can be turned off.
SystemContext.SystemContextIa32->Dr7 = Dr7.UintN;
return EFI_SUCCESS;
}
/**
Z1, [addr], [length]
Z2, [addr], [length]
Z3, [addr], [length]
Z4, [addr], [length]
Insert hardware breakpoint/watchpoint at address addr of size length
@param SystemContext Register content at time of the exception
@param *PacketData Pointer to the Payload data for the packet
**/
VOID
EFIAPI
InsertBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
UINTN Type;
UINTN Address;
UINTN Length;
UINTN Register;
EFI_STATUS Status;
BREAK_TYPE BreakType = NotSupported;
UINTN ErrorCode;
ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
if (ErrorCode > 0) {
SendError ((UINT8)ErrorCode);
return;
}
switch (Type) {
case 0: //Software breakpoint
BreakType = SoftwareBreakpoint;
break;
case 1: //Hardware breakpoint
BreakType = InstructionExecution;
break;
case 2: //Write watchpoint
BreakType = DataWrite;
break;
case 3: //Read watchpoint
BreakType = DataRead;
break;
case 4: //Access watchpoint
BreakType = DataReadWrite;
break;
default :
Print ((CHAR16 *)L"Insert breakpoint default: %x\n", Type);
SendError (GDB_EINVALIDBRKPOINTTYPE);
return;
}
// Find next free debug register
Status = FindNextFreeDebugRegister (SystemContext, &Register);
if (EFI_ERROR(Status)) {
Print ((CHAR16 *)L"No space left on device\n");
SendError (GDB_ENOSPACE);
return;
}
// Write Address, length data at particular DR register
Status = EnableDebugRegister (SystemContext, Register, Address, Length, (UINTN)BreakType);
if (EFI_ERROR(Status)) {
if (Status == EFI_UNSUPPORTED) {
Print ((CHAR16 *)L"Not supported\n");
SendNotSupported();
return;
}
Print ((CHAR16 *)L"Invalid argument\n");
SendError (GDB_EINVALIDARG);
return;
}
SendSuccess ();
}
/**
z1, [addr], [length]
z2, [addr], [length]
z3, [addr], [length]
z4, [addr], [length]
Remove hardware breakpoint/watchpoint at address addr of size length
@param *PacketData Pointer to the Payload data for the packet
**/
VOID
EFIAPI
RemoveBreakPoint (
IN EFI_SYSTEM_CONTEXT SystemContext,
IN CHAR8 *PacketData
)
{
UINTN Type;
UINTN Address;
UINTN Length;
UINTN Register;
BREAK_TYPE BreakType = NotSupported;
EFI_STATUS Status;
UINTN ErrorCode;
//Parse breakpoint packet data
ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
if (ErrorCode > 0) {
SendError ((UINT8)ErrorCode);
return;
}
switch (Type) {
case 0: //Software breakpoint
BreakType = SoftwareBreakpoint;
break;
case 1: //Hardware breakpoint
BreakType = InstructionExecution;
break;
case 2: //Write watchpoint
BreakType = DataWrite;
break;
case 3: //Read watchpoint
BreakType = DataRead;
break;
case 4: //Access watchpoint
BreakType = DataReadWrite;
break;
default :
SendError (GDB_EINVALIDBRKPOINTTYPE);
return;
}
//Find matching debug register
Status = FindMatchingDebugRegister (SystemContext, Address, Length, (UINTN)BreakType, &Register);
if (EFI_ERROR(Status)) {
if (Status == EFI_UNSUPPORTED) {
Print ((CHAR16 *)L"Not supported.\n");
SendNotSupported();
return;
}
Print ((CHAR16 *)L"No matching register found.\n");
SendError (GDB_ENOSPACE);
return;
}
//Remove breakpoint
Status = DisableDebugRegister(SystemContext, Register);
if (EFI_ERROR(Status)) {
Print ((CHAR16 *)L"Invalid argument.\n");
SendError (GDB_EINVALIDARG);
return;
}
SendSuccess ();
}
VOID
InitializeProcessor (
VOID
)
{
}
BOOLEAN
ValidateAddress (
IN VOID *Address
)
{
return TRUE;
}
BOOLEAN
ValidateException (
IN EFI_EXCEPTION_TYPE ExceptionType,
IN OUT EFI_SYSTEM_CONTEXT SystemContext
)
{
return TRUE;
}

View File

@ -1,15 +0,0 @@
arm-none-eabi-gcc -march=armv7-a -mthumb t.c -Wl,-nostdlib --emit-relocs
target remote com7
set debug remote 1
set remotetimeout 30
set remotelogfile log.txt
add-symbol-file c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll 0x80008360
qSupported
Hg0
Hc-1
qC
qAttached