windows-nt/Source/XPSP1/NT/sdktools/uwdump/uwdump.c
2020-09-26 16:20:57 +08:00

744 lines
17 KiB
C

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
uwdump.c
Abstract:
This module implements a program which dumps the function table and
unwind data for a specified executable file. It is an AMD64 specific
program.
Author:
David N. Cutler (davec) 6-Feb-2001
Environment:
User mode.
Revision History:
None.
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//
// Define AMD64 exception handling structures and function prototypes.
//
// Define unwind operation codes.
//
typedef enum _UNWIND_OP_CODES {
UWOP_PUSH_NONVOL = 0,
UWOP_ALLOC_LARGE,
UWOP_ALLOC_SMALL,
UWOP_SET_FPREG,
UWOP_SAVE_NONVOL,
UWOP_SAVE_NONVOL_FAR,
UWOP_SAVE_XMM,
UWOP_SAVE_XMM_FAR,
UWOP_SAVE_XMM128,
UWOP_SAVE_XMM128_FAR,
UWOP_PUSH_MACHFRAME
} UNWIND_OP_CODES, *PUNWIND_OP_CODES;
//
// Define unwind code structure.
//
typedef union _UNWIND_CODE {
struct {
UCHAR CodeOffset;
UCHAR UnwindOp : 4;
UCHAR OpInfo : 4;
};
USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;
//
// Define unwind information flags.
//
#define UNW_FLAG_NHANDLER 0x0
#define UNW_FLAG_EHANDLER 0x1
#define UNW_FLAG_UHANDLER 0x2
#define UNW_FLAG_CHAININFO 0x4
//
// Define unwind information structure.
//
typedef struct _UNWIND_INFO {
UCHAR Version : 3;
UCHAR Flags : 5;
UCHAR SizeOfProlog;
UCHAR CountOfCodes;
UCHAR FrameRegister : 4;
UCHAR FrameOffset : 4;
UNWIND_CODE UnwindCode[1];
//
// The unwind codes are followed by an optional DWORD aligned field that
// contains the exception handler address or the address of chained unwind
// information. If an exception handler address is specified, then it is
// followed by the language specified exception handler data.
//
// union {
// ULONG ExceptionHandler;
// ULONG FunctionEntry;
// };
//
// ULONG ExceptionData[];
//
} UNWIND_INFO, *PUNWIND_INFO;
//
// Define function table entry - a function table entry is generated for
// each frame function.
//
typedef struct _RUNTIME_FUNCTION {
ULONG BeginAddress;
ULONG EndAddress;
ULONG UnwindData;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
//
// Scope table structure definition.
//
typedef struct _SCOPE_ENTRY {
ULONG BeginAddress;
ULONG EndAddress;
ULONG HandlerAddress;
ULONG JumpTarget;
} SCOPE_ENTRY;
typedef struct _SCOPE_TABLE {
ULONG Count;
struct
{
ULONG BeginAddress;
ULONG EndAddress;
ULONG HandlerAddress;
ULONG JumpTarget;
} ScopeRecord[1];
} SCOPE_TABLE, *PSCOPE_TABLE;
//
// Define register names.
//
PCHAR Register[] = {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xxm6",
"xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12",
"xmm13", "xxm14", "xmm15"};
//
// Define the sector size and header buffer.
//
#define SECTOR_SIZE 512
CHAR LocalBuffer[SECTOR_SIZE * 2];
//
// Define input file stream.
//
FILE * InputFile;
//
// This gobal indicates whether we are processing an executable or an obj.
//
BOOLEAN IsObj;
//
// Define forward referenced prototypes.
//
VOID
DumpPdata (
IN ULONG NumberOfSections,
IN PIMAGE_SECTION_HEADER SectionHeaders,
IN PIMAGE_SECTION_HEADER PdataHeader
);
VOID
DumpUData (
IN ULONG NumberOfSections,
IN PIMAGE_SECTION_HEADER SectionHeaders,
IN ULONG Virtual
);
PIMAGE_SECTION_HEADER
FindSectionHeader (
IN ULONG NumberOfSections,
IN PIMAGE_SECTION_HEADER SectionHeaders,
IN PCHAR SectionName
);
VOID
ReadData (
IN ULONG Position,
OUT PVOID Buffer,
IN ULONG Count
);
USHORT
ReadWord (
IN ULONG Position
);
ULONG
ReadDword (
IN ULONG Position
);
//
// Main program.
//
int
__cdecl
main(
int argc,
char **argv
)
{
PIMAGE_FILE_HEADER FileHeader;
PCHAR FileName;
ULONG Index;
PIMAGE_NT_HEADERS NtHeaders;
ULONG NumberOfSections;
PIMAGE_SECTION_HEADER PDataHeader;
PIMAGE_SECTION_HEADER SectionHeaders;
if (argc < 2) {
printf("no executable file specified\n");
} else {
//
// Open the input file.
//
FileName = argv[1];
InputFile = fopen(FileName, "rb");
if (InputFile != NULL) {
//
// Read the file header.
//
if (fread(&LocalBuffer[0],
sizeof(CHAR),
SECTOR_SIZE * 2,
InputFile) == (SECTOR_SIZE * 2)) {
//
// Get the NT header address.
//
NtHeaders = RtlImageNtHeader(&LocalBuffer[0]);
if (NtHeaders != NULL) {
IsObj = FALSE;
FileHeader = &NtHeaders->FileHeader;
} else {
IsObj = TRUE;
FileHeader = (PIMAGE_FILE_HEADER)LocalBuffer;
}
printf("FileHeader->Machine %d\n",FileHeader->Machine);
if (FileHeader->Machine == IMAGE_FILE_MACHINE_AMD64) {
//
// Look up the .pdata section.
//
NumberOfSections = FileHeader->NumberOfSections;
SectionHeaders =
(PIMAGE_SECTION_HEADER)((PUCHAR)(FileHeader + 1) +
FileHeader->SizeOfOptionalHeader);
PDataHeader = FindSectionHeader(NumberOfSections,
SectionHeaders,
".pdata");
if (PDataHeader != NULL) {
printf("Dumping Unwind Information for file %s\n\n", FileName);
DumpPdata(NumberOfSections,
&SectionHeaders[0],
PDataHeader);
return 0;
}
printf("no .pdata section in image\n");
} else {
printf("the specified file is not an amd64 executable\n");
}
} else {
printf("premature end of file encountered on input file\n");
}
fclose(InputFile);
} else {
printf("can't open input file %s\n", FileName);
}
}
return 0;
}
VOID
DumpPdata (
IN ULONG NumberOfSections,
IN PIMAGE_SECTION_HEADER SectionHeaders,
IN PIMAGE_SECTION_HEADER PdataHeader
)
{
RUNTIME_FUNCTION Entry;
ULONG Number;
ULONG Offset;
ULONG SectionSize;
//
// Dump a .pdata function table entry and then dump the associated
// unwind data.
//
if (IsObj == FALSE) {
SectionSize = PdataHeader->Misc.VirtualSize;
} else {
SectionSize = PdataHeader->SizeOfRawData;
}
Number = 1;
Offset = 0;
do {
//
// Read and dump the next function table entry.
//
ReadData(PdataHeader->PointerToRawData + Offset,
&Entry,
sizeof(RUNTIME_FUNCTION));
printf(".pdata entry %d 0x%08lX 0x%08lX\n",
Number,
Entry.BeginAddress,
Entry.EndAddress);
//
// Dump the unwind data assoicated with the function table entry.
//
DumpUData(NumberOfSections, SectionHeaders, Entry.UnwindData);
//
// Increment the entry number and update the offset to the next
// function table entry.
//
Number += 1;
Offset += sizeof(RUNTIME_FUNCTION);
} while (Offset < SectionSize);
//
// Function offset and size of raw data should be equal if there is
// the correct amount of data in the .pdata section.
//
if (Offset != SectionSize) {
printf("incorrect size of raw data in .pdata, 0x%lx\n",
PdataHeader->SizeOfRawData);
}
return;
}
VOID
DumpUData (
IN ULONG NumberOfSections,
IN PIMAGE_SECTION_HEADER SectionHeaders,
IN ULONG Virtual
)
{
ULONG Allocation;
ULONG Count;
ULONG Displacement;
ULONG FrameOffset = 0;
ULONG FrameRegister = 0;
ULONG Handler;
ULONG Index;
ULONG Offset;
SCOPE_ENTRY ScopeEntry;
UNWIND_CODE UnwindCode;
UNWIND_INFO UnwindInfo;
PIMAGE_SECTION_HEADER XdataHeader;
//
// Locate the section that contains the unwind data.
//
printf("\n");
printf(" Unwind data: 0x%08lX\n\n", Virtual);
if (IsObj == FALSE) {
XdataHeader = SectionHeaders;
for (Index = 0; Index < NumberOfSections; Index += 1) {
if ((XdataHeader->VirtualAddress <= Virtual) &&
(Virtual < (XdataHeader->VirtualAddress + XdataHeader->Misc.VirtualSize))) {
break;
}
XdataHeader += 1;
}
if (Index == NumberOfSections) {
printf(" unwind data address outside of image\n\n");
return;
}
Offset = Virtual -
XdataHeader->VirtualAddress +
XdataHeader->PointerToRawData;
} else {
//
// This is an .obj, so there is only one Xdata header
//
XdataHeader = FindSectionHeader(NumberOfSections,
SectionHeaders,
".xdata");
Offset = Virtual + XdataHeader->PointerToRawData;
}
//
// Read unwind information.
//
ReadData(Offset,
&UnwindInfo,
sizeof(UNWIND_INFO) - sizeof(UNWIND_CODE));
//
// Dump unwind version.
//
printf(" Unwind version: %d\n", UnwindInfo.Version);
//
// Dump unwind flags.
//
printf(" Unwind Flags: ");
if ((UnwindInfo.Flags & UNW_FLAG_EHANDLER) != 0) {
printf("EHANDLER ");
}
if ((UnwindInfo.Flags & UNW_FLAG_UHANDLER) != 0) {
printf("UHANDLER ");
}
if ((UnwindInfo.Flags & UNW_FLAG_CHAININFO) != 0) {
printf("CHAININFO");
}
if (UnwindInfo.Flags == 0) {
printf("None");
}
printf("\n");
//
// Dump size of prologue.
//
printf(" Size of prologue: 0x%02lX\n", UnwindInfo.SizeOfProlog);
//
// Dump number of unwind codes.
//
printf(" Count of codes: %d\n", UnwindInfo.CountOfCodes);
//
// Dump frame register if specified.
//
if (UnwindInfo.FrameRegister != 0) {
FrameOffset = UnwindInfo.FrameOffset * 16;
FrameRegister = UnwindInfo.FrameRegister;
printf(" Frame register: %s\n", Register[FrameRegister]);
printf(" Frame offset: 0x%lx\n", FrameOffset);
}
//
// Dump the unwind codes.
//
Offset += sizeof(UNWIND_INFO) - sizeof(UNWIND_CODE);
if (UnwindInfo.CountOfCodes != 0) {
printf(" Unwind codes:\n\n");
Count = UnwindInfo.CountOfCodes;
do {
Count -= 1;
UnwindCode.FrameOffset = ReadWord(Offset);
Offset += sizeof(USHORT);
printf(" Code offset: 0x%02lX, ", UnwindCode.CodeOffset);
switch (UnwindCode.UnwindOp) {
case UWOP_PUSH_NONVOL:
printf("PUSH_NONVOL, register=%s\n", Register[UnwindCode.OpInfo]);
break;
case UWOP_ALLOC_LARGE:
Count -= 1;
Allocation = ReadWord(Offset);
Offset += sizeof(USHORT);
if (UnwindCode.OpInfo == 0) {
Allocation *= 8;
} else {
Count -= 1;
Allocation = (Allocation << 16) + ReadWord(Offset);
Offset += sizeof(USHORT);
}
printf("ALLOC_LARGE, size=0x%lX\n", Allocation);
break;
case UWOP_ALLOC_SMALL:
Allocation = (UnwindCode.OpInfo * 8) + 8;
printf("ALLOC_SMALL, size=0x%lX\n", Allocation);
break;
case UWOP_SET_FPREG:
printf("SET_FPREG, register=%s, offset=0x%02lX\n",
Register[FrameRegister], FrameOffset);
break;
case UWOP_SAVE_NONVOL:
Count -= 1;
Displacement = ReadWord(Offset) * 8;
Offset += sizeof(USHORT);
printf("SAVE_NONVOL, register=%s offset=0x%lX\n",
Register[UnwindCode.OpInfo],
Displacement);
break;
case UWOP_SAVE_NONVOL_FAR:
Count -= 2;
Displacement = ReadWord(Offset) << 16;
Offset += sizeof(USHORT);
Displacement = Displacement + ReadWord(Offset);
Offset += sizeof(USHORT);
printf("SAVE_NONVOL_FAR, register=%s offset=0x%lX\n",
Register[UnwindCode.OpInfo],
Displacement);
break;
case UWOP_SAVE_XMM:
Count -= 1;
Displacement = ReadWord(Offset) * 8;
Offset += sizeof(USHORT);
printf("SAVE_XMM, register=%s offset=0x%lX\n",
Register[UnwindCode.OpInfo + 16],
Displacement);
break;
case UWOP_SAVE_XMM_FAR:
Count -= 2;
Displacement = ReadWord(Offset) << 16;
Offset += sizeof(USHORT);
Displacement = Displacement + ReadWord(Offset);
Offset += sizeof(USHORT);
printf("SAVE_XMM_FAR, register=%s offset=0x%lX\n",
Register[UnwindCode.OpInfo + 16],
Displacement);
break;
case UWOP_SAVE_XMM128:
Count -= 1;
Displacement = ReadWord(Offset) * 16;
Offset += sizeof(USHORT);
printf("SAVE_XMM128, register=%s offset=0x%lX\n",
Register[UnwindCode.OpInfo + 16],
Displacement);
break;
case UWOP_SAVE_XMM128_FAR:
Count -= 2;
Displacement = ReadWord(Offset) << 16;
Offset += sizeof(USHORT);
Displacement = Displacement + ReadWord(Offset);
Offset += sizeof(USHORT);
printf("SAVE_XMM128_FAR, register=%s offset=0x%lX\n",
Register[UnwindCode.OpInfo + 16],
Displacement);
break;
case UWOP_PUSH_MACHFRAME:
if (UnwindCode.OpInfo == 0) {
printf("PUSH_MACHFRAME without error code\n");
} else {
printf("PUSH_MACHFRAME with error code\n");
}
break;
}
} while (Count != 0);
}
//
// Dump exception data if there is an excpetion or termination
// handler.
//
if (((UnwindInfo.Flags & UNW_FLAG_EHANDLER) != 0) ||
((UnwindInfo.Flags & UNW_FLAG_UHANDLER) != 0)) {
if ((UnwindInfo.CountOfCodes & 1) != 0) {
Offset += sizeof(USHORT);
}
Handler = ReadDword(Offset);
Offset += sizeof(ULONG);
Count = ReadDword(Offset);
Offset += sizeof(ULONG);
printf("\n");
printf(" Language specific handler: 0x%08lX\n", Handler);
printf(" Count of scope table entries: %d\n\n", Count);
if (Count != 0) {
printf(" Begin End Handler Target\n");
do {
ReadData(Offset, &ScopeEntry, sizeof(SCOPE_ENTRY));
printf(" 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n",
ScopeEntry.BeginAddress,
ScopeEntry.EndAddress,
ScopeEntry.HandlerAddress,
ScopeEntry.JumpTarget);
Count -= 1;
Offset += sizeof(SCOPE_ENTRY);
} while (Count != 0);
}
}
printf("\n");
return;
}
PIMAGE_SECTION_HEADER
FindSectionHeader (
IN ULONG NumberOfSections,
IN PIMAGE_SECTION_HEADER SectionHeaders,
IN PCHAR SectionName
)
{
ULONG RemainingSections;
PIMAGE_SECTION_HEADER SectionHeader;
SectionHeader = SectionHeaders;
RemainingSections = NumberOfSections;
while (RemainingSections > 0) {
if (strncmp(SectionHeader->Name,
SectionName,
IMAGE_SIZEOF_SHORT_NAME) == 0) {
return SectionHeader;
}
RemainingSections -= 1;
SectionHeader += 1;
}
return NULL;
}
VOID
ReadData (
IN ULONG Position,
OUT PVOID Buffer,
IN ULONG Count
)
{
if (fseek(InputFile,
Position,
SEEK_SET) == 0) {
if (fread((PCHAR)Buffer,
1,
Count,
InputFile) == Count) {
return;
}
}
printf("premature end of file encounterd on inpout file\n");
exit(0);
}
USHORT
ReadWord (
IN ULONG Position
)
{
USHORT Buffer;
ReadData(Position, &Buffer, sizeof(USHORT));
return Buffer;
}
ULONG
ReadDword (
IN ULONG Position
)
{
ULONG Buffer;
ReadData(Position, &Buffer, sizeof(ULONG));
return Buffer;
}