Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1476)

Unified Diff: third_party/codesighs/msmap2tsv.c

Issue 93155: Capture Mozilla's codesighs, for use in executable sizing.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/codesighs/msmap.h ('k') | third_party/codesighs/nm2tsv.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/codesighs/msmap2tsv.c
===================================================================
--- third_party/codesighs/msmap2tsv.c (revision 0)
+++ third_party/codesighs/msmap2tsv.c (revision 0)
@@ -0,0 +1,2237 @@
+/* -*- 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 msmap2tsv.c code, released
+ * Oct 3, 2002.
+ *
+ * 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, 03-October-2002
+ *
+ * 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 "msmap.h"
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <imagehlp.h>
+
+#define F_DEMANGLE 1
+#define DEMANGLE_STATE_NORMAL 0
+#define DEMANGLE_STATE_QDECODE 1
+#define DEMANGLE_STATE_PROLOGUE_1 2
+#define DEMANGLE_STATE_HAVE_TYPE 3
+#define DEMANGLE_STATE_DEC_LENGTH 4
+#define DEMANGLE_STATE_HEX_LENGTH 5
+#define DEMANGLE_STATE_PROLOGUE_SECONDARY 6
+#define DEMANGLE_STATE_DOLLAR_1 7
+#define DEMANGLE_STATE_DOLLAR_2 8
+#define DEMANGLE_STATE_START 9
+#define DEMANGLE_STATE_STOP 10
+#define DEMANGLE_SAFE_CHAR(eval) (isprint(eval) ? eval : ' ')
+
+#else
+#define F_DEMANGLE 0
+#endif /* WIN32 */
+
+
+#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_SymDB_Size
+/*
+** The size of the symbol.
+** The size is nested withing a symbols structures to produce a fast
+** lookup path.
+** The objects are listed in case the client of the symdb needs to
+** match the object name in the scenario where multiple symbol
+** sizes are present.
+**
+** mSize The size of the symbol in these objects.
+** mObjects A list of objects containing said symbol.
+** mObjectCount Number of objects.
+*/
+{
+ unsigned mSize;
+ char** mObjects;
+ unsigned mObjectCount;
+}
+SymDB_Size;
+
+
+typedef struct __struct_SymDB_Section
+/*
+** Each section for a symbol has a list of sizes.
+** Should there be exactly one size for the symbol, then that
+** is the size that should be accepted.
+** If there is more than one size, then a match on the object
+** should be attempted, held withing each size.
+**
+** mName The section name.
+** mSizes The varoius sizes of the symbol in this section.
+** mSizeCount The number of available sizes.
+*/
+{
+ char* mName;
+ SymDB_Size* mSizes;
+ unsigned mSizeCount;
+}
+SymDB_Section;
+
+
+typedef struct __struct_SymDB_Symbol
+/*
+** Each symbol has at least one section.
+** The section indicates what type of symbol a client may be looking for.
+** If there is no match on the section, then the client should not trust
+** the symbdb.
+**
+** mName The mangled name of the symbol.
+** mSections Various sections this symbol belongs to.
+** mSectionCount The number of sections.
+*/
+{
+ char* mName;
+ SymDB_Section* mSections;
+ unsigned mSectionCount;
+}
+SymDB_Symbol;
+
+
+#define SYMDB_SYMBOL_GROWBY 0x1000 /* how many sybols to allocate at a time */
+
+
+typedef struct __struct_SymDB_Container
+/*
+** The symbol DB container object.
+** The goal of the symbol DB is to have exactly one SymDB_Symbol for each
+** mangled name, no matter how ever many identical mangled names there
+** are in the input.
+** The input is already expected to be well sorted, futher this leads to
+** the ability to binary search for symbol name matches.
+**
+** mSymbols The symbols.
+** mSymbolCount The number of symbols in the DB.
+** mSymbolCapacity The number of symbols we can hold (before realloc).
+*/
+{
+ SymDB_Symbol* mSymbols;
+ unsigned mSymbolCount;
+ unsigned mSymbolCapacity;
+}
+SymDB_Container;
+
+
+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.
+** mMatchModules Array of strings which the module name should match.
+** mMatchModuleCount Number of items in array.
+** mSymDBName Symbol DB filename.
+** mBatchMode Batch mode.
+** When in batch mode, the input file contains a list of
+** map files to process.
+** Normally the input file is a single map file itself.
+*/
+{
+ const char* mProgramName;
+ FILE* mInput;
+ char* mInputName;
+ FILE* mOutput;
+ char* mOutputName;
+ int mHelp;
+ char** mMatchModules;
+ unsigned mMatchModuleCount;
+ char* mSymDBName;
+ SymDB_Container* mSymDB;
+ int mBatchMode;
+}
+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 gMatchModuleSwitch = {"--match-module", "-mm", 1, NULL, "Specify a valid module name." DESC_NEWLINE "Multiple specifications allowed." DESC_NEWLINE "If a module name does not match one of the names specified then no output will occur."};
+static Switch gSymDBSwitch = {"--symdb", "-sdb", 1, NULL, "Specify a symbol tsv db input file." DESC_NEWLINE "Such a symdb is produced using the tool msdump2symdb." DESC_NEWLINE "This allows better symbol size approximations." DESC_NEWLINE "The symdb file must be pre-sorted."};
+static Switch gBatchModeSwitch = {"--batch", "-b", 0, NULL, "Runs in batch mode." DESC_NEWLINE "The input file contains a list of map files." DESC_NEWLINE "Normally the input file is a map file itself." DESC_NEWLINE "This eliminates reprocessing the symdb for multiple map files."};
+
+static Switch* gSwitches[] = {
+ &gInputSwitch,
+ &gOutputSwitch,
+ &gMatchModuleSwitch,
+ &gSymDBSwitch,
+ &gBatchModeSwitch,
+ &gHelpSwitch
+};
+
+
+typedef struct __struct_MSMap_ReadState
+/*
+** Keep track of what state we are while reading input.
+** This gives the input context in which we absorb the datum.
+*/
+{
+ int mHasModule;
+
+ int mHasTimestamp;
+
+ int mHasPreferredLoadAddress;
+
+ int mHasSegmentData;
+ int mSegmentDataSkippedLine;
+
+ int mHasPublicSymbolData;
+ int mHasPublicSymbolDataSkippedLines;
+
+ int mHasEntryPoint;
+
+ int mFoundStaticSymbols;
+}
+MSMap_ReadState;
+
+
+char* skipWhite(char* inScan)
+/*
+** Skip whitespace.
+*/
+{
+ char* retval = inScan;
+
+ while(isspace(*retval))
+ {
+ retval++;
+ }
+
+ return retval;
+}
+
+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;
+ }
+ }
+}
+
+
+char* lastWord(char* inString)
+/*
+** Finds and returns the last word in a string.
+** It is assumed no whitespace is at the end of the string.
+*/
+{
+ int mod = 0;
+ int len = strlen(inString);
+
+ while(len)
+ {
+ len--;
+ if(isspace(*(inString + len)))
+ {
+ mod = 1;
+ break;
+ }
+ }
+
+ return inString + len + mod;
+}
+
+
+MSMap_Segment* getSymbolSection(MSMap_Module* inModule, MSMap_Symbol* inoutSymbol)
+/*
+** Perform a lookup for the section of the symbol.
+** The function could cache the value.
+*/
+{
+ MSMap_Segment* retval = NULL;
+
+ if(NULL != inoutSymbol->mSection)
+ {
+ /*
+ ** Use cached value.
+ */
+ retval = inoutSymbol->mSection;
+ }
+ else
+ {
+ unsigned secLoop = 0;
+
+ /*
+ ** Go through sections in module to find the match for the symbol.
+ */
+ for(secLoop = 0; secLoop < inModule->mSegmentCount; secLoop++)
+ {
+ if(inoutSymbol->mPrefix == inModule->mSegments[secLoop].mPrefix)
+ {
+ if(inoutSymbol->mOffset >= inModule->mSegments[secLoop].mOffset)
+ {
+ if(inoutSymbol->mOffset < (inModule->mSegments[secLoop].mOffset + inModule->mSegments[secLoop].mLength))
+ {
+ /*
+ ** We have the section.
+ */
+ retval = &inModule->mSegments[secLoop];
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ ** Cache the value for next time.
+ */
+ inoutSymbol->mSection = retval;
+ }
+
+ return retval;
+}
+
+
+int readSymDB(const char* inDBName, SymDB_Container** outDB)
+/*
+** Intialize the symbol DB.
+** Only call if the symbol DB should be initialized.
+*/
+{
+ int retval = 0;
+
+ /*
+ ** Initialize out arguments.
+ */
+ if(NULL != outDB)
+ {
+ *outDB = NULL;
+ }
+
+ if(NULL != outDB && NULL != inDBName)
+ {
+ FILE* symDB = NULL;
+
+ symDB = fopen(inDBName, "r");
+ if(NULL != symDB)
+ {
+ *outDB = (SymDB_Container*)calloc(1, sizeof(SymDB_Container));
+ if(NULL != *outDB)
+ {
+ char lineBuf[0x400];
+ char* symbol = NULL;
+ char* section = NULL;
+ char* object = NULL;
+ char* length = NULL;
+ unsigned lengthNum = 0;
+ char* endLength = NULL;
+
+ /*
+ ** Read the file line by line.
+ */
+ while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), symDB))
+ {
+ trimWhite(lineBuf);
+
+ /*
+ ** Each line has four arguments. tab separated values (tsv).
+ ** Symbol
+ ** Section
+ ** Length
+ ** Object
+ */
+
+ symbol = skipWhite(lineBuf);
+ if(NULL == symbol)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+ break;
+ }
+
+ section = strchr(symbol, '\t');
+ if(NULL == section)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+ break;
+ }
+ *section = '\0';
+ section++;
+
+ length = strchr(section, '\t');
+ if(NULL == length)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+ break;
+ }
+ *length = '\0';
+ length++;
+
+ object = strchr(length, '\t');
+ if(NULL == object)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
+ break;
+ }
+ *object = '\0';
+ object++;
+
+ /*
+ ** Convert the length into a number.
+ */
+ errno = 0;
+ lengthNum = strtoul(length, &endLength, 16);
+ if(0 == errno && endLength != length)
+ {
+ SymDB_Symbol* dbSymbol = NULL;
+ SymDB_Section* dbSection = NULL;
+ SymDB_Size* dbSize = NULL;
+ char* dbObject = NULL;
+ void* moved = NULL;
+
+ /*
+ ** Are we looking at the same symbol as last line?
+ ** This assumes the symdb is pre sorted!!!
+ */
+ if(0 != (*outDB)->mSymbolCount)
+ {
+ unsigned index = (*outDB)->mSymbolCount - 1;
+
+ if(0 == strcmp((*outDB)->mSymbols[index].mName, symbol))
+ {
+ dbSymbol = &(*outDB)->mSymbols[index];
+ }
+ }
+
+ /*
+ ** May need to create symbol.
+ */
+ if(NULL == dbSymbol)
+ {
+ /*
+ ** Could be time to grow the symbol pool.
+ */
+ if((*outDB)->mSymbolCount >= (*outDB)->mSymbolCapacity)
+ {
+ moved = realloc((*outDB)->mSymbols, sizeof(SymDB_Symbol) * ((*outDB)->mSymbolCapacity + SYMDB_SYMBOL_GROWBY));
+ if(NULL != moved)
+ {
+ (*outDB)->mSymbols = (SymDB_Symbol*)moved;
+ memset(&(*outDB)->mSymbols[(*outDB)->mSymbolCapacity], 0, sizeof(SymDB_Symbol) * SYMDB_SYMBOL_GROWBY);
+ (*outDB)->mSymbolCapacity += SYMDB_SYMBOL_GROWBY;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "Unable to grow symbol DB symbol array.");
+ break;
+ }
+ }
+
+ if((*outDB)->mSymbolCount < (*outDB)->mSymbolCapacity)
+ {
+ dbSymbol = &(*outDB)->mSymbols[(*outDB)->mSymbolCount];
+ (*outDB)->mSymbolCount++;
+
+ dbSymbol->mName = strdup(symbol);
+ if(NULL == dbSymbol->mName)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
+ break;
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, symbol, "Unable to grow symbol DB for symbol.");
+ break;
+ }
+ }
+
+ /*
+ ** Assume we have the symbol.
+ **
+ ** Is this the same section as the last section in the symbol?
+ ** This assumes the symdb was presorted!!!!
+ */
+ if(0 != dbSymbol->mSectionCount)
+ {
+ unsigned index = dbSymbol->mSectionCount - 1;
+
+ if(0 == strcmp(dbSymbol->mSections[index].mName, section))
+ {
+ dbSection = &dbSymbol->mSections[index];
+ }
+ }
+
+ /*
+ ** May need to create the section.
+ */
+ if(NULL == dbSection)
+ {
+ moved = realloc(dbSymbol->mSections, sizeof(SymDB_Section) * (dbSymbol->mSectionCount + 1));
+ if(NULL != moved)
+ {
+ dbSymbol->mSections = (SymDB_Section*)moved;
+ dbSection = &dbSymbol->mSections[dbSymbol->mSectionCount];
+ dbSymbol->mSectionCount++;
+
+ memset(dbSection, 0, sizeof(SymDB_Section));
+
+ dbSection->mName = strdup(section);
+ if(NULL == dbSection->mName)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, section, "Unable to duplicate string.");
+ break;
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, section, "Unable to grow symbol sections for symbol DB.");
+ break;
+ }
+ }
+
+ /*
+ ** Assume we have the section.
+ **
+ ** Is this the same size as the last size?
+ ** This assumes the symdb was presorted!!!
+ */
+ if(0 != dbSection->mSizeCount)
+ {
+ unsigned index = dbSection->mSizeCount - 1;
+
+ if(dbSection->mSizes[index].mSize == lengthNum)
+ {
+ dbSize = &dbSection->mSizes[index];
+ }
+ }
+
+ /*
+ ** May need to create the size in question.
+ */
+ if(NULL == dbSize)
+ {
+ moved = realloc(dbSection->mSizes, sizeof(SymDB_Size) * (dbSection->mSizeCount + 1));
+ if(NULL != moved)
+ {
+ dbSection->mSizes = (SymDB_Size*)moved;
+ dbSize = &dbSection->mSizes[dbSection->mSizeCount];
+ dbSection->mSizeCount++;
+
+ memset(dbSize, 0, sizeof(SymDB_Size));
+
+ dbSize->mSize = lengthNum;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, length, "Unable to grow symbol section sizes for symbol DB.");
+ break;
+ }
+ }
+
+ /*
+ ** Assume we have the size.
+ **
+ ** We assume a one to one correllation between size and object.
+ ** Always try to add the new object name.
+ ** As the symdb is assumed to be sorted, the object names should also be in order.
+ */
+ moved = realloc(dbSize->mObjects, sizeof(char*) * (dbSize->mObjectCount + 1));
+ if(NULL != moved)
+ {
+ dbObject = strdup(object);
+
+ dbSize->mObjects = (char**)moved;
+ dbSize->mObjects[dbSize->mObjectCount] = dbObject;
+ dbSize->mObjectCount++;
+
+ if(NULL == dbObject)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, object, "Unable to duplicate string.");
+ break;
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, object, "Unable to grow symbol section size objects for symbol DB.");
+ break;
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, length, "Unable to convert symbol DB length into a number.");
+ break;
+ }
+ }
+
+ if(0 == retval && 0 != ferror(symDB))
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "Unable to read file.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "Unable to allocate symbol DB.");
+ }
+
+ fclose(symDB);
+ symDB = NULL;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inDBName, "Unable to open symbol DB.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, "(NULL)", "Invalid arguments.");
+ }
+
+ return retval;
+}
+
+
+void cleanSymDB(SymDB_Container** inDB)
+/*
+** Free it all up.
+*/
+{
+ if(NULL != inDB && NULL != *inDB)
+ {
+ unsigned symLoop = 0;
+ unsigned secLoop = 0;
+ unsigned sizLoop = 0;
+ unsigned objLoop = 0;
+
+ for(symLoop = 0; symLoop < (*inDB)->mSymbolCount; symLoop++)
+ {
+ for(secLoop = 0; secLoop < (*inDB)->mSymbols[symLoop].mSectionCount; secLoop++)
+ {
+ for(sizLoop = 0; sizLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizeCount; sizLoop++)
+ {
+ for(objLoop = 0; objLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjectCount; objLoop++)
+ {
+ CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects[objLoop]);
+ }
+ CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects);
+ }
+ CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mName);
+ CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes);
+ }
+ CLEANUP((*inDB)->mSymbols[symLoop].mName);
+ CLEANUP((*inDB)->mSymbols[symLoop].mSections);
+ }
+ CLEANUP((*inDB)->mSymbols);
+ CLEANUP(*inDB);
+ }
+}
+
+
+int symDBLookup(const void* inKey, const void* inItem)
+/*
+** bsearch utility routine to find the symbol in the symdb.
+*/
+{
+ int retval = 0;
+ const char* key = (const char*)inKey;
+ const SymDB_Symbol* symbol = (const SymDB_Symbol*)inItem;
+
+ retval = strcmp(key, symbol->mName);
+
+ return retval;
+}
+
+
+int fillSymbolSizeFromDB(Options* inOptions, MSMap_Module* inModule, MSMap_Symbol* inoutSymbol, const char* inMangledName)
+/*
+** If we have a symbol DB, attempt to determine the real size of the symbol
+** up front.
+** This helps us later in the game to avoid performing size guesses by
+** offset.
+*/
+{
+ int retval = 0;
+
+ /*
+ ** May need to initialize symdb.
+ */
+ if(NULL == inOptions->mSymDB && NULL != inOptions->mSymDBName)
+ {
+ retval = readSymDB(inOptions->mSymDBName, &inOptions->mSymDB);
+ }
+
+ /*
+ ** Optional
+ */
+ if(0 == retval && NULL != inOptions->mSymDB)
+ {
+ void* match = NULL;
+
+ /*
+ ** Find the symbol.
+ */
+ match = bsearch(inMangledName, inOptions->mSymDB->mSymbols, inOptions->mSymDB->mSymbolCount, sizeof(SymDB_Symbol), symDBLookup);
+ if(NULL != match)
+ {
+ SymDB_Symbol* symbol = (SymDB_Symbol*)match;
+ unsigned symDBSize = 0;
+ MSMap_Segment* mapSection = NULL;
+
+ /*
+ ** We found the symbol.
+ **
+ ** See if it has the section in question.
+ */
+ mapSection = getSymbolSection(inModule, inoutSymbol);
+ if(NULL != mapSection)
+ {
+ unsigned secLoop = 0;
+
+ for(secLoop = 0; secLoop < symbol->mSectionCount; secLoop++)
+ {
+ if(0 == strcmp(mapSection->mSegment, symbol->mSections[secLoop].mName))
+ {
+ SymDB_Section* section = &symbol->mSections[secLoop];
+
+ /*
+ ** We have a section match.
+ ** Should there be a single size for the symbol,
+ ** then we just default to that.
+ ** If more than one size, we have to do an
+ ** object match search.
+ ** Should there be no object match, we do nothign.
+ */
+ if(1 == section->mSizeCount)
+ {
+ symDBSize = section->mSizes[0].mSize;
+ }
+ else
+ {
+ char* mapObject = NULL;
+
+ /*
+ ** Figure out the map object file name.
+ ** Skip any colon.
+ ** If it doesn't have a .obj in it, not worth continuing.
+ */
+ mapObject = strrchr(inoutSymbol->mObject, ':');
+ if(NULL == mapObject)
+ {
+ mapObject = inoutSymbol->mObject;
+ }
+ else
+ {
+ mapObject++; /* colon */
+ }
+
+ if(NULL != strstr(mapObject, ".obj"))
+ {
+ unsigned sizLoop = 0;
+ unsigned objLoop = 0;
+ SymDB_Size* size = NULL;
+
+ for(sizLoop = 0; sizLoop < section->mSizeCount; sizLoop++)
+ {
+ size = &section->mSizes[sizLoop];
+
+ for(objLoop = 0; objLoop < size->mObjectCount; objLoop++)
+ {
+ if(NULL != strstr(size->mObjects[objLoop], mapObject))
+ {
+ /*
+ ** As we matched the object, in a particular section,
+ ** we'll go with this as the number.
+ */
+ symDBSize = size->mSize;
+ break;
+ }
+ }
+
+ /*
+ ** If the object loop broke early, we break too.
+ */
+ if(objLoop < size->mObjectCount)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ /*
+ ** Put the size in.
+ */
+ inoutSymbol->mSymDBSize = symDBSize;
+ }
+ }
+
+ return retval;
+}
+
+
+char* symdup(const char* inSymbol)
+/*
+** Attempts to demangle the symbol if appropriate.
+** Otherwise acts like strdup.
+*/
+{
+ char* retval = NULL;
+
+#if F_DEMANGLE
+ {
+ int isImport = 0;
+
+ if(0 == strncmp("__imp_", inSymbol, 6))
+ {
+ isImport = __LINE__;
+ inSymbol += 6;
+ }
+
+ if('?' == inSymbol[0])
+ {
+ char demangleBuf[0x200];
+ DWORD demangleRes = 0;
+
+ demangleRes = UnDecorateSymbolName(inSymbol, demangleBuf, sizeof(demangleBuf), UNDNAME_COMPLETE);
+ if(0 != demangleRes)
+ {
+ if (strcmp(demangleBuf, "`string'") == 0)
+ {
+
+ /* attempt manual demangling of string prefix.. */
+
+ /* first make sure we have enough space for the
+ updated string - the demangled string will
+ always be shorter than strlen(inSymbol) and the
+ prologue will always be longer than the
+ "string: " that we tack on the front of the string
+ */
+ char *curresult = retval = malloc(strlen(inSymbol) + 11);
+ const char *curchar = inSymbol;
+
+ int state = DEMANGLE_STATE_START;
+
+ /* the hex state is for stuff like ?$EA which
+ really means hex value 0x40 */
+ char hex_state = 0;
+ char string_is_unicode = 0;
+
+ /* sometimes we get a null-termination before the
+ final @ sign - in that case, remember that
+ we've seen the whole string */
+ int have_null_char = 0;
+
+ /* stick our user-readable prefix on */
+ strcpy(curresult, "string: \"");
+ curresult += 9;
+
+ while (*curchar) {
+
+ // process current state
+ switch (state) {
+
+ /* the Prologue states are divided up so
+ that someday we can try to decode
+ the random letters in between the '@'
+ signs. Also, some strings only have 2
+ prologue '@' signs, so we have to
+ figure out how to distinguish between
+ them at some point. */
+ case DEMANGLE_STATE_START:
+ if (*curchar == '@')
+ state = DEMANGLE_STATE_PROLOGUE_1;
+ /* ignore all other states */
+ break;
+
+ case DEMANGLE_STATE_PROLOGUE_1:
+ switch (*curchar) {
+ case '0':
+ string_is_unicode=0;
+ state = DEMANGLE_STATE_HAVE_TYPE;
+ break;
+ case '1':
+ string_is_unicode=1;
+ state = DEMANGLE_STATE_HAVE_TYPE;
+ break;
+
+ /* ignore all other characters */
+ }
+ break;
+
+ case DEMANGLE_STATE_HAVE_TYPE:
+ if (*curchar >= '0' && *curchar <= '9') {
+ state = DEMANGLE_STATE_DEC_LENGTH;
+ } else if (*curchar >= 'A' && *curchar <= 'Z') {
+ state = DEMANGLE_STATE_HEX_LENGTH;
+ }
+ case DEMANGLE_STATE_DEC_LENGTH:
+ /* decimal lengths don't have the 2nd
+ field
+ */
+ if (*curchar == '@')
+ state = DEMANGLE_STATE_NORMAL;
+ break;
+
+ case DEMANGLE_STATE_HEX_LENGTH:
+ /* hex lengths have a 2nd field
+ (though I have no idea what it is for)
+ */
+ if (*curchar == '@')
+ state = DEMANGLE_STATE_PROLOGUE_SECONDARY;
+ break;
+
+ case DEMANGLE_STATE_PROLOGUE_SECONDARY:
+ if (*curchar == '@')
+ state = DEMANGLE_STATE_NORMAL;
+ break;
+
+ case DEMANGLE_STATE_NORMAL:
+ switch (*curchar) {
+ case '?':
+ state = DEMANGLE_STATE_QDECODE;
+ break;
+ case '@':
+ state = DEMANGLE_STATE_STOP;
+ break;
+ default:
+ *curresult++ = DEMANGLE_SAFE_CHAR(*curchar);
+ state = DEMANGLE_STATE_NORMAL;
+ break;
+ }
+ break;
+
+ /* found a '?' */
+ case DEMANGLE_STATE_QDECODE:
+ state = DEMANGLE_STATE_NORMAL;
+
+ /* there are certain shortcuts, like
+ "?3" means ":"
+ */
+ switch (*curchar) {
+ case '1':
+ *curresult++ = '/';
+ break;
+ case '2':
+ *curresult++ = '\\';
+ break;
+ case '3':
+ *curresult++ = ':';
+ break;
+ case '4':
+ *curresult++ = '.';
+ break;
+ case '5':
+ *curresult++ = ' ';
+ break;
+ case '6':
+ *curresult++ = '\\';
+ *curresult++ = 'n';
+ break;
+ case '8':
+ *curresult++ = '\'';
+ break;
+ case '9':
+ *curresult++ = '-';
+ break;
+
+ /* any other arbitrary ASCII value can
+ be stored by prefixing it with ?$
+ */
+ case '$':
+ state = DEMANGLE_STATE_DOLLAR_1;
+ }
+ break;
+
+ case DEMANGLE_STATE_DOLLAR_1:
+ /* first digit of ?$ notation. All digits
+ are hex, represented starting with the
+ capital leter 'A' such that 'A' means 0x0,
+ 'B' means 0x1, 'K' means 0xA
+ */
+ hex_state = (*curchar - 'A') * 0x10;
+ state = DEMANGLE_STATE_DOLLAR_2;
+ break;
+
+ case DEMANGLE_STATE_DOLLAR_2:
+ /* same mechanism as above */
+ hex_state += (*curchar - 'A');
+ if (hex_state) {
+ *curresult++ = DEMANGLE_SAFE_CHAR(hex_state);
+ have_null_char = 0;
+ }
+ else {
+ have_null_char = 1;
+ }
+
+ state = DEMANGLE_STATE_NORMAL;
+ break;
+
+ case DEMANGLE_STATE_STOP:
+ break;
+ }
+
+ curchar++;
+ }
+
+ /* add the appropriate termination depending
+ if we completed the string or not */
+ if (!have_null_char)
+ strcpy(curresult, "...\"");
+ else
+ strcpy(curresult, "\"");
+ } else {
+ retval = strdup(demangleBuf);
+ }
+ }
+ else
+ {
+ /*
+ ** fall back to normal.
+ */
+ retval = strdup(inSymbol);
+ }
+ }
+ else if('_' == inSymbol[0])
+ {
+ retval = strdup(inSymbol + 1);
+ }
+ else
+ {
+ retval = strdup(inSymbol);
+ }
+
+ /*
+ ** May need to rewrite the symbol if an import.
+ */
+ if(NULL != retval && isImport)
+ {
+ const char importPrefix[] = "__declspec(dllimport) ";
+ char importBuf[0x200];
+ int printRes = 0;
+
+ printRes = _snprintf(importBuf, sizeof(importBuf), "%s%s", importPrefix, retval);
+ free(retval);
+ retval = NULL;
+
+ if(printRes > 0)
+ {
+ retval = strdup(importBuf);
+ }
+ }
+ }
+#else /* F_DEMANGLE */
+ retval = strdup(inSymbol);
+#endif /* F_DEMANGLE */
+
+ return retval;
+}
+
+
+int readmap(Options* inOptions, MSMap_Module* inModule)
+/*
+** Read the input line by line, adding it to the module.
+*/
+{
+ int retval = 0;
+ char lineBuffer[0x400];
+ char* current = NULL;
+ MSMap_ReadState fsm;
+ int len = 0;
+ int forceContinue = 0;
+
+ memset(&fsm, 0, sizeof(fsm));
+
+ /*
+ ** Read the map file line by line.
+ ** We keep a simple state machine to determine what we're looking at.
+ */
+ while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
+ {
+ if(forceContinue)
+ {
+ /*
+ ** Used to skip anticipated blank lines.
+ */
+ forceContinue--;
+ continue;
+ }
+
+ current = skipWhite(lineBuffer);
+ trimWhite(current);
+
+ len = strlen(current);
+
+ if(fsm.mHasModule)
+ {
+ if(fsm.mHasTimestamp)
+ {
+ if(fsm.mHasPreferredLoadAddress)
+ {
+ if(fsm.mHasSegmentData)
+ {
+ if(fsm.mHasPublicSymbolData)
+ {
+ if(fsm.mHasEntryPoint)
+ {
+ if(fsm.mFoundStaticSymbols)
+ {
+ /*
+ ** A blank line means we've reached the end of all static symbols.
+ */
+ if(len)
+ {
+ /*
+ ** We're adding a new symbol.
+ ** Make sure we have room for it.
+ */
+ if(inModule->mSymbolCapacity == inModule->mSymbolCount)
+ {
+ void* moved = NULL;
+
+ moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
+ if(NULL != moved)
+ {
+ inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
+ inModule->mSymbols = (MSMap_Symbol*)moved;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
+ }
+ }
+
+ if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
+ {
+ MSMap_Symbol* theSymbol = NULL;
+ unsigned index = 0;
+ int scanRes = 0;
+ char symbolBuf[0x200];
+
+ index = inModule->mSymbolCount;
+ inModule->mSymbolCount++;
+ theSymbol = (inModule->mSymbols + index);
+
+ memset(theSymbol, 0, sizeof(MSMap_Symbol));
+ theSymbol->mScope = STATIC;
+
+ scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned*)&(theSymbol->mRVABase));
+ if(4 == scanRes)
+ {
+ theSymbol->mSymbol = symdup(symbolBuf);
+
+ if(0 == retval)
+ {
+ if(NULL != theSymbol->mSymbol)
+ {
+ char *last = lastWord(current);
+
+ theSymbol->mObject = strdup(last);
+ if(NULL == theSymbol->mObject)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, last, "Unable to copy object name.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
+ }
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inModule->mModule, "Unable to scan static symbols.");
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** All done.
+ */
+ break;
+ }
+ }
+ else
+ {
+ /*
+ ** Static symbols are optional.
+ ** If no static symbols we're done.
+ ** Otherwise, set the flag such that it will work more.
+ */
+ if(0 == strcmp(current, "Static symbols"))
+ {
+ fsm.mFoundStaticSymbols = __LINE__;
+ forceContinue = 1;
+ }
+ else
+ {
+ /*
+ ** All done.
+ */
+ break;
+ }
+ }
+ }
+ else
+ {
+ int scanRes = 0;
+
+ scanRes = sscanf(current, "entry point at %x:%x", (unsigned*)&(inModule->mEntryPrefix), (unsigned*)&(inModule->mEntryOffset));
+ if(2 == scanRes)
+ {
+ fsm.mHasEntryPoint = __LINE__;
+ forceContinue = 1;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current, "Unable to obtain entry point.");
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** Skip the N lines of public symbol data (column headers).
+ */
+ if(2 <= fsm.mHasPublicSymbolDataSkippedLines)
+ {
+ /*
+ ** A blank line indicates end of public symbols.
+ */
+ if(len)
+ {
+ /*
+ ** We're adding a new symbol.
+ ** Make sure we have room for it.
+ */
+ if(inModule->mSymbolCapacity == inModule->mSymbolCount)
+ {
+ void* moved = NULL;
+
+ moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
+ if(NULL != moved)
+ {
+ inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
+ inModule->mSymbols = (MSMap_Symbol*)moved;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
+ }
+ }
+
+ if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
+ {
+ MSMap_Symbol* theSymbol = NULL;
+ unsigned index = 0;
+ int scanRes = 0;
+ char symbolBuf[0x200];
+
+ index = inModule->mSymbolCount;
+ inModule->mSymbolCount++;
+ theSymbol = (inModule->mSymbols + index);
+
+ memset(theSymbol, 0, sizeof(MSMap_Symbol));
+ theSymbol->mScope = PUBLIC;
+
+ scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned *)&(theSymbol->mRVABase));
+ if(4 == scanRes)
+ {
+ theSymbol->mSymbol = symdup(symbolBuf);
+
+ if(NULL != theSymbol->mSymbol)
+ {
+ char *last = lastWord(current);
+
+ theSymbol->mObject = strdup(last);
+ if(NULL != theSymbol->mObject)
+ {
+ /*
+ ** Finally, attempt to lookup the actual size of the symbol
+ ** if there is a symbol DB available.
+ */
+ retval = fillSymbolSizeFromDB(inOptions, inModule, theSymbol, symbolBuf);
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, last, "Unable to copy object name.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inModule->mModule, "Unable to scan public symbols.");
+ }
+ }
+ }
+ else
+ {
+ fsm.mHasPublicSymbolData = __LINE__;
+ }
+ }
+ else
+ {
+ fsm.mHasPublicSymbolDataSkippedLines++;
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** Skip the first line of segment data (column headers).
+ ** Mark that we've begun grabbing segement data.
+ */
+ if(fsm.mSegmentDataSkippedLine)
+ {
+ /*
+ ** A blank line means end of the segment data.
+ */
+ if(len)
+ {
+ /*
+ ** We're adding a new segment.
+ ** Make sure we have room for it.
+ */
+ if(inModule->mSegmentCapacity == inModule->mSegmentCount)
+ {
+ void* moved = NULL;
+
+ moved = realloc(inModule->mSegments, sizeof(MSMap_Segment) * (inModule->mSegmentCapacity + MSMAP_SEGMENT_GROWBY));
+ if(NULL != moved)
+ {
+ inModule->mSegmentCapacity += MSMAP_SEGMENT_GROWBY;
+ inModule->mSegments = (MSMap_Segment*)moved;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inModule->mModule, "Unable to grow segments.");
+ }
+ }
+
+ if(0 == retval && inModule->mSegmentCapacity > inModule->mSegmentCount)
+ {
+ MSMap_Segment* theSegment = NULL;
+ unsigned index = 0;
+ char classBuf[0x10];
+ char nameBuf[0x20];
+ int scanRes = 0;
+
+ index = inModule->mSegmentCount;
+ inModule->mSegmentCount++;
+ theSegment = (inModule->mSegments + index);
+
+ memset(theSegment, 0, sizeof(MSMap_Segment));
+
+ scanRes = sscanf(current, "%x:%x %xH %s %s", (unsigned*)&(theSegment->mPrefix), (unsigned*)&(theSegment->mOffset), (unsigned*)&(theSegment->mLength), nameBuf, classBuf);
+ if(5 == scanRes)
+ {
+ if('.' == nameBuf[0])
+ {
+ theSegment->mSegment = strdup(&nameBuf[1]);
+ }
+ else
+ {
+ theSegment->mSegment = strdup(nameBuf);
+ }
+
+ if(NULL != theSegment->mSegment)
+ {
+ if(0 == strcmp("DATA", classBuf))
+ {
+ theSegment->mClass = DATA;
+ }
+ else if(0 == strcmp("CODE", classBuf))
+ {
+ theSegment->mClass = CODE;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, classBuf, "Unrecognized segment class.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, nameBuf, "Unable to copy segment name.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inModule->mModule, "Unable to scan segments.");
+ }
+ }
+ }
+ else
+ {
+ fsm.mHasSegmentData = __LINE__;
+ }
+ }
+ else
+ {
+ fsm.mSegmentDataSkippedLine = __LINE__;
+ }
+ }
+ }
+ else
+ {
+ int scanRes = 0;
+
+ /*
+ ** The PLA has a particular format.
+ */
+ scanRes = sscanf(current, "Preferred load address is %x", (unsigned*)&(inModule->mPreferredLoadAddress));
+ if(1 == scanRes)
+ {
+ fsm.mHasPreferredLoadAddress = __LINE__;
+ forceContinue = 1;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current, "Unable to obtain preferred load address.");
+ }
+ }
+ }
+ else
+ {
+ int scanRes = 0;
+
+ /*
+ ** The timestamp has a particular format.
+ */
+ scanRes = sscanf(current, "Timestamp is %x", (unsigned*)&(inModule->mTimestamp));
+ if(1 == scanRes)
+ {
+ fsm.mHasTimestamp = __LINE__;
+ forceContinue = 1;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current, "Unable to obtain timestamp.");
+ }
+ }
+ }
+ else
+ {
+ /*
+ ** The module is on a line by itself.
+ */
+ inModule->mModule = strdup(current);
+ if(NULL != inModule->mModule)
+ {
+ fsm.mHasModule = __LINE__;
+ forceContinue = 1;
+
+ if(0 != inOptions->mMatchModuleCount)
+ {
+ unsigned matchLoop = 0;
+
+ /*
+ ** If this module name doesn't match, then bail.
+ ** Compare in a case sensitive manner, exact match only.
+ */
+ for(matchLoop = 0; matchLoop < inOptions->mMatchModuleCount; matchLoop++)
+ {
+ if(0 == strcmp(inModule->mModule, inOptions->mMatchModules[matchLoop]))
+ {
+ break;
+ }
+ }
+
+ if(matchLoop == inOptions->mMatchModuleCount)
+ {
+ /*
+ ** A match did not occur, bail out of read loop.
+ ** No error, however.
+ */
+ break;
+ }
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current, "Unable to obtain module.");
+ }
+ }
+ }
+
+ if(0 == retval && 0 != ferror(inOptions->mInput))
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
+ }
+
+ return retval;
+}
+
+
+static int qsortRVABase(const void* in1, const void* in2)
+/*
+** qsort callback to sort the symbols by their RVABase.
+*/
+{
+ MSMap_Symbol* sym1 = (MSMap_Symbol*)in1;
+ MSMap_Symbol* sym2 = (MSMap_Symbol*)in2;
+ int retval = 0;
+
+ if(sym1->mRVABase < sym2->mRVABase)
+ {
+ retval = -1;
+ }
+ else if(sym1->mRVABase > sym2->mRVABase)
+ {
+ retval = 1;
+ }
+
+ return retval;
+}
+
+
+static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClass, MSMap_SymbolScope inScope, const char* inModule, const char* inSegment, const char* inObject, const char* inSymbol)
+/*
+** Output a line of map information separated by tabs.
+** Some items (const char*), if not present, will receive a default value.
+*/
+{
+ int retval = 0;
+
+ /*
+ ** No need to output on no size.
+ ** This can happen with zero sized segments,
+ ** or an imported symbol which has multiple names (one will count).
+ */
+ if(0 != inSize)
+ {
+ char objectBuf[0x100];
+ const char* symScope = NULL;
+ const char* segClass = NULL;
+ const char* undefined = "UNDEF";
+
+ /*
+ ** Fill in unspecified values.
+ */
+ if(NULL == inObject)
+ {
+ sprintf(objectBuf, "%s:%s:%s", undefined, inModule, inSegment);
+ inObject = objectBuf;
+ }
+ if(NULL == inSymbol)
+ {
+ inSymbol = inObject;
+ }
+
+ /*
+ ** Convert some enumerations to text.
+ */
+ switch(inClass)
+ {
+ case CODE:
+ segClass = "CODE";
+ break;
+ case DATA:
+ segClass = "DATA";
+ break;
+ default:
+ retval = __LINE__;
+ ERROR_REPORT(retval, "", "Unable to determine class for output.");
+ break;
+ }
+
+ switch(inScope)
+ {
+ case PUBLIC:
+ symScope = "PUBLIC";
+ break;
+ case STATIC:
+ symScope = "STATIC";
+ break;
+ case UNDEFINED:
+ symScope = undefined;
+ break;
+ default:
+ retval = __LINE__;
+ ERROR_REPORT(retval, "", "Unable to determine scope for symbol.");
+ break;
+ }
+
+ if(0 == retval)
+ {
+ int printRes = 0;
+
+ printRes = fprintf(inOptions->mOutput,
+ "%.8X\t%s\t%s\t%s\t%s\t%s\t%s\n",
+ inSize,
+ segClass,
+ symScope,
+ inModule,
+ inSegment,
+ inObject,
+ inSymbol
+ );
+
+ if(0 > printRes)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, inOptions->mOutputName, "Unable to output tsv data.");
+ }
+ }
+ }
+
+ return retval;
+}
+
+
+void cleanModule(MSMap_Module* inModule)
+{
+ unsigned loop = 0;
+
+ for(loop = 0; loop < inModule->mSymbolCount; loop++)
+ {
+ CLEANUP(inModule->mSymbols[loop].mObject);
+ CLEANUP(inModule->mSymbols[loop].mSymbol);
+ }
+ CLEANUP(inModule->mSymbols);
+
+ for(loop = 0; loop < inModule->mSegmentCount; loop++)
+ {
+ CLEANUP(inModule->mSegments[loop].mSegment);
+ }
+ CLEANUP(inModule->mSegments);
+
+ CLEANUP(inModule->mModule);
+
+ memset(inModule, 0, sizeof(MSMap_Module));
+}
+
+
+int map2tsv(Options* inOptions)
+/*
+** Read all input.
+** Output tab separated value data.
+*/
+{
+ int retval = 0;
+ MSMap_Module module;
+
+ memset(&module, 0, sizeof(module));
+
+ /*
+ ** Read in the map file.
+ */
+ retval = readmap(inOptions, &module);
+ if(0 == retval)
+ {
+ unsigned symLoop = 0;
+ MSMap_Symbol* symbol = NULL;
+ unsigned secLoop = 0;
+ MSMap_Segment* section = NULL;
+ unsigned size = 0;
+ unsigned dbSize = 0;
+ unsigned offsetSize = 0;
+ unsigned endOffset = 0;
+
+ /*
+ ** Quick sort the symbols via RVABase.
+ */
+ qsort(module.mSymbols, module.mSymbolCount, sizeof(MSMap_Symbol), qsortRVABase);
+
+ /*
+ ** Go through all the symbols (in order by sort).
+ ** Output their sizes.
+ */
+ for(symLoop = 0; 0 == retval && symLoop < module.mSymbolCount; symLoop++)
+ {
+ symbol = &module.mSymbols[symLoop];
+ section = getSymbolSection(&module, symbol);
+ if (!section)
+ continue;
+
+ /*
+ ** Use the symbol DB size if available.
+ */
+ dbSize = symbol->mSymDBSize;
+
+ /*
+ ** Guess using offsets.
+ ** Is there a next symbol available? If so, its start offset is the end of this symbol.
+ ** Otherwise, our section offset + length is the end of this symbol.
+ **
+ ** The trick is, the DB size can not go beyond the offset size, for sanity.
+ */
+
+ /*
+ ** Try next symbol, but only if in same section.
+ ** If still not, use the end of the segment.
+ ** This implies we were the last symbol in the segment.
+ */
+ if((symLoop + 1) < module.mSymbolCount)
+ {
+ MSMap_Symbol* nextSymbol = NULL;
+ MSMap_Segment* nextSection = NULL;
+
+ nextSymbol = &module.mSymbols[symLoop + 1];
+ nextSection = getSymbolSection(&module, nextSymbol);
+
+ if(section == nextSection)
+ {
+ endOffset = nextSymbol->mOffset;
+ }
+ else
+ {
+ endOffset = section->mOffset + section->mLength;
+ }
+ }
+ else
+ {
+ endOffset = section->mOffset + section->mLength;
+ }
+
+ /*
+ ** Can now guess at size.
+ */
+ offsetSize = endOffset - symbol->mOffset;
+
+ /*
+ ** Now, determine which size to use.
+ ** This is really a sanity check as well.
+ */
+ size = offsetSize;
+ if(0 != dbSize)
+ {
+ if(dbSize < offsetSize)
+ {
+ size = dbSize;
+ }
+ }
+
+ /*
+ ** Output the symbol with the size.
+ */
+ retval = tsvout(inOptions,
+ size,
+ section->mClass,
+ symbol->mScope,
+ module.mModule,
+ section->mSegment,
+ symbol->mObject,
+ symbol->mSymbol
+ );
+
+ /*
+ ** Make sure we mark this amount of space as used in the section.
+ */
+ section->mUsed += size;
+ }
+
+ /*
+ ** Go through the sections, and those whose length is longer than the
+ ** amount of space used, output dummy filler values.
+ */
+ for(secLoop = 0; 0 == retval && secLoop < module.mSegmentCount; secLoop++)
+ {
+ section = &module.mSegments[secLoop];
+
+ if(section && section->mUsed < section->mLength)
+ {
+ retval = tsvout(inOptions,
+ section->mLength - section->mUsed,
+ section->mClass,
+ UNDEFINED,
+ module.mModule,
+ section->mSegment,
+ NULL,
+ NULL
+ );
+ }
+ }
+ }
+
+ /*
+ ** Cleanup.
+ */
+ cleanModule(&module);
+
+ 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 if(current == &gMatchModuleSwitch)
+ {
+ void* moved = NULL;
+
+ /*
+ ** Add the value to the list of allowed module names.
+ */
+ moved = realloc(outOptions->mMatchModules, sizeof(char*) * (outOptions->mMatchModuleCount + 1));
+ if(NULL != moved)
+ {
+ outOptions->mMatchModules = (char**)moved;
+ outOptions->mMatchModules[outOptions->mMatchModuleCount] = strdup(current->mValue);
+ if(NULL != outOptions->mMatchModules[outOptions->mMatchModuleCount])
+ {
+ outOptions->mMatchModuleCount++;
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
+ }
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current->mValue, "Unable to allocate space for string.");
+ }
+ }
+ else if(current == &gSymDBSwitch)
+ {
+ CLEANUP(outOptions->mSymDBName);
+ outOptions->mSymDBName = strdup(current->mValue);
+ if(NULL == outOptions->mSymDBName)
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, current->mValue, "Unable to duplicate symbol db name.");
+ }
+ }
+ else if(current == &gBatchModeSwitch)
+ {
+ outOptions->mBatchMode = __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, et. al.
+*/
+{
+ 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);
+ }
+ while(0 != inOptions->mMatchModuleCount)
+ {
+ inOptions->mMatchModuleCount--;
+ CLEANUP(inOptions->mMatchModules[inOptions->mMatchModuleCount]);
+ }
+ CLEANUP(inOptions->mMatchModules);
+
+ cleanSymDB(&inOptions->mSymDB);
+
+ 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 normalizes MS linker .map files for use by other tools.\n");
+}
+
+
+int batchMode(Options* inOptions)
+/*
+** Batch mode means that the input file is actually a list of map files.
+** We simply swap out our input file names while we do this.
+*/
+{
+ int retval = 0;
+ char lineBuf[0x400];
+ FILE* realInput = NULL;
+ char* realInputName = NULL;
+ FILE* mapFile = NULL;
+ int finalRes = 0;
+
+ realInput = inOptions->mInput;
+ realInputName = inOptions->mInputName;
+
+ while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), realInput))
+ {
+ trimWhite(lineBuf);
+
+ /*
+ ** Skip/allow blank lines.
+ */
+ if('\0' == lineBuf[0])
+ {
+ continue;
+ }
+
+ /*
+ ** Override what we believe to be the input for this line.
+ */
+ inOptions->mInputName = lineBuf;
+ inOptions->mInput = fopen(lineBuf, "r");
+ if(NULL != inOptions->mInput)
+ {
+ int mapRes = 0;
+
+ /*
+ ** Do it.
+ */
+ mapRes = map2tsv(inOptions);
+
+ /*
+ ** We report the first error that we encounter, but we continue.
+ ** This is batch mode after all.
+ */
+ if(0 == finalRes)
+ {
+ finalRes = mapRes;
+ }
+
+ /*
+ ** Close the input file.
+ */
+ fclose(inOptions->mInput);
+ }
+ else
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, lineBuf, "Unable to open map file.");
+ break;
+ }
+ }
+
+ if(0 == retval && 0 != ferror(realInput))
+ {
+ retval = __LINE__;
+ ERROR_REPORT(retval, realInputName, "Unable to read file.");
+ }
+
+ /*
+ ** Restore what we've swapped.
+ */
+ inOptions->mInput = realInput;
+ inOptions->mInputName = realInputName;
+
+ /*
+ ** Report first map file error if there were no other operational
+ ** problems.
+ */
+ if(0 == retval)
+ {
+ retval = finalRes;
+ }
+
+ return retval;
+}
+
+
+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)
+ {
+ if(options.mBatchMode)
+ {
+ retval = batchMode(&options);
+ }
+ else
+ {
+ retval = map2tsv(&options);
+ }
+ }
+
+ cleanOptions(&options);
+ return retval;
+}
+
Property changes on: third_party/codesighs/msmap2tsv.c
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « third_party/codesighs/msmap.h ('k') | third_party/codesighs/nm2tsv.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698