InOsEmuPkg/Unix: Auto-load symbols files in gdb

Images that can't be loaded with dlopen are
added to SecMain.gdb.

Whenever gdb stops, the hook-stop macro will automatically
load the symbol files.

Signed-off-by: jljusten

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11888 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
jljusten 2011-06-26 18:58:10 +00:00
parent 8e4b3d32a8
commit 0bc9421b14
2 changed files with 193 additions and 136 deletions

View File

@ -27,6 +27,43 @@ set $_exitcode = 42
define hook-stop define hook-stop
if $_exitcode != 42 if $_exitcode != 42
quit quit
else
source SecMain.gdb
end
end
#
# We keep track of the number of symbol files we have loaded via gdb
# scripts in the $SymbolFilesAdded variable
#
set $SymbolFileChangesCount = 0
#
# This macro adds a symbols file for gdb
#
# @param $arg0 - Symbol file changes number
# @param $arg1 - Symbol file name
# @param $arg2 - Image address
#
define AddFirmwareSymbolFile
if $SymbolFileChangesCount < $arg0
add-symbol-file $arg1 $arg2
set $SymbolFileChangesCount = $arg0
end
end
#
# This macro removes a symbols file for gdb
#
# @param $arg0 - Symbol file changes number
# @param $arg1 - Symbol file name
#
define RemoveFirmwareSymbolFile
if $SymbolFileChangesCount < $arg0
#
# Currently there is not a method to remove a single symbol file
#
set $SymbolFileChangesCount = $arg0
end end
end end

View File

@ -16,7 +16,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#ifdef __APPLE__ #ifdef __APPLE__
#define MAP_ANONYMOUS MAP_ANON #define MAP_ANONYMOUS MAP_ANON
char *gGdbWorkingFileName = NULL;
#endif #endif
@ -30,7 +29,8 @@ EMU_THUNK_PPI mSecEmuThunkPpi = {
GasketSecEmuThunkAddress GasketSecEmuThunkAddress
}; };
char *gGdbWorkingFileName = NULL;
UINTN mScriptSymbolChangesCount = 0;
// //
@ -95,6 +95,7 @@ main (
CHAR16 *MemorySizeStr; CHAR16 *MemorySizeStr;
CHAR16 *FirmwareVolumesStr; CHAR16 *FirmwareVolumesStr;
UINTN *StackPointer; UINTN *StackPointer;
FILE *GdbTempFile;
setbuf (stdout, 0); setbuf (stdout, 0);
setbuf (stderr, 0); setbuf (stderr, 0);
@ -128,19 +129,22 @@ main (
gPpiList = GetThunkPpiList (); gPpiList = GetThunkPpiList ();
#ifdef __APPLE__
// //
// We can't use dlopen on OS X, so we need a scheme to get symboles into gdb // If dlopen doesn't work, then we build a gdb script to allow the
// We need to create a temp file that contains gdb commands so we can load // symbols to be loaded.
// symbols when we load every PE/COFF image.
// //
Index = strlen (*Argv); Index = strlen (*Argv);
gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1); gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1);
strcpy (gGdbWorkingFileName, *Argv); strcpy (gGdbWorkingFileName, *Argv);
strcat (gGdbWorkingFileName, ".gdb"); strcat (gGdbWorkingFileName, ".gdb");
#endif
//
// Empty out the gdb symbols script file.
//
GdbTempFile = fopen (gGdbWorkingFileName, "w");
if (GdbTempFile != NULL) {
fclose (GdbTempFile);
}
// //
// Allocate space for gSystemMemory Array // Allocate space for gSystemMemory Array
@ -1050,89 +1054,25 @@ PrintLoadAddress (
} }
VOID /**
EFIAPI Loads the image using dlopen so symbols will be automatically
SecPeCoffRelocateImageExtraAction ( loaded by gdb.
@param ImageContext The PE/COFF image context
@retval TRUE - The image was successfully loaded
@retval FALSE - The image was successfully loaded
**/
BOOLEAN
DlLoadImage (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
) )
{ {
#ifdef __APPLE__ #ifdef __APPLE__
BOOLEAN EnabledOnEntry;
// return FALSE;
// Make sure writting of the file is an atomic operation
//
if (SecInterruptEanbled ()) {
SecDisableInterrupt ();
EnabledOnEntry = TRUE;
} else {
EnabledOnEntry = FALSE;
}
PrintLoadAddress (ImageContext);
//
// In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
// To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
// .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
//
FILE *GdbTempFile;
//
// In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
// Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
//
if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
//
// Now we have a database of the images that are currently loaded
//
//
// 'symbol-file' will clear out currnet symbol mappings in gdb.
// you can do a 'add-symbol-file filename address' for every image we loaded to get source
// level debug in gdb. Note Sec, being a true application will work differently.
//
// We add the PE/COFF header size into the image as the mach-O does not have a header in
// loaded into system memory.
//
// This gives us a data base of gdb commands and after something is unloaded that entry will be
// removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
// data base of info ready to roll.
//
// We could use qXfer:libraries:read, but OS X GDB does not currently support it.
// <library-list>
// <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
// <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
// </library>
// </library-list>
//
//
// Write the file we need for the gdb script
//
GdbTempFile = fopen (gGdbWorkingFileName, "w");
if (GdbTempFile != NULL) {
fprintf (GdbTempFile, "add-symbol-file %s 0x%08lx\n", ImageContext->PdbPointer, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
fclose (GdbTempFile);
//
// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
// Hey what can you say scripting in gdb is not that great....
//
SecGdbScriptBreak ();
} else {
ASSERT (FALSE);
}
AddHandle (ImageContext, ImageContext->PdbPointer);
if (EnabledOnEntry) {
SecEnableInterrupt ();
}
}
#else #else
@ -1140,11 +1080,11 @@ SecPeCoffRelocateImageExtraAction (
void *Entry = NULL; void *Entry = NULL;
if (ImageContext->PdbPointer == NULL) { if (ImageContext->PdbPointer == NULL) {
return; return FALSE;
} }
if (!IsPdbFile (ImageContext->PdbPointer)) { if (!IsPdbFile (ImageContext->PdbPointer)) {
return; return FALSE;
} }
fprintf ( fprintf (
@ -1166,13 +1106,131 @@ SecPeCoffRelocateImageExtraAction (
if (Entry != NULL) { if (Entry != NULL) {
ImageContext->EntryPoint = (UINTN)Entry; ImageContext->EntryPoint = (UINTN)Entry;
printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry); printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
return TRUE;
} else {
return FALSE;
} }
SecUnixLoaderBreak ();
#endif #endif
}
return;
/**
Adds the image to a gdb script so it's symbols can be loaded.
The AddFirmwareSymbolFile helper macro is used.
@param ImageContext The PE/COFF image context
**/
VOID
GdbScriptAddImage (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
BOOLEAN InterruptsWereEnabled;
//
// Disable interrupts to make sure writing of the .gdb file
// is an atomic operation.
//
if (SecInterruptEanbled ()) {
SecDisableInterrupt ();
InterruptsWereEnabled = TRUE;
} else {
InterruptsWereEnabled = FALSE;
}
PrintLoadAddress (ImageContext);
if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
FILE *GdbTempFile;
GdbTempFile = fopen (gGdbWorkingFileName, "a");
if (GdbTempFile != NULL) {
long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders);
mScriptSymbolChangesCount++;
fprintf (
GdbTempFile,
"AddFirmwareSymbolFile 0x%x %s 0x%08lx\n",
mScriptSymbolChangesCount,
ImageContext->PdbPointer,
SymbolsAddr
);
fclose (GdbTempFile);
} else {
ASSERT (FALSE);
}
AddHandle (ImageContext, ImageContext->PdbPointer);
if (InterruptsWereEnabled) {
SecEnableInterrupt ();
}
}
}
VOID
EFIAPI
SecPeCoffRelocateImageExtraAction (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
if (!DlLoadImage (ImageContext)) {
GdbScriptAddImage (ImageContext);
}
}
/**
Adds the image to a gdb script so it's symbols can be unloaded.
The RemoveFirmwareSymbolFile helper macro is used.
@param ImageContext The PE/COFF image context
**/
VOID
GdbScriptRemoveImage (
IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
)
{
FILE *GdbTempFile;
BOOLEAN InterruptsWereEnabled;
//
// Need to skip .PDB files created from VC++
//
if (IsPdbFile (ImageContext->PdbPointer)) {
return;
}
if (SecInterruptEanbled ()) {
SecDisableInterrupt ();
InterruptsWereEnabled = TRUE;
} else {
InterruptsWereEnabled = FALSE;
}
//
// Write the file we need for the gdb script
//
GdbTempFile = fopen (gGdbWorkingFileName, "a");
if (GdbTempFile != NULL) {
mScriptSymbolChangesCount++;
fprintf (
GdbTempFile,
"RemoveFirmwareSymbolFile 0x%x %s\n",
mScriptSymbolChangesCount,
ImageContext->PdbPointer
);
fclose (GdbTempFile);
} else {
ASSERT (FALSE);
}
if (InterruptsWereEnabled) {
SecEnableInterrupt ();
}
} }
@ -1184,57 +1242,19 @@ SecPeCoffUnloadImageExtraAction (
{ {
VOID *Handle; VOID *Handle;
//
// Check to see if the image symbols were loaded with gdb script, or dlopen
//
Handle = RemoveHandle (ImageContext); Handle = RemoveHandle (ImageContext);
#ifdef __APPLE__ if (Handle == NULL) {
FILE *GdbTempFile; #ifndef __APPLE__
BOOLEAN EnabledOnEntry;
if (Handle != NULL) {
//
// Need to skip .PDB files created from VC++
//
if (!IsPdbFile (ImageContext->PdbPointer)) {
if (SecInterruptEanbled ()) {
SecDisableInterrupt ();
EnabledOnEntry = TRUE;
} else {
EnabledOnEntry = FALSE;
}
//
// Write the file we need for the gdb script
//
GdbTempFile = fopen (gGdbWorkingFileName, "w");
if (GdbTempFile != NULL) {
fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
fclose (GdbTempFile);
//
// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
// Hey what can you say scripting in gdb is not that great....
//
SecGdbScriptBreak ();
} else {
ASSERT (FALSE);
}
if (EnabledOnEntry) {
SecEnableInterrupt ();
}
}
}
#else
//
// Don't want to confuse gdb with symbols for something that got unloaded
//
if (Handle != NULL) {
dlclose (Handle); dlclose (Handle);
#endif
return;
} }
#endif GdbScriptRemoveImage (ImageContext);
return;
} }