| Index: third_party/codesighs/msdump2symdb.c
|
| ===================================================================
|
| --- third_party/codesighs/msdump2symdb.c (revision 0)
|
| +++ third_party/codesighs/msdump2symdb.c (revision 0)
|
| @@ -0,0 +1,1090 @@
|
| +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
| + *
|
| + * ***** BEGIN LICENSE BLOCK *****
|
| + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
| + *
|
| + * The contents of this file are subject to the Mozilla Public License Version
|
| + * 1.1 (the "License"); you may not use this file except in compliance with
|
| + * the License. You may obtain a copy of the License at
|
| + * http://www.mozilla.org/MPL/
|
| + *
|
| + * Software distributed under the License is distributed on an "AS IS" basis,
|
| + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
| + * for the specific language governing rights and limitations under the
|
| + * License.
|
| + *
|
| + * The Original Code is msdump2symdb.c code, released
|
| + * Jan 16, 2003.
|
| + *
|
| + * The Initial Developer of the Original Code is
|
| + * Netscape Communications Corporation.
|
| + * Portions created by the Initial Developer are Copyright (C) 2002
|
| + * the Initial Developer. All Rights Reserved.
|
| + *
|
| + * Contributor(s):
|
| + * Garrett Arch Blythe, 16-January-2003
|
| + *
|
| + * Alternatively, the contents of this file may be used under the terms of
|
| + * either the GNU General Public License Version 2 or later (the "GPL"), or
|
| + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
| + * in which case the provisions of the GPL or the LGPL are applicable instead
|
| + * of those above. If you wish to allow use of your version of this file only
|
| + * under the terms of either the GPL or the LGPL, and not to allow others to
|
| + * use your version of this file under the terms of the MPL, indicate your
|
| + * decision by deleting the provisions above and replace them with the notice
|
| + * and other provisions required by the GPL or the LGPL. If you do not delete
|
| + * the provisions above, a recipient may use your version of this file under
|
| + * the terms of any one of the MPL, the GPL or the LGPL.
|
| + *
|
| + * ***** END LICENSE BLOCK ***** */
|
| +
|
| +#include <stdio.h>
|
| +#include <stdlib.h>
|
| +#include <string.h>
|
| +#include <time.h>
|
| +#include <ctype.h>
|
| +#include <errno.h>
|
| +
|
| +#define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
|
| +#define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
|
| +
|
| +
|
| +typedef struct __struct_Options
|
| +/*
|
| +** Options to control how we perform.
|
| +**
|
| +** mProgramName Used in help text.
|
| +** mInput File to read for input.
|
| +** Default is stdin.
|
| +** mInputName Name of the file.
|
| +** mOutput Output file, append.
|
| +** Default is stdout.
|
| +** mOutputName Name of the file.
|
| +** mHelp Whether or not help should be shown.
|
| +*/
|
| +{
|
| + const char* mProgramName;
|
| + FILE* mInput;
|
| + char* mInputName;
|
| + FILE* mOutput;
|
| + char* mOutputName;
|
| + int mHelp;
|
| +}
|
| +Options;
|
| +
|
| +
|
| +typedef struct __struct_Switch
|
| +/*
|
| +** Command line options.
|
| +*/
|
| +{
|
| + const char* mLongName;
|
| + const char* mShortName;
|
| + int mHasValue;
|
| + const char* mValue;
|
| + const char* mDescription;
|
| +}
|
| +Switch;
|
| +
|
| +#define DESC_NEWLINE "\n\t\t"
|
| +
|
| +static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
|
| +static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
|
| +static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
|
| +
|
| +static Switch* gSwitches[] = {
|
| + &gInputSwitch,
|
| + &gOutputSwitch,
|
| + &gHelpSwitch
|
| +};
|
| +
|
| +
|
| +typedef struct __struct_MSDump_Symbol
|
| +/*
|
| +** Struct to hold infomration on a symbol.
|
| +**
|
| +** mSize Size of the symbol once all work is complete.
|
| +** mOffset Offset of the symbol in the section.
|
| +** mName Symbolic name.
|
| +*/
|
| +{
|
| + unsigned mSize;
|
| + unsigned mOffset;
|
| + char* mName;
|
| +}
|
| +MSDump_Symbol;
|
| +
|
| +
|
| +typedef struct __struct_MSDump_Section
|
| +/*
|
| +** Struct for holding information on a section.
|
| +**
|
| +** mLength Length of the section in bytes.
|
| +** mUsed Number of bytes used in the section thus far.
|
| +** Should eventually match mLength after work is done.
|
| +** mType Type of section, as string (.data, .text, et. al.)
|
| +** mSymbols Symbols found inside the section.
|
| +** mSymbolCount Number of symbols in array.
|
| +*/
|
| +{
|
| + unsigned mLength;
|
| + unsigned mUsed;
|
| + char* mType;
|
| +
|
| + MSDump_Symbol* mSymbols;
|
| + unsigned mSymbolCount;
|
| +}
|
| +MSDump_Section;
|
| +
|
| +
|
| +typedef struct __struct_MSDump_Object
|
| +/*
|
| +** Struct for holding object's data.
|
| +*/
|
| +{
|
| + char* mObject;
|
| +
|
| + MSDump_Section* mSections;
|
| + unsigned mSectionCount;
|
| +}
|
| +MSDump_Object;
|
| +
|
| +
|
| +typedef struct __struct_MSDump_ReadState
|
| +/*
|
| +** State flags while reading the input gives us hints on what to do.
|
| +**
|
| +** mSkipLines Number of lines to skip without parsing.
|
| +** mSectionDetails Section information next, like line length.
|
| +** mCurrentObject Object file we are dealing with.
|
| +*/
|
| +{
|
| + unsigned mSkipLines;
|
| + unsigned mSectionDetails;
|
| + MSDump_Object* mCurrentObject;
|
| +}
|
| +MSDump_ReadState;
|
| +
|
| +
|
| +typedef struct __struct_MSDump_Container
|
| +/*
|
| +** Umbrella container for all data encountered.
|
| +*/
|
| +{
|
| + MSDump_ReadState mReadState;
|
| +
|
| + MSDump_Object* mObjects;
|
| + unsigned mObjectCount;
|
| +}
|
| +MSDump_Container;
|
| +
|
| +
|
| +void trimWhite(char* inString)
|
| +/*
|
| +** Remove any whitespace from the end of the string.
|
| +*/
|
| +{
|
| + int len = strlen(inString);
|
| +
|
| + while(len)
|
| + {
|
| + len--;
|
| +
|
| + if(isspace(*(inString + len)))
|
| + {
|
| + *(inString + len) = '\0';
|
| + }
|
| + else
|
| + {
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +const char* skipWhite(const char* inString)
|
| +/*
|
| +** Return pointer to first non white space character.
|
| +*/
|
| +{
|
| + const char* retval = inString;
|
| +
|
| + while('\0' != *retval && isspace(*retval))
|
| + {
|
| + retval++;
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +const char* skipNonWhite(const char* inString)
|
| +/*
|
| +** Return pointer to first white space character.
|
| +*/
|
| +{
|
| + const char* retval = inString;
|
| +
|
| + while('\0' != *retval && !isspace(*retval))
|
| + {
|
| + retval++;
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +void slash2bs(char* inString)
|
| +/*
|
| +** Change any forward slash to a backslash.
|
| +*/
|
| +{
|
| + char* slash = inString;
|
| +
|
| + while(NULL != (slash = strchr(slash, '/')))
|
| + {
|
| + *slash = '\\';
|
| + slash++;
|
| + }
|
| +}
|
| +
|
| +
|
| +const char* skipToArg(const char* inString, unsigned inArgIndex)
|
| +/*
|
| +** Return pointer either to the arg or NULL.
|
| +** 1 indexed.
|
| +*/
|
| +{
|
| + const char* retval = NULL;
|
| +
|
| + while(0 != inArgIndex && '\0' != *inString)
|
| + {
|
| + inArgIndex--;
|
| +
|
| + inString = skipWhite(inString);
|
| + if(0 != inArgIndex)
|
| + {
|
| + inString = skipNonWhite(inString);
|
| + }
|
| + }
|
| +
|
| + if('\0' != *inString)
|
| + {
|
| + retval = inString;
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +const char* getLastArg(const char* inString)
|
| +/*
|
| +** Return pointer to last arg in string.
|
| +*/
|
| +{
|
| + const char* retval = NULL;
|
| + int length = 0;
|
| + int sawString = 0;
|
| +
|
| + length = strlen(inString);
|
| + while(0 != length)
|
| + {
|
| + length--;
|
| +
|
| + if(0 == sawString)
|
| + {
|
| + if(0 == isspace(inString[length]))
|
| + {
|
| + sawString = __LINE__;
|
| + }
|
| + }
|
| + else
|
| + {
|
| + if(0 != isspace(inString[length]))
|
| + {
|
| + retval = inString + length + 1;
|
| + }
|
| + }
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +int processLine(Options* inOptions, MSDump_Container* inContainer, const char* inLine)
|
| +/*
|
| +** Handle one line at a time.
|
| +** Looking for several different types of lines.
|
| +** Ignore all other lines.
|
| +** The container is the state machine.
|
| +** returns 0 on no error.
|
| +*/
|
| +{
|
| + int retval = 0;
|
| +
|
| + /*
|
| + ** Check to see if we were expecting section details.
|
| + */
|
| + if(0 != inContainer->mReadState.mSectionDetails)
|
| + {
|
| + const char* length = NULL;
|
| + unsigned sectionIndex = 0;
|
| +
|
| + /*
|
| + ** Detail is a 1 based index....
|
| + ** Reset.
|
| + */
|
| + sectionIndex = inContainer->mReadState.mSectionDetails - 1;
|
| + inContainer->mReadState.mSectionDetails = 0;
|
| +
|
| + if(0 == strncmp(" Section length", inLine, 18))
|
| + {
|
| + const char* sectionLength = NULL;
|
| + unsigned numericLength = 0;
|
| + char* endScan = NULL;
|
| +
|
| + sectionLength = skipWhite(inLine + 18);
|
| +
|
| + errno = 0;
|
| + numericLength = strtoul(sectionLength, &endScan, 16);
|
| + if(0 == errno && endScan != sectionLength)
|
| + {
|
| + inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mLength = numericLength;
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Cannot scan for section length.");
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Cannot parse section line.");
|
| + }
|
| + }
|
| + /*
|
| + ** Check for switching object file symbols.
|
| + */
|
| + else if(0 == strncmp("Dump of file ", inLine, 13))
|
| + {
|
| + const char* dupMe = inLine + 13;
|
| + char* dup = NULL;
|
| +
|
| + dup = strdup(dupMe);
|
| + if(NULL != dup)
|
| + {
|
| + void* growth = NULL;
|
| +
|
| + trimWhite(dup);
|
| + slash2bs(dup);
|
| +
|
| +
|
| + growth = realloc(inContainer->mObjects, (inContainer->mObjectCount + 1) * sizeof(MSDump_Object));
|
| + if(NULL != growth)
|
| + {
|
| + unsigned int index = inContainer->mObjectCount;
|
| +
|
| + inContainer->mObjectCount++;
|
| + inContainer->mObjects = growth;
|
| + memset(inContainer->mObjects + index, 0, sizeof(MSDump_Object));
|
| +
|
| + inContainer->mObjects[index].mObject = dup;
|
| +
|
| + /*
|
| + ** Reset the read state for this new object.
|
| + */
|
| + memset(&inContainer->mReadState, 0, sizeof(MSDump_ReadState));
|
| +
|
| + /*
|
| + ** Record our current object file.
|
| + */
|
| + inContainer->mReadState.mCurrentObject = inContainer->mObjects + index;
|
| +
|
| + /*
|
| + ** We can skip a few lines.
|
| + */
|
| + inContainer->mReadState.mSkipLines = 4;
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, dup, "Unable to grow object array.");
|
| + free(dup);
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, dupMe, "Unable to copy string.");
|
| +
|
| + }
|
| + }
|
| + /*
|
| + ** Check for a symbol dump or a section header.
|
| + */
|
| + else if(isxdigit(*inLine) && isxdigit(*(inLine + 1)) && isxdigit(*(inLine + 2)))
|
| + {
|
| + const char* sectionString = NULL;
|
| +
|
| + /*
|
| + ** Determine the section for this line.
|
| + ** Ignore DEBUG sections.
|
| + */
|
| + sectionString = skipToArg(inLine, 3);
|
| + if(NULL != sectionString)
|
| + {
|
| + if(0 != strncmp(sectionString, "DEBUG", 5) && 0 != strncmp(sectionString, "ABS", 3) && 0 != strncmp(sectionString, "UNDEF", 5))
|
| + {
|
| + /*
|
| + ** MUST start with "SECT"
|
| + */
|
| + if(0 == strncmp(sectionString, "SECT", 4))
|
| + {
|
| + unsigned sectionIndex1 = 0;
|
| +
|
| + char *endScan = NULL;
|
| +
|
| + sectionString += 4;
|
| +
|
| + /*
|
| + ** Convert the remaining string to an index.
|
| + ** It will be 1 based.
|
| + */
|
| + errno = 0;
|
| + sectionIndex1 = strtoul(sectionString, &endScan, 16);
|
| + if(0 == errno && endScan != sectionString && 0 != sectionIndex1)
|
| + {
|
| + unsigned sectionIndex = sectionIndex1 - 1;
|
| +
|
| + /*
|
| + ** Is this a new section? Assumed to be ascending.
|
| + ** Or is this a symbol in the section?
|
| + */
|
| + if(sectionIndex1 > inContainer->mReadState.mCurrentObject->mSectionCount)
|
| + {
|
| + const char* typeArg = NULL;
|
| +
|
| + /*
|
| + ** New Section, figure out the type.
|
| + */
|
| + typeArg = skipToArg(sectionString, 5);
|
| + if(NULL != typeArg)
|
| + {
|
| + char* typeDup = NULL;
|
| +
|
| + /*
|
| + ** Skip the leading period before duping.
|
| + */
|
| + if('.' == *typeArg)
|
| + {
|
| + typeArg++;
|
| + }
|
| + typeDup = strdup(typeArg);
|
| +
|
| + if(NULL != typeDup)
|
| + {
|
| + void* moved = NULL;
|
| + char* nonWhite = NULL;
|
| +
|
| + /*
|
| + ** Terminate the duplicate after the section type.
|
| + */
|
| + nonWhite = (char*)skipNonWhite(typeDup);
|
| + if(NULL != nonWhite)
|
| + {
|
| + *nonWhite = '\0';
|
| + }
|
| +
|
| + /*
|
| + ** Create more space for the section in the object...
|
| + */
|
| + moved = realloc(inContainer->mReadState.mCurrentObject->mSections, sizeof(MSDump_Section) * sectionIndex1);
|
| + if(NULL != moved)
|
| + {
|
| + unsigned oldCount = inContainer->mReadState.mCurrentObject->mSectionCount;
|
| +
|
| + inContainer->mReadState.mCurrentObject->mSections = (MSDump_Section*)moved;
|
| + inContainer->mReadState.mCurrentObject->mSectionCount = sectionIndex1;
|
| + memset(&inContainer->mReadState.mCurrentObject->mSections[oldCount], 0, sizeof(MSDump_Section) * (sectionIndex1 - oldCount));
|
| +
|
| + /*
|
| + ** Other section details.
|
| + */
|
| + inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mType = typeDup;
|
| +
|
| +
|
| + /*
|
| + ** Mark it so that we look for the length on the next line.
|
| + ** This happens on next entry into the read state.
|
| + */
|
| + inContainer->mReadState.mSectionDetails = sectionIndex1;
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to grow for new section.");
|
| + free(typeDup);
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, typeArg, "Unable to duplicate type.");
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to determine section type.");
|
| + }
|
| +
|
| + }
|
| + else
|
| + {
|
| + const char* offsetArg = NULL;
|
| + const char* classArg = NULL;
|
| + unsigned classWords = 1;
|
| + const char* symbolArg = NULL;
|
| +
|
| + /*
|
| + ** This is an section we've seen before, and must list a symbol.
|
| + ** Figure out the things we want to know about the symbol, e.g. size.
|
| + ** We will ignore particular classes of symbols.
|
| + */
|
| +
|
| + offsetArg = skipToArg(inLine, 2);
|
| +
|
| + classArg = skipToArg(offsetArg, 4);
|
| + if(0 == strncmp(classArg, "()", 2))
|
| + {
|
| + classArg = skipToArg(classArg, 2);
|
| + }
|
| + if(0 == strncmp(classArg, ".bf or.ef", 9))
|
| + {
|
| + classWords = 2;
|
| + }
|
| +
|
| + symbolArg = skipToArg(classArg, 3 + (classWords - 1));
|
| +
|
| + /*
|
| + ** Skip particular lines/items.
|
| + */
|
| + if(
|
| + 0 != strncmp(classArg, "Label", 5) &&
|
| + 0 != strncmp(symbolArg, ".bf", 3) &&
|
| + 0 != strncmp(symbolArg, ".lf", 3) &&
|
| + 0 != strncmp(symbolArg, ".ef", 3)
|
| + )
|
| + {
|
| + char* endOffsetArg = NULL;
|
| + unsigned offset = 0;
|
| +
|
| + /*
|
| + ** Convert the offset to something meaninful (size).
|
| + */
|
| + errno = 0;
|
| + offset = strtoul(offsetArg, &endOffsetArg, 16);
|
| + if(0 == errno && endOffsetArg != offsetArg)
|
| + {
|
| + void* moved = NULL;
|
| +
|
| + /*
|
| + ** Increase the size of the symbol array in the section.
|
| + ** Assumed symbols are unique within each section.
|
| + */
|
| + moved = realloc(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols, sizeof(MSDump_Symbol) * (inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount + 1));
|
| + if(NULL != moved)
|
| + {
|
| + unsigned symIndex = 0;
|
| +
|
| + /*
|
| + ** Record symbol details.
|
| + ** Assumed symbols are encountered in order for their section (size calc depends on it).
|
| + */
|
| + symIndex = inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount;
|
| + inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount++;
|
| + inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols = (MSDump_Symbol*)moved;
|
| + memset(&inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex], 0, sizeof(MSDump_Symbol));
|
| +
|
| + inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mOffset = offset;
|
| +
|
| + /*
|
| + ** We could allocate smarter here if it ever mattered.
|
| + */
|
| + inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName = strdup(symbolArg);
|
| + if(NULL != inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName)
|
| + {
|
| + char* trim = NULL;
|
| +
|
| + trim = (char*)skipNonWhite(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName);
|
| + if(NULL != trim)
|
| + {
|
| + *trim = '\0';
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to duplicate symbol name.");
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to grow symbol array for section.");
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to convert offset to a number.");
|
| + }
|
| + }
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to determine section index.");
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "No match for section prefix.");
|
| + }
|
| + }
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inLine, "Unable to scan for section.");
|
| + }
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +void dumpCleanup(MSDump_Container* inContainer)
|
| +/*
|
| +** Attempt to be nice and free up what we have allocated.
|
| +*/
|
| +{
|
| + unsigned objectLoop = 0;
|
| + unsigned sectionLoop = 0;
|
| + unsigned symbolLoop = 0;
|
| +
|
| + for(objectLoop = 0; objectLoop < inContainer->mObjectCount; objectLoop++)
|
| + {
|
| + for(sectionLoop = 0; sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
|
| + {
|
| + for(symbolLoop = 0; symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
|
| + {
|
| + CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName);
|
| + }
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount = 0;
|
| + CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols);
|
| + CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mType);
|
| + }
|
| + inContainer->mObjects[objectLoop].mSectionCount = 0;
|
| + CLEANUP(inContainer->mObjects[objectLoop].mSections);
|
| + }
|
| + CLEANUP(inContainer->mObjects);
|
| + inContainer->mObjectCount = 0;
|
| +}
|
| +
|
| +
|
| +int qsortSymOffset(const void* in1, const void* in2)
|
| +/*
|
| +** qsort callback to sort the symbols by their offset.
|
| +*/
|
| +{
|
| + MSDump_Symbol* sym1 = (MSDump_Symbol*)in1;
|
| + MSDump_Symbol* sym2 = (MSDump_Symbol*)in2;
|
| + int retval = 0;
|
| +
|
| + if(sym1->mOffset < sym2->mOffset)
|
| + {
|
| + retval = 1;
|
| + }
|
| + else if(sym1->mOffset > sym2->mOffset)
|
| + {
|
| + retval = -1;
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +int calcContainer(Options* inOptions, MSDump_Container* inContainer)
|
| +/*
|
| +** Resposible for doing any size calculations based on the offsets known.
|
| +** After this calculation, each sections mUsed will match mSize.
|
| +** After this calculation, all symbols should know how big they are.
|
| +*/
|
| +{
|
| + int retval = 0;
|
| + unsigned objectLoop = 0;
|
| + unsigned sectionLoop = 0;
|
| + unsigned symbolLoop = 0;
|
| +
|
| +
|
| + /*
|
| + ** Need to sort all symbols by their offsets.
|
| + */
|
| + for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
|
| + {
|
| + for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
|
| + {
|
| + qsort(
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols,
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount,
|
| + sizeof(MSDump_Symbol),
|
| + qsortSymOffset
|
| + );
|
| + }
|
| + }
|
| +
|
| +
|
| + /*
|
| + ** Need to go through all symbols and calculate their size.
|
| + */
|
| + for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
|
| + {
|
| + for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
|
| + {
|
| + for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
|
| + {
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize =
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mLength -
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed -
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mOffset;
|
| +
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed +=
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize;
|
| + }
|
| + }
|
| + }
|
| +
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +int reportContainer(Options* inOptions, MSDump_Container* inContainer)
|
| +/*
|
| +** Display all symbols and their data.
|
| +** We'll use a tsv format.
|
| +*/
|
| +{
|
| + int retval = 0;
|
| + unsigned objectLoop = 0;
|
| + unsigned sectionLoop = 0;
|
| + unsigned symbolLoop = 0;
|
| + int printRes = 0;
|
| +
|
| + for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
|
| + {
|
| + for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
|
| + {
|
| + for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
|
| + {
|
| + printRes = fprintf(inOptions->mOutput, "%s\t%s\t%.8X\t%s\n",
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName,
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mType,
|
| + inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize,
|
| + inContainer->mObjects[objectLoop].mObject
|
| + );
|
| +
|
| + if(0 > printRes)
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inOptions->mOutputName, "Unable to write to file.");
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +int dump2symdb(Options* inOptions)
|
| +/*
|
| +** Convert the input into the output, respecting the options.
|
| +** Returns 0 on success.
|
| +*/
|
| +{
|
| + int retval = 0;
|
| + char lineBuffer[0x800];
|
| + MSDump_Container container;
|
| +
|
| + memset(&container, 0, sizeof(container));
|
| +
|
| + /*
|
| + ** Read the file line by line.
|
| + */
|
| + while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
|
| + {
|
| + if(0 != container.mReadState.mSkipLines)
|
| + {
|
| + container.mReadState.mSkipLines--;
|
| + continue;
|
| + }
|
| + retval = processLine(inOptions, &container, lineBuffer);
|
| + }
|
| +
|
| + /*
|
| + ** Perform whatever calculations desired.
|
| + */
|
| + if(0 == retval)
|
| + {
|
| + retval = calcContainer(inOptions, &container);
|
| + }
|
| +
|
| + /*
|
| + ** Output what we know.
|
| + */
|
| + if(0 == retval)
|
| + {
|
| + retval = reportContainer(inOptions, &container);
|
| + }
|
| +
|
| + /*
|
| + ** Cleanup what we've done.
|
| + */
|
| + dumpCleanup(&container);
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +int initOptions(Options* outOptions, int inArgc, char** inArgv)
|
| +/*
|
| +** returns int 0 if successful.
|
| +*/
|
| +{
|
| + int retval = 0;
|
| + int loop = 0;
|
| + int switchLoop = 0;
|
| + int match = 0;
|
| + const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
|
| + Switch* current = NULL;
|
| +
|
| + /*
|
| + ** Set any defaults.
|
| + */
|
| + memset(outOptions, 0, sizeof(Options));
|
| + outOptions->mProgramName = inArgv[0];
|
| + outOptions->mInput = stdin;
|
| + outOptions->mInputName = strdup("stdin");
|
| + outOptions->mOutput = stdout;
|
| + outOptions->mOutputName = strdup("stdout");
|
| +
|
| + if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
|
| + }
|
| +
|
| + /*
|
| + ** Go through and attempt to do the right thing.
|
| + */
|
| + for(loop = 1; loop < inArgc && 0 == retval; loop++)
|
| + {
|
| + match = 0;
|
| + current = NULL;
|
| +
|
| + for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
|
| + {
|
| + if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
|
| + {
|
| + match = __LINE__;
|
| + }
|
| + else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
|
| + {
|
| + match = __LINE__;
|
| + }
|
| +
|
| + if(match)
|
| + {
|
| + if(gSwitches[switchLoop]->mHasValue)
|
| + {
|
| + /*
|
| + ** Attempt to absorb next option to fullfill value.
|
| + */
|
| + if(loop + 1 < inArgc)
|
| + {
|
| + loop++;
|
| +
|
| + current = gSwitches[switchLoop];
|
| + current->mValue = inArgv[loop];
|
| + }
|
| + }
|
| + else
|
| + {
|
| + current = gSwitches[switchLoop];
|
| + }
|
| +
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if(0 == match)
|
| + {
|
| + outOptions->mHelp = __LINE__;
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
|
| + }
|
| + else if(NULL == current)
|
| + {
|
| + outOptions->mHelp = __LINE__;
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
|
| + }
|
| + else
|
| + {
|
| + /*
|
| + ** Do something based on address/swtich.
|
| + */
|
| + if(current == &gInputSwitch)
|
| + {
|
| + CLEANUP(outOptions->mInputName);
|
| + if(NULL != outOptions->mInput && stdin != outOptions->mInput)
|
| + {
|
| + fclose(outOptions->mInput);
|
| + outOptions->mInput = NULL;
|
| + }
|
| +
|
| + outOptions->mInput = fopen(current->mValue, "r");
|
| + if(NULL == outOptions->mInput)
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
|
| + }
|
| + else
|
| + {
|
| + outOptions->mInputName = strdup(current->mValue);
|
| + if(NULL == outOptions->mInputName)
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
|
| + }
|
| + }
|
| + }
|
| + else if(current == &gOutputSwitch)
|
| + {
|
| + CLEANUP(outOptions->mOutputName);
|
| + if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
|
| + {
|
| + fclose(outOptions->mOutput);
|
| + outOptions->mOutput = NULL;
|
| + }
|
| +
|
| + outOptions->mOutput = fopen(current->mValue, "a");
|
| + if(NULL == outOptions->mOutput)
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
|
| + }
|
| + else
|
| + {
|
| + outOptions->mOutputName = strdup(current->mValue);
|
| + if(NULL == outOptions->mOutputName)
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
|
| + }
|
| + }
|
| + }
|
| + else if(current == &gHelpSwitch)
|
| + {
|
| + outOptions->mHelp = __LINE__;
|
| + }
|
| + else
|
| + {
|
| + retval = __LINE__;
|
| + ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
|
| + }
|
| + }
|
| + }
|
| +
|
| + return retval;
|
| +}
|
| +
|
| +
|
| +void cleanOptions(Options* inOptions)
|
| +/*
|
| +** Clean up any open handles.
|
| +*/
|
| +{
|
| + CLEANUP(inOptions->mInputName);
|
| + if(NULL != inOptions->mInput && stdin != inOptions->mInput)
|
| + {
|
| + fclose(inOptions->mInput);
|
| + }
|
| + CLEANUP(inOptions->mOutputName);
|
| + if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
|
| + {
|
| + fclose(inOptions->mOutput);
|
| + }
|
| +
|
| + memset(inOptions, 0, sizeof(Options));
|
| +}
|
| +
|
| +
|
| +void showHelp(Options* inOptions)
|
| +/*
|
| +** Show some simple help text on usage.
|
| +*/
|
| +{
|
| + int loop = 0;
|
| + const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
|
| + const char* valueText = NULL;
|
| +
|
| + printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
|
| + printf("\n");
|
| + printf("arguments:\n");
|
| +
|
| + for(loop = 0; loop < switchCount; loop++)
|
| + {
|
| + if(gSwitches[loop]->mHasValue)
|
| + {
|
| + valueText = " <value>";
|
| + }
|
| + else
|
| + {
|
| + valueText = "";
|
| + }
|
| +
|
| + printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
|
| + printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
|
| + printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
|
| + }
|
| +
|
| + printf("This tool takes the output of \"dumpbin /symbols\" to produce a simple\n");
|
| + printf("tsv db file of symbols and their respective attributes, like size.\n");
|
| +}
|
| +
|
| +
|
| +int main(int inArgc, char** inArgv)
|
| +{
|
| + int retval = 0;
|
| + Options options;
|
| +
|
| + retval = initOptions(&options, inArgc, inArgv);
|
| + if(options.mHelp)
|
| + {
|
| + showHelp(&options);
|
| + }
|
| + else if(0 == retval)
|
| + {
|
| + retval = dump2symdb(&options);
|
| + }
|
| +
|
| + cleanOptions(&options);
|
| + return retval;
|
| +}
|
| +
|
|
|
| Property changes on: third_party/codesighs/msdump2symdb.c
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|