mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 04:11:30 +00:00
911 lines
27 KiB
C
911 lines
27 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "rsym.h"
|
|
#include "rsym64.h"
|
|
#include "dwarf2.h"
|
|
|
|
char DoPrint = 0;
|
|
ULONG g_ehframep;
|
|
|
|
#define DPRINT if(DoPrint) printf
|
|
|
|
struct {char *name; char regnt;} regs[] =
|
|
{ {"rax", REG_RAX}, {"rdx", REG_RDX}, {"rcx", REG_RCX}, {"rbx", REG_RBX},
|
|
{"rsi", REG_RSI}, {"rdi", REG_RDI}, {"rbp", REG_RBP}, {"rsp", REG_RSP},
|
|
{"r8", REG_R8}, {"r9", REG_R9}, {"r10", REG_R10}, {"r11", REG_R11},
|
|
{"r12", REG_R12}, {"r13", REG_R13}, {"r14", REG_R14}, {"r15", REG_R15},
|
|
{"xmm0", REG_XMM0}, {"xmm1", REG_XMM1}, {"xmm2", REG_XMM2}, {"xmm3", REG_XMM3},
|
|
{"xmm4", REG_XMM4}, {"xmm5", REG_XMM5}, {"xmm6", REG_XMM6}, {"xmm7", REG_XMM7},
|
|
{"xmm8", REG_XMM8}, {"xmm9", REG_XMM9}, {"xmm10",REG_XMM10},{"xmm11",REG_XMM11},
|
|
{"xmm12",REG_XMM12},{"xmm13",REG_XMM13},{"xmm14",REG_XMM14},{"xmm15",REG_XMM15},
|
|
// "st0", "st1", "st2", "st3",
|
|
// "st4", "st5", "st6", "st7",
|
|
// "mm0", "mm1", "mm2", "mm3",
|
|
// "mm4", "mm5", "mm6", "mm7"
|
|
};
|
|
|
|
/** Functions for DWARF2 ******************************************************/
|
|
|
|
unsigned long
|
|
DwDecodeUleb128(unsigned long *pResult, char *pc)
|
|
{
|
|
unsigned long ulResult = 0;
|
|
unsigned long ulShift = 0;
|
|
unsigned char current;
|
|
unsigned long ulSize = 0;
|
|
|
|
do
|
|
{
|
|
current = pc[ulSize];
|
|
ulSize++;
|
|
ulResult |= (current & 0x7f) << ulShift;
|
|
ulShift += 7;
|
|
}
|
|
while (current & 0x80);
|
|
|
|
*pResult = ulResult;
|
|
return ulSize;
|
|
}
|
|
|
|
unsigned long
|
|
DwDecodeSleb128(long *pResult, char *pc)
|
|
{
|
|
long lResult = 0;
|
|
unsigned long ulShift = 0;
|
|
unsigned char current;
|
|
unsigned long ulSize = 0;
|
|
|
|
do
|
|
{
|
|
current = pc[ulSize];
|
|
ulSize++;
|
|
lResult |= (current & 0x7f) << ulShift;
|
|
ulShift += 7;
|
|
}
|
|
while (current & 0x80);
|
|
|
|
if (current & 0x40)
|
|
lResult |= - (1 << (ulShift));
|
|
|
|
*pResult = lResult;
|
|
|
|
return ulSize;
|
|
}
|
|
|
|
unsigned long
|
|
DwDecodeCie(PDW2CIE Cie, char *pc)
|
|
{
|
|
Cie->Length = *(ULONG*)pc;
|
|
Cie->Next = pc + 4 + Cie->Length;
|
|
Cie->CieId = *(ULONG*)(pc + 4);
|
|
Cie->Version = pc[8];
|
|
Cie->AugString = pc + 9;
|
|
Cie->AugStringLength = strlen(Cie->AugString);
|
|
pc = Cie->AugString + Cie->AugStringLength + 1;
|
|
pc += DwDecodeUleb128(&Cie->CodeAlign, pc);
|
|
pc += DwDecodeSleb128(&Cie->DataAlign, pc);
|
|
pc += DwDecodeUleb128(&Cie->ReturnAddressRegister, pc);
|
|
pc += DwDecodeUleb128(&Cie->AugLength, pc);
|
|
Cie->AugData = pc;
|
|
pc += Cie->AugLength;
|
|
Cie->Instructions = pc;
|
|
|
|
return Cie->Length + 4;
|
|
}
|
|
|
|
unsigned long
|
|
DwDecodeFde(PDW2FDE Fde, char *pc)
|
|
{
|
|
Fde->Length = *(ULONG*)pc;
|
|
Fde->Next = pc + 4 + Fde->Length;
|
|
Fde->CiePointer = pc + 4 - *(ULONG*)(pc + 4);
|
|
Fde->PcBegin = *(ULONG*)(pc + 8);
|
|
Fde->PcRange = *(ULONG*)(pc + 12);
|
|
pc += 16;
|
|
pc += DwDecodeUleb128(&Fde->AugLength, pc);
|
|
Fde->AugData = pc;
|
|
Fde->Instructions = Fde->AugData + Fde->AugLength;
|
|
|
|
return Fde->Length + 4;
|
|
}
|
|
|
|
unsigned long
|
|
DwExecIntruction(PDW2CFSTATE State, char *pc)
|
|
{
|
|
unsigned char Code;
|
|
unsigned long Length;
|
|
unsigned long PrevFramePtr = State->FramePtr;
|
|
|
|
State->Scope = 0;
|
|
State->IsUwop = 0;
|
|
State->Code = Code = *pc;
|
|
Length = 1;
|
|
if ((Code & 0xc0) == DW_CFA_advance_loc)
|
|
{
|
|
State->Code = DW_CFA_advance_loc;
|
|
State->Location += Code & 0x3f;
|
|
}
|
|
else if ((Code & 0xc0) == DW_CFA_offset)
|
|
{
|
|
State->Code = DW_CFA_offset;
|
|
State->Reg = Code & 0x3f;
|
|
Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + 1);
|
|
State->Offset *= 8; // fixme data alignment
|
|
State->IsUwop = 1;
|
|
}
|
|
else if ((Code & 0xc0) == DW_CFA_restore)
|
|
{
|
|
State->Code = DW_CFA_restore;
|
|
State->Reg = Code & 0x3f;
|
|
}
|
|
else switch (Code)
|
|
{
|
|
case DW_CFA_nop:
|
|
break;
|
|
case DW_CFA_set_loc:
|
|
Length = 9; // address
|
|
State->Location = *(DWORD*)(pc + 1);
|
|
break;
|
|
case DW_CFA_advance_loc1:
|
|
Length = 2;
|
|
State->Location += pc[1];
|
|
break;
|
|
case DW_CFA_advance_loc2:
|
|
Length = 3;
|
|
// printf("Found a DW_CFA_advance_loc2 : 0x%lx ->", *(WORD*)(pc + 1));
|
|
State->Location += *(WORD*)(pc + 1);
|
|
// printf(" 0x%lx\n", State->Location);
|
|
break;
|
|
case DW_CFA_advance_loc4:
|
|
Length = 5;
|
|
// printf("Found a DW_CFA_advance_loc4 : 0x%lx ->", *(DWORD*)(pc + 1));
|
|
State->Location += *(DWORD*)(pc + 1);
|
|
// printf(" 0x%lx\n", State->Location);
|
|
break;
|
|
case DW_CFA_offset_extended:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
Length += DwDecodeUleb128((unsigned long*)&State->Offset, pc + Length);
|
|
State->IsUwop = 1;
|
|
break;
|
|
case DW_CFA_offset_extended_sf:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
Length += DwDecodeSleb128(&State->Offset, pc + Length);
|
|
State->IsUwop = 1;
|
|
break;
|
|
case DW_CFA_restore_extended:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
break;
|
|
case DW_CFA_undefined:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
break;
|
|
case DW_CFA_same_value:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
break;
|
|
case DW_CFA_register:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
Length += DwDecodeUleb128(&State->Reg2, pc + Length);
|
|
break;
|
|
case DW_CFA_remember_state:
|
|
break;
|
|
case DW_CFA_restore_state:
|
|
break;
|
|
case DW_CFA_def_cfa:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length);
|
|
State->IsUwop = 1;
|
|
break;
|
|
case DW_CFA_def_cfa_register:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
break;
|
|
case DW_CFA_def_cfa_offset:
|
|
Length += DwDecodeUleb128((unsigned long*)&State->FramePtr, pc + Length);
|
|
State->IsUwop = 1;
|
|
break;
|
|
case DW_CFA_def_cfa_sf:
|
|
Length += DwDecodeUleb128(&State->Reg, pc + Length);
|
|
Length += DwDecodeSleb128(&State->FramePtr, pc + Length);
|
|
State->FramePtr *= 8; // data alignment
|
|
State->IsUwop = 1;
|
|
break;
|
|
case DW_CFA_GNU_args_size:
|
|
{
|
|
unsigned long argsize;
|
|
printf("Warning, DW_CFA_GNU_args_size is unimplemented\n");
|
|
Length += DwDecodeUleb128(&argsize, pc + Length);
|
|
break;
|
|
}
|
|
/* PSEH */
|
|
case 0x21:
|
|
{
|
|
unsigned long SehType;
|
|
|
|
// printf("found 0x21 at %lx\n", State->Location);
|
|
Length += DwDecodeUleb128(&SehType, pc + Length);
|
|
switch (SehType)
|
|
{
|
|
case 1: /* Begin Try */
|
|
State->TryLevel++;
|
|
if (State->TryLevel >= 20)
|
|
{
|
|
printf("WTF? Trylevel of 20 exceeded...\n");
|
|
exit(1);
|
|
}
|
|
State->SehBlock[State->TryLevel-1].BeginTry = State->Location;
|
|
// printf("Found begintry at 0x%lx\n", State->Location);
|
|
State->Scope = 1;
|
|
break;
|
|
|
|
case 2: /* End Try */
|
|
State->SehBlock[State->TryLevel-1].EndTry = State->Location;
|
|
State->Scope = 2;
|
|
break;
|
|
|
|
case 3: /* Jump target */
|
|
State->SehBlock[State->TryLevel-1].Target = State->Location;
|
|
State->Scope = 3;
|
|
break;
|
|
|
|
case 4: /* SEH End */
|
|
if (State->TryLevel == 20)
|
|
{
|
|
printf("Ooops, end of SEH with trylevel at 0!\n");
|
|
exit(1);
|
|
}
|
|
State->SehBlock[State->TryLevel-1].End = State->Location;
|
|
State->TryLevel--;
|
|
State->cScopes++;
|
|
State->Scope = 0;
|
|
break;
|
|
|
|
case 5: /* Constant filter */
|
|
{
|
|
unsigned long value;
|
|
Length += DwDecodeUleb128(&value, pc + Length);
|
|
State->SehBlock[State->TryLevel-1].Handler = value;
|
|
// printf("Found a constant filter at 0x%lx\n", State->Location);
|
|
break;
|
|
}
|
|
|
|
/* These work differently. We are in a new function.
|
|
* We have to parse a lea opcode to find the adress of
|
|
* the jump target. This is the reference to find the
|
|
* appropriate C_SCOPE_TABLE. */
|
|
case 6: /* Filter func */
|
|
// printf("Found a filter func at 0x%lx\n", State->Location);
|
|
break;
|
|
|
|
case 7: /* Finally func */
|
|
{
|
|
// printf("Found a finally func at 0x%lx\n", State->Location);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
printf("Found unknow PSEH code 0x%lx\n", SehType);
|
|
exit(1);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
fprintf(stderr, "unknown instruction 0x%x at 0x%p\n", Code, pc);
|
|
exit(1);
|
|
}
|
|
|
|
State->FramePtrDiff = State->FramePtr - PrevFramePtr;
|
|
DPRINT("@%p: code=%x, Loc=%lx, offset=%lx, reg=0x%lx:%s\n",
|
|
(void*)((ULONG)pc - g_ehframep), Code, State->Location, State->Offset, State->Reg, regs[State->Reg].name);
|
|
return Length;
|
|
}
|
|
|
|
/** Windows unwind data functions *********************************************/
|
|
|
|
ULONG
|
|
StoreUnwindCodes(PUNWIND_INFO Info, PDW2CFSTATE State, ULONG FunctionStart)
|
|
{
|
|
ULONG cCodes = 0;
|
|
ULONG AllocSize;
|
|
UNWIND_CODE Code[3];
|
|
int i;
|
|
|
|
Code[0].CodeOffset = State->Location - FunctionStart;
|
|
|
|
switch (State->Code)
|
|
{
|
|
case DW_CFA_offset:
|
|
case DW_CFA_offset_extended:
|
|
// save register at offset
|
|
Code[0].OpInfo = regs[State->Reg].regnt;
|
|
if (State->Offset <= 0x7FFF8)
|
|
{
|
|
Code[0].UnwindOp = UWOP_SAVE_NONVOL;
|
|
Code[1].FrameOffset = State->Offset / 8;
|
|
cCodes = 2;
|
|
}
|
|
else
|
|
{
|
|
Code[0].UnwindOp = UWOP_SAVE_NONVOL_FAR;
|
|
Code[1].FrameOffset = (State->Offset / 8);
|
|
Code[2].FrameOffset = (State->Offset / 8) >> 16;
|
|
cCodes = 3;
|
|
}
|
|
break;
|
|
|
|
case DW_CFA_def_cfa:
|
|
//case DW_CFA_def_cfa_register:
|
|
case DW_CFA_def_cfa_offset:
|
|
case DW_CFA_def_cfa_sf:
|
|
AllocSize = State->FramePtrDiff;
|
|
if (AllocSize <= 128)
|
|
{
|
|
Code[0].UnwindOp = UWOP_ALLOC_SMALL;
|
|
Code[0].OpInfo = (AllocSize / 8) - 1;
|
|
cCodes = 1;
|
|
}
|
|
else if (AllocSize <= 0x7FFF8)
|
|
{
|
|
Code[0].UnwindOp = UWOP_ALLOC_LARGE;
|
|
Code[0].OpInfo = 0;
|
|
Code[1].FrameOffset = AllocSize / 8;
|
|
cCodes = 2;
|
|
}
|
|
else // if (AllocSize > 0x7FFF8)
|
|
{
|
|
Code[0].UnwindOp = UWOP_ALLOC_LARGE;
|
|
Code[0].OpInfo = 1;
|
|
Code[1].FrameOffset = (USHORT)AllocSize;
|
|
Code[2].FrameOffset = (USHORT)(AllocSize >> 16);
|
|
cCodes = 3;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (Info)
|
|
{
|
|
/* Move old codes */
|
|
for (i = Info->CountOfCodes - 1; i >= 0; i--)
|
|
{
|
|
Info->UnwindCode[i + cCodes] = Info->UnwindCode[i];
|
|
}
|
|
|
|
/* Copy new codes */
|
|
for (i = 0; i < cCodes; i++)
|
|
{
|
|
Info->UnwindCode[i] = Code[i];
|
|
}
|
|
|
|
Info->CountOfCodes += cCodes;
|
|
}
|
|
|
|
return cCodes;
|
|
}
|
|
|
|
#define GetxdataSize(cFuncs, cUWOP, cScopes) \
|
|
( cFuncs * (sizeof(UNWIND_INFO) + 2 + 4 + 4) \
|
|
+ cUWOP * sizeof(UNWIND_CODE) \
|
|
+ cScopes * sizeof(C_SCOPE_TABLE_ENTRY) )
|
|
|
|
ULONG
|
|
StoreUnwindInfo(PUNWIND_INFO Info, PDW2FDE pFde, ULONG FunctionStart)
|
|
{
|
|
ULONG cbSize;
|
|
DW2CFSTATE State;
|
|
char *pInst;
|
|
ULONG c;
|
|
DW2CIE Cie;
|
|
|
|
cbSize = 4; // sizeof(UNWIND_INFO);
|
|
Info->Version = 1;
|
|
Info->Flags = 0;
|
|
Info->SizeOfProlog = 0;
|
|
Info->CountOfCodes = 0;
|
|
Info->FrameRegister = 0;
|
|
Info->FrameOffset = 0;
|
|
|
|
/* Decode the CIE */
|
|
DwDecodeCie(&Cie, pFde->CiePointer);
|
|
|
|
/* Initialize state */
|
|
State.Location = FunctionStart;
|
|
State.FramePtr = 0;
|
|
State.TryLevel = 0;
|
|
State.cScopes = 0;
|
|
|
|
/* Parse the CIE's initial instructions */
|
|
pInst = Cie.Instructions;
|
|
while (pInst < Cie.Next)
|
|
{
|
|
pInst += DwExecIntruction(&State, pInst);
|
|
}
|
|
|
|
/* Parse the FDE instructions */
|
|
pInst = pFde->Instructions;
|
|
while (pInst < pFde->Next)
|
|
{
|
|
pInst += DwExecIntruction(&State, pInst);
|
|
|
|
if (State.IsUwop)
|
|
{
|
|
c = StoreUnwindCodes(Info, &State, FunctionStart);
|
|
cbSize += c * sizeof(UNWIND_CODE);
|
|
Info->SizeOfProlog = State.Location - FunctionStart;
|
|
}
|
|
}
|
|
cbSize = ROUND_UP(cbSize, 4);
|
|
|
|
/* Do we have scope table to write? */
|
|
if (State.cScopes > 0)
|
|
{
|
|
unsigned long i;
|
|
ULONG *pExceptionHandler;
|
|
PC_SCOPE_TABLE pScopeTable;
|
|
|
|
/* Set flag for exception handler */
|
|
Info->Flags |= UNW_FLAG_EHANDLER;
|
|
|
|
/* Store address of handler and number of scope tables */
|
|
pExceptionHandler = (ULONG*)((char*)Info + cbSize);
|
|
// HACK for testing purpose
|
|
*pExceptionHandler = FunctionStart; // _C_specific_handler
|
|
|
|
pScopeTable = (PC_SCOPE_TABLE)(pExceptionHandler + 1);
|
|
pScopeTable->NumEntries = State.cScopes;
|
|
|
|
/* Store the scope table entries */
|
|
for (i = 0; i < State.cScopes; i++)
|
|
{
|
|
pScopeTable->Entry[i].Begin = State.SehBlock[i].BeginTry;
|
|
pScopeTable->Entry[i].End = State.SehBlock[i].EndTry;
|
|
pScopeTable->Entry[i].Handler = 1;//State.SehBlock[i].Handler;
|
|
pScopeTable->Entry[i].Target = State.SehBlock[i].Target;
|
|
}
|
|
|
|
/* Update size */
|
|
cbSize += 8 + State.cScopes * sizeof(C_SCOPE_TABLE_ENTRY);
|
|
}
|
|
|
|
return cbSize;
|
|
}
|
|
|
|
void
|
|
CountUnwindData(PFILE_INFO File)
|
|
{
|
|
DW2CIEFDE *p;
|
|
DW2FDE Fde;
|
|
char *pInst, *pmax;
|
|
DW2CFSTATE State;
|
|
|
|
File->cFuncs = 0;
|
|
File->cScopes = 0;
|
|
File->cUWOP = 0;
|
|
State.FramePtr = 0;
|
|
State.TryLevel = 0;
|
|
|
|
p = File->eh_frame.p;
|
|
pmax = (char*)p + File->eh_frame.psh->Misc.VirtualSize;
|
|
for (; p->Length && (char*)p < pmax; p = NextCIE(p))
|
|
{
|
|
/* Is this an FDE? */
|
|
if (p->CiePointer != 0)
|
|
{
|
|
File->cFuncs++;
|
|
DwDecodeFde(&Fde, (char*)p);
|
|
|
|
pInst = Fde.Instructions;
|
|
while (pInst < Fde.Next)
|
|
{
|
|
pInst += DwExecIntruction(&State, pInst);
|
|
File->cUWOP += StoreUnwindCodes(NULL, &State, 0);
|
|
File->cScopes += State.Scope ? 1 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int CompFunc(const void *p1, const void *p2)
|
|
{
|
|
PRUNTIME_FUNCTION prf1 = (void*)p1, prf2 = (void*)p2;
|
|
return (prf1->FunctionStart > prf2->FunctionStart ? 1 : -1);
|
|
}
|
|
|
|
void
|
|
GeneratePData(PFILE_INFO File)
|
|
{
|
|
DW2CIEFDE *p;
|
|
DW2FDE Fde;
|
|
PIMAGE_DATA_DIRECTORY Dir;
|
|
ULONG i, Offset;
|
|
void * eh_frame;
|
|
PRUNTIME_FUNCTION pdata;
|
|
ULONG xdata_va;
|
|
char *xdata_p;
|
|
ULONG cbSize;
|
|
PIMAGE_SECTION_HEADER pshp, pshx;
|
|
ULONG FileAlignment;
|
|
char *pmax;
|
|
|
|
FileAlignment = File->OptionalHeader->FileAlignment;
|
|
|
|
/* Get pointer to eh_frame section */
|
|
eh_frame = File->eh_frame.p;
|
|
g_ehframep = (ULONG)eh_frame;
|
|
|
|
/* Get sizes */
|
|
CountUnwindData(File);
|
|
// printf("cFuncs = %ld, cUWOPS = %ld, cScopes = %ld\n",
|
|
// File->cFuncs, File->cUWOP, File->cScopes);
|
|
|
|
/* Initialize section header for .pdata */
|
|
i = File->pdata.idx = File->UsedSections;
|
|
pshp = File->pdata.psh = &File->NewSectionHeaders[i];
|
|
memcpy(pshp->Name, ".pdata", 7);
|
|
pshp->Misc.VirtualSize = (File->cFuncs + 1) * sizeof(RUNTIME_FUNCTION);
|
|
pshp->VirtualAddress = File->NewSectionHeaders[i - 1].VirtualAddress +
|
|
File->NewSectionHeaders[i - 1].SizeOfRawData;
|
|
pshp->SizeOfRawData = ROUND_UP(pshp->Misc.VirtualSize, FileAlignment);
|
|
pshp->PointerToRawData = File->NewSectionHeaders[i - 1].PointerToRawData +
|
|
File->NewSectionHeaders[i - 1].SizeOfRawData;
|
|
pshp->PointerToRelocations = 0;
|
|
pshp->PointerToLinenumbers = 0;
|
|
pshp->NumberOfRelocations = 0;
|
|
pshp->NumberOfLinenumbers = 0;
|
|
pshp->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED |
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA;
|
|
|
|
/* Allocate .pdata buffer */
|
|
pdata = File->pdata.p = malloc(pshp->SizeOfRawData);
|
|
memset(File->pdata.p, 0, pshp->SizeOfRawData);
|
|
|
|
/* Init exception data dir */
|
|
Dir = &File->OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
|
|
Dir->VirtualAddress = pshp->VirtualAddress;
|
|
Dir->Size = pshp->Misc.VirtualSize;
|
|
|
|
/* Initialize section header for .xdata */
|
|
File->xdata.idx = File->pdata.idx + 1;
|
|
pshx = File->xdata.psh = &File->NewSectionHeaders[File->xdata.idx];
|
|
memcpy(pshx->Name, ".xdata", 7);
|
|
pshx->Misc.VirtualSize = GetxdataSize(File->cFuncs, File->cUWOP, File->cScopes);
|
|
pshx->VirtualAddress = pshp->VirtualAddress + pshp->SizeOfRawData;
|
|
pshx->SizeOfRawData = ROUND_UP(pshx->Misc.VirtualSize, FileAlignment);
|
|
pshx->PointerToRawData = pshp->PointerToRawData + pshp->SizeOfRawData;
|
|
pshx->PointerToRelocations = 0;
|
|
pshx->PointerToLinenumbers = 0;
|
|
pshx->NumberOfRelocations = 0;
|
|
pshx->NumberOfLinenumbers = 0;
|
|
pshx->Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_NOT_PAGED |
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA;
|
|
|
|
/* Allocate .xdata buffer */
|
|
File->xdata.p = malloc(pshx->SizeOfRawData);
|
|
memset(File->xdata.p, 0, pshx->SizeOfRawData);
|
|
|
|
i = 0;
|
|
Offset = File->eh_frame.psh->VirtualAddress;
|
|
xdata_va = pshx->VirtualAddress;
|
|
xdata_p = File->xdata.p;
|
|
pmax = (char*)eh_frame + File->eh_frame.psh->Misc.VirtualSize - 100;
|
|
|
|
for (p = eh_frame; p->Length && (char*)p < pmax; p = NextCIE(p))
|
|
{
|
|
/* Is this an FDE? */
|
|
if (p->CiePointer != 0)
|
|
{
|
|
DwDecodeFde(&Fde, (char*)p);
|
|
pdata[i].FunctionStart = Offset + 8 + Fde.PcBegin;
|
|
pdata[i].FunctionEnd = pdata[i].FunctionStart + Fde.PcRange;
|
|
pdata[i].UnwindInfo = xdata_va;
|
|
|
|
// printf("%ld: RUNTIME_FUNCTION: {0x%lx, 0x%lx, 0x%lx}\n", i, pdata[i].FunctionStart, pdata[i].FunctionEnd, pdata[i].UnwindInfo);
|
|
|
|
cbSize = StoreUnwindInfo((void*)xdata_p, &Fde, pdata[i].FunctionStart);
|
|
xdata_va += cbSize;
|
|
xdata_p += cbSize;
|
|
i++;
|
|
}
|
|
Offset += 4 + p->Length;
|
|
}
|
|
|
|
/* Sort the RUNTIME_FUNCTIONS */
|
|
qsort(pdata, i, sizeof(RUNTIME_FUNCTION), CompFunc);
|
|
|
|
}
|
|
|
|
/** Functions for COFF ********************************************************/
|
|
|
|
|
|
WORD
|
|
CalculateChecksum(DWORD Start, void *pFile, ULONG cbSize)
|
|
{
|
|
WORD *Ptr = pFile;
|
|
DWORD i;
|
|
DWORD checksum = Start;
|
|
|
|
for (i = 0; i < (cbSize + 1) / sizeof(WORD); i++)
|
|
{
|
|
checksum += Ptr[i];
|
|
checksum = (checksum + (checksum >> 16)) & 0xffff;
|
|
}
|
|
|
|
return checksum ;
|
|
}
|
|
|
|
void
|
|
WriteOutFile(FILE *handle, PFILE_INFO File)
|
|
{
|
|
int ret, Size, Pos = 0;
|
|
DWORD CheckSum;
|
|
ULONG i, Alignment;
|
|
|
|
Alignment = File->OptionalHeader->FileAlignment;
|
|
|
|
/* Update section count */
|
|
File->FileHeader->NumberOfSections = File->UsedSections + 2; // FIXME!!!
|
|
|
|
/* Update SizeOfImage */
|
|
Size = File->xdata.psh->VirtualAddress
|
|
+ File->xdata.psh->SizeOfRawData;
|
|
File->OptionalHeader->SizeOfImage = Size;
|
|
|
|
/* Recalculate checksum */
|
|
CheckSum = CalculateChecksum(0, File->FilePtr, File->HeaderSize);
|
|
for (i = 0; i < File->AllSections; i++)
|
|
{
|
|
if (File->UseSection[i])
|
|
{
|
|
Size = File->SectionHeaders[i].SizeOfRawData;
|
|
if (Size)
|
|
{
|
|
void *p;
|
|
p = File->FilePtr + File->SectionHeaders[i].PointerToRawData;
|
|
CheckSum = CalculateChecksum(CheckSum, p, Size);
|
|
}
|
|
}
|
|
}
|
|
Size = File->pdata.psh->Misc.VirtualSize;
|
|
CheckSum = CalculateChecksum(CheckSum, File->pdata.p, Size);
|
|
Size = File->xdata.psh->Misc.VirtualSize;
|
|
CheckSum = CalculateChecksum(CheckSum, File->xdata.p, Size);
|
|
CheckSum += File->HeaderSize;
|
|
CheckSum += File->pdata.psh->Misc.VirtualSize;
|
|
CheckSum += File->xdata.psh->Misc.VirtualSize;
|
|
File->OptionalHeader->CheckSum = CheckSum;
|
|
|
|
/* Write file header */
|
|
Size = File->HeaderSize;
|
|
ret = fwrite(File->DosHeader, 1, Size, handle);
|
|
Pos = Size;
|
|
|
|
/* Write Section headers */
|
|
Size = File->NewSectionHeaderSize;
|
|
ret = fwrite(File->NewSectionHeaders, 1, Size, handle);
|
|
Pos += Size;
|
|
|
|
/* Fill up to next alignement */
|
|
Size = ROUND_UP(Pos, Alignment) - Pos;
|
|
ret = fwrite(File->AlignBuf, 1, Size, handle);
|
|
Pos += Size;
|
|
|
|
/* Write sections */
|
|
for (i = 0; i < File->AllSections; i++)
|
|
{
|
|
if (File->UseSection[i])
|
|
{
|
|
void *p;
|
|
Size = File->SectionHeaders[i].SizeOfRawData;
|
|
if (Size)
|
|
{
|
|
p = File->FilePtr + File->SectionHeaders[i].PointerToRawData;
|
|
ret = fwrite(p, 1, Size, handle);
|
|
Pos += Size;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Write .pdata section */
|
|
Size = File->pdata.psh->SizeOfRawData;
|
|
ret = fwrite(File->pdata.p, 1, Size, handle);
|
|
Pos += Size;
|
|
|
|
/* Write .xdata section */
|
|
Size = File->xdata.psh->SizeOfRawData;
|
|
ret = fwrite(File->xdata.p, 1, Size, handle);
|
|
Pos += Size;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
ParsePEHeaders(PFILE_INFO File)
|
|
{
|
|
DWORD OldChecksum, Checksum;
|
|
ULONG Alignment, CurrentPos;
|
|
int i, j;
|
|
|
|
/* Check if MZ header exists */
|
|
File->DosHeader = (PIMAGE_DOS_HEADER)File->FilePtr;
|
|
if ((File->DosHeader->e_magic != IMAGE_DOS_MAGIC) ||
|
|
(File->DosHeader->e_lfanew == 0L))
|
|
{
|
|
perror("Input file is not a PE image.\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Locate PE file header */
|
|
File->FileHeader = (PIMAGE_FILE_HEADER)(File->FilePtr +
|
|
File->DosHeader->e_lfanew + sizeof(ULONG));
|
|
|
|
/* Check for x64 image */
|
|
if (File->FileHeader->Machine != IMAGE_FILE_MACHINE_AMD64)
|
|
{
|
|
perror("Input file is not an x64 image.\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Locate optional header */
|
|
File->OptionalHeader = (PIMAGE_OPTIONAL_HEADER64)(File->FileHeader + 1);
|
|
|
|
/* Check if checksum is correct */
|
|
OldChecksum = File->OptionalHeader->CheckSum;
|
|
File->OptionalHeader->CheckSum = 0;
|
|
Checksum = CalculateChecksum(0, File->FilePtr, File->cbInFileSize);
|
|
Checksum += File->cbInFileSize;
|
|
if ((Checksum & 0xffff) != (OldChecksum & 0xffff))
|
|
{
|
|
fprintf(stderr, "Input file has incorrect PE checksum: 0x%lx (calculated: 0x%lx)\n",
|
|
OldChecksum, Checksum);
|
|
// return 0;
|
|
}
|
|
|
|
/* Locate PE section headers */
|
|
File->SectionHeaders = (PIMAGE_SECTION_HEADER)((char*)File->OptionalHeader
|
|
+ File->FileHeader->SizeOfOptionalHeader);
|
|
|
|
File->HeaderSize = File->DosHeader->e_lfanew
|
|
+ sizeof(ULONG)
|
|
+ sizeof(IMAGE_FILE_HEADER)
|
|
+ File->FileHeader->SizeOfOptionalHeader;
|
|
|
|
if (!File->FileHeader->PointerToSymbolTable)
|
|
{
|
|
fprintf(stderr, "No symbol table.\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Create some shortcuts */
|
|
File->ImageBase = File->OptionalHeader->ImageBase;
|
|
File->Symbols = File->FilePtr + File->FileHeader->PointerToSymbolTable;
|
|
File->Strings = (char*)File->Symbols + File->FileHeader->NumberOfSymbols * 18;
|
|
|
|
/* Check section names */
|
|
File->AllSections = File->FileHeader->NumberOfSections;
|
|
Alignment = File->OptionalHeader->FileAlignment;
|
|
File->NewSectionHeaders = malloc((File->AllSections+2) * sizeof(IMAGE_SECTION_HEADER));
|
|
File->UsedSections = 0;
|
|
File->eh_frame.idx = -1;
|
|
|
|
/* Allocate array of chars, specifiying whether to copy the section */
|
|
File->UseSection = malloc(File->AllSections);
|
|
|
|
for (i = 0; i < File->AllSections; i++)
|
|
{
|
|
char *pName = (char*)File->SectionHeaders[i].Name;
|
|
File->UseSection[i] = 1;
|
|
|
|
/* Check for long name */
|
|
if (pName[0] == '/')
|
|
{
|
|
unsigned long index = strtoul(pName+1, 0, 10);
|
|
pName = File->Strings + index;
|
|
|
|
// Hack, simply remove all sections with long names
|
|
File->UseSection[i] = 0;
|
|
}
|
|
|
|
/* Chek if we have the eh_frame section */
|
|
if (strcmp(pName, ".eh_frame") == 0)
|
|
{
|
|
File->eh_frame.psh = &File->SectionHeaders[i];
|
|
File->eh_frame.idx = i;
|
|
File->eh_frame.p = File->FilePtr + File->eh_frame.psh->PointerToRawData;
|
|
}
|
|
|
|
/* Increase number of used sections */
|
|
if (File->UseSection[i])
|
|
File->UsedSections = i+1;
|
|
|
|
}
|
|
|
|
/* This is the actual size of the new section headers */
|
|
File->NewSectionHeaderSize =
|
|
(File->UsedSections+2) * sizeof(IMAGE_SECTION_HEADER);
|
|
|
|
/* Calculate the position to start writing the sections to */
|
|
CurrentPos = File->HeaderSize + File->NewSectionHeaderSize;
|
|
CurrentPos = ROUND_UP(CurrentPos, Alignment);
|
|
|
|
/* Create new section headers */
|
|
for (i = 0, j = 0; i < File->UsedSections; i++)
|
|
{
|
|
/* Copy section header */
|
|
File->NewSectionHeaders[j] = File->SectionHeaders[i];
|
|
|
|
/* Shall we strip the section? */
|
|
if (File->UseSection[i] == 0)
|
|
{
|
|
/* Make it a bss section */
|
|
File->NewSectionHeaders[j].PointerToRawData = 0;
|
|
File->NewSectionHeaders[j].SizeOfRawData = 0;
|
|
File->NewSectionHeaders[j].Characteristics = 0xC0500080;
|
|
}
|
|
|
|
/* Fix Offset into File */
|
|
File->NewSectionHeaders[j].PointerToRawData =
|
|
File->NewSectionHeaders[j].PointerToRawData ? CurrentPos : 0;
|
|
CurrentPos += File->NewSectionHeaders[j].SizeOfRawData;
|
|
j++;
|
|
}
|
|
|
|
if (File->eh_frame.idx == -1)
|
|
{
|
|
//fprintf(stderr, "No .eh_frame section found\n");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
char* pszInFile;
|
|
char* pszOutFile;
|
|
FILE_INFO File;
|
|
FILE* outfile;
|
|
int ret;
|
|
|
|
if (argc != 3)
|
|
{
|
|
fprintf(stderr, "Usage: rsym <exefile> <symfile>\n");
|
|
exit(1);
|
|
}
|
|
|
|
pszInFile = convert_path(argv[1]);
|
|
pszOutFile = convert_path(argv[2]);
|
|
|
|
File.FilePtr = load_file(pszInFile, &File.cbInFileSize);
|
|
if (!File.FilePtr)
|
|
{
|
|
fprintf(stderr, "An error occured loading '%s'\n", pszInFile);
|
|
exit(1);
|
|
}
|
|
|
|
ret = ParsePEHeaders(&File);
|
|
if (ret != 1)
|
|
{
|
|
free(File.FilePtr);
|
|
exit(ret == -1 ? 1 : 0);
|
|
}
|
|
|
|
File.AlignBuf = malloc(File.OptionalHeader->FileAlignment);
|
|
memset(File.AlignBuf, 0, File.OptionalHeader->FileAlignment);
|
|
|
|
GeneratePData(&File);
|
|
|
|
outfile = fopen(pszOutFile, "wb");
|
|
if (outfile == NULL)
|
|
{
|
|
perror("Cannot open output file");
|
|
free(File.FilePtr);
|
|
exit(1);
|
|
}
|
|
|
|
WriteOutFile(outfile, &File);
|
|
|
|
fclose(outfile);
|
|
|
|
return 0;
|
|
}
|