reactos/sdk/tools/rsym/rsym.c

1564 lines
51 KiB
C

/*
* Usage: rsym input-file output-file
*
* There are two sources of information: the .stab/.stabstr
* sections of the executable and the COFF symbol table. Most
* of the information is in the .stab/.stabstr sections.
* However, most of our asm files don't contain .stab directives,
* so routines implemented in assembler won't show up in the
* .stab section. They are present in the COFF symbol table.
* So, we mostly use the .stab/.stabstr sections, but we augment
* the info there with info from the COFF symbol table when
* possible.
*
* This is a tool and is compiled using the host compiler,
* i.e. on Linux gcc and not mingw-gcc (cross-compiler).
* Therefore we can't include SDK headers and we have to
* duplicate some definitions here.
* Also note that the internal functions are "old C-style",
* returning an int, where a return of 0 means success and
* non-zero is failure.
*/
#include "../../dll/win32/dbghelp/compat.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <wchar.h>
#include "rsym.h"
#define MAX_PATH 260
#define MAX_SYM_NAME 2000
struct StringEntry
{
struct StringEntry *Next;
ULONG Offset;
char *String;
};
struct StringHashTable
{
ULONG TableSize;
struct StringEntry **Table;
};
/* This is the famous DJB hash */
static unsigned int
ComputeDJBHash(const char *name)
{
unsigned int val = 5381;
int i = 0;
for (i = 0; name[i]; i++)
{
val = (33 * val) + name[i];
}
return val;
}
static void
AddStringToHash(struct StringHashTable *StringTable,
unsigned int hash,
ULONG Offset,
char *StringPtr)
{
struct StringEntry *entry = calloc(1, sizeof(struct StringEntry));
entry->Offset = Offset;
entry->String = StringPtr;
entry->Next = StringTable->Table[hash];
StringTable->Table[hash] = entry;
}
static void
StringHashTableInit(struct StringHashTable *StringTable,
ULONG StringsLength,
char *StringsBase)
{
char *Start = StringsBase;
char *End = StringsBase + StringsLength;
StringTable->TableSize = 1024;
StringTable->Table = calloc(1024, sizeof(struct StringEntry *));
while (Start < End)
{
AddStringToHash(StringTable,
ComputeDJBHash(Start) % StringTable->TableSize,
Start - StringsBase,
Start);
Start += strlen(Start) + 1;
}
}
static void
StringHashTableFree(struct StringHashTable *StringTable)
{
int i;
struct StringEntry *entry;
for (i = 0; i < StringTable->TableSize; i++)
{
while ((entry = StringTable->Table[i]))
{
entry = entry->Next;
free(StringTable->Table[i]);
StringTable->Table[i] = entry;
}
}
free(StringTable->Table);
}
static int
CompareSymEntry(const PROSSYM_ENTRY SymEntry1, const PROSSYM_ENTRY SymEntry2)
{
if (SymEntry1->Address < SymEntry2->Address)
{
return -1;
}
if (SymEntry2->Address < SymEntry1->Address)
{
return +1;
}
if (SymEntry2->SourceLine == 0)
{
return -1;
}
if (SymEntry1->SourceLine == 0)
{
return +1;
}
return 0;
}
static int
GetStabInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
PIMAGE_SECTION_HEADER PESectionHeaders,
ULONG *StabSymbolsLength, void **StabSymbolsBase,
ULONG *StabStringsLength, void **StabStringsBase)
{
ULONG Idx;
/* Load .stab and .stabstr sections if available */
*StabSymbolsBase = NULL;
*StabSymbolsLength = 0;
*StabStringsBase = NULL;
*StabStringsLength = 0;
for (Idx = 0; Idx < PEFileHeader->NumberOfSections; Idx++)
{
/* printf("section: '%.08s'\n", PESectionHeaders[Idx].Name); */
if ((strncmp((char *) PESectionHeaders[Idx].Name, ".stab", 5) == 0)
&& (PESectionHeaders[Idx].Name[5] == 0))
{
/* printf(".stab section found. Size %d\n", PESectionHeaders[Idx].SizeOfRawData); */
*StabSymbolsLength = PESectionHeaders[Idx].SizeOfRawData;
*StabSymbolsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
}
if (strncmp((char *) PESectionHeaders[Idx].Name, ".stabstr", 8) == 0)
{
/* printf(".stabstr section found. Size %d\n", PESectionHeaders[Idx].SizeOfRawData); */
*StabStringsLength = PESectionHeaders[Idx].SizeOfRawData;
*StabStringsBase = (void *)((char *) FileData + PESectionHeaders[Idx].PointerToRawData);
}
}
return 0;
}
static int
GetCoffInfo(void *FileData, PIMAGE_FILE_HEADER PEFileHeader,
PIMAGE_SECTION_HEADER PESectionHeaders,
ULONG *CoffSymbolsLength, void **CoffSymbolsBase,
ULONG *CoffStringsLength, void **CoffStringsBase)
{
if (PEFileHeader->PointerToSymbolTable == 0 || PEFileHeader->NumberOfSymbols == 0)
{
/* No COFF symbol table */
*CoffSymbolsLength = 0;
*CoffStringsLength = 0;
}
else
{
*CoffSymbolsLength = PEFileHeader->NumberOfSymbols * sizeof(COFF_SYMENT);
*CoffSymbolsBase = (void *)((char *) FileData + PEFileHeader->PointerToSymbolTable);
*CoffStringsLength = *((ULONG *) ((char *) *CoffSymbolsBase + *CoffSymbolsLength));
*CoffStringsBase = (void *)((char *) *CoffSymbolsBase + *CoffSymbolsLength);
}
return 0;
}
static ULONG
FindOrAddString(struct StringHashTable *StringTable,
char *StringToFind,
ULONG *StringsLength,
void *StringsBase)
{
unsigned int hash = ComputeDJBHash(StringToFind) % StringTable->TableSize;
struct StringEntry *entry = StringTable->Table[hash];
while (entry && strcmp(entry->String, StringToFind))
entry = entry->Next;
if (entry)
{
return entry->Offset;
}
else
{
char *End = (char *)StringsBase + *StringsLength;
strcpy(End, StringToFind);
*StringsLength += strlen(StringToFind) + 1;
AddStringToHash(StringTable, hash, End - (char *)StringsBase, End);
return End - (char *)StringsBase;
}
}
static int
ConvertStabs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
ULONG *StringsLength, void *StringsBase,
ULONG StabSymbolsLength, void *StabSymbolsBase,
ULONG StabStringsLength, void *StabStringsBase,
ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
PIMAGE_SECTION_HEADER PESectionHeaders)
{
PSTAB_ENTRY StabEntry;
ULONG Count, i;
ULONG_PTR Address, LastFunctionAddress;
int First = 1;
char *Name;
ULONG NameLen;
char FuncName[256];
PROSSYM_ENTRY Current;
struct StringHashTable StringHash;
StabEntry = StabSymbolsBase;
Count = StabSymbolsLength / sizeof(STAB_ENTRY);
*SymbolsCount = 0;
if (Count == 0)
{
/* No symbol info */
*SymbolsBase = NULL;
return 0;
}
*SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
if (*SymbolsBase == NULL)
{
fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n");
return 1;
}
Current = *SymbolsBase;
memset(Current, 0, sizeof(*Current));
StringHashTableInit(&StringHash, *StringsLength, (char *)StringsBase);
LastFunctionAddress = 0;
for (i = 0; i < Count; i++)
{
if (LastFunctionAddress == 0)
{
Address = StabEntry[i].n_value - ImageBase;
}
else
{
Address = LastFunctionAddress + StabEntry[i].n_value;
}
switch (StabEntry[i].n_type)
{
case N_SO:
case N_SOL:
case N_BINCL:
Name = (char *) StabStringsBase + StabEntry[i].n_strx;
if (StabStringsLength < StabEntry[i].n_strx
|| *Name == '\0' || Name[strlen(Name) - 1] == '/'
|| Name[strlen(Name) - 1] == '\\'
|| StabEntry[i].n_value < ImageBase)
{
continue;
}
if (First || Address != Current->Address)
{
if (!First)
{
memset(++Current, 0, sizeof(*Current));
Current->FunctionOffset = Current[-1].FunctionOffset;
}
else
First = 0;
Current->Address = Address;
}
Current->FileOffset = FindOrAddString(&StringHash,
(char *)StabStringsBase + StabEntry[i].n_strx,
StringsLength,
StringsBase);
break;
case N_FUN:
if (StabEntry[i].n_desc == 0 || StabEntry[i].n_value < ImageBase)
{
LastFunctionAddress = 0; /* line # 0 = end of function */
continue;
}
if (First || Address != Current->Address)
{
if (!First)
memset(++Current, 0, sizeof(*Current));
else
First = 0;
Current->Address = Address;
Current->FileOffset = Current[-1].FileOffset;
}
Name = (char *)StabStringsBase + StabEntry[i].n_strx;
NameLen = strcspn(Name, ":");
if (sizeof(FuncName) <= NameLen)
{
free(*SymbolsBase);
fprintf(stderr, "Function name too long\n");
return 1;
}
memcpy(FuncName, Name, NameLen);
FuncName[NameLen] = '\0';
Current->FunctionOffset = FindOrAddString(&StringHash,
FuncName,
StringsLength,
StringsBase);
Current->SourceLine = 0;
LastFunctionAddress = Address;
break;
case N_SLINE:
if (First || Address != Current->Address)
{
if (!First)
{
memset(++Current, 0, sizeof(*Current));
Current->FileOffset = Current[-1].FileOffset;
Current->FunctionOffset = Current[-1].FunctionOffset;
}
else
First = 0;
Current->Address = Address;
}
Current->SourceLine = StabEntry[i].n_desc;
break;
default:
continue;
}
}
*SymbolsCount = (Current - *SymbolsBase + 1);
qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
StringHashTableFree(&StringHash);
return 0;
}
static int
ConvertCoffs(ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
ULONG *StringsLength, void *StringsBase,
ULONG CoffSymbolsLength, void *CoffSymbolsBase,
ULONG CoffStringsLength, void *CoffStringsBase,
ULONG_PTR ImageBase, PIMAGE_FILE_HEADER PEFileHeader,
PIMAGE_SECTION_HEADER PESectionHeaders)
{
ULONG Count, i;
PCOFF_SYMENT CoffEntry;
char FuncName[256], FileName[1024];
char *p;
PROSSYM_ENTRY Current;
struct StringHashTable StringHash;
CoffEntry = (PCOFF_SYMENT) CoffSymbolsBase;
Count = CoffSymbolsLength / sizeof(COFF_SYMENT);
*SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
if (*SymbolsBase == NULL)
{
fprintf(stderr, "Unable to allocate memory for converted COFF symbols\n");
return 1;
}
*SymbolsCount = 0;
Current = *SymbolsBase;
StringHashTableInit(&StringHash, *StringsLength, (char*)StringsBase);
for (i = 0; i < Count; i++)
{
if (ISFCN(CoffEntry[i].e_type) || C_EXT == CoffEntry[i].e_sclass)
{
Current->Address = CoffEntry[i].e_value;
if (CoffEntry[i].e_scnum > 0)
{
if (PEFileHeader->NumberOfSections < CoffEntry[i].e_scnum)
{
free(*SymbolsBase);
fprintf(stderr,
"Invalid section number %d in COFF symbols (only %d sections present)\n",
CoffEntry[i].e_scnum,
PEFileHeader->NumberOfSections);
return 1;
}
Current->Address += PESectionHeaders[CoffEntry[i].e_scnum - 1].VirtualAddress;
}
Current->FileOffset = 0;
if (CoffEntry[i].e.e.e_zeroes == 0)
{
if (sizeof(FuncName) <= strlen((char *) CoffStringsBase + CoffEntry[i].e.e.e_offset))
{
free(*SymbolsBase);
fprintf(stderr, "Function name too long\n");
StringHashTableFree(&StringHash);
return 1;
}
strcpy(FuncName, (char *) CoffStringsBase + CoffEntry[i].e.e.e_offset);
}
else
{
memcpy(FuncName, CoffEntry[i].e.e_name, E_SYMNMLEN);
FuncName[E_SYMNMLEN] = '\0';
}
/* Name demangling: stdcall */
p = strrchr(FuncName, '@');
if (p != NULL)
{
*p = '\0';
}
p = ('_' == FuncName[0] || '@' == FuncName[0] ? FuncName + 1 : FuncName);
Current->FunctionOffset = FindOrAddString(&StringHash,
p,
StringsLength,
StringsBase);
Current->SourceLine = 0;
memset(++Current, 0, sizeof(*Current));
}
i += CoffEntry[i].e_numaux;
}
*SymbolsCount = (Current - *SymbolsBase + 1);
qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
StringHashTableFree(&StringHash);
return 0;
}
struct DbgHelpLineEntry {
ULONG vma;
ULONG fileId;
ULONG functionId;
ULONG line;
};
struct DbgHelpStringTab {
ULONG Length;
ULONG Bytes;
char ***Table;
ULONG LineEntries, CurLineEntries;
struct DbgHelpLineEntry *LineEntryData;
void *process;
DWORD module_base;
char *PathChop;
char *SourcePath;
struct DbgHelpLineEntry *lastLineEntry;
};
static struct DbgHelpLineEntry*
DbgHelpAddLineEntry(struct DbgHelpStringTab *tab)
{
if (tab->CurLineEntries == tab->LineEntries)
{
struct DbgHelpLineEntry *newEntries = realloc(tab->LineEntryData,
tab->LineEntries * 2 * sizeof(struct DbgHelpLineEntry));
if (!newEntries)
return 0;
tab->LineEntryData = newEntries;
memset(tab->LineEntryData + tab->LineEntries, 0, sizeof(struct DbgHelpLineEntry) * tab->LineEntries);
tab->LineEntries *= 2;
}
return &tab->LineEntryData[tab->CurLineEntries++];
}
static int
DbgHelpAddStringToTable(struct DbgHelpStringTab *tab, char *name)
{
unsigned int bucket = ComputeDJBHash(name) % tab->Length;
char **tabEnt = tab->Table[bucket];
int i;
char **newBucket;
if (tabEnt)
{
for (i = 0; tabEnt[i] && strcmp(tabEnt[i], name); i++);
if (tabEnt[i])
{
free(name);
return (i << 10) | bucket;
}
}
else
i = 0;
/* At this point, we need to insert */
tab->Bytes += strlen(name) + 1;
newBucket = realloc(tab->Table[bucket], (i+2) * sizeof(char *));
if (!newBucket)
{
fprintf(stderr, "realloc failed!\n");
return -1;
}
tab->Table[bucket] = newBucket;
tab->Table[bucket][i+1] = 0;
tab->Table[bucket][i] = name;
return (i << 10) | bucket;
}
const char*
DbgHelpGetString(struct DbgHelpStringTab *tab, int id)
{
int i = id >> 10;
int bucket = id & 0x3ff;
return tab->Table[bucket][i];
}
/* Remove a prefix of PathChop if it exists and return a copy of the tail. */
static char *
StrDupShortenPath(char *PathChop, char *FilePath)
{
int pclen = strlen(PathChop);
if (!strncmp(FilePath, PathChop, pclen))
{
return strdup(FilePath+pclen);
}
else
{
return strdup(FilePath);
}
}
static BOOL
DbgHelpAddLineNumber(PSRCCODEINFO LineInfo, void *UserContext)
{
struct DbgHelpStringTab *tab = (struct DbgHelpStringTab *)UserContext;
DWORD64 disp;
int fileId, functionId;
PSYMBOL_INFO pSymbol = malloc(FIELD_OFFSET(SYMBOL_INFO, Name[MAX_SYM_NAME]));
if (!pSymbol) return FALSE;
memset(pSymbol, 0, FIELD_OFFSET(SYMBOL_INFO, Name[MAX_SYM_NAME]));
/* If any file can be opened by relative path up to a certain level, then
record that path. */
if (!tab->PathChop)
{
int i, endLen;
char *end = strrchr(LineInfo->FileName, '/');
if (!end)
end = strrchr(LineInfo->FileName, '\\');
if (end)
{
for (i = (end - LineInfo->FileName) - 1; i >= 0; i--)
{
if (LineInfo->FileName[i] == '/' || LineInfo->FileName[i] == '\\')
{
char *synthname = malloc(strlen(tab->SourcePath) +
strlen(LineInfo->FileName + i + 1)
+ 2);
strcpy(synthname, tab->SourcePath);
strcat(synthname, "/");
strcat(synthname, LineInfo->FileName + i + 1);
FILE *f = fopen(synthname, "r");
free(synthname);
if (f)
{
fclose(f);
break;
}
}
}
i++; /* Be in the string or past the next slash */
tab->PathChop = malloc(i + 1);
memcpy(tab->PathChop, LineInfo->FileName, i);
tab->PathChop[i] = 0;
}
}
fileId = DbgHelpAddStringToTable(tab,
StrDupShortenPath(tab->PathChop,
LineInfo->FileName));
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
if (!SymFromAddr(tab->process, LineInfo->Address, &disp, pSymbol))
{
//fprintf(stderr, "SymFromAddr failed.\n");
free(pSymbol);
return FALSE;
}
functionId = DbgHelpAddStringToTable(tab, strdup(pSymbol->Name));
if (LineInfo->Address == 0)
fprintf(stderr, "Address is 0.\n");
tab->lastLineEntry = DbgHelpAddLineEntry(tab);
tab->lastLineEntry->vma = LineInfo->Address - LineInfo->ModBase;
tab->lastLineEntry->functionId = functionId;
tab->lastLineEntry->fileId = fileId;
tab->lastLineEntry->line = LineInfo->LineNumber;
free(pSymbol);
return TRUE;
}
static int
ConvertDbgHelp(void *process, DWORD module_base, char *SourcePath,
ULONG *SymbolsCount, PROSSYM_ENTRY *SymbolsBase,
ULONG *StringsLength, void **StringsBase)
{
char *strings, *strings_copy;
int i, j, bucket, entry;
PROSSYM_ENTRY rossym;
struct DbgHelpStringTab strtab = { 0 };
strtab.process = process;
strtab.module_base = module_base;
strtab.Bytes = 1;
strtab.Length = 1024;
strtab.Table = calloc(1024, sizeof(const char **));
strtab.Table[0] = calloc(2, sizeof(const char *));
strtab.Table[0][0] = strdup(""); // The zero string
strtab.CurLineEntries = 0;
strtab.LineEntries = 16384;
strtab.LineEntryData = calloc(strtab.LineEntries, sizeof(struct DbgHelpLineEntry));
strtab.PathChop = NULL;
strtab.SourcePath = SourcePath ? SourcePath : "";
SymEnumLines(process, module_base, NULL, NULL, DbgHelpAddLineNumber, &strtab);
/* Transcribe necessary strings */
*StringsLength = strtab.Bytes;
strings = strings_copy = ((char *)(*StringsBase = malloc(strtab.Bytes)));
/* Copy in strings */
for (i = 0; i < strtab.Length; i++)
{
for (j = 0; strtab.Table[i] && strtab.Table[i][j]; j++)
{
/* Each entry is replaced by its corresponding entry in our string
section. We can substract the strings origin to get an offset. */
char *toFree = strtab.Table[i][j];
strtab.Table[i][j] = strcpy(strings_copy, strtab.Table[i][j]);
free(toFree);
strings_copy += strlen(strings_copy) + 1;
}
}
assert(strings_copy == strings + strtab.Bytes);
*SymbolsBase = calloc(strtab.CurLineEntries, sizeof(ROSSYM_ENTRY));
*SymbolsCount = strtab.CurLineEntries;
/* Copy symbols into rossym entries */
for (i = 0; i < strtab.CurLineEntries; i++)
{
rossym = &(*SymbolsBase)[i];
rossym->Address = strtab.LineEntryData[i].vma;
bucket = strtab.LineEntryData[i].fileId & 0x3ff;
entry = strtab.LineEntryData[i].fileId >> 10;
rossym->FileOffset = strtab.Table[bucket][entry] - strings;
bucket = strtab.LineEntryData[i].functionId & 0x3ff;
entry = strtab.LineEntryData[i].functionId >> 10;
rossym->FunctionOffset = strtab.Table[bucket][entry] - strings;
rossym->SourceLine = strtab.LineEntryData[i].line;
}
/* Free stringtab */
for (i = 0; i < strtab.Length; i++)
{
free(strtab.Table[i]);
}
free(strtab.LineEntryData);
free(strtab.PathChop);
qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *))CompareSymEntry);
return 0;
}
static int
MergeStabsAndCoffs(ULONG *MergedSymbolCount, PROSSYM_ENTRY *MergedSymbols,
ULONG StabSymbolsCount, PROSSYM_ENTRY StabSymbols,
ULONG CoffSymbolsCount, PROSSYM_ENTRY CoffSymbols)
{
ULONG StabIndex, j;
ULONG CoffIndex;
ULONG_PTR StabFunctionStartAddress;
ULONG StabFunctionStringOffset, NewStabFunctionStringOffset, CoffFunctionStringOffset;
PROSSYM_ENTRY CoffFunctionSymbol;
*MergedSymbolCount = 0;
if (StabSymbolsCount == 0)
{
*MergedSymbols = NULL;
return 0;
}
*MergedSymbols = malloc((StabSymbolsCount + CoffSymbolsCount) * sizeof(ROSSYM_ENTRY));
if (*MergedSymbols == NULL)
{
fprintf(stderr, "Unable to allocate memory for merged symbols\n");
return 1;
}
StabFunctionStartAddress = 0;
StabFunctionStringOffset = 0;
CoffFunctionStringOffset = 0;
CoffFunctionSymbol = NULL;
CoffIndex = 0;
for (StabIndex = 0; StabIndex < StabSymbolsCount; StabIndex++)
{
(*MergedSymbols)[*MergedSymbolCount] = StabSymbols[StabIndex];
for (j = StabIndex + 1;
j < StabSymbolsCount && StabSymbols[j].Address == StabSymbols[StabIndex].Address;
j++)
{
if (StabSymbols[j].FileOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FileOffset == 0)
{
(*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
}
if (StabSymbols[j].FunctionOffset != 0 && (*MergedSymbols)[*MergedSymbolCount].FunctionOffset == 0)
{
(*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
}
if (StabSymbols[j].SourceLine != 0 && (*MergedSymbols)[*MergedSymbolCount].SourceLine == 0)
{
(*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
}
}
StabIndex = j - 1;
while (CoffIndex < CoffSymbolsCount &&
CoffSymbols[CoffIndex].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
{
if (CoffSymbols[CoffIndex].FunctionOffset != 0)
{
CoffFunctionSymbol = &CoffSymbols[CoffIndex];
CoffFunctionStringOffset = CoffFunctionSymbol->FunctionOffset;
}
CoffIndex++;
}
NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
if (CoffFunctionSymbol &&
CoffFunctionSymbol->Address <= (*MergedSymbols)[*MergedSymbolCount].Address &&
StabFunctionStartAddress < CoffFunctionSymbol->Address)
{
(*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffFunctionStringOffset;
CoffFunctionSymbol->FunctionOffset = 0;
}
if (StabFunctionStringOffset != NewStabFunctionStringOffset)
{
StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
}
StabFunctionStringOffset = NewStabFunctionStringOffset;
(*MergedSymbolCount)++;
}
/* Handle functions that have no analog in the upstream data */
for (CoffIndex = 0; CoffIndex < CoffSymbolsCount; CoffIndex++)
{
if (CoffSymbols[CoffIndex].Address &&
CoffSymbols[CoffIndex].FunctionOffset)
{
(*MergedSymbols)[*MergedSymbolCount] = CoffSymbols[CoffIndex];
(*MergedSymbolCount)++;
}
}
qsort(*MergedSymbols, *MergedSymbolCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
return 0;
}
static PIMAGE_SECTION_HEADER
FindSectionForRVA(DWORD RVA, unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
{
unsigned Section;
for (Section = 0; Section < NumberOfSections; Section++)
{
if (SectionHeaders[Section].VirtualAddress <= RVA &&
RVA < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].Misc.VirtualSize)
{
return SectionHeaders + Section;
}
}
return NULL;
}
static int
ProcessRelocations(ULONG *ProcessedRelocsLength, void **ProcessedRelocs,
void *RawData, PIMAGE_OPTIONAL_HEADER OptHeader,
unsigned NumberOfSections, PIMAGE_SECTION_HEADER SectionHeaders)
{
PIMAGE_SECTION_HEADER RelocSectionHeader, TargetSectionHeader;
PIMAGE_BASE_RELOCATION BaseReloc, End, AcceptedRelocs;
int Found;
if (OptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
{
/* No relocation entries */
*ProcessedRelocsLength = 0;
*ProcessedRelocs = NULL;
return 0;
}
RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
NumberOfSections, SectionHeaders);
if (RelocSectionHeader == NULL)
{
fprintf(stderr, "Can't find section header for relocation data\n");
return 1;
}
*ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
if (*ProcessedRelocs == NULL)
{
fprintf(stderr,
"Failed to allocate %u bytes for relocations\n",
(unsigned int)RelocSectionHeader->SizeOfRawData);
return 1;
}
*ProcessedRelocsLength = 0;
BaseReloc = (PIMAGE_BASE_RELOCATION) ((char *) RawData +
RelocSectionHeader->PointerToRawData +
(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress -
RelocSectionHeader->VirtualAddress));
End = (PIMAGE_BASE_RELOCATION) ((char *) BaseReloc +
OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);
while (BaseReloc < End && BaseReloc->SizeOfBlock > 0)
{
TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress,
NumberOfSections,
SectionHeaders);
if (TargetSectionHeader != NULL)
{
AcceptedRelocs = *ProcessedRelocs;
Found = 0;
while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
*ProcessedRelocsLength)
&& !Found)
{
Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock &&
memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock) == 0;
AcceptedRelocs = (PIMAGE_BASE_RELOCATION) ((char *) AcceptedRelocs +
AcceptedRelocs->SizeOfBlock);
}
if (!Found)
{
memcpy((char *) *ProcessedRelocs + *ProcessedRelocsLength,
BaseReloc,
BaseReloc->SizeOfBlock);
*ProcessedRelocsLength += BaseReloc->SizeOfBlock;
}
}
BaseReloc = (PIMAGE_BASE_RELOCATION)((char *) BaseReloc + BaseReloc->SizeOfBlock);
}
return 0;
}
static const BYTE*
GetSectionName(void *StringsBase, const BYTE *SectionTitle)
{
if (SectionTitle[0] == '/')
{
int offset = atoi((char*)SectionTitle+1);
return ((BYTE *)StringsBase) + offset;
}
else
return SectionTitle;
}
static int
CreateOutputFile(FILE *OutFile, void *InData,
PIMAGE_DOS_HEADER InDosHeader, PIMAGE_FILE_HEADER InFileHeader,
PIMAGE_OPTIONAL_HEADER InOptHeader, PIMAGE_SECTION_HEADER InSectionHeaders,
ULONG RosSymLength, void *RosSymSection)
{
ULONG StartOfRawData;
unsigned Section;
void *OutHeader, *ProcessedRelocs, *PaddedRosSym, *Data;
unsigned char *PaddedStringTable;
PIMAGE_DOS_HEADER OutDosHeader;
PIMAGE_FILE_HEADER OutFileHeader;
PIMAGE_OPTIONAL_HEADER OutOptHeader;
PIMAGE_SECTION_HEADER OutSectionHeaders, CurrentSectionHeader;
DWORD CheckSum;
ULONG Length, i;
ULONG ProcessedRelocsLength;
ULONG RosSymOffset, RosSymFileLength;
ULONG PaddedStringTableLength;
int InRelocSectionIndex;
PIMAGE_SECTION_HEADER OutRelocSection;
/* Each coff symbol is 18 bytes and the string table follows */
char *StringTable = (char *)InData +
InFileHeader->PointerToSymbolTable + 18 * InFileHeader->NumberOfSymbols;
ULONG StringTableLength = 0;
ULONG StringTableLocation;
StartOfRawData = 0;
for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
{
const BYTE *SectionName = GetSectionName(StringTable,
InSectionHeaders[Section].Name);
if (InSectionHeaders[Section].Name[0] == '/')
{
StringTableLength = atoi((const char *)InSectionHeaders[Section].Name + 1) +
strlen((const char *)SectionName) + 1;
}
if ((StartOfRawData == 0 || InSectionHeaders[Section].PointerToRawData < StartOfRawData)
&& InSectionHeaders[Section].PointerToRawData != 0
&& (strncmp((char *) SectionName, ".stab", 5)) != 0
&& (strncmp((char *) SectionName, ".debug_", 7)) != 0)
{
StartOfRawData = InSectionHeaders[Section].PointerToRawData;
}
}
OutHeader = malloc(StartOfRawData);
if (OutHeader == NULL)
{
fprintf(stderr,
"Failed to allocate %u bytes for output file header\n",
(unsigned int)StartOfRawData);
return 1;
}
memset(OutHeader, '\0', StartOfRawData);
OutDosHeader = (PIMAGE_DOS_HEADER) OutHeader;
memcpy(OutDosHeader, InDosHeader, InDosHeader->e_lfanew + sizeof(ULONG));
OutFileHeader = (PIMAGE_FILE_HEADER)((char *) OutHeader + OutDosHeader->e_lfanew + sizeof(ULONG));
memcpy(OutFileHeader, InFileHeader, sizeof(IMAGE_FILE_HEADER));
OutFileHeader->PointerToSymbolTable = 0;
OutFileHeader->NumberOfSymbols = 0;
OutFileHeader->Characteristics &= ~(IMAGE_FILE_LINE_NUMS_STRIPPED | IMAGE_FILE_LOCAL_SYMS_STRIPPED |
IMAGE_FILE_DEBUG_STRIPPED);
OutOptHeader = (PIMAGE_OPTIONAL_HEADER)(OutFileHeader + 1);
memcpy(OutOptHeader, InOptHeader, sizeof(IMAGE_OPTIONAL_HEADER));
OutOptHeader->CheckSum = 0;
OutSectionHeaders = (PIMAGE_SECTION_HEADER)((char *) OutOptHeader + OutFileHeader->SizeOfOptionalHeader);
if (ProcessRelocations(&ProcessedRelocsLength,
&ProcessedRelocs,
InData,
InOptHeader,
InFileHeader->NumberOfSections,
InSectionHeaders))
{
return 1;
}
if (InOptHeader->NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_BASERELOC ||
InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress == 0)
{
InRelocSectionIndex = -1;
}
else
{
InRelocSectionIndex = FindSectionForRVA(InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
InFileHeader->NumberOfSections, InSectionHeaders) - InSectionHeaders;
}
OutFileHeader->NumberOfSections = 0;
CurrentSectionHeader = OutSectionHeaders;
OutOptHeader->SizeOfImage = 0;
RosSymOffset = 0;
OutRelocSection = NULL;
StringTableLocation = StartOfRawData;
for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
{
const BYTE *SectionName = GetSectionName(StringTable,
InSectionHeaders[Section].Name);
if ((strncmp((char *) SectionName, ".stab", 5) != 0) &&
(strncmp((char *) SectionName, ".debug_", 7)) != 0)
{
*CurrentSectionHeader = InSectionHeaders[Section];
CurrentSectionHeader->PointerToLinenumbers = 0;
CurrentSectionHeader->NumberOfLinenumbers = 0;
if (OutOptHeader->SizeOfImage < CurrentSectionHeader->VirtualAddress +
CurrentSectionHeader->Misc.VirtualSize)
{
OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress +
CurrentSectionHeader->Misc.VirtualSize,
OutOptHeader->SectionAlignment);
}
if (RosSymOffset < CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData)
{
RosSymOffset = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
}
if (Section == (ULONG)InRelocSectionIndex)
{
OutRelocSection = CurrentSectionHeader;
}
StringTableLocation = CurrentSectionHeader->PointerToRawData + CurrentSectionHeader->SizeOfRawData;
OutFileHeader->NumberOfSections++;
CurrentSectionHeader++;
}
}
if (OutRelocSection == CurrentSectionHeader - 1)
{
OutOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = ProcessedRelocsLength;
if (OutOptHeader->SizeOfImage == OutRelocSection->VirtualAddress +
ROUND_UP(OutRelocSection->Misc.VirtualSize,
OutOptHeader->SectionAlignment))
{
OutOptHeader->SizeOfImage = OutRelocSection->VirtualAddress +
ROUND_UP(ProcessedRelocsLength,
OutOptHeader->SectionAlignment);
}
OutRelocSection->Misc.VirtualSize = ProcessedRelocsLength;
if (RosSymOffset == OutRelocSection->PointerToRawData +
OutRelocSection->SizeOfRawData)
{
RosSymOffset = OutRelocSection->PointerToRawData +
ROUND_UP(ProcessedRelocsLength,
OutOptHeader->FileAlignment);
}
OutRelocSection->SizeOfRawData = ROUND_UP(ProcessedRelocsLength,
OutOptHeader->FileAlignment);
}
if (RosSymLength > 0)
{
RosSymFileLength = ROUND_UP(RosSymLength, OutOptHeader->FileAlignment);
memcpy(CurrentSectionHeader->Name, ".rossym", 8); /* We're lucky: string is exactly 8 bytes long */
CurrentSectionHeader->Misc.VirtualSize = RosSymLength;
CurrentSectionHeader->VirtualAddress = OutOptHeader->SizeOfImage;
CurrentSectionHeader->SizeOfRawData = RosSymFileLength;
CurrentSectionHeader->PointerToRawData = RosSymOffset;
CurrentSectionHeader->PointerToRelocations = 0;
CurrentSectionHeader->PointerToLinenumbers = 0;
CurrentSectionHeader->NumberOfRelocations = 0;
CurrentSectionHeader->NumberOfLinenumbers = 0;
CurrentSectionHeader->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
| IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_TYPE_NOLOAD;
OutOptHeader->SizeOfImage = ROUND_UP(CurrentSectionHeader->VirtualAddress + CurrentSectionHeader->Misc.VirtualSize,
OutOptHeader->SectionAlignment);
OutFileHeader->NumberOfSections++;
PaddedRosSym = malloc(RosSymFileLength);
if (PaddedRosSym == NULL)
{
fprintf(stderr,
"Failed to allocate %u bytes for padded .rossym\n",
(unsigned int)RosSymFileLength);
return 1;
}
memcpy(PaddedRosSym, RosSymSection, RosSymLength);
memset((char *) PaddedRosSym + RosSymLength,
'\0',
RosSymFileLength - RosSymLength);
/* Position the string table after our new section */
StringTableLocation = RosSymOffset + RosSymFileLength;
}
else
{
PaddedRosSym = NULL;
}
/* Set the string table area in the header if we need it */
if (StringTableLength)
{
OutFileHeader->PointerToSymbolTable = StringTableLocation;
OutFileHeader->NumberOfSymbols = 0;
}
CheckSum = 0;
for (i = 0; i < StartOfRawData / 2; i++)
{
CheckSum += ((unsigned short*) OutHeader)[i];
CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
}
Length = StartOfRawData;
for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
{
DWORD SizeOfRawData;
if (OutRelocSection == OutSectionHeaders + Section)
{
Data = (void *) ProcessedRelocs;
SizeOfRawData = ProcessedRelocsLength;
}
else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
{
Data = (void *) PaddedRosSym;
SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
}
else
{
Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
}
for (i = 0; i < SizeOfRawData / 2; i++)
{
CheckSum += ((unsigned short*) Data)[i];
CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
}
Length += OutSectionHeaders[Section].SizeOfRawData;
}
if (OutFileHeader->PointerToSymbolTable)
{
int PaddingFrom = (OutFileHeader->PointerToSymbolTable + StringTableLength) %
OutOptHeader->FileAlignment;
int PaddingSize = PaddingFrom ? OutOptHeader->FileAlignment - PaddingFrom : 0;
PaddedStringTableLength = StringTableLength + PaddingSize;
PaddedStringTable = malloc(PaddedStringTableLength);
/* COFF string section is preceeded by a length */
assert(sizeof(StringTableLength) == 4);
memcpy(PaddedStringTable, &StringTableLength, sizeof(StringTableLength));
/* We just copy enough of the string table to contain the strings we want
The string table length technically counts as part of the string table
space itself. */
memcpy(PaddedStringTable + 4, StringTable + 4, StringTableLength - 4);
memset(PaddedStringTable + StringTableLength, 0, PaddingSize);
assert(OutFileHeader->PointerToSymbolTable % 2 == 0);
for (i = 0; i < PaddedStringTableLength / 2; i++)
{
CheckSum += ((unsigned short*)PaddedStringTable)[i];
CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
}
Length += PaddedStringTableLength;
}
else
{
PaddedStringTable = NULL;
}
CheckSum += Length;
OutOptHeader->CheckSum = CheckSum;
if (fwrite(OutHeader, 1, StartOfRawData, OutFile) != StartOfRawData)
{
perror("Error writing output header\n");
free(OutHeader);
return 1;
}
for (Section = 0; Section < OutFileHeader->NumberOfSections; Section++)
{
if (OutSectionHeaders[Section].SizeOfRawData != 0)
{
DWORD SizeOfRawData;
fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
if (OutRelocSection == OutSectionHeaders + Section)
{
Data = (void *) ProcessedRelocs;
SizeOfRawData = ProcessedRelocsLength;
}
else if (RosSymLength > 0 && Section + 1 == OutFileHeader->NumberOfSections)
{
Data = (void *) PaddedRosSym;
SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
}
else
{
Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
SizeOfRawData = OutSectionHeaders[Section].SizeOfRawData;
}
if (fwrite(Data, 1, SizeOfRawData, OutFile) != SizeOfRawData)
{
perror("Error writing section data\n");
free(PaddedRosSym);
free(OutHeader);
return 1;
}
}
}
if (PaddedStringTable)
{
fseek(OutFile, OutFileHeader->PointerToSymbolTable, SEEK_SET);
fwrite(PaddedStringTable, 1, PaddedStringTableLength, OutFile);
free(PaddedStringTable);
}
if (PaddedRosSym)
{
free(PaddedRosSym);
}
free(OutHeader);
return 0;
}
int main(int argc, char* argv[])
{
PSYMBOLFILE_HEADER SymbolFileHeader;
PIMAGE_DOS_HEADER PEDosHeader;
PIMAGE_FILE_HEADER PEFileHeader;
PIMAGE_OPTIONAL_HEADER PEOptHeader;
PIMAGE_SECTION_HEADER PESectionHeaders;
ULONG ImageBase;
void *StabBase;
ULONG StabsLength;
void *StabStringBase;
ULONG StabStringsLength;
void *CoffBase = NULL;
ULONG CoffsLength;
void *CoffStringBase = NULL;
ULONG CoffStringsLength;
char* path1;
char* path2;
FILE* out;
void *StringBase = NULL;
ULONG StringsLength = 0;
ULONG StabSymbolsCount = 0;
PROSSYM_ENTRY StabSymbols = NULL;
ULONG CoffSymbolsCount = 0;
PROSSYM_ENTRY CoffSymbols = NULL;
ULONG MergedSymbolsCount = 0;
PROSSYM_ENTRY MergedSymbols = NULL;
size_t FileSize;
void *FileData;
ULONG RosSymLength;
void *RosSymSection;
DWORD module_base;
void *file;
char elfhdr[4] = { '\177', 'E', 'L', 'F' };
BOOLEAN UseDbgHelp = FALSE;
int arg, argstate = 0;
char *SourcePath = NULL;
for (arg = 1; arg < argc; arg++)
{
switch (argstate)
{
default:
argstate = -1;
break;
case 0:
if (!strcmp(argv[arg], "-s"))
{
argstate = 1;
}
else
{
argstate = 2;
path1 = convert_path(argv[arg]);
}
break;
case 1:
free(SourcePath);
SourcePath = strdup(argv[arg]);
argstate = 0;
break;
case 2:
path2 = convert_path(argv[arg]);
argstate = 3;
break;
}
}
if (argstate != 3)
{
fprintf(stderr, "Usage: rsym [-s <sources>] <input> <output>\n");
exit(1);
}
FileData = load_file(path1, &FileSize);
if (!FileData)
{
fprintf(stderr, "An error occured loading '%s'\n", path1);
exit(1);
}
file = fopen(path1, "rb");
/* Check if MZ header exists */
PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC ||
PEDosHeader->e_lfanew == 0L)
{
/* Ignore elf */
if (!memcmp(PEDosHeader, elfhdr, sizeof(elfhdr)))
exit(0);
perror("Input file is not a PE image.\n");
free(FileData);
exit(1);
}
/* Locate PE file header */
/* sizeof(ULONG) = sizeof(MAGIC) */
PEFileHeader = (PIMAGE_FILE_HEADER)((char *) FileData + PEDosHeader->e_lfanew + sizeof(ULONG));
/* Locate optional header */
assert(sizeof(ULONG) == 4);
PEOptHeader = (PIMAGE_OPTIONAL_HEADER)(PEFileHeader + 1);
ImageBase = PEOptHeader->ImageBase;
/* Locate PE section headers */
PESectionHeaders = (PIMAGE_SECTION_HEADER)((char *) PEOptHeader + PEFileHeader->SizeOfOptionalHeader);
if (GetStabInfo(FileData,
PEFileHeader,
PESectionHeaders,
&StabsLength,
&StabBase,
&StabStringsLength,
&StabStringBase))
{
free(FileData);
exit(1);
}
if (StabsLength == 0)
{
// SYMOPT_AUTO_PUBLICS
// SYMOPT_FAVOR_COMPRESSED
// SYMOPT_LOAD_ANYTHING
// SYMOPT_LOAD_LINES
SymSetOptions(0x10000 | 0x800000 | 0x40 | 0x10);
SymInitialize(FileData, ".", 0);
module_base = SymLoadModule(FileData, file, path1, path1, 0, FileSize) & 0xffffffff;
if (ConvertDbgHelp(FileData,
module_base,
SourcePath,
&StabSymbolsCount,
&StabSymbols,
&StringsLength,
&StringBase))
{
free(FileData);
exit(1);
}
UseDbgHelp = TRUE;
SymUnloadModule(FileData, module_base);
SymCleanup(FileData);
}
if (GetCoffInfo(FileData,
PEFileHeader,
PESectionHeaders,
&CoffsLength,
&CoffBase,
&CoffStringsLength,
&CoffStringBase))
{
free(FileData);
exit(1);
}
if (!UseDbgHelp)
{
StringBase = malloc(1 + StringsLength + CoffStringsLength +
(CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
if (StringBase == NULL)
{
free(FileData);
fprintf(stderr, "Failed to allocate memory for strings table\n");
exit(1);
}
/* Make offset 0 into an empty string */
*((char *) StringBase) = '\0';
StringsLength = 1;
if (ConvertStabs(&StabSymbolsCount,
&StabSymbols,
&StringsLength,
StringBase,
StabsLength,
StabBase,
StabStringsLength,
StabStringBase,
ImageBase,
PEFileHeader,
PESectionHeaders))
{
free(StringBase);
free(FileData);
fprintf(stderr, "Failed to allocate memory for strings table\n");
exit(1);
}
}
else
{
StringBase = realloc(StringBase, StringsLength + CoffStringsLength);
if (!StringBase)
{
free(FileData);
fprintf(stderr, "Failed to allocate memory for strings table\n");
exit(1);
}
}
if (ConvertCoffs(&CoffSymbolsCount,
&CoffSymbols,
&StringsLength,
StringBase,
CoffsLength,
CoffBase,
CoffStringsLength,
CoffStringBase,
ImageBase,
PEFileHeader,
PESectionHeaders))
{
if (StabSymbols)
{
free(StabSymbols);
}
free(StringBase);
free(FileData);
exit(1);
}
if (MergeStabsAndCoffs(&MergedSymbolsCount,
&MergedSymbols,
StabSymbolsCount,
StabSymbols,
CoffSymbolsCount,
CoffSymbols))
{
if (CoffSymbols)
{
free(CoffSymbols);
}
if (StabSymbols)
{
free(StabSymbols);
}
free(StringBase);
free(FileData);
exit(1);
}
if (CoffSymbols)
{
free(CoffSymbols);
}
if (StabSymbols)
{
free(StabSymbols);
}
if (MergedSymbolsCount == 0)
{
RosSymLength = 0;
RosSymSection = NULL;
}
else
{
RosSymLength = sizeof(SYMBOLFILE_HEADER) +
MergedSymbolsCount * sizeof(ROSSYM_ENTRY) +
StringsLength;
RosSymSection = malloc(RosSymLength);
if (RosSymSection == NULL)
{
free(MergedSymbols);
free(StringBase);
free(FileData);
fprintf(stderr, "Unable to allocate memory for .rossym section\n");
exit(1);
}
memset(RosSymSection, '\0', RosSymLength);
SymbolFileHeader = (PSYMBOLFILE_HEADER)RosSymSection;
SymbolFileHeader->SymbolsOffset = sizeof(SYMBOLFILE_HEADER);
SymbolFileHeader->SymbolsLength = MergedSymbolsCount * sizeof(ROSSYM_ENTRY);
SymbolFileHeader->StringsOffset = SymbolFileHeader->SymbolsOffset +
SymbolFileHeader->SymbolsLength;
SymbolFileHeader->StringsLength = StringsLength;
memcpy((char *) RosSymSection + SymbolFileHeader->SymbolsOffset,
MergedSymbols,
SymbolFileHeader->SymbolsLength);
memcpy((char *) RosSymSection + SymbolFileHeader->StringsOffset,
StringBase,
SymbolFileHeader->StringsLength);
free(MergedSymbols);
}
free(StringBase);
out = fopen(path2, "wb");
if (out == NULL)
{
perror("Cannot open output file");
free(RosSymSection);
free(FileData);
exit(1);
}
if (CreateOutputFile(out,
FileData,
PEDosHeader,
PEFileHeader,
PEOptHeader,
PESectionHeaders,
RosSymLength,
RosSymSection))
{
fclose(out);
if (RosSymSection)
{
free(RosSymSection);
}
free(FileData);
exit(1);
}
fclose(out);
if (RosSymSection)
{
free(RosSymSection);
}
free(FileData);
return 0;
}
/* EOF */