From 5637b9f123cd754f4adaa687763116b07ef11056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Sun, 9 Jan 2005 00:00:31 +0000 Subject: [PATCH] Include COFF symbols in our .sym files svn path=/trunk/; revision=12895 --- reactos/include/coff.h | 13 -- reactos/include/ntos/kdbgsyms.h | 4 + reactos/ntoskrnl/dbg/kdb_stabs.c | 4 +- reactos/ntoskrnl/dbg/kdb_symbols.c | 238 ++++++++++++++++++++---- reactos/tools/rsym.c | 282 ++++++++++++++++++++++++----- 5 files changed, 447 insertions(+), 94 deletions(-) diff --git a/reactos/include/coff.h b/reactos/include/coff.h index 41993831c76..4ec6a8f3de6 100644 --- a/reactos/include/coff.h +++ b/reactos/include/coff.h @@ -6,12 +6,6 @@ extern "C" { #endif -/* - * #ifndef __dj_ENFORCE_ANSI_FREESTANDING - * #ifndef __STRICT_ANSI__ - * #ifndef _POSIX_SOURCE - */ - /*** coff information for Intel 386/486. */ /********************** FILE HEADER **********************/ @@ -329,13 +323,6 @@ struct external_reloc { /* For new sections we havn't heard of before */ #define DEFAULT_SECTION_ALIGNMENT 4 -/* - * #endif /* !_POSIX_SOURCE */ - * #endif /* !__STRICT_ANSI__ */ - * #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */ - */ -#ifndef __dj_ENFORCE_FUNCTION_CALLS -#endif /* !__dj_ENFORCE_FUNCTION_CALLS */ #ifdef __cplusplus } diff --git a/reactos/include/ntos/kdbgsyms.h b/reactos/include/ntos/kdbgsyms.h index 9fd15094c5f..ca93e773577 100644 --- a/reactos/include/ntos/kdbgsyms.h +++ b/reactos/include/ntos/kdbgsyms.h @@ -8,6 +8,10 @@ typedef struct _IMAGE_SYMBOL_INFO ULONG_PTR ImageBase; ULONG_PTR ImageSize; PVOID FileBuffer; + PVOID StabsBase; + ULONG StabsLength; + PVOID StabStringsBase; + ULONG StabStringsLength; PVOID SymbolsBase; ULONG SymbolsLength; PVOID SymbolStringsBase; diff --git a/reactos/ntoskrnl/dbg/kdb_stabs.c b/reactos/ntoskrnl/dbg/kdb_stabs.c index ca3952386db..c6677a00c1d 100644 --- a/reactos/ntoskrnl/dbg/kdb_stabs.c +++ b/reactos/ntoskrnl/dbg/kdb_stabs.c @@ -69,8 +69,8 @@ KdbpStabFindEntry(IN PIMAGE_SYMBOL_INFO SymbolInfo, PVOID StabsEnd; ULONG_PTR AddrFound = 0; - StabEntry = SymbolInfo->SymbolsBase; - StabsEnd = (PVOID)((ULONG_PTR)SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength); + StabEntry = SymbolInfo->StabsBase; + StabsEnd = (PVOID)((ULONG_PTR)SymbolInfo->StabsBase + SymbolInfo->StabsLength); if (StartEntry != NULL) { ASSERT((ULONG_PTR)StartEntry >= (ULONG_PTR)StabEntry); diff --git a/reactos/ntoskrnl/dbg/kdb_symbols.c b/reactos/ntoskrnl/dbg/kdb_symbols.c index 623169243c6..efa60877b7e 100644 --- a/reactos/ntoskrnl/dbg/kdb_symbols.c +++ b/reactos/ntoskrnl/dbg/kdb_symbols.c @@ -16,6 +16,34 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* + * Parts of this file based on work Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ /* * PROJECT: ReactOS kernel * FILE: ntoskrnl/dbg/kdb_symbols.c @@ -41,6 +69,7 @@ #include #include #include +#include #define NDEBUG #include @@ -55,6 +84,10 @@ typedef struct _SYMBOLFILE_HEADER { ULONG StabsLength; ULONG StabstrOffset; ULONG StabstrLength; + ULONG SymbolsOffset; + ULONG SymbolsLength; + ULONG SymbolstrOffset; + ULONG SymbolstrLength; } SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER; typedef struct _IMAGE_SYMBOL_INFO_CACHE { @@ -62,6 +95,10 @@ typedef struct _IMAGE_SYMBOL_INFO_CACHE { ULONG RefCount; UNICODE_STRING FileName; PVOID FileBuffer; + PVOID StabsBase; + ULONG StabsLength; + PVOID StabStringsBase; + ULONG StabStringsLength; PVOID SymbolsBase; ULONG SymbolsLength; PVOID SymbolStringsBase; @@ -282,6 +319,67 @@ KdbSymPrintAddress(IN PVOID Address) return TRUE; } +/*! \brief Find a COFF symbol entry... + * + * Finds the COFF symbol as close as possible before the specified address + * + * \param SymbolInfo Pointer to the symbol info. + * \param RelativeAddress Relative address of address to look for. + * + * \returns Pointer to a external_syment + * \retval NULL No entry found. + */ +static struct external_syment * +KdbpSymbolsFindEntry(IN PIMAGE_SYMBOL_INFO SymbolInfo, + IN ULONG_PTR RelativeAddress) +{ + /* + * Perform a binary search. + * + * The code below is a bit sneaky. After a comparison fails, we + * divide the work in half by moving either left or right. If lim + * is odd, moving left simply involves halving lim: e.g., when lim + * is 5 we look at item 2, so we change lim to 2 so that we will + * look at items 0 & 1. If lim is even, the same applies. If lim + * is odd, moving right again involes halving lim, this time moving + * the base up one item past p: e.g., when lim is 5 we change base + * to item 3 and make lim 2 so that we will look at items 3 and 4. + * If lim is even, however, we have to shrink it by one before + * halving: e.g., when lim is 4, we still looked at item 2, so we + * have to make lim 3, then halve, obtaining 1, so that we will only + * look at item 3. + */ + struct external_syment *Base = (struct external_syment *) SymbolInfo->SymbolsBase; + ULONG Lim; + struct external_syment *Mid, *Low; + + if (SymbolInfo->SymbolsLength < sizeof(struct external_syment) + || RelativeAddress < Base->e_value) + { + return NULL; + } + + Low = Base; + for (Lim = SymbolInfo->SymbolsLength / sizeof(struct external_syment); Lim != 0; Lim >>= 1) + { + Mid = Base + (Lim >> 1); + if (RelativeAddress == Mid->e_value) + { + return Mid; + } + if (Mid->e_value < RelativeAddress) /* key > mid: move right */ + { + Low = Mid; + Base = Mid + 1; + Lim--; + } /* else move left */ + } + + ASSERT(Low->e_value < RelativeAddress); + + return Low; +} + /*! \brief Get information for an address (source file, line number, * function name) @@ -306,12 +404,13 @@ KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, OUT PCH FileName OPTIONAL, OUT PCH FunctionName OPTIONAL) { - PSTAB_ENTRY FunctionEntry = NULL, FileEntry = NULL, LineEntry = NULL; + PSTAB_ENTRY StabsFunctionEntry = NULL, FileEntry = NULL, LineEntry = NULL; + struct external_syment *SymbolsFunctionEntry = NULL; DPRINT("RelativeAddress = 0x%08x\n", RelativeAddress); - if (SymbolInfo->SymbolsBase == NULL || SymbolInfo->SymbolsLength == 0 || - SymbolInfo->SymbolStringsBase == NULL || SymbolInfo->SymbolStringsLength == 0) + if (SymbolInfo->StabsBase == NULL || SymbolInfo->StabsLength == 0 || + SymbolInfo->StabStringsBase == NULL || SymbolInfo->StabStringsLength == 0) { return STATUS_UNSUCCESSFUL; } @@ -330,24 +429,24 @@ KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, if (LineNumber != NULL || FunctionName != NULL) { /* find stab entry for function */ - FunctionEntry = KdbpStabFindEntry(SymbolInfo, N_FUN, (PVOID)RelativeAddress, NULL); - if (FunctionEntry == NULL) + StabsFunctionEntry = KdbpStabFindEntry(SymbolInfo, N_FUN, (PVOID)RelativeAddress, NULL); + if (StabsFunctionEntry == NULL) { DPRINT("No function stab entry found. RelativeAddress %p\n", RelativeAddress); } - if (LineNumber != NULL && FunctionEntry != NULL) + if (LineNumber != NULL && StabsFunctionEntry != NULL) { /* find stab entry for line number */ - ULONG_PTR FunctionRelativeAddress = RelativeAddress - FunctionEntry->n_value; + ULONG_PTR FunctionRelativeAddress = RelativeAddress - StabsFunctionEntry->n_value; ULONG_PTR AddrFound = 0; PSTAB_ENTRY NextLineEntry; - LineEntry = NextLineEntry = FunctionEntry; + LineEntry = NextLineEntry = StabsFunctionEntry; while (NextLineEntry != NULL) { NextLineEntry++; - if ((ULONG_PTR)NextLineEntry >= ((ULONG_PTR)SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength)) + if ((ULONG_PTR)NextLineEntry >= ((ULONG_PTR)SymbolInfo->StabsBase + SymbolInfo->StabsLength)) break; if (NextLineEntry->n_type == N_FUN) break; @@ -364,6 +463,14 @@ KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, } } + if (FunctionName != NULL + && SymbolInfo->SymbolsBase != NULL && SymbolInfo->SymbolsLength != 0 + && SymbolInfo->SymbolStringsBase != NULL && SymbolInfo->SymbolStringsLength != 0) + { + /* find symbol entry for function */ + SymbolsFunctionEntry = KdbpSymbolsFindEntry(SymbolInfo, RelativeAddress); + } + if (FileName != NULL) { /* find stab entry for file name */ @@ -373,7 +480,7 @@ KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, FileEntry = KdbpStabFindEntry(SymbolInfo, N_SO, (PVOID)RelativeAddress, NULL); if (FileEntry != NULL) { - p = (PCHAR)SymbolInfo->SymbolStringsBase + FileEntry->n_strx; + p = (PCHAR)SymbolInfo->StabStringsBase + FileEntry->n_strx; Length = strlen(p); if (p[Length - 1] == '/' || p[Length - 1] == '\\') /* source dir */ FileEntry = KdbpStabFindEntry(SymbolInfo, N_SO, (PVOID)RelativeAddress, FileEntry + 1); @@ -384,9 +491,10 @@ KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, } } - if (((LineNumber != NULL && LineEntry == NULL) || LineNumber == NULL) && - ((FileName != NULL && FileEntry == NULL) || FileName == NULL) && - ((FunctionName != NULL && FunctionEntry == NULL) || FunctionName == NULL)) + if (((LineNumber != NULL && LineEntry == NULL) || LineNumber == NULL) && + ((FileName != NULL && FileEntry == NULL) || FileName == NULL) && + ((FunctionName != NULL && StabsFunctionEntry == NULL && SymbolsFunctionEntry == NULL) || + FunctionName == NULL)) { DPRINT("None of the requested information was found!\n"); return STATUS_UNSUCCESSFUL; @@ -403,18 +511,56 @@ KdbSymGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo, PCHAR Name = ""; if (FileEntry != NULL) { - Name = (PCHAR)SymbolInfo->SymbolStringsBase + FileEntry->n_strx; + Name = (PCHAR)SymbolInfo->StabStringsBase + FileEntry->n_strx; } strcpy(FileName, Name); } if (FunctionName != NULL) { PCHAR Name = "", p; - if (FunctionEntry != NULL) - Name = (PCHAR)SymbolInfo->SymbolStringsBase + FunctionEntry->n_strx; - strcpy(FunctionName, Name); - if ((p = strchr(FunctionName, ':')) != NULL) /* remove extra info from function name */ - *p = '\0'; + if (StabsFunctionEntry != NULL) + { + if (SymbolsFunctionEntry == NULL || + SymbolsFunctionEntry->e_value <= StabsFunctionEntry->n_value) + { + Name = (PCHAR)SymbolInfo->StabStringsBase + StabsFunctionEntry->n_strx; + strcpy(FunctionName, Name); + if ((p = strchr(FunctionName, ':')) != NULL) /* remove extra info from function name */ + { + *p = '\0'; + } + } + else if (SymbolsFunctionEntry != NULL) + { + if (SymbolsFunctionEntry->e.e.e_zeroes == 0) + { + Name = (PCHAR) SymbolInfo->SymbolStringsBase + SymbolsFunctionEntry->e.e.e_offset; + strcpy(FunctionName, Name); + } + else + { + memcpy(FunctionName, SymbolsFunctionEntry->e.e_name, E_SYMNMLEN); + FunctionName[E_SYMNMLEN] = '\0'; + } + } + } + else if (SymbolsFunctionEntry != NULL) + { + if (SymbolsFunctionEntry->e.e.e_zeroes == 0) + { + Name = (PCHAR) SymbolInfo->SymbolStringsBase + SymbolsFunctionEntry->e.e.e_offset; + strcpy(FunctionName, Name); + } + else + { + memcpy(FunctionName, SymbolsFunctionEntry->e.e_name, E_SYMNMLEN); + FunctionName[E_SYMNMLEN] = '\0'; + } + } + else + { + FunctionName[0] = '\0'; + } } return STATUS_SUCCESS; @@ -449,14 +595,14 @@ KdbpSymGetSourceAddress(IN PIMAGE_SYMBOL_INFO SymbolInfo, FileNameLength = strlen(FileName); FuncNameLength = strlen(FuncName); - for (Entry = SymbolInfo->SymbolsBase; - (ULONG_PTR)Entry < (ULONG_PTR)(SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength); + for (Entry = SymbolInfo->StabsBase; + (ULONG_PTR)Entry < (ULONG_PTR)(SymbolInfo->StabsBase + SymbolInfo->StabsLength); Entry++) { if (Entry->n_type != N_SO) continue; - SymbolName = (PCHAR)SymbolInfo->SymbolStringsBase + Entry->n_strx; + SymbolName = (PCHAR)SymbolInfo->StabStringsBase + Entry->n_strx; Length = strlen(SymbolName); if (SymbolName[Length - 1] == '/' || SymbolName[Length - 1] == '\\') @@ -473,7 +619,7 @@ KdbpSymGetSourceAddress(IN PIMAGE_SYMBOL_INFO SymbolInfo, continue; Entry++; - for (;(ULONG_PTR)Entry < (ULONG_PTR)(SymbolInfo->SymbolsBase + SymbolInfo->SymbolsLength); + for (;(ULONG_PTR)Entry < (ULONG_PTR)(SymbolInfo->StabsBase + SymbolInfo->StabsLength); Entry++) { if (Entry->n_type == N_FUN) @@ -487,7 +633,7 @@ KdbpSymGetSourceAddress(IN PIMAGE_SYMBOL_INFO SymbolInfo, continue; else /* if (FunctionName != NULL) */ { - SymbolName = (PCHAR)SymbolInfo->SymbolStringsBase + Entry->n_strx; + SymbolName = (PCHAR)SymbolInfo->StabStringsBase + Entry->n_strx; p = strchr(SymbolName, ':'); if (p == NULL) return FALSE; @@ -589,6 +735,10 @@ KdbpSymAddCachedFile(IN PUNICODE_STRING FileName, ASSERT(CacheEntry->FileName.Buffer); CacheEntry->RefCount = 1; CacheEntry->FileBuffer = SymbolInfo->FileBuffer; + CacheEntry->StabsBase = SymbolInfo->StabsBase; + CacheEntry->StabsLength = SymbolInfo->StabsLength; + CacheEntry->StabStringsBase = SymbolInfo->StabStringsBase; + CacheEntry->StabStringsLength = SymbolInfo->StabStringsLength; CacheEntry->SymbolsBase = SymbolInfo->SymbolsBase; CacheEntry->SymbolsLength = SymbolInfo->SymbolsLength; CacheEntry->SymbolStringsBase = SymbolInfo->SymbolStringsBase; @@ -692,6 +842,10 @@ KdbpSymLoadModuleSymbols(IN PUNICODE_STRING FileName, { DPRINT("Found cached symbol file %wZ\n", &SymFileName); SymbolInfo->FileBuffer = CachedSymbolFile->FileBuffer; + SymbolInfo->StabsBase = CachedSymbolFile->StabsBase; + SymbolInfo->StabsLength = CachedSymbolFile->StabsLength; + SymbolInfo->StabStringsBase = CachedSymbolFile->StabStringsBase; + SymbolInfo->StabStringsLength = CachedSymbolFile->StabStringsLength; SymbolInfo->SymbolsBase = CachedSymbolFile->SymbolsBase; SymbolInfo->SymbolsLength = CachedSymbolFile->SymbolsLength; SymbolInfo->SymbolStringsBase = CachedSymbolFile->SymbolStringsBase; @@ -769,16 +923,23 @@ KdbpSymLoadModuleSymbols(IN PUNICODE_STRING FileName, SymbolFileHeader = (PSYMBOLFILE_HEADER) FileBuffer; SymbolInfo->FileBuffer = FileBuffer; - SymbolInfo->SymbolsBase = FileBuffer + SymbolFileHeader->StabsOffset; - SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength; - SymbolInfo->SymbolStringsBase = FileBuffer + SymbolFileHeader->StabstrOffset; - SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength; + SymbolInfo->StabsBase = FileBuffer + SymbolFileHeader->StabsOffset; + SymbolInfo->StabsLength = SymbolFileHeader->StabsLength; + SymbolInfo->StabStringsBase = FileBuffer + SymbolFileHeader->StabstrOffset; + SymbolInfo->StabStringsLength = SymbolFileHeader->StabstrLength; + SymbolInfo->SymbolsBase = FileBuffer + SymbolFileHeader->SymbolsOffset; + SymbolInfo->SymbolsLength = SymbolFileHeader->SymbolsLength; + SymbolInfo->SymbolStringsBase = FileBuffer + SymbolFileHeader->SymbolstrOffset; + SymbolInfo->SymbolStringsLength = SymbolFileHeader->SymbolstrLength; /* add file to cache */ KdbpSymAddCachedFile(&SymFileName, SymbolInfo); - DPRINT("Installed stabs: %wZ (%08x-%08x,%08x)\n", + DPRINT("Installed stabs: %wZ (%08x-%08x,%08x) (%08x-%08x,%08x)\n", FileName, + SymbolInfo->StabsBase, + SymbolInfo->StabsLength + SymbolInfo->StabsBase, + SymbolInfo->StabStringsBase, SymbolInfo->SymbolsBase, SymbolInfo->SymbolsLength + SymbolInfo->SymbolsBase, SymbolInfo->SymbolStringsBase); @@ -800,6 +961,8 @@ KdbpSymUnloadModuleSymbols(IN PIMAGE_SYMBOL_INFO SymbolInfo) { KdbpSymRemoveCachedFile(SymbolInfo); SymbolInfo->FileBuffer = NULL; + SymbolInfo->StabsBase = NULL; + SymbolInfo->StabsLength = 0; SymbolInfo->SymbolsBase = NULL; SymbolInfo->SymbolsLength = 0; } @@ -955,10 +1118,14 @@ KdbSymProcessBootSymbols(IN PCHAR FileName) KeLoaderModules[i].ModEnd - KeLoaderModules[i].ModStart); SymbolInfo->FileBuffer = SymbolFileHeader; - SymbolInfo->SymbolsBase = (PVOID)SymbolFileHeader + SymbolFileHeader->StabsOffset; - SymbolInfo->SymbolsLength = SymbolFileHeader->StabsLength; - SymbolInfo->SymbolStringsBase = (PVOID)SymbolFileHeader + SymbolFileHeader->StabstrOffset; - SymbolInfo->SymbolStringsLength = SymbolFileHeader->StabstrLength; + SymbolInfo->StabsBase = (PVOID)SymbolFileHeader + SymbolFileHeader->StabsOffset; + SymbolInfo->StabsLength = SymbolFileHeader->StabsLength; + SymbolInfo->StabStringsBase = (PVOID)SymbolFileHeader + SymbolFileHeader->StabstrOffset; + SymbolInfo->StabStringsLength = SymbolFileHeader->StabstrLength; + SymbolInfo->SymbolsBase = (PVOID)SymbolFileHeader + SymbolFileHeader->SymbolsOffset; + SymbolInfo->SymbolsLength = SymbolFileHeader->SymbolsLength; + SymbolInfo->SymbolStringsBase = (PVOID)SymbolFileHeader + SymbolFileHeader->SymbolstrOffset; + SymbolInfo->SymbolStringsLength = SymbolFileHeader->SymbolstrLength; /* add file to cache */ RtlInitAnsiString(&AnsiString, SymbolName); @@ -966,10 +1133,13 @@ KdbSymProcessBootSymbols(IN PCHAR FileName) KdbpSymAddCachedFile(&UnicodeString, SymbolInfo); RtlFreeUnicodeString(&UnicodeString); - DPRINT("Installed stabs: %s@%08x-%08x (%08x-%08x,%08x)\n", + DPRINT("Installed stabs: %s@%08x-%08x (%08x-%08x,%08x) (%08x-%08x,%08x)\n", FileName, ModuleObject->Base, ModuleObject->Length + ModuleObject->Base, + SymbolInfo->StabsBase, + SymbolInfo->StabsLength + SymbolInfo->StabsBase, + SymbolInfo->StabStringsBase, SymbolInfo->SymbolsBase, SymbolInfo->SymbolsLength + SymbolInfo->SymbolsBase, SymbolInfo->SymbolStringsBase); diff --git a/reactos/tools/rsym.c b/reactos/tools/rsym.c index 9b0ba1fc523..705d4f6aff1 100644 --- a/reactos/tools/rsym.c +++ b/reactos/tools/rsym.c @@ -111,6 +111,10 @@ typedef struct _SYMBOLFILE_HEADER { unsigned long StabsLength; unsigned long StabstrOffset; unsigned long StabstrLength; + unsigned long SymbolsOffset; + unsigned long SymbolsLength; + unsigned long SymbolstrOffset; + unsigned long SymbolstrLength; } SYMBOLFILE_HEADER, *PSYMBOLFILE_HEADER; typedef struct _STAB_ENTRY { @@ -133,6 +137,83 @@ typedef struct unsigned long Length; } STR_ENTRY, *PSTR_ENTRY; +/* COFF symbol table */ + +#define E_SYMNMLEN 8 /* # characters in a symbol name */ +#define E_FILNMLEN 14 /* # characters in a file name */ +#define E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +#define N_BTMASK (0xf) +#define N_TMASK (0x30) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +/* derived types, in e_type */ +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +#define BTYPE(x) ((x) & N_BTMASK) + +#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT)) +#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT)) +#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT)) +#define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG) +#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) + +#define C_EFCN 0xff /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ +#define C_AUTOARG 19 /* auto argument */ +#define C_LASTENT 20 /* dummy entry (end of block) */ +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* line # reformatted as symbol table entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* ext symbol in dmert public lib */ + +#pragma pack(push,1) +typedef struct _EXTERNAL_SYMENT +{ + union + { + char e_name[E_SYMNMLEN]; + struct + { + unsigned long e_zeroes; + unsigned long e_offset; + } + e; + } + e; + unsigned long e_value; + short e_scnum; + unsigned short e_type; + unsigned char e_sclass; + unsigned char e_numaux; +} EXTERNAL_SYMENT, *PEXTERNAL_SYMENT; +#pragma pack(pop) + char* convert_path(char* origpath) { char* newpath; @@ -161,6 +242,52 @@ char* convert_path(char* origpath) return(newpath); } +static void +RelocateString(ULONG *Offset, PSTR_ENTRY StrEntry, ULONG *StrCount, PVOID SymbolStringsBase) +{ + ULONG i; + + for (i = 0; i < *StrCount; i++) + { + if (*Offset == StrEntry[i].OldOffset) + { + *Offset = StrEntry[i].NewOffset; + return; + } + } + + StrEntry[*StrCount].OldOffset = *Offset; + StrEntry[*StrCount].Name = (char*) SymbolStringsBase + StrEntry[*StrCount].OldOffset; + StrEntry[*StrCount].Length = strlen(StrEntry[*StrCount].Name) + 1; + if (*StrCount == 0) + { + StrEntry[*StrCount].NewOffset = 0; + } + else + { + StrEntry[*StrCount].NewOffset = StrEntry[*StrCount - 1].NewOffset + + StrEntry[*StrCount - 1].Length; + } + *Offset = StrEntry[*StrCount].NewOffset; + (*StrCount)++; +} + +static int +CompareSyment(const PEXTERNAL_SYMENT SymEntry1, const PEXTERNAL_SYMENT SymEntry2) +{ + if (SymEntry1->e_value < SymEntry2->e_value) + { + return -1; + } + + if (SymEntry2->e_value < SymEntry1->e_value) + { + return +1; + } + + return 0; +} + #define TRANSFER_SIZE (65536) int main(int argc, char* argv[]) @@ -175,6 +302,10 @@ int main(int argc, char* argv[]) ULONG SymbolsLength; PVOID SymbolStringsBase; ULONG SymbolStringsLength; + PVOID CoffSymbolsBase; + ULONG CoffSymbolsLength; + PVOID CoffSymbolStringsBase; + ULONG CoffSymbolStringsLength; ULONG Idx; char* path1; char* path2; @@ -188,31 +319,34 @@ int main(int argc, char* argv[]) ULONG SymbolsCount; PSTR_ENTRY StrEntry; ULONG StrCount; - ULONG j; + PSTR_ENTRY CoffStrEntry; + ULONG CoffStrCount; + PEXTERNAL_SYMENT SymEntry; + unsigned NumAux; - if (argc != 3) - { - fprintf(stderr, "Too many arguments\n"); - exit(1); - } + if (argc != 3) + { + fprintf(stderr, "Too many arguments\n"); + exit(1); + } - path1 = convert_path(argv[1]); - path2 = convert_path(argv[2]); + path1 = convert_path(argv[1]); + path2 = convert_path(argv[2]); - in = fopen(path1, "rb"); - if (in == NULL) - { - perror("Cannot open input file"); - exit(1); - } + in = fopen(path1, "rb"); + if (in == NULL) + { + perror("Cannot open input file"); + exit(1); + } - out = fopen(path2, "wb"); - if (out == NULL) - { - perror("Cannot open output file"); - fclose(in); - exit(1); - } + out = fopen(path2, "wb"); + if (out == NULL) + { + perror("Cannot open output file"); + fclose(in); + exit(1); + } /* Check if MZ header exists */ n_in = fread(&PEDosHeader, 1, sizeof(PEDosHeader), in); @@ -302,30 +436,7 @@ int main(int argc, char* argv[]) for (i = 0; i < Count; i++) { - for (j = 0; j < StrCount; j++) - { - if (StabEntry[i].n_strx == StrEntry[j].OldOffset) - { - StabEntry[i].n_strx = StrEntry[j].NewOffset; - break; - } - } - if (j >= StrCount) - { - StrEntry[StrCount].OldOffset = StabEntry[i].n_strx; - StrEntry[StrCount].Name = (char*)SymbolStringsBase + StrEntry[StrCount].OldOffset; - StrEntry[StrCount].Length = strlen(StrEntry[StrCount].Name) + 1; - if (StrCount == 0) - { - StrEntry[StrCount].NewOffset = 0; - } - else - { - StrEntry[StrCount].NewOffset = StrEntry[StrCount-1].NewOffset + StrEntry[StrCount-1].Length; - } - StabEntry[i].n_strx = StrEntry[StrCount].NewOffset; - StrCount++; - } + RelocateString(&StabEntry[i].n_strx, StrEntry, &StrCount, SymbolStringsBase); } SymbolFileHeader.StabsOffset = sizeof(SYMBOLFILE_HEADER); @@ -333,12 +444,93 @@ int main(int argc, char* argv[]) SymbolFileHeader.StabstrOffset = SymbolFileHeader.StabsOffset + SymbolFileHeader.StabsLength; SymbolFileHeader.StabstrLength = StrEntry[StrCount-1].NewOffset + StrEntry[StrCount-1].Length; + if (0 == PEFileHeader.PointerToSymbolTable || 0 == PEFileHeader.NumberOfSymbols) + { + /* No COFF symbol table */ + SymbolFileHeader.SymbolsOffset = 0; + SymbolFileHeader.SymbolsLength = 0; + SymbolFileHeader.SymbolstrOffset = 0; + SymbolFileHeader.SymbolstrLength = 0; + } + else + { + CoffSymbolsLength = PEFileHeader.NumberOfSymbols * sizeof(EXTERNAL_SYMENT); + CoffSymbolsBase = malloc(CoffSymbolsLength); + if (NULL == CoffSymbolsBase) + { + fprintf(stderr, "Unable to allocate %u bytes for COFF symbols\n", + (unsigned) CoffSymbolsLength); + exit(1); + } + fseek(in, PEFileHeader.PointerToSymbolTable, SEEK_SET); + n_in = fread(CoffSymbolsBase, 1, CoffSymbolsLength, in); + + SymEntry = CoffSymbolsBase; + Count = 0; + for (i = 0; i < PEFileHeader.NumberOfSymbols; i++) + { + NumAux = SymEntry[i].e_numaux; + if (ISFCN(SymEntry[i].e_type)) + { + SymEntry[Count] = SymEntry[i]; + if (0 < SymEntry[Count].e_scnum) + { + if (PEFileHeader.NumberOfSections < SymEntry[Count].e_scnum) + { + fprintf(stderr, "Invalid section number %d in COFF symbols (only %d sections present)\n", + SymEntry[Count].e_scnum, PEFileHeader.NumberOfSections); + exit(1); + } + SymEntry[Count].e_value += PESectionHeaders[SymEntry[Count].e_scnum - 1].VirtualAddress; + SymEntry[Count].e_scnum = -3; + SymEntry[Count].e_numaux = 0; + } + Count++; + } + i += NumAux; + } + + qsort(CoffSymbolsBase, Count, sizeof(EXTERNAL_SYMENT), (int (*)(const void *, const void *)) CompareSyment); + + n_in = fread(&CoffSymbolStringsLength, 1, sizeof(ULONG), in); + CoffSymbolStringsBase = malloc(CoffSymbolStringsLength); + if (NULL == CoffSymbolStringsBase) + { + fprintf(stderr, "Unable to allocate %u bytes for COFF symbol strings\n", + (unsigned) CoffSymbolStringsLength); + exit(1); + } + n_in = fread((char *) CoffSymbolStringsBase + sizeof(ULONG), 1, CoffSymbolStringsLength - 4, in); + + CoffStrEntry = malloc(sizeof(STR_ENTRY) * Count); + CoffStrCount = 0; + + for (i = 0; i < Count; i++) + { + if (0 == SymEntry[i].e.e.e_zeroes) + { + RelocateString(&SymEntry[i].e.e.e_offset, CoffStrEntry, &CoffStrCount, CoffSymbolStringsBase); + } + } + + SymbolFileHeader.SymbolsOffset = SymbolFileHeader.StabstrOffset + SymbolFileHeader.StabstrLength; + SymbolFileHeader.SymbolsLength = Count * sizeof(EXTERNAL_SYMENT); + SymbolFileHeader.SymbolstrOffset = SymbolFileHeader.SymbolsOffset + SymbolFileHeader.SymbolsLength; + SymbolFileHeader.SymbolstrLength = CoffStrEntry[CoffStrCount - 1].NewOffset + + CoffStrEntry[CoffStrCount - 1].Length; + } + n_out = fwrite(&SymbolFileHeader, 1, sizeof(SYMBOLFILE_HEADER), out); n_out = fwrite(SymbolsBase, 1, SymbolFileHeader.StabsLength, out); for (i = 0; i < StrCount; i++) { fwrite(StrEntry[i].Name, 1, StrEntry[i].Length, out); } + n_out = fwrite(CoffSymbolsBase, 1, SymbolFileHeader.SymbolsLength, out); + for (i = 0; i < CoffStrCount; i++) + { + fwrite(CoffStrEntry[i].Name, 1, CoffStrEntry[i].Length, out); + } fclose(out); exit(0);