mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-07-04 13:47:04 -04:00
Added rtti-reader and made various cleanups, switching to Shutdown_M for error handling
This commit is contained in:
parent
5444c9aea6
commit
6dddbd2efa
25 changed files with 771 additions and 194 deletions
|
@ -1,4 +1,5 @@
|
|||
add_subdirectory(FARDive)
|
||||
add_subdirectory(hitutils)
|
||||
add_subdirectory(iff2html)
|
||||
add_subdirectory(rtti-reader)
|
||||
add_subdirectory(tsoscan)
|
|
@ -27,23 +27,23 @@ int main(){
|
|||
return -1;
|
||||
}
|
||||
|
||||
cEdithEditorCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||
(cEdithEditorCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||
cTSOEdithEditorDCOMDirector * (__stdcall *GZDllGetGZCOMDirector)(void) =
|
||||
(cTSOEdithEditorDCOMDirector * (__stdcall *)(void)) GetProcAddress(dllmodule, "GZDllGetGZCOMDirector");
|
||||
if(GZDllGetGZCOMDirector == NULL){
|
||||
printf("TSOEdithEditor: Error: Failed to find GZDllGetGZCOMDirector() in TSOEdithEditorD.dll.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("TSOEdithEditor: Calling GZDllGetGZCOMDirector() ...\n");
|
||||
cEdithEditorCOMDirector * Edith = GZDllGetGZCOMDirector();
|
||||
cTSOEdithEditorDCOMDirector * Edith = GZDllGetGZCOMDirector();
|
||||
printf("TSOEdithEditor: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Edith);
|
||||
|
||||
while(true){
|
||||
char buffer[8];
|
||||
printf("\nCall a function (0, 1, 2, ...) or q to exit. ");
|
||||
fgets(buffer, 8, stdin);
|
||||
if(buffer[0] == 'q') break;
|
||||
Edith->Object1.vtable5[atoi(buffer)]();
|
||||
//fgets(buffer, 8, stdin);
|
||||
//if(buffer[0] == 'q') break;
|
||||
//Edith->Object1.vtable5[atoi(buffer)]();
|
||||
}
|
||||
|
||||
printf("TSOEdithEditor: Exiting.\n");
|
||||
|
|
|
@ -41,7 +41,7 @@ DECLARE_INTERFACE(cUnknownObject1)
|
|||
DWORD Unknown12;
|
||||
};
|
||||
|
||||
DECLARE_INTERFACE(cEdithEditorCOMDirector)
|
||||
DECLARE_INTERFACE(cTSOEdithEditorDCOMDirector)
|
||||
{
|
||||
void * vtable2;
|
||||
void * vtable1;
|
||||
|
|
|
@ -1 +1 @@
|
|||
gcc -Wall -Wextra -Wabi -pedantic -m32 -o TSOEdithEditor.exe TSOEdithEditor.cpp -mconsole
|
||||
gcc -Wall -Wextra -Wabi -pedantic -fno-exceptions -m32 -o TSOEdithEditor.exe TSOEdithEditor.cpp -mconsole
|
|
@ -38,7 +38,7 @@ int main(){
|
|||
cTSOSimulatorClientDCOMDirector * Simulator = GZDllGetGZCOMDirector();
|
||||
printf("TSOSimulatorClient: Finished calling GZDllGetGZCOMDirector().\nThe value returned was: %p.\n", (void *) Simulator);
|
||||
|
||||
printf("%s\n%s\n%s\n", Simulator->Object1.Strings1[0], Simulator->Object1.Strings2[0], Simulator->Object1.Strings3[0]);
|
||||
printf("%s\n%s\n%s\n", Simulator->String1.Strings1[0], Simulator->String1.Strings2[0], Simulator->String1.Strings3[0]);
|
||||
|
||||
printf("TSOSimulatorClient: Exiting.\n");
|
||||
FreeLibrary(dllmodule);
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
#include <basetyps.h>
|
||||
#pragma pack(0)
|
||||
|
||||
DECLARE_INTERFACE(cUnknownObject1)
|
||||
DECLARE_INTERFACE(cRZString)
|
||||
{
|
||||
//Base classes: cRZString, std::char_traits, ?$_String_base@DV?$__default_alloc_template@$00$0A@@std@@@std, cIGZString, cIGZUnknown
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
void * vtable5;
|
||||
|
@ -43,13 +44,14 @@ DECLARE_INTERFACE(cUnknownObject1)
|
|||
|
||||
DECLARE_INTERFACE(cTSOSimulatorClientDCOMDirector)
|
||||
{
|
||||
//Base classes: cTSOSimulatorClientDCOMDirector, cRZCOMDllDirector, cIGZCOMDirector, cIGZUnknown, cIGZFrameWorkHooks, cIGZUnknown
|
||||
void * vtable2;
|
||||
void * vtable1;
|
||||
cUnknownObject1 Object1;
|
||||
cRZString String1;
|
||||
void * vtable4;
|
||||
void * vtable3;
|
||||
cUnknownObject1 Object2;
|
||||
cUnknownObject1 Object3;
|
||||
cRZString String2;
|
||||
cRZString String3;
|
||||
|
||||
DWORD Zero1;
|
||||
DWORD Zero2;
|
||||
|
|
|
@ -1 +1 @@
|
|||
gcc -Wall -Wextra -Wabi -pedantic -m32 -o TSOSimulatorClient.exe TSOSimulatorClient.cpp -mconsole
|
||||
gcc -Wall -Wextra -Wabi -pedantic -fno-exceptions -m32 -o TSOSimulatorClient.exe TSOSimulatorClient.cpp -mconsole
|
|
@ -119,6 +119,7 @@ int main(int argc, char *argv[]){
|
|||
fseek(hFile, 0, SEEK_END);
|
||||
FileSize = ftell(hFile);
|
||||
if(FileSize < 64){
|
||||
fclose(hFile);
|
||||
printf("%sNot a valid IFF file.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
@ -126,10 +127,12 @@ int main(int argc, char *argv[]){
|
|||
|
||||
IFFData = malloc(FileSize);
|
||||
if(IFFData == NULL){
|
||||
fclose(hFile);
|
||||
printf("%sMemory for this file could not be allocated.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
if(!fread(IFFData, FileSize, 1, hFile)){
|
||||
if(fread(IFFData, 1, FileSize, hFile) != FileSize){
|
||||
fclose(hFile);
|
||||
printf("%sThe input file could not be read.", "iff2html: error: ");
|
||||
return -1;
|
||||
}
|
||||
|
|
8
Tools/rtti-reader/CMakeLists.txt
Normal file
8
Tools/rtti-reader/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
project(rtti-reader)
|
||||
|
||||
set(RTTIREADER_SOURCES
|
||||
rtti-reader.cpp
|
||||
)
|
||||
|
||||
add_executable(rtti-reader ${RTTIREADER_SOURCES})
|
524
Tools/rtti-reader/rtti-reader.cpp
Normal file
524
Tools/rtti-reader/rtti-reader.cpp
Normal file
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
rtti-reader - The Sims Online MSVC RTTI Class Hierarchy Extractor
|
||||
rtti-reader.cpp - Copyright (c) 2012 Niotso Project <http://niotso.org/>
|
||||
Author(s): Fatbag <X-Fi6@phppoll.org>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
//For information about MSVC RTTI, read:
|
||||
//<http://www.openrce.org/articles/full_view/23>
|
||||
//<https://www.blackhat.com/presentations/bh-dc-07/Sabanal_Yason/Paper/bh-dc-07-Sabanal_Yason-WP.pdf>
|
||||
|
||||
//For information about the Windows PE header, read:
|
||||
//<https://en.wikibooks.org/wiki/X86_Disassembly/Windows_Executable_Files#File_Format>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef read_int32
|
||||
#define read_uint32(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)) | ((x)[2]<<(8*2)) | ((x)[3]<<(8*3)))
|
||||
#define read_uint16(x) (unsigned)(((x)[0]<<(8*0)) | ((x)[1]<<(8*1)))
|
||||
#endif
|
||||
#ifndef write_int32
|
||||
#define write_uint32(dest, src) do { \
|
||||
(dest)[0] = ((src)&0x000000FF)>>(8*0); \
|
||||
(dest)[1] = ((src)&0x0000FF00)>>(8*1); \
|
||||
(dest)[2] = ((src)&0x00FF0000)>>(8*2); \
|
||||
(dest)[3] = ((src)&0xFF000000)>>(8*3); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
static void Shutdown_M(const char * Message);
|
||||
|
||||
struct Segment {
|
||||
size_t size, offset;
|
||||
Segment() : size(0) {}
|
||||
};
|
||||
|
||||
struct ByteReaderContext {
|
||||
size_t start, position, end;
|
||||
bool seek(size_t pos){
|
||||
if(pos > end)
|
||||
return false;
|
||||
position = pos;
|
||||
return true;
|
||||
}
|
||||
bool skip(int pos = 1){
|
||||
if(position + pos > end)
|
||||
return false;
|
||||
position += pos;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct PaddingTest {
|
||||
uint32_t A;
|
||||
uint32_t B;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct RTTIVector {
|
||||
size_t Count, SizeAllocated;
|
||||
T * Buffer;
|
||||
|
||||
void init(){
|
||||
Count = 0, SizeAllocated = sizeof(T);
|
||||
if(!(Buffer = (T*) malloc(sizeof(T))))
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
}
|
||||
T& add(){
|
||||
if((Count+1)*sizeof(T) > SizeAllocated)
|
||||
if(SizeAllocated > SIZE_MAX/2 || !(Buffer = (T*) realloc(Buffer, SizeAllocated<<=1)))
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
|
||||
return Buffer[Count++];
|
||||
}
|
||||
};
|
||||
|
||||
struct RTTITypeDescriptor {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t VTableAddress;
|
||||
uint32_t Reserved;
|
||||
} Fields;
|
||||
char * Name;
|
||||
char * UnmangledName;
|
||||
};
|
||||
|
||||
struct RTTIBaseClassDescriptor {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t TypeDescriptorAddress;
|
||||
uint32_t BaseClassCount;
|
||||
uint32_t MemberOffset;
|
||||
uint32_t COLAddressOffset;
|
||||
uint32_t VTableOffset;
|
||||
uint32_t Attributes;
|
||||
} Fields;
|
||||
RTTITypeDescriptor TD;
|
||||
};
|
||||
|
||||
struct RTTIClassHierarchyDescriptor {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t Reserved;
|
||||
uint32_t Attributes;
|
||||
uint32_t BaseClassCount;
|
||||
uint32_t BaseClassListAddress;
|
||||
} Fields;
|
||||
RTTIVector<RTTIBaseClassDescriptor> BCDL;
|
||||
};
|
||||
|
||||
struct RTTICompleteObjectLocator {
|
||||
struct {
|
||||
uint32_t Address;
|
||||
uint32_t Reserved;
|
||||
uint32_t Offset;
|
||||
uint32_t CDOffset;
|
||||
uint32_t TypeDescriptorAddress;
|
||||
uint32_t ClassDescriptorAddress;
|
||||
} Fields;
|
||||
uint32_t VTableAddress;
|
||||
};
|
||||
|
||||
struct RTTIClass {
|
||||
RTTIVector<RTTICompleteObjectLocator> COLL;
|
||||
RTTITypeDescriptor TD;
|
||||
RTTIClassHierarchyDescriptor CHD;
|
||||
void init(){
|
||||
COLL.init();
|
||||
CHD.BCDL.init();
|
||||
}
|
||||
bool DependsOn(const RTTIClass& X) const {
|
||||
for(uint32_t i=1; i<CHD.BCDL.Count; i++)
|
||||
if(CHD.BCDL.Buffer[i].TD.Fields.Address == X.TD.Fields.Address)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
static int Compare(const void * Aptr, const void * Bptr){
|
||||
const RTTIClass& A = *reinterpret_cast<const RTTIClass*>(Aptr);
|
||||
const RTTIClass& B = *reinterpret_cast<const RTTIClass*>(Bptr);
|
||||
|
||||
if(A.DependsOn(B)) return 1; //If A depends on B, A > B
|
||||
if(B.DependsOn(A)) return -1; //If B depends on A, B > A
|
||||
return strcmp(A.TD.UnmangledName, B.TD.UnmangledName);
|
||||
}
|
||||
};
|
||||
|
||||
struct PEFile {
|
||||
static PEFile * ptr;
|
||||
FILE * hFile;
|
||||
uint8_t * Data;
|
||||
Segment rdata, data;
|
||||
ByteReaderContext brc;
|
||||
|
||||
PEFile(const char * filename) : Data(NULL) {
|
||||
PEFile::ptr = this;
|
||||
|
||||
hFile = fopen(filename, "rb");
|
||||
if(!hFile)
|
||||
Shutdown_M("The specified input file does not exist or could not be opened for reading");
|
||||
|
||||
fseek(hFile, 0, SEEK_END);
|
||||
size_t FileSize = ftell(hFile);
|
||||
if(FileSize < 64)
|
||||
Shutdown_M("Not a valid Windows PE file");
|
||||
fseek(hFile, 0, SEEK_SET);
|
||||
|
||||
Data = (uint8_t*) malloc(FileSize);
|
||||
if(!Data)
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
if(fread(Data, 1, FileSize, hFile) != FileSize)
|
||||
Shutdown_M("Failed to read input file");
|
||||
|
||||
fclose(hFile);
|
||||
|
||||
brc.start = brc.position = 0;
|
||||
brc.end = FileSize;
|
||||
}
|
||||
~PEFile(){
|
||||
if(hFile)
|
||||
fclose(hFile);
|
||||
if(Data)
|
||||
free(Data);
|
||||
}
|
||||
|
||||
inline bool seek(size_t pos, int offset = 0){
|
||||
return brc.seek(pos + offset);
|
||||
}
|
||||
|
||||
inline bool skip(size_t pos = 1, int offset = 0){
|
||||
return brc.skip(pos + offset);
|
||||
}
|
||||
int nextchar(){
|
||||
if(!brc.skip())
|
||||
return EOF;
|
||||
return Data[brc.position-1];
|
||||
}
|
||||
void lookat(Segment& segment){
|
||||
brc.start = brc.position = segment.offset;
|
||||
brc.end = segment.offset + segment.size;
|
||||
}
|
||||
|
||||
uint32_t read32(){
|
||||
return brc.skip(4) ? read_uint32(Data+brc.position-4) : -1;
|
||||
}
|
||||
uint16_t read16(){
|
||||
return brc.skip(2) ? read_uint16(Data+brc.position-2) : -1;
|
||||
}
|
||||
size_t strlen(){
|
||||
size_t i = (size_t)-1;
|
||||
int byte;
|
||||
do {
|
||||
byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return -1;
|
||||
i++;
|
||||
} while(byte);
|
||||
skip(-(int)i-1); //Seek back
|
||||
return i;
|
||||
}
|
||||
bool strcpy(char * dest){
|
||||
int i = 0;
|
||||
do {
|
||||
int byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return false;
|
||||
*dest = (char) byte;
|
||||
i--;
|
||||
} while(*dest++);
|
||||
skip(i); //Seek back
|
||||
return true;
|
||||
}
|
||||
int strcmp(const char * data){
|
||||
int i = 0;
|
||||
int byte;
|
||||
do {
|
||||
byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return -1;
|
||||
i--;
|
||||
} while(*data++ && (char)byte == *(data-1));
|
||||
skip(i); //Seek back
|
||||
return byte - *(data-1);
|
||||
}
|
||||
enum { Parse_QuestionMark = 1};
|
||||
bool memfind(const char * data, size_t size, int MemParse = 0){
|
||||
size_t i = 0;
|
||||
do {
|
||||
int byte = nextchar();
|
||||
if(byte == EOF)
|
||||
return false;
|
||||
else if((char)byte != data[i] && (!MemParse || data[i] != '?')){
|
||||
skip(-(int)i);
|
||||
i = 0;
|
||||
} else i++;
|
||||
} while(i<size);
|
||||
skip(-(int)i); //Seek back
|
||||
return true;
|
||||
}
|
||||
|
||||
bool find32(uint32_t address){
|
||||
char buffer[4];
|
||||
write_uint32(buffer, address);
|
||||
return memfind(buffer, 4);
|
||||
}
|
||||
|
||||
bool GenericFill(uint8_t *ptr, size_t count){
|
||||
const size_t padding = offsetof(PaddingTest,B)-offsetof(PaddingTest,A);
|
||||
count -= padding;
|
||||
if(count > brc.end - brc.position)
|
||||
return false;
|
||||
|
||||
uint32_t *field = reinterpret_cast<uint32_t*>(ptr);
|
||||
*field = brc.position; //The Address field always comes first
|
||||
|
||||
do {
|
||||
ptr += padding; count -= padding;
|
||||
field = reinterpret_cast<uint32_t*>(ptr);
|
||||
*field = read32();
|
||||
} while(count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool Fill(T& context) {
|
||||
return GenericFill(reinterpret_cast<uint8_t*>(&context.Fields), sizeof(context.Fields));
|
||||
}
|
||||
};
|
||||
|
||||
PEFile * PEFile::ptr;
|
||||
|
||||
static void Shutdown_M(const char * Message){
|
||||
fprintf(stderr, "rtti-reader: error: %s.", Message);
|
||||
if(PEFile::ptr)
|
||||
PEFile::ptr->~PEFile();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
unsigned i;
|
||||
const char * InFile, * BaseName;
|
||||
|
||||
if(argc != 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")){
|
||||
printf("Usage: rtti-reader infile\n"
|
||||
"Extract class information from an EXE or DLL using MSVC RTTI.\n"
|
||||
"\n"
|
||||
"Report bugs to <X-Fi6@phppoll.org>.\n"
|
||||
"rtti-reader is maintained by the Niotso project.\n"
|
||||
"Home page: <http://www.niotso.org/>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
InFile = argv[1];
|
||||
|
||||
int slash;
|
||||
for(i=0, slash=-1; InFile[i]; i++)
|
||||
if(InFile[i] == '/' || InFile[i] == '\\') slash = i;
|
||||
BaseName = InFile + slash + 1;
|
||||
|
||||
PEFile DLL(InFile);
|
||||
if(DLL.read16() != 0x5A4D) //"MZ"
|
||||
Shutdown_M("Not a valid Windows PE file");
|
||||
|
||||
DLL.seek(60);
|
||||
DLL.seek(DLL.read32(), 6); unsigned SegmentCount = DLL.read16();
|
||||
DLL.skip(12); unsigned OptionalHeaderSize = DLL.read16();
|
||||
DLL.skip(30); unsigned ImageBase = DLL.read32();
|
||||
DLL.skip(OptionalHeaderSize, -32);
|
||||
|
||||
for(i=0; i<SegmentCount; i++){
|
||||
if(!DLL.strcmp(".rdata")){
|
||||
DLL.skip(8); DLL.rdata.size = DLL.read32();
|
||||
DLL.rdata.offset = DLL.read32();
|
||||
DLL.skip(24);
|
||||
} else if(!DLL.strcmp(".data")){
|
||||
DLL.skip(8); DLL.data.size = DLL.read32();
|
||||
DLL.data.offset = DLL.read32();
|
||||
DLL.skip(24);
|
||||
} else DLL.skip(40);
|
||||
}
|
||||
if(DLL.rdata.size == 0)
|
||||
Shutdown_M("Missing .rdata segment");
|
||||
else if(DLL.data.size == 0)
|
||||
Shutdown_M("Missing .data segment");
|
||||
else if(DLL.rdata.size > UINT_MAX-DLL.rdata.offset || DLL.rdata.size+DLL.rdata.offset > DLL.brc.end)
|
||||
Shutdown_M(".rdata segment is invalid");
|
||||
else if(DLL.data.size > UINT_MAX-DLL.data.offset || DLL.data.size+DLL.data.offset > DLL.brc.end)
|
||||
Shutdown_M(".data segment is invalid");
|
||||
|
||||
printf("\n****\n** [ 1 of 2] RTTI Report for %s\n****\n", BaseName);
|
||||
|
||||
RTTIVector<RTTIClass> RCL;
|
||||
RCL.init();
|
||||
|
||||
DLL.lookat(DLL.data);
|
||||
unsigned TotalClassCount = 0;
|
||||
while(DLL.skip(8) && DLL.memfind(".?AV", 4, PEFile::Parse_QuestionMark)){
|
||||
TotalClassCount++;
|
||||
size_t length = DLL.strlen();
|
||||
if(length == (unsigned)-1)
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
size_t TDAddress = DLL.brc.position + ImageBase - 8, datapos = DLL.brc.position + length + 1;
|
||||
DLL.lookat(DLL.rdata);
|
||||
|
||||
RTTIClass * RCPointer = NULL;
|
||||
|
||||
for(size_t rdatapos = DLL.brc.position + 12;
|
||||
DLL.seek(rdatapos) && DLL.find32(TDAddress); rdatapos += 4, DLL.lookat(DLL.rdata)){
|
||||
//Find all complete object locators that belong to this class
|
||||
rdatapos = DLL.brc.position;
|
||||
if(!DLL.skip(4))
|
||||
continue;
|
||||
size_t CDAddress = DLL.read32() - ImageBase;
|
||||
if(CDAddress < DLL.brc.start || CDAddress > DLL.brc.end-4)
|
||||
continue; //This was a base class descriptor
|
||||
|
||||
//Add this COL to our respective RTTIClass
|
||||
bool newclass = false;
|
||||
if(RCPointer == NULL){
|
||||
//This is a new class; add it to the RCL
|
||||
newclass = true;
|
||||
RTTIClass& RC = RCL.add();
|
||||
RCPointer = &RC;
|
||||
RC.init();
|
||||
}
|
||||
RTTIClass& RC = *RCPointer;
|
||||
|
||||
RTTICompleteObjectLocator& COL = RC.COLL.add();
|
||||
|
||||
DLL.seek(rdatapos,-12);
|
||||
size_t COLAddress = DLL.brc.position + ImageBase;
|
||||
if(!DLL.Fill(COL))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
DLL.lookat(DLL.rdata);
|
||||
COL.VTableAddress = (DLL.find32(COLAddress)) ? DLL.brc.position + ImageBase : (uint32_t)-1;
|
||||
|
||||
if(newclass){
|
||||
if(!DLL.seek(COL.Fields.ClassDescriptorAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
RTTIClassHierarchyDescriptor& CHD = RC.CHD;
|
||||
if(!DLL.Fill(CHD))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
if(!DLL.seek(CHD.Fields.BaseClassListAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
size_t bcdlpos;
|
||||
for(i=0, bcdlpos = DLL.brc.position; i<CHD.Fields.BaseClassCount; i++, bcdlpos+=4){
|
||||
DLL.lookat(DLL.rdata);
|
||||
if(!DLL.seek(bcdlpos))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
uint32_t BCDAddress = DLL.read32();
|
||||
if(!DLL.seek(BCDAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
RTTIBaseClassDescriptor& BCD = CHD.BCDL.add();
|
||||
if(!DLL.Fill(BCD))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
DLL.lookat(DLL.data);
|
||||
if(!DLL.seek(BCD.Fields.TypeDescriptorAddress - ImageBase))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
if(!DLL.Fill(BCD.TD))
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
|
||||
length = DLL.strlen();
|
||||
if(length == (unsigned)-1)
|
||||
Shutdown_M("Unexpectedly reached end of binary");
|
||||
BCD.TD.Name = (char*) malloc(length+1);
|
||||
BCD.TD.UnmangledName = (char*) malloc(length+1-6);
|
||||
if(!BCD.TD.Name || !BCD.TD.UnmangledName)
|
||||
Shutdown_M("Failed to allocate memory");
|
||||
DLL.strcpy(BCD.TD.Name);
|
||||
for(size_t j=0; j<length-6; j++){
|
||||
char c = BCD.TD.Name[j+4];
|
||||
BCD.TD.UnmangledName[j] = (
|
||||
(c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
|
||||
(c >= '0' && c <= '9') || c == '_')
|
||||
? c : ' ';
|
||||
}
|
||||
BCD.TD.UnmangledName[length-6] = '\0';
|
||||
|
||||
if(newclass){
|
||||
newclass = false;
|
||||
memcpy(&RC.TD, &BCD.TD, sizeof(RTTITypeDescriptor));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DLL.lookat(DLL.data);
|
||||
DLL.seek(datapos);
|
||||
}
|
||||
|
||||
for (i=0; i<RCL.Count; i++){
|
||||
RTTIClass& RC = RCL.Buffer[i];
|
||||
RTTIClassHierarchyDescriptor& CHD = RC.CHD;
|
||||
printf("\nClass %s (mangled: %s)\n", RC.TD.UnmangledName, RC.TD.Name);
|
||||
printf(" * Class Hierarchy Descriptor: (Address %08X)\n", CHD.Fields.Address + ImageBase);
|
||||
printf(" * Reserved: %u\n", CHD.Fields.Reserved);
|
||||
printf(" * Attributes: %u\n", CHD.Fields.Attributes);
|
||||
printf(" * Base class count: %u\n", CHD.Fields.BaseClassCount);
|
||||
printf(" * Base class list address: %08X\n", CHD.Fields.BaseClassListAddress);
|
||||
for(uint32_t j=0; j<CHD.Fields.BaseClassCount; j++){
|
||||
RTTIBaseClassDescriptor& BCD = CHD.BCDL.Buffer[j];
|
||||
printf(" * Base class descriptor #%u: (Address %08X)\n", j, BCD.Fields.Address + ImageBase);
|
||||
printf(" * Base class count: %u\n", BCD.Fields.BaseClassCount);
|
||||
printf(" * Member offset: %d\n", BCD.Fields.MemberOffset);
|
||||
printf(" * COL address offset: %d\n", BCD.Fields.COLAddressOffset);
|
||||
printf(" * v-table offset: %d\n", BCD.Fields.VTableOffset);
|
||||
printf(" * Attributes: %u\n", BCD.Fields.Attributes);
|
||||
printf(" * Type descriptor: (Address %08X)\n", BCD.Fields.TypeDescriptorAddress);
|
||||
printf(" * v-table address: %08X\n", BCD.TD.Fields.VTableAddress);
|
||||
printf(" * Reserved: %u\n", BCD.TD.Fields.Reserved);
|
||||
printf(" * Name: %s (mangled: %s)\n", BCD.TD.UnmangledName, BCD.TD.Name);
|
||||
}
|
||||
for(uint32_t j=0; j<RC.COLL.Count; j++){
|
||||
RTTICompleteObjectLocator& COL = RC.COLL.Buffer[j];
|
||||
printf(" * Complete object locator #%u: (Address %08X)\n", j, COL.Fields.Address + ImageBase);
|
||||
printf(" * Reserved: %u\n", COL.Fields.Reserved);
|
||||
printf(" * Offset: %d\n", COL.Fields.Offset);
|
||||
printf(" * CD Offset: %d\n", COL.Fields.CDOffset);
|
||||
printf(" * Type descriptor address: %08X\n", COL.Fields.TypeDescriptorAddress);
|
||||
printf(" * Class descriptor address: %08X\n", COL.Fields.ClassDescriptorAddress);
|
||||
printf(" * v-table address: %08X\n", COL.VTableAddress);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n****\n** [ 2 of 2 ] Class Hierarchy for %s\n****\n", BaseName);
|
||||
|
||||
qsort(RCL.Buffer, RCL.Count, sizeof(RTTIClass), RTTIClass::Compare);
|
||||
|
||||
for(i=0; i<RCL.Count; i++){
|
||||
RTTIClass& RC = RCL.Buffer[i];
|
||||
printf("\nclass %s", RC.TD.UnmangledName);
|
||||
if(RC.CHD.BCDL.Count > 1){
|
||||
//The first BCD always refers to the class itself, e.g. class A "depends on class A".
|
||||
printf(" : %s", RC.CHD.BCDL.Buffer[1].TD.UnmangledName);
|
||||
for(uint32_t j=2; j<RC.CHD.BCDL.Count; j++)
|
||||
printf(", %s", RC.CHD.BCDL.Buffer[j].TD.UnmangledName);
|
||||
}
|
||||
printf(";");
|
||||
}
|
||||
|
||||
printf("\n\nCompleted RTTI report.\nDependencies provided for %u of %u classes.\n", RCL.Count, TotalClassCount);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -24,7 +24,7 @@
|
|||
#include <iff/iff.h>
|
||||
#include "tsoscan.h"
|
||||
|
||||
void print_usage(){
|
||||
static void print_usage(){
|
||||
printf("Usage: tsoscan [-f] [-o outfile] indir1 [indir2 [...]]\n"
|
||||
"Generate a statistical HTML page based on a number of IFF files.\n"
|
||||
"Use -f to force overwriting without confirmation.\n"
|
||||
|
@ -43,7 +43,7 @@ int main(int argc, char *argv[]){
|
|||
FILE *OutFile;
|
||||
|
||||
if(!stats_create(&Stats)){
|
||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ int main(int argc, char *argv[]){
|
|||
unsigned DirStartIndex;
|
||||
|
||||
if(dir == NULL){
|
||||
printf("%sUnable to open the specified directory '%s'. Skipping.\n", TSOSCAN_WARNING, CmdArgs->InDirs[i]);
|
||||
fprintf(stderr, "%sUnable to open the specified directory '%s'. Skipping.\n", TSOSCAN_WARNING, CmdArgs->InDirs[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ int main(int argc, char *argv[]){
|
|||
rewinddir(dir);
|
||||
Files = realloc(Files, FileCount*sizeof(char**));
|
||||
if(Files == NULL){
|
||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ int main(int argc, char *argv[]){
|
|||
int pathlen = strlen(entry->d_name);
|
||||
Files[DirStartIndex] = malloc(dirlen+pathlen+2);
|
||||
if(Files[DirStartIndex] == NULL){
|
||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -126,7 +126,7 @@ int main(int argc, char *argv[]){
|
|||
|
||||
file = fopen(Files[i], "rb");
|
||||
if(file == NULL){
|
||||
printf("%sUnable to open the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
fprintf(stderr, "%sUnable to open the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
continue;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
|
@ -135,11 +135,11 @@ int main(int argc, char *argv[]){
|
|||
|
||||
data = malloc(FileSize);
|
||||
if(data == NULL){
|
||||
printf("%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if(!fread(data, FileSize, 1, file)){
|
||||
printf("%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
if(fread(data, 1, FileSize, file) != FileSize){
|
||||
fprintf(stderr, "%sUnable to read the specified file '%s'. Skipping.\n", TSOSCAN_WARNING, Files[i]);
|
||||
free(data);
|
||||
fclose(file);
|
||||
continue;
|
||||
|
@ -147,7 +147,7 @@ int main(int argc, char *argv[]){
|
|||
fclose(file);
|
||||
|
||||
if(!iff_create(&iff)){
|
||||
printf("%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate memory for the specified files.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if(!iff_read_header(&iff, data, FileSize) || !iff_enumerate_chunks(&iff, data+64, FileSize-64)){
|
||||
|
@ -168,7 +168,7 @@ int main(int argc, char *argv[]){
|
|||
for(ChunkIndex = 0, ChunkData = iff.Chunks; ChunkIndex < iff.ChunkCount; ChunkIndex++, ChunkData++){
|
||||
unsigned version = stats_get_version(ChunkData->Type, ChunkData->Data);
|
||||
if(!stats_version_increment(&Stats, ChunkData->Type, version)){
|
||||
printf("%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
fprintf(stderr, "%sUnable to allocate enough memory.\n", TSOSCAN_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ int main(int argc, char *argv[]){
|
|||
}
|
||||
OutFile = fopen(CmdArgs->OutFile, "wb");
|
||||
if(OutFile == NULL){
|
||||
printf("%sThe output file '%s' could not be opened for writing.", TSOSCAN_ERROR, CmdArgs->OutFile);
|
||||
fprintf(stderr, "%sThe output file '%s' could not be opened for writing.", TSOSCAN_ERROR, CmdArgs->OutFile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue