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

1019 lines
22 KiB
C++

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
dc.cpp
Abstract:
Command line utility for dumping importing information from DLL's
and executables.
Command Line Options:
/v Verbose mode
/s:Func Only display functions matching search string "Func"
/o:File Send output to File
/f Sort by function, not by module.
History:
05/10/2000 t-michkr Created
--*/
#include <windows.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
// For some reason, this is needed to compile in
// the sdktools tree.
#define strdup _strdup
#define stricmp _stricmp
#define strnicmp _strnicmp
// Structure containing all info relevent to an imported function.
struct SFunction
{
// The name this function is imported by.
char* m_szName;
// Ordinal number, Win3.1 compatibility.
int m_iOrdinal;
// Lookup index into a DLL's export table
// for quick patching.
int m_iHint;
// Starting address of the function.
DWORD m_dwAddress;
// Whether or not it is a delayed import.
bool m_fDelayedImport;
// Forwarded function name
char* m_szForward;
// Link to next function
SFunction* m_pNext;
SFunction()
{
m_szName = m_szForward = 0;
m_iOrdinal = m_iHint = -1;
m_dwAddress = static_cast<DWORD>(-1);
m_fDelayedImport = false;
m_pNext = 0;
}
};
// A module used by the executable (ie, DLL's)
struct SModule
{
// The name of this module
char* m_szName;
// All functions imported from this module
SFunction* m_pFunctions;
// Link to next module
SModule* m_pNext;
SModule()
{
m_szName = 0;
m_pFunctions = 0;
m_pNext = 0;
}
};
// All modules imported by the executable.
SModule* g_pModules = 0;
void InsertFunctionSorted(SModule* pMod, SFunction* pFunc)
{
// Special case, insert at front
if(pMod->m_pFunctions == 0
|| stricmp(pMod->m_pFunctions->m_szName, pFunc->m_szName) > 0)
{
pFunc->m_pNext = pMod->m_pFunctions;
pMod->m_pFunctions = pFunc;
return;
}
SFunction* pfPrev = pMod->m_pFunctions;
SFunction* pfTemp = pMod->m_pFunctions->m_pNext;
while(pfTemp)
{
if(stricmp(pfTemp->m_szName, pFunc->m_szName) > 0)
{
pFunc->m_pNext = pfTemp;
pfPrev->m_pNext = pFunc;
return;
}
pfPrev = pfTemp;
pfTemp = pfTemp->m_pNext;
}
// Insert at end.
pFunc->m_pNext = 0;
pfPrev->m_pNext = pFunc;
}
void InsertModuleSorted(SModule* pMod)
{
// Special case, insert at front
if(g_pModules == 0
|| stricmp(g_pModules->m_szName, pMod->m_szName) > 0)
{
pMod->m_pNext = g_pModules;
g_pModules = pMod;
return;
}
SModule* pmPrev = g_pModules;
SModule* pmTemp = g_pModules->m_pNext;
while(pmTemp)
{
if(stricmp(pmTemp->m_szName, pMod->m_szName) > 0)
{
pMod->m_pNext = pmTemp;
pmPrev->m_pNext = pMod;
return;
}
pmPrev = pmTemp;
pmTemp = pmTemp->m_pNext;
}
// Insert at end.
pMod->m_pNext = 0;
pmPrev->m_pNext = pMod;
}
// Print a message about the last error that occurred.
void PrintLastError()
{
// Get the message string
void* pvMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<PTSTR>(&pvMsgBuf),0, 0);
// Print it.
fprintf(stderr, "%s\n", pvMsgBuf);
// Free the buffer.
LocalFree(pvMsgBuf);
}
/*************************************************************************
* LinkName2Name
*
*************************************************************************/
void
LinkName2Name(
char* szLinkName,
char* szName)
{
/*
* the link name is expected like ?Function@Class@@Params
* to be converted to Class::Function
*/
static CHAR arrOperators[][8] =
{
"",
"",
"new",
"delete",
"=",
">>",
"<<",
"!",
"==",
"!="
};
DWORD dwCrr = 0;
DWORD dwCrrFunction = 0;
DWORD dwCrrClass = 0;
DWORD dwSize;
BOOL fIsCpp = FALSE;
BOOL fHasClass = FALSE;
BOOL fIsContructor = FALSE;
BOOL fIsDestructor = FALSE;
BOOL fIsOperator = FALSE;
DWORD dwOperatorIndex = 0;
char szFunction[1024];
char szClass[1024];
if (*szLinkName == '@')
szLinkName++;
dwSize = lstrlen(szLinkName);
/*
* skip '?'
*/
while (dwCrr < dwSize) {
if (szLinkName[dwCrr] == '?') {
dwCrr++;
fIsCpp = TRUE;
}
break;
}
/*
* check to see if this is a special function (like ??0)
*/
if (fIsCpp) {
if (szLinkName[dwCrr] == '?') {
dwCrr++;
/*
* the next digit should tell as the function type
*/
if (isdigit(szLinkName[dwCrr])) {
switch (szLinkName[dwCrr]) {
case '0':
fIsContructor = TRUE;
break;
case '1':
fIsDestructor = TRUE;
break;
default:
fIsOperator = TRUE;
dwOperatorIndex = szLinkName[dwCrr] - '0';
break;
}
dwCrr++;
}
}
}
/*
* get the function name
*/
while (dwCrr < dwSize) {
if (szLinkName[dwCrr] != '@') {
szFunction[dwCrrFunction] = szLinkName[dwCrr];
dwCrrFunction++;
dwCrr++;
} else {
break;
}
}
szFunction[dwCrrFunction] = '\0';
if (fIsCpp) {
/*
* skip '@'
*/
if (dwCrr < dwSize) {
if (szLinkName[dwCrr] == '@') {
dwCrr++;
}
}
/*
* get the class name (if any)
*/
while (dwCrr < dwSize) {
if (szLinkName[dwCrr] != '@') {
fHasClass = TRUE;
szClass[dwCrrClass] = szLinkName[dwCrr];
dwCrrClass++;
dwCrr++;
} else {
break;
}
}
szClass[dwCrrClass] = '\0';
}
/*
* print the new name
*/
if (fIsContructor) {
sprintf(szName, "%s::%s", szFunction, szFunction);
} else if (fIsDestructor) {
sprintf(szName, "%s::~%s", szFunction, szFunction);
} else if (fIsOperator) {
sprintf(szName, "%s::operator %s", szFunction, arrOperators[dwOperatorIndex]);
} else if (fHasClass) {
sprintf(szName, "%s::%s", szClass, szFunction);
} else {
sprintf(szName, "%s", szFunction);
}
}
// Get function forwarding information for
// imported functions.
// This is done by loading the module and sniffing
// its export table.
bool GetForwardFunctions(SModule* pModule)
{
// Open the DLL module.
char szFileName[1024];
char* pstr;
// Search the path and windows directories for it.
if(SearchPath(0, pModule->m_szName, 0, 1024, szFileName, &pstr)==0)
return false;
HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ,
0, OPEN_EXISTING, 0, 0);
if(hFile == INVALID_HANDLE_VALUE)
{
PrintLastError();
return false;
}
HANDLE hMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
if(hMap == 0)
{
PrintLastError();
return false;
}
void* pvFileBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if(!pvFileBase)
{
PrintLastError();
return false;
}
// Get the MS-DOS compatible header
PIMAGE_DOS_HEADER pidh = reinterpret_cast<PIMAGE_DOS_HEADER>(pvFileBase);
if(pidh->e_magic != IMAGE_DOS_SIGNATURE)
{
fprintf(stderr, "File is not a valid executable\n");
return false;
}
// Get the NT header
PIMAGE_NT_HEADERS pinth = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<DWORD>(pvFileBase) + pidh->e_lfanew);
if(pinth->Signature != IMAGE_NT_SIGNATURE)
{
// Not a valid Win32 executable, may be a Win16 or OS/2 exe
fprintf(stderr, "File is not a valid executable\n");
return false;
}
// Get the other headers
PIMAGE_FILE_HEADER pifh = &pinth->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = &pinth->OptionalHeader;
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);
// If no exports, we're done.
if(pioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size == 0)
return true;
DWORD dwVAImageDir =
pioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
// Locate the section with this image directory.
for(int i = 0; i < pifh->NumberOfSections; i++)
{
if( (dwVAImageDir >= pish[i].VirtualAddress) &&
(dwVAImageDir < (pish[i].VirtualAddress + pish[i].SizeOfRawData)))
{
pish = &pish[i];
break;
}
}
if(i == pifh->NumberOfSections)
{
fprintf(stderr, "Could not locate export directory section\n");
return false;
}
DWORD dwBase = reinterpret_cast<DWORD>(pvFileBase) +
pish->PointerToRawData - pish->VirtualAddress;
PIMAGE_EXPORT_DIRECTORY pied =
reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(dwBase + dwVAImageDir);
DWORD* pdwNames = reinterpret_cast<DWORD*>(dwBase +
pied->AddressOfNames);
WORD* pwOrdinals = reinterpret_cast<WORD*>(dwBase +
pied->AddressOfNameOrdinals);
DWORD* pdwAddresses = reinterpret_cast<DWORD*>(dwBase +
pied->AddressOfFunctions);
for(unsigned hint = 0; hint < pied->NumberOfNames; hint++)
{
char* szFunction = reinterpret_cast<PSTR>(dwBase + pdwNames[hint]);
// Duck out early if this function isn't used in the executable.
SFunction* pFunc = pModule->m_pFunctions;
while(pFunc)
{
if(strcmp(pFunc->m_szName, szFunction)==0)
break;
pFunc = pFunc->m_pNext;
}
if(pFunc == 0)
continue;
int ordinal = pied->Base + static_cast<DWORD>(pwOrdinals[hint]);
DWORD dwAddress = pdwAddresses[ordinal-pied->Base];
// Check if this function has been forwarded to another DLL
if( ((dwAddress) >= dwVAImageDir) &&
((dwAddress) <
(dwVAImageDir + pioh->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size)))
{
char* szForward = reinterpret_cast<char*>(dwBase + dwAddress);
pFunc->m_szForward = strdup(szForward);
}
}
UnmapViewOfFile(pvFileBase);
CloseHandle(hMap);
CloseHandle(hFile);
return true;
}
// Look through the import directory, and build a list of all imported functions
bool ParseImportDirectory(PIMAGE_FILE_HEADER pifh, PIMAGE_OPTIONAL_HEADER pioh,
PIMAGE_SECTION_HEADER pish, void* pvFileBase,
bool fDelayed)
{
// Get which directory we want (normal imports or delayed imports)
DWORD dwDir = (fDelayed) ?
IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT : IMAGE_DIRECTORY_ENTRY_IMPORT;
// Bail if no imports
if(pioh->DataDirectory[dwDir].Size == 0)
return true;
// Locate the import directory in the image.
PIMAGE_SECTION_HEADER pishImportDirectory = 0;
DWORD dwVAImageDir = pioh->DataDirectory[dwDir].VirtualAddress;
for(int i = 0; i < pifh->NumberOfSections; i++)
{
if((dwVAImageDir >= pish[i].VirtualAddress) &&
dwVAImageDir < (pish[i].VirtualAddress + pish[i].SizeOfRawData))
{
// This is it.
pishImportDirectory = &pish[i];
break;
}
}
if(pishImportDirectory == 0)
{
fprintf(stderr, "Cannot locate %s%s\n",((fDelayed) ? "delayed " : ""),
"import directory section");
return false;
}
// Get the base address for the image.
DWORD dwBase = reinterpret_cast<DWORD>(pvFileBase)
+ pishImportDirectory->PointerToRawData
- pishImportDirectory->VirtualAddress;
// Get the import descriptor array
PIMAGE_IMPORT_DESCRIPTOR piid =
reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(dwBase + dwVAImageDir);
// Loop through all imported modules
while(piid->FirstThunk || piid->OriginalFirstThunk)
{
SModule* psm = new SModule;
psm->m_szName = strdup(reinterpret_cast<char*>(dwBase + piid->Name));
// Check if it is already in the list
SModule* pTemp = g_pModules;
while(pTemp)
{
if(strcmp(pTemp->m_szName, psm->m_szName) == 0)
break;
pTemp = pTemp->m_pNext;
}
// If not, insert it
if(pTemp == 0)
{
InsertModuleSorted(psm);
}
else
{
// Otherwise, get rid of it.
pTemp = g_pModules;
while(pTemp)
{
if(strcmp(pTemp->m_szName, psm->m_szName)==0)
break;
pTemp = pTemp->m_pNext;
}
assert(pTemp);
free(psm->m_szName);
delete psm;
psm = pTemp;
}
// Get the function imports from this module.
PIMAGE_THUNK_DATA pitdf = 0;
PIMAGE_THUNK_DATA pitda = 0;
// Check for MS or Borland format
if(piid->OriginalFirstThunk)
{
// MS format, function array is in original first thunk.
pitdf = reinterpret_cast<PIMAGE_THUNK_DATA>(dwBase +
piid->OriginalFirstThunk);
// If the time stamp is set, the module has been bound,
// and first thunk is the bound address array.
if(piid->TimeDateStamp)
{
pitda = reinterpret_cast<PIMAGE_THUNK_DATA>(dwBase +
piid->FirstThunk);
}
}
else
{
// Borland format uses first thunk for function array
pitdf = reinterpret_cast<PIMAGE_THUNK_DATA>(dwBase +
piid->FirstThunk);
}
while(pitdf->u1.Ordinal)
{
SFunction* psf = new SFunction;
if(IMAGE_SNAP_BY_ORDINAL(pitdf->u1.Ordinal))
{
psf->m_iOrdinal = static_cast<int>(IMAGE_ORDINAL(pitdf->u1.Ordinal));
psf->m_iHint = -1;
char szTemp[1024];
sprintf(szTemp, "Unnamed%6d", psf->m_iOrdinal);
psf->m_szName = strdup(szTemp);
}
else
{
PIMAGE_IMPORT_BY_NAME piibn =
reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(dwBase +
(DWORD)(pitdf->u1.AddressOfData));
char* szName = reinterpret_cast<char*>(piibn->Name);
char szBuffer[512];
LinkName2Name(szName, szBuffer);
psf->m_szName = strdup(szBuffer);
psf->m_iOrdinal = -1;
psf->m_iHint = piibn->Hint;
}
psf->m_fDelayedImport = fDelayed;
psf->m_dwAddress = pitda ? (DWORD) pitda->u1.Function :
reinterpret_cast<DWORD>(INVALID_HANDLE_VALUE);
// Do a sorted insert of the function
InsertFunctionSorted(psm, psf);
// Go to next function
pitdf++;
if(pitda)
pitda++;
}
// Go to next entry
piid++;
}
return true;
}
bool GetImports(char* szExecutable)
{
// Open the file
HANDLE hFile = CreateFile(szExecutable, GENERIC_READ, FILE_SHARE_READ, 0,
OPEN_EXISTING, 0, 0);
if(hFile == INVALID_HANDLE_VALUE)
{
PrintLastError();
return false;
}
// Map this file into memory
HANDLE hMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, 0);
if(hMap == 0)
{
PrintLastError();
return false;
}
void* pvFileBase;
pvFileBase = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0);
if(pvFileBase == 0)
{
PrintLastError();
return false;
}
// Get the MS-DOS compatible header
PIMAGE_DOS_HEADER pidh = reinterpret_cast<PIMAGE_DOS_HEADER>(pvFileBase);
if(pidh->e_magic != IMAGE_DOS_SIGNATURE)
{
fprintf(stderr,"File is not a valid executable\n");
return false;
}
// Get the NT header
PIMAGE_NT_HEADERS pinth = reinterpret_cast<PIMAGE_NT_HEADERS>(
reinterpret_cast<DWORD>(pvFileBase) + pidh->e_lfanew);
if(pinth->Signature != IMAGE_NT_SIGNATURE)
{
// Not a valid Win32 executable, may be a Win16 or OS/2 exe
fprintf(stderr, "File is not a valid executable\n");
return false;
}
// Get the other headers
PIMAGE_FILE_HEADER pifh = &pinth->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = &pinth->OptionalHeader;
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);
// Get normal imports
if(!ParseImportDirectory(pifh, pioh, pish, pvFileBase, false))
{
return false;
}
// Get delayed imports
if(!ParseImportDirectory(pifh, pioh, pish, pvFileBase, true))
{
return false;
}
// Resolve forwarded functions
SModule* pModule = g_pModules;
while(pModule)
{
GetForwardFunctions(pModule);
pModule = pModule->m_pNext;
}
// We're done with the file.
if(!UnmapViewOfFile(pvFileBase))
{
PrintLastError();
return false;
}
CloseHandle(hMap);
CloseHandle(hFile);
return true;
}
// Return true if function name matches search string, false otherwise.
bool MatchFunction(const char* szFunc, const char* szSearch)
{
if(strcmp(szSearch, "*") == 0)
return true;
while(*szSearch != '\0' && *szFunc != '\0')
{
// If we get a ?, we don't care and move on to the next
// character.
if(*szSearch == '?')
{
szSearch++;
szFunc++;
continue;
}
// If we have a wildcard, move to next search string and search for substring
if(*szSearch == '*')
{
const char* szCurrSearch;
szSearch++;
if(*szSearch == '\0')
return true;
// Don't change starting point.
szCurrSearch = szSearch;
for(;;)
{
// We're done if we hit another wildcard
if(*szCurrSearch == '*' ||
*szCurrSearch == '?')
{
// Update the permanent search position.
szSearch = szCurrSearch;
break;
}
// At end of both strings, return true.
if((*szCurrSearch == '\0') && (*szFunc == '\0'))
return true;
// We never found it
if(*szFunc == '\0')
return false;
// If it doesn't match, start over
if(toupper(*szFunc) != toupper(*szCurrSearch))
{
// If mismatch on first character
// of search string, move to next
// character in function string.
if(szCurrSearch == szSearch)
szFunc++;
else
szCurrSearch = szSearch;
}
else
{
szFunc++;
szCurrSearch++;
}
}
}
else
{
if(toupper(*szFunc) != toupper(*szSearch))
{
return false;
}
szFunc++;
szSearch++;
}
}
if((*szFunc == 0) && ((*szSearch == '\0') || (strcmp(szSearch,"*")==0)))
return true;
else
return false;
}
void PrintModule(SModule* pMod, char* szSearch, bool fVerbose, FILE* pfOut)
{
bool fModNamePrinted = false;
SFunction* pFunc = pMod->m_pFunctions;
while(pFunc)
{
if(!MatchFunction(pFunc->m_szName, szSearch))
{
pFunc = pFunc->m_pNext;
continue;
}
if(!fModNamePrinted)
{
fModNamePrinted = true;
fprintf(pfOut, "\n%s:\n", pMod->m_szName);
if(fVerbose)
fprintf(pfOut, "%-42s%-8s%-5s%-12s%s\n", "Function", "Ordinal",
"Hint", "Address", "Delayed");
}
if(fVerbose)
{
fprintf(pfOut,"%-45s", (pFunc->m_szForward == 0)
? pFunc->m_szName : pFunc->m_szForward);
if(pFunc->m_iOrdinal==-1)
fprintf(pfOut, "%-5s", "N/A");
else
fprintf(pfOut, "%-5d", pFunc->m_iOrdinal);
if(pFunc->m_iHint == -1)
fprintf(pfOut, "%-5s", "N/A");
else
fprintf(pfOut, "%-5d", pFunc->m_iHint);
if(pFunc->m_dwAddress == static_cast<DWORD>(-1))
fprintf(pfOut, "%-12s", "Not Bound");
else
fprintf(pfOut, "%-#12x", pFunc->m_dwAddress);
fprintf(pfOut,"%s\n", pFunc->m_fDelayedImport ? "Yes" : "No");
}
else
fprintf(pfOut, "%s\n", pFunc->m_szName);
pFunc = pFunc->m_pNext;
}
}
int _cdecl main(int argc, char** argv)
{
if(argc < 2)
{
fprintf(stderr,"Usage: dc executable [/v /s: func /f]\n");
return 0;
}
// Parse command line
char* szFileName = argv[1];
if( (strnicmp(szFileName, "/?", 2) == 0) ||
(strncmp(szFileName, "/h", 2) == 0))
{
printf("Usage: dc executable [/v /s: func /f]\n");
printf("executable:\t\tName of executable file to check\n");
printf("/v:\t\t\tVerbose\n");
printf("/s: func\t\tDisplay all functions matching func search string");
printf(", * and ? allowed.\n");
printf("/f:\t\t\tDisplay alphabetically by function, not module.\n");
printf("/o: File\t\tRedirect all output to File.\n");
return 0;
}
FILE* pfOutput = 0;
// If no extension, just add .exe
if(strchr(szFileName, '.') == 0)
{
szFileName = new char[strlen(argv[1]) + 5];
strcpy(szFileName, argv[1]);
strcat(szFileName, ".exe");
}
bool fVerbose = false;
bool fUseStdout = true;
char* szSearch = "*";
bool fSortByFunction = false;
// Get flags.
for(int i = 2; i < argc; i++)
{
char* szFlag = argv[i];
if(stricmp(szFlag, "/v") == 0)
{
fVerbose = true;
}
else if(strnicmp(szFlag, "/s:", 3) == 0)
{
if((i == argc-1) && (strlen(szFlag) <= 3))
{
fprintf(stderr,"Missing search string\n");
return 0;
}
if(strlen(szFlag) > 3)
{
szSearch = strdup(&szFlag[3]);
}
else
{
szSearch = argv[i+1];
i++;
}
}
else if(stricmp(szFlag, "/f") == 0)
{
fSortByFunction = true;
}
else if( (strnicmp(szFlag, "/h",2) == 0) ||
(strnicmp(szFlag, "/?",2) == 0))
{
printf("Usage: dc executable [/v /s: func /f]\n");
printf("executable:\t\tName of executable file to check\n");
printf("/v:\t\t\tVerbose\n");
printf("/s: func\t\tDisplay all functions matching func search string");
printf(", * and ? allowed.\n");
printf("/f:\t\t\tDisplay alphabetically by function, not module.\n");
printf("/o: File\t\tRedirect all output to File.\n");
return 0;
}
else if(strnicmp(szFlag, "/o:", 3) == 0)
{
fUseStdout = false;
if( (i == argc-1) && (strlen(szFlag) <= 3))
{
fprintf(stderr, "Missing output file name\n");
return 0;
}
if(strlen(szFlag) > 3)
{
pfOutput = fopen(&szFlag[3], "wt");
}
else
{
pfOutput = fopen(argv[i+1], "wt");
i++;
}
}
else
{
fprintf(stderr,"Unknown command line option, %s\n", szFlag);
return 0;
}
}
if(fUseStdout)
pfOutput = stdout;
if(!pfOutput)
{
fprintf(stderr,"Unable to open output file\n");
return 0;
}
// We wrap this code in a try block, because
// we map the file into memory. If the file
// is invalid and if the pointers in it are garbage,
// we should get an access violation, which is caught.
try
{
if(!GetImports(szFileName))
{
return 0;
}
}
catch(...)
{
fprintf(stderr, "Invalid executable file\n");
return 0;
}
if(fSortByFunction)
{
// Create a global list of functions
SModule* pGlobal = new SModule;
pGlobal->m_szName = "All Imported Functions";
SModule* pMod = g_pModules;
while(pMod)
{
SFunction* pFunc = pMod->m_pFunctions;
while(pFunc)
{
// Create a copy of this function
// This is a shallow copy, but
// it should be ok, since we don't
// delete the original
SFunction* pNew = new SFunction;
memcpy(pNew, pFunc, sizeof(*pFunc));
InsertFunctionSorted(pGlobal, pNew);
pFunc = pFunc->m_pNext;
}
pMod = pMod->m_pNext;
}
PrintModule(pGlobal, szSearch, fVerbose, pfOutput);
}
else
{
SModule* pMod = g_pModules;
while(pMod)
{
PrintModule(pMod, szSearch, fVerbose, pfOutput);
pMod = pMod->m_pNext;
}
}
return 0;
}