123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833 |
- /*++
- Copyright (c) 2012 Minoca Corp. All Rights Reserved
- Module Name:
- elf.c
- Abstract:
- This module handles parsing ELF symbol tables for the debugger.
- Author:
- Evan Green 14-Sep-2012
- Environment:
- Debug Client
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "dbgrtl.h"
- #include <minoca/lib/im.h>
- #include <minoca/debug/dbgext.h>
- #include "elf.h"
- #include "symbols.h"
- #include "stabs.h"
- #include <assert.h>
- #include <errno.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- #define MALLOC(_x) malloc(_x)
- #define FREE(_x) free(_x)
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- typedef struct _ELF_SECTION ELF_SECTION, *PELF_SECTION;
- struct _ELF_SECTION {
- PELF_SECTION Next;
- LONG SectionIndex;
- ULONG SectionAddress;
- };
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- LONG
- DbgpGetFileSize (
- FILE *File
- );
- VOID
- DbgpElfFreeSymbols (
- PDEBUG_SYMBOLS Symbols
- );
- BOOL
- DbgpLoadElfSymbolTable (
- PDEBUG_SYMBOLS Symbols,
- PSTR Filename,
- PELF_SECTION *SectionList
- );
- BOOL
- DbgpParseElfSymbolTable (
- PDEBUG_SYMBOLS Symbols,
- PELF_SECTION SectionList
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- DEBUG_SYMBOL_INTERFACE DbgElfSymbolInterface = {
- DbgpElfLoadSymbols,
- DbgpElfFreeSymbols,
- NULL,
- NULL,
- NULL
- };
- //
- // ------------------------------------------------------------------ Functions
- //
- INT
- DbgpElfLoadSymbols (
- PSTR Filename,
- IMAGE_MACHINE_TYPE MachineType,
- ULONG Flags,
- PVOID HostContext,
- PDEBUG_SYMBOLS *Symbols
- )
- /*++
- Routine Description:
- This routine loads ELF debugging symbol information from the specified file.
- Arguments:
- Filename - Supplies the name of the binary to load symbols from.
- MachineType - Supplies the required machine type of the image. Set to
- unknown to allow the symbol library to load a file with any machine
- type.
- Flags - Supplies a bitfield of flags governing the behavior during load.
- These flags are specific to each symbol library.
- HostContext - Supplies the value to store in the host context field of the
- debug symbols.
- Symbols - Supplies an optional pointer where a pointer to the symbols will
- be returned on success.
- Return Value:
- 0 on success.
- Returns an error number on failure.
- --*/
- {
- UINTN AllocationSize;
- PDEBUG_SYMBOLS ElfSymbols;
- BOOL Result;
- INT Status;
- AllocationSize = sizeof(DEBUG_SYMBOLS) + sizeof(STAB_CONTEXT);
- ElfSymbols = MALLOC(AllocationSize);
- if (ElfSymbols == NULL) {
- Status = ENOMEM;
- goto ElfLoadSymbolsEnd;
- }
- memset(ElfSymbols, 0, AllocationSize);
- INITIALIZE_LIST_HEAD(&(ElfSymbols->SourcesHead));
- ElfSymbols->Interface = &DbgElfSymbolInterface;
- ElfSymbols->SymbolContext = ElfSymbols + 1;
- ElfSymbols->HostContext = HostContext;
- Result = DbgpLoadElfSymbols(ElfSymbols, Filename);
- if (Result == FALSE) {
- Status = EINVAL;
- goto ElfLoadSymbolsEnd;
- }
- Status = 0;
- ElfLoadSymbolsEnd:
- if (Status != 0) {
- if (ElfSymbols != NULL) {
- DbgpElfFreeSymbols(ElfSymbols);
- ElfSymbols = NULL;
- }
- }
- *Symbols = ElfSymbols;
- return 0;
- }
- BOOL
- DbgpLoadElfSymbols (
- PDEBUG_SYMBOLS Symbols,
- PSTR Filename
- )
- /*++
- Routine Description:
- This routine loads ELF symbols into a pre-existing set of ELF symbols.
- Arguments:
- Symbols - Supplies a pointer to debug symbols that are assumed to have
- already been allocated and initialized.
- Filename - Supplies the name of the file to load ELF symbols for.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PELF_SECTION FirstSection;
- PELF_SECTION NextSection;
- BOOL Result;
- FirstSection = NULL;
- Result = DbgpLoadElfSymbolTable(Symbols, Filename, &FirstSection);
- if (Result == FALSE) {
- DbgOut("Error reading ELF symbol table.\n");
- goto LoadElfSymbolsEnd;
- }
- Result = DbgpParseElfSymbolTable(Symbols, FirstSection);
- if (Result == FALSE) {
- DbgOut("Error parsing ELF symbol table.\n");
- goto LoadElfSymbolsEnd;
- }
- LoadElfSymbolsEnd:
- while (FirstSection != NULL) {
- NextSection = FirstSection->Next;
- FREE(FirstSection);
- FirstSection = NextSection;
- }
- return Result;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- VOID
- DbgpElfFreeSymbols (
- PDEBUG_SYMBOLS Symbols
- )
- /*++
- Routine Description:
- This routine frees all memory associated with an instance of debugging
- symbols. Once called, the pointer passed in should not be dereferenced
- again by the caller.
- Arguments:
- Symbols - Supplies a pointer to the debugging symbols.
- Return Value:
- None.
- --*/
- {
- PLIST_ENTRY CurrentFunctionEntry;
- PLIST_ENTRY CurrentGlobalEntry;
- PLIST_ENTRY CurrentSourceEntry;
- PFUNCTION_SYMBOL Function;
- PDATA_SYMBOL GlobalVariable;
- PLIST_ENTRY NextFunctionEntry;
- PSOURCE_FILE_SYMBOL SourceFile;
- PSTAB_CONTEXT StabContext;
- StabContext = Symbols->SymbolContext;
- if (Symbols->Filename != NULL) {
- FREE(Symbols->Filename);
- }
- if (StabContext->RawSymbolTable != NULL) {
- FREE(StabContext->RawSymbolTable);
- }
- if (StabContext->RawSymbolTableStrings != NULL) {
- FREE(StabContext->RawSymbolTableStrings);
- }
- //
- // Free Source files.
- //
- CurrentSourceEntry = Symbols->SourcesHead.Next;
- while ((CurrentSourceEntry != &(Symbols->SourcesHead)) &&
- (CurrentSourceEntry != NULL)) {
- SourceFile = LIST_VALUE(CurrentSourceEntry,
- SOURCE_FILE_SYMBOL,
- ListEntry);
- assert(LIST_EMPTY(&(SourceFile->TypesHead)));
- //
- // Free functions.
- //
- CurrentFunctionEntry = SourceFile->FunctionsHead.Next;
- while (CurrentFunctionEntry != &(SourceFile->FunctionsHead)) {
- Function = LIST_VALUE(CurrentFunctionEntry,
- FUNCTION_SYMBOL,
- ListEntry);
- assert(LIST_EMPTY(&(Function->ParametersHead)));
- assert(LIST_EMPTY(&(Function->LocalsHead)));
- if (Function->Name != NULL) {
- FREE(Function->Name);
- }
- NextFunctionEntry = CurrentFunctionEntry->Next;
- FREE(Function);
- CurrentFunctionEntry = NextFunctionEntry;
- }
- assert(LIST_EMPTY(&(SourceFile->SourceLinesHead)));
- //
- // Free global/static symbols.
- //
- CurrentGlobalEntry = SourceFile->DataSymbolsHead.Next;
- while (CurrentGlobalEntry != &(SourceFile->DataSymbolsHead)) {
- GlobalVariable = LIST_VALUE(CurrentGlobalEntry,
- DATA_SYMBOL,
- ListEntry);
- if (GlobalVariable->Name != NULL) {
- FREE(GlobalVariable->Name);
- }
- CurrentGlobalEntry = CurrentGlobalEntry->Next;
- FREE(GlobalVariable);
- }
- CurrentSourceEntry = CurrentSourceEntry->Next;
- FREE(SourceFile);
- }
- FREE(Symbols);
- return;
- }
- BOOL
- DbgpLoadElfSymbolTable (
- PDEBUG_SYMBOLS Symbols,
- PSTR Filename,
- PELF_SECTION *SectionList
- )
- /*++
- Routine Description:
- This routine loads the raw ELF symbol table out of the file.
- Arguments:
- Symbols - Supplies a pointer to debug symbols that are assumed to have
- already been allocated and initialized.
- Filename - Supplies the name of the file to load ELF symbols for.
- SectionList - Supplies a pointer that will receive a pointer to the list of
- sections in the ELF file. Most ELF symbol values are relative to a
- section like .text or .bss.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- ULONG BytesRead;
- PELF32_SECTION_HEADER CurrentSection;
- PELF32_HEADER ElfHeader;
- FILE *File;
- PVOID FileBuffer;
- ULONG FileSize;
- PELF_SECTION FirstSection;
- PELF32_SECTION_HEADER FirstSectionHeader;
- IMAGE_BUFFER ImageBuffer;
- PELF_SECTION NewSection;
- PELF_SECTION NextSection;
- BOOL Result;
- ULONG SectionIndex;
- PUCHAR Source;
- PSTAB_CONTEXT StabContext;
- PELF32_SECTION_HEADER StringSection;
- PELF32_SECTION_HEADER SymbolSection;
- CurrentSection = NULL;
- StabContext = Symbols->SymbolContext;
- FileBuffer = NULL;
- FirstSection = NULL;
- memset(&ImageBuffer, 0, sizeof(IMAGE_BUFFER));
- SymbolSection = NULL;
- StabContext->RawSymbolTable = NULL;
- StabContext->RawSymbolTableStrings = NULL;
- *SectionList = NULL;
- //
- // Determine the file size and load the file into memory.
- //
- File = fopen(Filename, "rb");
- if (File == NULL) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- FileSize = DbgpGetFileSize(File);
- if (FileSize <= 0) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- FileBuffer = MALLOC(FileSize);
- if (FileBuffer == NULL) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- BytesRead = fread(FileBuffer, 1, FileSize, File);
- if (BytesRead != FileSize) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- ImageBuffer.Data = FileBuffer;
- ImageBuffer.Size = FileSize;
- //
- // Get the ELF headers to determine the location of the sections.
- //
- Result = ImpElf32GetHeader(&ImageBuffer, &ElfHeader);
- if (Result == FALSE) {
- goto LoadElfSymbolTableEnd;
- }
- FirstSectionHeader =
- (PELF32_SECTION_HEADER)((PUCHAR)FileBuffer +
- ElfHeader->SectionHeaderOffset);
- CurrentSection = FirstSectionHeader;
- for (SectionIndex = 0;
- SectionIndex < ElfHeader->SectionHeaderCount;
- SectionIndex += 1) {
- //
- // Remember the symbols section.
- //
- if (CurrentSection->SectionType == ELF_SECTION_TYPE_SYMBOLS) {
- SymbolSection = CurrentSection;
- }
- //
- // Skip non-loadable sections.
- //
- if ((CurrentSection->Flags & ELF_SECTION_FLAG_LOAD) == 0) {
- CurrentSection += 1;
- continue;
- }
- //
- // Record this section and its address for easy access later.
- //
- NewSection = MALLOC(sizeof(ELF_SECTION));
- if (NewSection == NULL) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- RtlZeroMemory(NewSection, sizeof(ELF_SECTION));
- NewSection->SectionIndex = SectionIndex;
- NewSection->SectionAddress = CurrentSection->VirtualAddress;
- NewSection->Next = FirstSection;
- FirstSection = NewSection;
- NewSection = NULL;
- CurrentSection += 1;
- }
- //
- // If no symbol section was found, error out.
- //
- if (SymbolSection == NULL) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- //
- // Get the string table for this symbol table, stored in the Link field.
- //
- if ((SymbolSection->Link == 0) ||
- (SymbolSection->Link >= ElfHeader->SectionHeaderCount)) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- StringSection = FirstSectionHeader + SymbolSection->Link;
- if (StringSection->SectionType != ELF_SECTION_TYPE_STRINGS) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- StabContext->RawSymbolTableSize = SymbolSection->Size;
- StabContext->RawSymbolTableStringsSize = StringSection->Size;
- StabContext->RawSymbolTable = MALLOC(StabContext->RawSymbolTableSize);
- if (StabContext->RawSymbolTable == NULL) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- StabContext->RawSymbolTableStrings =
- MALLOC(StabContext->RawSymbolTableStringsSize);
- if (StabContext->RawSymbolTableStrings == NULL) {
- Result = FALSE;
- goto LoadElfSymbolTableEnd;
- }
- Source = (PUCHAR)FileBuffer + SymbolSection->Offset;
- RtlCopyMemory(StabContext->RawSymbolTable,
- Source,
- StabContext->RawSymbolTableSize);
- Source = (PUCHAR)FileBuffer + StringSection->Offset;
- RtlCopyMemory(StabContext->RawSymbolTableStrings,
- Source,
- StabContext->RawSymbolTableStringsSize);
- Result = TRUE;
- LoadElfSymbolTableEnd:
- if (FileBuffer != NULL) {
- FREE(FileBuffer);
- }
- if (Result == FALSE) {
- if (StabContext->RawSymbolTable != NULL) {
- FREE(StabContext->RawSymbolTable);
- }
- if (StabContext->RawSymbolTableStrings != NULL) {
- FREE(StabContext->RawSymbolTableStrings);
- }
- //
- // Free all section entries.
- //
- while (FirstSection != NULL) {
- NextSection = FirstSection->Next;
- FREE(FirstSection);
- FirstSection = NextSection;
- }
- //
- // If successful, return the section list.
- //
- } else {
- *SectionList = FirstSection;
- }
- if (File != NULL) {
- fclose(File);
- }
- return Result;
- }
- BOOL
- DbgpParseElfSymbolTable (
- PDEBUG_SYMBOLS Symbols,
- PELF_SECTION SectionList
- )
- /*++
- Routine Description:
- This routine parses ELF symbol tables and combines them with existing
- debug symbols.
- Arguments:
- Symbols - Supplies a pointer to debug symbols that are assumed to have
- already been allocated and initialized. The raw symbol tables and
- string table are expected to be valid.
- SectionList - Supplies a list of all loadable section in the image. Most
- ELF symbols are relative to a section, so this is needed to determine
- the real address.
- Return Value:
- TRUE on success.
- FALSE on failure.
- --*/
- {
- PELF_SECTION CurrentSection;
- PSOURCE_FILE_SYMBOL CurrentSource;
- PLIST_ENTRY CurrentSourceEntry;
- PELF32_SYMBOL CurrentSymbol;
- PSOURCE_FILE_SYMBOL FunctionParent;
- PFUNCTION_SYMBOL NewFunction;
- SYMBOL_SEARCH_RESULT Result;
- PSYMBOL_SEARCH_RESULT ResultPointer;
- PSTAB_CONTEXT StabContext;
- BOOL Status;
- ULONG SymbolAddress;
- PELF32_SYMBOL SymbolEnd;
- PSTR SymbolName;
- PSTR SymbolNameCopy;
- ELF_SYMBOL_TYPE SymbolType;
- StabContext = Symbols->SymbolContext;
- Status = TRUE;
- NewFunction = NULL;
- SymbolNameCopy = NULL;
- SymbolEnd = (PELF32_SYMBOL)((PUCHAR)StabContext->RawSymbolTable +
- StabContext->RawSymbolTableSize);
- CurrentSymbol = (PELF32_SYMBOL)(StabContext->RawSymbolTable);
- while (CurrentSymbol + 1 <= SymbolEnd) {
- Result.Variety = SymbolResultInvalid;
- SymbolAddress = 0;
- SymbolType = ELF_GET_SYMBOL_TYPE(CurrentSymbol->Information);
- SymbolName = (PSTR)StabContext->RawSymbolTableStrings +
- CurrentSymbol->NameOffset;
- //
- // Create a copy of the symbol name.
- //
- SymbolNameCopy = MALLOC(strlen(SymbolName) + 1);
- if (SymbolNameCopy == NULL) {
- Status = FALSE;
- goto ParseElfSymbolTableEnd;
- }
- strcpy(SymbolNameCopy, SymbolName);
- //
- // Attempt to find the section address this symbol relates to.
- //
- if (CurrentSymbol->SectionIndex != 0) {
- CurrentSection = SectionList;
- while (CurrentSection != NULL) {
- if (CurrentSection->SectionIndex ==
- CurrentSymbol->SectionIndex) {
- SymbolAddress = CurrentSection->SectionAddress;
- break;
- }
- CurrentSection = CurrentSection->Next;
- }
- }
- switch (SymbolType) {
- case ElfSymbolFunction:
- SymbolAddress += CurrentSymbol->Value;
- //
- // Don't add symbols with no value.
- //
- if (SymbolAddress == 0) {
- break;
- }
- ResultPointer =
- DbgFindFunctionSymbol(Symbols, SymbolName, 0, &Result);
- //
- // If the function does not exist, create it. For now, only create
- // new functions, don't update existing ones.
- //
- if (ResultPointer == NULL) {
- //
- // Attempt to find the source file this belongs under. Loop
- // through all source files looking for one whose address range
- // contains this function.
- //
- CurrentSourceEntry = Symbols->SourcesHead.Next;
- FunctionParent = NULL;
- while (CurrentSourceEntry != &(Symbols->SourcesHead)) {
- CurrentSource = LIST_VALUE(CurrentSourceEntry,
- SOURCE_FILE_SYMBOL,
- ListEntry);
- if ((CurrentSource->StartAddress <= SymbolAddress) &&
- (CurrentSource->EndAddress > SymbolAddress)) {
- FunctionParent = CurrentSource;
- break;
- }
- CurrentSourceEntry = CurrentSourceEntry->Next;
- }
- //
- // If a parent source could not be found, there's nowhere to add
- // this function to.
- //
- if (FunctionParent == NULL) {
- break;
- }
- NewFunction = MALLOC(sizeof(FUNCTION_SYMBOL));
- if (NewFunction == NULL) {
- Status = FALSE;
- break;
- }
- RtlZeroMemory(NewFunction, sizeof(FUNCTION_SYMBOL));
- NewFunction->ParentSource = FunctionParent;
- NewFunction->Name = SymbolNameCopy;
- NewFunction->FunctionNumber = 1000;
- INITIALIZE_LIST_HEAD(&(NewFunction->ParametersHead));
- INITIALIZE_LIST_HEAD(&(NewFunction->LocalsHead));
- NewFunction->StartAddress = SymbolAddress;
- NewFunction->EndAddress = SymbolAddress + 0x20;
- NewFunction->ReturnTypeNumber = 0;
- NewFunction->ReturnTypeOwner = NULL;
- //
- // Insert the function into the current source file's list of
- // functions.
- //
- INSERT_BEFORE(&(NewFunction->ListEntry),
- &(FunctionParent->FunctionsHead));
- //
- // Null out the allocated variables so they don't get freed by
- // the end of this function.
- //
- NewFunction = NULL;
- SymbolNameCopy = NULL;
- }
- break;
- case ElfSymbolObject:
- SymbolAddress = CurrentSymbol->Value;
- ResultPointer = DbgFindDataSymbol(Symbols, SymbolName, 0, &Result);
- //
- // If it exists and it's current value is NULL, update it. For now,
- // only update, do not create globals.
- //
- if ((ResultPointer != NULL) &&
- (Result.U.DataResult->LocationType ==
- DataLocationAbsoluteAddress) &&
- (Result.U.DataResult->Location.Address == (UINTN)NULL)) {
- Result.U.DataResult->Location.Address = SymbolAddress;
- }
- break;
- //
- // Ignore other symbol types.
- //
- default:
- break;
- }
- //
- // Free the symbol name copy if it wasn't used.
- //
- if (SymbolNameCopy != NULL) {
- FREE(SymbolNameCopy);
- SymbolNameCopy = NULL;
- }
- //
- // Break on failure.
- //
- if (Status == FALSE) {
- break;
- }
- CurrentSymbol += 1;
- }
- ParseElfSymbolTableEnd:
- if (SymbolNameCopy != NULL) {
- FREE(SymbolNameCopy);
- }
- if (NewFunction != NULL) {
- FREE(NewFunction);
- }
- return Status;
- }
|