reactos/reactos/tools/rsym.c
Royce Mitchell III e2303991a6 raddr2line utility
moved code common betw rsym and raddr2line to rsym_common.c
simplified tools/Makefile

svn path=/trunk/; revision=14542
2005-04-08 05:35:20 +00:00

907 lines
32 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "rsym.h"
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;
}
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 (0 == PEFileHeader->PointerToSymbolTable || 0 == PEFileHeader->NumberOfSymbols)
{
/* 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(char *StringToFind, ULONG *StringsLength, void *StringsBase)
{
char *Search, *End;
Search = (char *) StringsBase;
End = Search + *StringsLength;
while (Search < End)
{
if (0 == strcmp(Search, StringToFind))
{
return Search - (char *) StringsBase;
}
Search += strlen(Search) + 1;
}
strcpy(Search, StringToFind);
*StringsLength += strlen(StringToFind) + 1;
return Search - (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;
char *Name;
char FuncName[256];
StabEntry = StabSymbolsBase;
Count = StabSymbolsLength / sizeof(STAB_ENTRY);
*SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
if (NULL == *SymbolsBase)
{
fprintf(stderr, "Failed to allocate memory for converted .stab symbols\n");
return 1;
}
*SymbolsCount = 0;
LastFunctionAddress = 0;
First = 1;
for (i = 0; i < Count; i++)
{
switch (StabEntry[i].n_type)
{
case N_SO:
Name = (char *) StabStringsBase + StabEntry[i].n_strx;
if (StabStringsLength < StabEntry[i].n_strx
||'\0' == *Name || '/' == Name[strlen(Name) - 1]
|| '\\' == Name[strlen(Name) - 1]
|| StabEntry[i].n_value < ImageBase)
{
continue;
}
Address = StabEntry[i].n_value - ImageBase;
if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
{
(*SymbolsCount)++;
}
(*SymbolsBase)[*SymbolsCount].Address = Address;
(*SymbolsBase)[*SymbolsCount].FileOffset = FindOrAddString((char *) StabStringsBase
+ StabEntry[i].n_strx,
StringsLength,
StringsBase);
(*SymbolsBase)[*SymbolsCount].FunctionOffset = 0;
(*SymbolsBase)[*SymbolsCount].SourceLine = 0;
LastFunctionAddress = 0;
break;
case N_FUN:
if (0 == StabEntry[i].n_desc || StabEntry[i].n_value < ImageBase) /* line # 0 isn't valid */
{
continue;
}
Address = StabEntry[i].n_value - ImageBase;
if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
{
(*SymbolsCount)++;
(*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
}
(*SymbolsBase)[*SymbolsCount].Address = Address;
if (sizeof(FuncName) <= strlen((char *) StabStringsBase + StabEntry[i].n_strx))
{
free(*SymbolsBase);
fprintf(stderr, "Function name too long\n");
return 1;
}
strcpy(FuncName, (char *) StabStringsBase + StabEntry[i].n_strx);
Name = strchr(FuncName, ':');
if (NULL != Name)
{
*Name = '\0';
}
(*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(FuncName,
StringsLength,
StringsBase);
(*SymbolsBase)[*SymbolsCount].SourceLine = 0;
LastFunctionAddress = Address;
break;
case N_SLINE:
if (0 == LastFunctionAddress)
{
Address = StabEntry[i].n_value - ImageBase;
}
else
{
Address = LastFunctionAddress + StabEntry[i].n_value;
}
if (Address != (*SymbolsBase)[*SymbolsCount].Address && ! First)
{
(*SymbolsCount)++;
(*SymbolsBase)[*SymbolsCount].FileOffset = (*SymbolsBase)[*SymbolsCount - 1].FileOffset;
(*SymbolsBase)[*SymbolsCount].FunctionOffset = (*SymbolsBase)[*SymbolsCount - 1].FunctionOffset;
}
(*SymbolsBase)[*SymbolsCount].Address = Address;
(*SymbolsBase)[*SymbolsCount].SourceLine = StabEntry[i].n_desc;
break;
default:
continue;
}
First = 0;
}
(*SymbolsCount)++;
qsort(*SymbolsBase, *SymbolsCount, sizeof(ROSSYM_ENTRY), (int (*)(const void *, const void *)) CompareSymEntry);
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];
char *p;
CoffEntry = (PCOFF_SYMENT) CoffSymbolsBase;
Count = CoffSymbolsLength / sizeof(COFF_SYMENT);
*SymbolsBase = malloc(Count * sizeof(ROSSYM_ENTRY));
if (NULL == *SymbolsBase)
{
fprintf(stderr, "Unable to allocate memory for converted COFF symbols\n");
return 1;
}
*SymbolsCount = 0;
for (i = 0; i < Count; i++)
{
if (ISFCN(CoffEntry[i].e_type) || C_EXT == CoffEntry[i].e_sclass)
{
(*SymbolsBase)[*SymbolsCount].Address = CoffEntry[i].e_value;
if (0 < CoffEntry[i].e_scnum)
{
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;
}
(*SymbolsBase)[*SymbolsCount].Address += PESectionHeaders[CoffEntry[i].e_scnum - 1].VirtualAddress;
}
(*SymbolsBase)[*SymbolsCount].FileOffset = 0;
if (0 == CoffEntry[i].e.e.e_zeroes)
{
if (sizeof(FuncName) <= strlen((char *) CoffStringsBase + CoffEntry[i].e.e.e_offset))
{
free(*SymbolsBase);
fprintf(stderr, "Function name too long\n");
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 (NULL != p)
{
*p = '\0';
}
p = ('_' == FuncName[0] || '@' == FuncName[0] ? FuncName + 1 : FuncName);
(*SymbolsBase)[*SymbolsCount].FunctionOffset = FindOrAddString(p,
StringsLength,
StringsBase);
(*SymbolsBase)[*SymbolsCount].SourceLine = 0;
(*SymbolsCount)++;
}
i += CoffEntry[i].e_numaux;
}
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;
*MergedSymbols = malloc(StabSymbolsCount * sizeof(ROSSYM_ENTRY));
if (NULL == *MergedSymbols)
{
fprintf(stderr, "Unable to allocate memory for merged symbols\n");
return 1;
}
*MergedSymbolCount = 0;
StabFunctionStartAddress = 0;
StabFunctionStringOffset = 0;
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 (0 != StabSymbols[j].FileOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FileOffset)
{
(*MergedSymbols)[*MergedSymbolCount].FileOffset = StabSymbols[j].FileOffset;
}
if (0 != StabSymbols[j].FunctionOffset && 0 == (*MergedSymbols)[*MergedSymbolCount].FunctionOffset)
{
(*MergedSymbols)[*MergedSymbolCount].FunctionOffset = StabSymbols[j].FunctionOffset;
}
if (0 != StabSymbols[j].SourceLine && 0 == (*MergedSymbols)[*MergedSymbolCount].SourceLine)
{
(*MergedSymbols)[*MergedSymbolCount].SourceLine = StabSymbols[j].SourceLine;
}
}
StabIndex = j - 1;
while (CoffIndex < CoffSymbolsCount
&& CoffSymbols[CoffIndex + 1].Address <= (*MergedSymbols)[*MergedSymbolCount].Address)
{
CoffIndex++;
}
NewStabFunctionStringOffset = (*MergedSymbols)[*MergedSymbolCount].FunctionOffset;
if (CoffSymbols[CoffIndex].Address < (*MergedSymbols)[*MergedSymbolCount].Address
&& StabFunctionStartAddress < CoffSymbols[CoffIndex].Address
&& 0 != CoffSymbols[CoffIndex].FunctionOffset)
{
(*MergedSymbols)[*MergedSymbolCount].FunctionOffset = CoffSymbols[CoffIndex].FunctionOffset;
}
if (StabFunctionStringOffset != NewStabFunctionStringOffset)
{
StabFunctionStartAddress = (*MergedSymbols)[*MergedSymbolCount].Address;
}
StabFunctionStringOffset = NewStabFunctionStringOffset;
(*MergedSymbolCount)++;
}
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
IncludeRelocationsForSection(PIMAGE_SECTION_HEADER SectionHeader)
{
static char *BlacklistedSections[] =
{
".idata",
".reloc"
};
char SectionName[IMAGE_SIZEOF_SHORT_NAME];
unsigned i;
if (0 != (SectionHeader->Characteristics & IMAGE_SCN_LNK_REMOVE))
{
return 0;
}
for (i = 0; i < sizeof(BlacklistedSections) / sizeof(BlacklistedSections[0]); i++)
{
strncpy(SectionName, BlacklistedSections[i], IMAGE_SIZEOF_SHORT_NAME);
if (0 == memcmp(SectionName, SectionHeader->Name, IMAGE_SIZEOF_SHORT_NAME))
{
return 0;
}
}
return 1;
}
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
|| 0 == OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
{
/* No relocation entries */
*ProcessedRelocsLength = 0;
*ProcessedRelocs = NULL;
return 0;
}
RelocSectionHeader = FindSectionForRVA(OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,
NumberOfSections, SectionHeaders);
if (NULL == RelocSectionHeader)
{
fprintf(stderr, "Can't find section header for relocation data\n");
return 1;
}
*ProcessedRelocs = malloc(RelocSectionHeader->SizeOfRawData);
if (NULL == *ProcessedRelocs)
{
fprintf(stderr, "Failed to allocate %lu bytes for relocations\n", 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 && 0 < BaseReloc->SizeOfBlock)
{
TargetSectionHeader = FindSectionForRVA(BaseReloc->VirtualAddress, NumberOfSections,
SectionHeaders);
if (NULL != TargetSectionHeader && IncludeRelocationsForSection(TargetSectionHeader))
{
AcceptedRelocs = *ProcessedRelocs;
Found = 0;
while (AcceptedRelocs < (PIMAGE_BASE_RELOCATION) ((char *) *ProcessedRelocs +
*ProcessedRelocsLength)
&& ! Found)
{
Found = BaseReloc->SizeOfBlock == AcceptedRelocs->SizeOfBlock
&& 0 == memcmp(BaseReloc, AcceptedRelocs, AcceptedRelocs->SizeOfBlock);
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 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;
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;
int InRelocSectionIndex;
PIMAGE_SECTION_HEADER OutRelocSection;
StartOfRawData = 0;
for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
{
if ((0 == StartOfRawData
|| InSectionHeaders[Section].PointerToRawData < StartOfRawData)
&& 0 != InSectionHeaders[Section].PointerToRawData
&& 0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
{
StartOfRawData = InSectionHeaders[Section].PointerToRawData;
}
}
OutHeader = malloc(StartOfRawData);
if (NULL == OutHeader)
{
fprintf(stderr, "Failed to allocate %lu bytes for output file header\n", 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
|| 0 == InOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
{
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;
for (Section = 0; Section < InFileHeader->NumberOfSections; Section++)
{
if (0 == (InSectionHeaders[Section].Characteristics & IMAGE_SCN_LNK_REMOVE))
{
*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 == InRelocSectionIndex)
{
OutRelocSection = CurrentSectionHeader;
}
(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);
}
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 (NULL == PaddedRosSym)
{
fprintf(stderr, "Failed to allocate %lu bytes for padded .rossym\n", RosSymFileLength);
return 1;
}
memcpy(PaddedRosSym, RosSymSection, RosSymLength);
memset((char *) PaddedRosSym + RosSymLength, '\0', RosSymFileLength - RosSymLength);
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++)
{
if (OutRelocSection == OutSectionHeaders + Section)
{
Data = (void *) ProcessedRelocs;
}
else if (Section + 1 == OutFileHeader->NumberOfSections)
{
Data = (void *) PaddedRosSym;
}
else
{
Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
}
for (i = 0; i < OutSectionHeaders[Section].SizeOfRawData / 2; i++)
{
CheckSum += ((unsigned short*) Data)[i];
CheckSum = 0xffff & (CheckSum + (CheckSum >> 16));
}
Length += OutSectionHeaders[Section].SizeOfRawData;
}
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 (0 != OutSectionHeaders[Section].SizeOfRawData)
{
fseek(OutFile, OutSectionHeaders[Section].PointerToRawData, SEEK_SET);
if (OutRelocSection == OutSectionHeaders + Section)
{
Data = (void *) ProcessedRelocs;
}
else if (Section + 1 == OutFileHeader->NumberOfSections)
{
Data = (void *) PaddedRosSym;
}
else
{
Data = (void *) ((char *) InData + OutSectionHeaders[Section].PointerToRawData);
}
if (fwrite(Data, 1, OutSectionHeaders[Section].SizeOfRawData, OutFile) !=
OutSectionHeaders[Section].SizeOfRawData)
{
perror("Error writing section data\n");
free(PaddedRosSym);
free(OutHeader);
return 1;
}
}
}
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;
ULONG CoffsLength;
void *CoffStringBase;
ULONG CoffStringsLength;
char* path1;
char* path2;
FILE* out;
void *StringBase;
ULONG StringsLength;
ULONG StabSymbolsCount;
PROSSYM_ENTRY StabSymbols;
ULONG CoffSymbolsCount;
PROSSYM_ENTRY CoffSymbols;
ULONG MergedSymbolsCount;
PROSSYM_ENTRY MergedSymbols;
size_t FileSize;
void *FileData;
ULONG RosSymLength;
void *RosSymSection;
if (3 != argc)
{
fprintf(stderr, "Usage: rsym <exefile> <symfile>\n");
exit(1);
}
path1 = convert_path(argv[1]);
path2 = convert_path(argv[2]);
FileData = load_file ( path1, &FileSize );
if ( !FileData )
{
fprintf ( stderr, "An error occured loading '%s'\n", path1 );
exit(1);
}
/* Check if MZ header exists */
PEDosHeader = (PIMAGE_DOS_HEADER) FileData;
if (PEDosHeader->e_magic != IMAGE_DOS_MAGIC || PEDosHeader->e_lfanew == 0L)
{
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 */
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 (GetCoffInfo(FileData, PEFileHeader, PESectionHeaders, &CoffsLength, &CoffBase,
&CoffStringsLength, &CoffStringBase))
{
free(FileData);
exit(1);
}
StringBase = malloc(1 + StabStringsLength + CoffStringsLength +
(CoffsLength / sizeof(ROSSYM_ENTRY)) * (E_SYMNMLEN + 1));
if (NULL == StringBase)
{
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);
}
if (ConvertCoffs(&CoffSymbolsCount, &CoffSymbols, &StringsLength, StringBase,
CoffsLength, CoffBase, CoffStringsLength, CoffStringBase,
ImageBase, PEFileHeader, PESectionHeaders))
{
free(StabSymbols);
free(StringBase);
free(FileData);
exit(1);
}
if (MergeStabsAndCoffs(&MergedSymbolsCount, &MergedSymbols,
StabSymbolsCount, StabSymbols,
CoffSymbolsCount, CoffSymbols))
{
free(CoffSymbols);
free(StabSymbols);
free(StringBase);
free(FileData);
exit(1);
}
free(CoffSymbols);
free(StabSymbols);
RosSymLength = sizeof(SYMBOLFILE_HEADER) + MergedSymbolsCount * sizeof(ROSSYM_ENTRY)
+ StringsLength;
RosSymSection = malloc(RosSymLength);
if (NULL == RosSymSection)
{
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);
free(RosSymSection);
free(FileData);
exit(1);
}
fclose(out);
free(RosSymSection);
free(FileData);
return 0;
}
/* EOF */