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 |