Home | History | Annotate | Download | only in codesighs
      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
      2  *
      3  * ***** BEGIN LICENSE BLOCK *****
      4  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
      5  *
      6  * The contents of this file are subject to the Mozilla Public License Version
      7  * 1.1 (the "License"); you may not use this file except in compliance with
      8  * the License. You may obtain a copy of the License at
      9  * http://www.mozilla.org/MPL/
     10  *
     11  * Software distributed under the License is distributed on an "AS IS" basis,
     12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     13  * for the specific language governing rights and limitations under the
     14  * License.
     15  *
     16  * The Original Code is msdump2symdb.c code, released
     17  * Jan 16, 2003.
     18  *
     19  * The Initial Developer of the Original Code is
     20  * Netscape Communications Corporation.
     21  * Portions created by the Initial Developer are Copyright (C) 2002
     22  * the Initial Developer. All Rights Reserved.
     23  *
     24  * Contributor(s):
     25  *   Garrett Arch Blythe, 16-January-2003
     26  *
     27  * Alternatively, the contents of this file may be used under the terms of
     28  * either the GNU General Public License Version 2 or later (the "GPL"), or
     29  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
     30  * in which case the provisions of the GPL or the LGPL are applicable instead
     31  * of those above. If you wish to allow use of your version of this file only
     32  * under the terms of either the GPL or the LGPL, and not to allow others to
     33  * use your version of this file under the terms of the MPL, indicate your
     34  * decision by deleting the provisions above and replace them with the notice
     35  * and other provisions required by the GPL or the LGPL. If you do not delete
     36  * the provisions above, a recipient may use your version of this file under
     37  * the terms of any one of the MPL, the GPL or the LGPL.
     38  *
     39  * ***** END LICENSE BLOCK ***** */
     40 
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <time.h>
     45 #include <ctype.h>
     46 #include <errno.h>
     47 
     48 #define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
     49 #define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
     50 
     51 
     52 typedef struct __struct_Options
     53 /*
     54 **  Options to control how we perform.
     55 **
     56 **  mProgramName    Used in help text.
     57 **  mInput          File to read for input.
     58 **                  Default is stdin.
     59 **  mInputName      Name of the file.
     60 **  mOutput         Output file, append.
     61 **                  Default is stdout.
     62 **  mOutputName     Name of the file.
     63 **  mHelp           Whether or not help should be shown.
     64 */
     65 {
     66     const char* mProgramName;
     67     FILE* mInput;
     68     char* mInputName;
     69     FILE* mOutput;
     70     char* mOutputName;
     71     int mHelp;
     72 }
     73 Options;
     74 
     75 
     76 typedef struct __struct_Switch
     77 /*
     78 **  Command line options.
     79 */
     80 {
     81     const char* mLongName;
     82     const char* mShortName;
     83     int mHasValue;
     84     const char* mValue;
     85     const char* mDescription;
     86 }
     87 Switch;
     88 
     89 #define DESC_NEWLINE "\n\t\t"
     90 
     91 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
     92 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
     93 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
     94 
     95 static Switch* gSwitches[] = {
     96         &gInputSwitch,
     97         &gOutputSwitch,
     98         &gHelpSwitch
     99 };
    100 
    101 
    102 typedef struct __struct_MSDump_Symbol
    103 /*
    104 **  Struct to hold infomration on a symbol.
    105 **
    106 **  mSize               Size of the symbol once all work is complete.
    107 **  mOffset             Offset of the symbol in the section.
    108 **  mName               Symbolic name.
    109 */
    110 {
    111     unsigned    mSize;
    112     unsigned    mOffset;
    113     char*       mName;
    114 }
    115 MSDump_Symbol;
    116 
    117 
    118 typedef struct __struct_MSDump_Section
    119 /*
    120 **  Struct for holding information on a section.
    121 **
    122 **  mLength             Length of the section in bytes.
    123 **  mUsed               Number of bytes used in the section thus far.
    124 **                      Should eventually match mLength after work is done.
    125 **  mType               Type of section, as string (.data, .text, et. al.)
    126 **  mSymbols            Symbols found inside the section.
    127 **  mSymbolCount        Number of symbols in array.
    128 */
    129 {
    130     unsigned            mLength;
    131     unsigned            mUsed;
    132     char*               mType;
    133 
    134     MSDump_Symbol*      mSymbols;
    135     unsigned            mSymbolCount;
    136 }
    137 MSDump_Section;
    138 
    139 
    140 typedef struct __struct_MSDump_Object
    141 /*
    142 **  Struct for holding object's data.
    143 */
    144 {
    145     char*   mObject;
    146 
    147     MSDump_Section*     mSections;
    148     unsigned            mSectionCount;
    149 }
    150 MSDump_Object;
    151 
    152 
    153 typedef struct __struct_MSDump_ReadState
    154 /*
    155 **  State flags while reading the input gives us hints on what to do.
    156 **
    157 **  mSkipLines                  Number of lines to skip without parsing.
    158 **  mSectionDetails             Section information next, like line length.
    159 **  mCurrentObject              Object file we are dealing with.
    160 */
    161 {
    162     unsigned            mSkipLines;
    163     unsigned            mSectionDetails;
    164     MSDump_Object*      mCurrentObject;
    165 }
    166 MSDump_ReadState;
    167 
    168 
    169 typedef struct __struct_MSDump_Container
    170 /*
    171 **  Umbrella container for all data encountered.
    172 */
    173 {
    174     MSDump_ReadState    mReadState;
    175 
    176     MSDump_Object*      mObjects;
    177     unsigned            mObjectCount;
    178 }
    179 MSDump_Container;
    180 
    181 
    182 void trimWhite(char* inString)
    183 /*
    184 **  Remove any whitespace from the end of the string.
    185 */
    186 {
    187     int len = strlen(inString);
    188 
    189     while(len)
    190     {
    191         len--;
    192 
    193         if(isspace(*(inString + len)))
    194         {
    195             *(inString + len) = '\0';
    196         }
    197         else
    198         {
    199             break;
    200         }
    201     }
    202 }
    203 
    204 
    205 const char* skipWhite(const char* inString)
    206 /*
    207 **  Return pointer to first non white space character.
    208 */
    209 {
    210     const char* retval = inString;
    211 
    212     while('\0' != *retval && isspace(*retval))
    213     {
    214         retval++;
    215     }
    216 
    217     return retval;
    218 }
    219 
    220 
    221 const char* skipNonWhite(const char* inString)
    222 /*
    223 **  Return pointer to first white space character.
    224 */
    225 {
    226     const char* retval = inString;
    227 
    228     while('\0' != *retval && !isspace(*retval))
    229     {
    230         retval++;
    231     }
    232 
    233     return retval;
    234 }
    235 
    236 
    237 void slash2bs(char* inString)
    238 /*
    239 **  Change any forward slash to a backslash.
    240 */
    241 {
    242     char* slash = inString;
    243 
    244     while(NULL != (slash = strchr(slash, '/')))
    245     {
    246         *slash = '\\';
    247         slash++;
    248     }
    249 }
    250 
    251 
    252 const char* skipToArg(const char* inString, unsigned inArgIndex)
    253 /*
    254 **  Return pointer either to the arg or NULL.
    255 **  1 indexed.
    256 */
    257 {
    258     const char* retval = NULL;
    259 
    260     while(0 != inArgIndex && '\0' != *inString)
    261     {
    262         inArgIndex--;
    263 
    264         inString = skipWhite(inString);
    265         if(0 != inArgIndex)
    266         {
    267             inString = skipNonWhite(inString);
    268         }
    269     }
    270 
    271     if('\0' != *inString)
    272     {
    273         retval = inString;
    274     }
    275 
    276     return retval;
    277 }
    278 
    279 
    280 const char* getLastArg(const char* inString)
    281 /*
    282 **  Return pointer to last arg in string.
    283 */
    284 {
    285     const char* retval = NULL;
    286     int length = 0;
    287     int sawString = 0;
    288 
    289     length = strlen(inString);
    290     while(0 != length)
    291     {
    292         length--;
    293 
    294         if(0 == sawString)
    295         {
    296             if(0 == isspace(inString[length]))
    297             {
    298                 sawString = __LINE__;
    299             }
    300         }
    301         else
    302         {
    303             if(0 != isspace(inString[length]))
    304             {
    305                 retval = inString + length + 1;
    306             }
    307         }
    308     }
    309 
    310     return retval;
    311 }
    312 
    313 
    314 int processLine(Options* inOptions, MSDump_Container* inContainer, const char* inLine)
    315 /*
    316 **  Handle one line at a time.
    317 **  Looking for several different types of lines.
    318 **  Ignore all other lines.
    319 **  The container is the state machine.
    320 **  returns 0 on no error.
    321 */
    322 {
    323     int retval = 0;
    324 
    325     /*
    326     **  Check to see if we were expecting section details.
    327     */
    328     if(0 != inContainer->mReadState.mSectionDetails)
    329     {
    330         const char* length = NULL;
    331         unsigned sectionIndex = 0;
    332 
    333         /*
    334         **  Detail is a 1 based index....
    335         **  Reset.
    336         */
    337         sectionIndex = inContainer->mReadState.mSectionDetails - 1;
    338         inContainer->mReadState.mSectionDetails = 0;
    339 
    340         if(0 == strncmp("    Section length", inLine, 18))
    341         {
    342             const char* sectionLength = NULL;
    343             unsigned numericLength = 0;
    344             char* endScan = NULL;
    345 
    346             sectionLength = skipWhite(inLine + 18);
    347 
    348             errno = 0;
    349             numericLength = strtoul(sectionLength, &endScan, 16);
    350             if(0 == errno && endScan != sectionLength)
    351             {
    352                 inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mLength = numericLength;
    353             }
    354             else
    355             {
    356                 retval = __LINE__;
    357                 ERROR_REPORT(retval, inLine, "Cannot scan for section length.");
    358             }
    359         }
    360         else
    361         {
    362             retval = __LINE__;
    363             ERROR_REPORT(retval, inLine, "Cannot parse section line.");
    364         }
    365     }
    366     /*
    367     **  Check for switching object file symbols.
    368     */
    369     else if(0 == strncmp("Dump of file ", inLine, 13))
    370     {
    371         const char* dupMe = inLine + 13;
    372         char* dup = NULL;
    373 
    374         dup = strdup(dupMe);
    375         if(NULL != dup)
    376         {
    377             void* growth = NULL;
    378 
    379             trimWhite(dup);
    380             slash2bs(dup);
    381 
    382 
    383             growth = realloc(inContainer->mObjects, (inContainer->mObjectCount + 1) * sizeof(MSDump_Object));
    384             if(NULL != growth)
    385             {
    386                 unsigned int index = inContainer->mObjectCount;
    387 
    388                 inContainer->mObjectCount++;
    389                 inContainer->mObjects = growth;
    390                 memset(inContainer->mObjects + index, 0, sizeof(MSDump_Object));
    391 
    392                 inContainer->mObjects[index].mObject = dup;
    393 
    394                 /*
    395                 **  Reset the read state for this new object.
    396                 */
    397                 memset(&inContainer->mReadState, 0, sizeof(MSDump_ReadState));
    398 
    399                 /*
    400                 **  Record our current object file.
    401                 */
    402                 inContainer->mReadState.mCurrentObject = inContainer->mObjects + index;
    403 
    404                 /*
    405                 **  We can skip a few lines.
    406                 */
    407                 inContainer->mReadState.mSkipLines = 4;
    408             }
    409             else
    410             {
    411                 retval = __LINE__;
    412                 ERROR_REPORT(retval, dup, "Unable to grow object array.");
    413                 free(dup);
    414             }
    415         }
    416         else
    417         {
    418             retval = __LINE__;
    419             ERROR_REPORT(retval, dupMe, "Unable to copy string.");
    420 
    421         }
    422     }
    423     /*
    424     **  Check for a symbol dump or a section header.
    425     */
    426     else if(isxdigit(*inLine) && isxdigit(*(inLine + 1)) && isxdigit(*(inLine + 2)))
    427     {
    428         const char* sectionString = NULL;
    429 
    430         /*
    431         **  Determine the section for this line.
    432         **  Ignore DEBUG sections.
    433         */
    434         sectionString = skipToArg(inLine, 3);
    435         if(NULL != sectionString)
    436         {
    437             if(0 != strncmp(sectionString, "DEBUG", 5) && 0 != strncmp(sectionString, "ABS", 3) && 0 != strncmp(sectionString, "UNDEF", 5))
    438             {
    439                 /*
    440                 **  MUST start with "SECT"
    441                 */
    442                 if(0 == strncmp(sectionString, "SECT", 4))
    443                 {
    444                     unsigned sectionIndex1 = 0;
    445 
    446                     char *endScan = NULL;
    447 
    448                     sectionString += 4;
    449 
    450                     /*
    451                     **  Convert the remaining string to an index.
    452                     **  It will be 1 based.
    453                     */
    454                     errno = 0;
    455                     sectionIndex1 = strtoul(sectionString, &endScan, 16);
    456                     if(0 == errno && endScan != sectionString && 0 != sectionIndex1)
    457                     {
    458                         unsigned sectionIndex = sectionIndex1 - 1;
    459 
    460                         /*
    461                         **  Is this a new section? Assumed to be ascending.
    462                         **  Or is this a symbol in the section?
    463                         */
    464                         if(sectionIndex1 > inContainer->mReadState.mCurrentObject->mSectionCount)
    465                         {
    466                             const char* typeArg = NULL;
    467 
    468                             /*
    469                             **  New Section, figure out the type.
    470                             */
    471                             typeArg = skipToArg(sectionString, 5);
    472                             if(NULL != typeArg)
    473                             {
    474                                 char* typeDup = NULL;
    475 
    476                                 /*
    477                                 **  Skip the leading period before duping.
    478                                 */
    479                                 if('.' == *typeArg)
    480                                 {
    481                                     typeArg++;
    482                                 }
    483                                 typeDup = strdup(typeArg);
    484 
    485                                 if(NULL != typeDup)
    486                                 {
    487                                     void* moved = NULL;
    488                                     char* nonWhite = NULL;
    489 
    490                                     /*
    491                                     **  Terminate the duplicate after the section type.
    492                                     */
    493                                     nonWhite = (char*)skipNonWhite(typeDup);
    494                                     if(NULL != nonWhite)
    495                                     {
    496                                         *nonWhite = '\0';
    497                                     }
    498 
    499                                     /*
    500                                     **  Create more space for the section in the object...
    501                                     */
    502                                     moved = realloc(inContainer->mReadState.mCurrentObject->mSections, sizeof(MSDump_Section) * sectionIndex1);
    503                                     if(NULL != moved)
    504                                     {
    505                                         unsigned oldCount = inContainer->mReadState.mCurrentObject->mSectionCount;
    506 
    507                                         inContainer->mReadState.mCurrentObject->mSections = (MSDump_Section*)moved;
    508                                         inContainer->mReadState.mCurrentObject->mSectionCount = sectionIndex1;
    509                                         memset(&inContainer->mReadState.mCurrentObject->mSections[oldCount], 0, sizeof(MSDump_Section) * (sectionIndex1 - oldCount));
    510 
    511                                         /*
    512                                         **  Other section details.
    513                                         */
    514                                         inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mType = typeDup;
    515 
    516 
    517                                         /*
    518                                         **  Mark it so that we look for the length on the next line.
    519                                         **  This happens on next entry into the read state.
    520                                         */
    521                                         inContainer->mReadState.mSectionDetails = sectionIndex1;
    522                                     }
    523                                     else
    524                                     {
    525                                         retval = __LINE__;
    526                                         ERROR_REPORT(retval, inLine, "Unable to grow for new section.");
    527                                         free(typeDup);
    528                                     }
    529                                 }
    530                                 else
    531                                 {
    532                                     retval = __LINE__;
    533                                     ERROR_REPORT(retval, typeArg, "Unable to duplicate type.");
    534                                 }
    535                             }
    536                             else
    537                             {
    538                                 retval = __LINE__;
    539                                 ERROR_REPORT(retval, inLine, "Unable to determine section type.");
    540                             }
    541 
    542                         }
    543                         else
    544                         {
    545                             const char* offsetArg = NULL;
    546                             const char* classArg = NULL;
    547                             unsigned classWords = 1;
    548                             const char* symbolArg = NULL;
    549 
    550                             /*
    551                             **  This is an section we've seen before, and must list a symbol.
    552                             **  Figure out the things we want to know about the symbol, e.g. size.
    553                             **  We will ignore particular classes of symbols.
    554                             */
    555 
    556                             offsetArg = skipToArg(inLine, 2);
    557 
    558                             classArg = skipToArg(offsetArg, 4);
    559                             if(0 == strncmp(classArg, "()", 2))
    560                             {
    561                                 classArg = skipToArg(classArg, 2);
    562                             }
    563                             if(0 == strncmp(classArg, ".bf or.ef", 9))
    564                             {
    565                                 classWords = 2;
    566                             }
    567 
    568                             symbolArg = skipToArg(classArg, 3 + (classWords - 1));
    569 
    570                             /*
    571                             **  Skip particular lines/items.
    572                             */
    573                             if(
    574                                 0 != strncmp(classArg, "Label", 5) &&
    575                                 0 != strncmp(symbolArg, ".bf", 3) &&
    576                                 0 != strncmp(symbolArg, ".lf", 3) &&
    577                                 0 != strncmp(symbolArg, ".ef", 3)
    578                                 )
    579                             {
    580                                 char* endOffsetArg = NULL;
    581                                 unsigned offset = 0;
    582 
    583                                 /*
    584                                 ** Convert the offset to something meaninful (size).
    585                                 */
    586                                 errno = 0;
    587                                 offset = strtoul(offsetArg, &endOffsetArg, 16);
    588                                 if(0 == errno && endOffsetArg != offsetArg)
    589                                 {
    590                                     void* moved = NULL;
    591 
    592                                     /*
    593                                     **  Increase the size of the symbol array in the section.
    594                                     **  Assumed symbols are unique within each section.
    595                                     */
    596                                     moved = realloc(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols, sizeof(MSDump_Symbol) * (inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount + 1));
    597                                     if(NULL != moved)
    598                                     {
    599                                         unsigned symIndex = 0;
    600 
    601                                         /*
    602                                         **  Record symbol details.
    603                                         **  Assumed symbols are encountered in order for their section (size calc depends on it).
    604                                         */
    605                                         symIndex = inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount;
    606                                         inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbolCount++;
    607                                         inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols = (MSDump_Symbol*)moved;
    608                                         memset(&inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex], 0, sizeof(MSDump_Symbol));
    609 
    610                                         inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mOffset = offset;
    611 
    612                                         /*
    613                                         **  We could allocate smarter here if it ever mattered.
    614                                         */
    615                                         inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName = strdup(symbolArg);
    616                                         if(NULL != inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName)
    617                                         {
    618                                             char* trim = NULL;
    619 
    620                                             trim = (char*)skipNonWhite(inContainer->mReadState.mCurrentObject->mSections[sectionIndex].mSymbols[symIndex].mName);
    621                                             if(NULL != trim)
    622                                             {
    623                                                 *trim = '\0';
    624                                             }
    625                                         }
    626                                         else
    627                                         {
    628                                             retval = __LINE__;
    629                                             ERROR_REPORT(retval, inLine, "Unable to duplicate symbol name.");
    630                                         }
    631                                     }
    632                                     else
    633                                     {
    634                                         retval = __LINE__;
    635                                         ERROR_REPORT(retval, inLine, "Unable to grow symbol array for section.");
    636                                     }
    637                                 }
    638                                 else
    639                                 {
    640                                     retval = __LINE__;
    641                                     ERROR_REPORT(retval, inLine, "Unable to convert offset to a number.");
    642                                 }
    643                             }
    644                         }
    645                     }
    646                     else
    647                     {
    648                         retval = __LINE__;
    649                         ERROR_REPORT(retval, inLine, "Unable to determine section index.");
    650                     }
    651                 }
    652                 else
    653                 {
    654                     retval = __LINE__;
    655                     ERROR_REPORT(retval, inLine, "No match for section prefix.");
    656                 }
    657             }
    658         }
    659         else
    660         {
    661             retval = __LINE__;
    662             ERROR_REPORT(retval, inLine, "Unable to scan for section.");
    663         }
    664     }
    665 
    666     return retval;
    667 }
    668 
    669 
    670 void dumpCleanup(MSDump_Container* inContainer)
    671 /*
    672 **  Attempt to be nice and free up what we have allocated.
    673 */
    674 {
    675     unsigned objectLoop = 0;
    676     unsigned sectionLoop = 0;
    677     unsigned symbolLoop = 0;
    678 
    679     for(objectLoop = 0; objectLoop < inContainer->mObjectCount; objectLoop++)
    680     {
    681         for(sectionLoop = 0; sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
    682         {
    683             for(symbolLoop = 0; symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
    684             {
    685                 CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName);
    686             }
    687             inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount = 0;
    688             CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols);
    689             CLEANUP(inContainer->mObjects[objectLoop].mSections[sectionLoop].mType);
    690         }
    691         inContainer->mObjects[objectLoop].mSectionCount = 0;
    692         CLEANUP(inContainer->mObjects[objectLoop].mSections);
    693     }
    694     CLEANUP(inContainer->mObjects);
    695     inContainer->mObjectCount = 0;
    696 }
    697 
    698 
    699 int qsortSymOffset(const void* in1, const void* in2)
    700 /*
    701 **  qsort callback to sort the symbols by their offset.
    702 */
    703 {
    704     MSDump_Symbol* sym1 = (MSDump_Symbol*)in1;
    705     MSDump_Symbol* sym2 = (MSDump_Symbol*)in2;
    706     int retval = 0;
    707 
    708     if(sym1->mOffset < sym2->mOffset)
    709     {
    710         retval = 1;
    711     }
    712     else if(sym1->mOffset > sym2->mOffset)
    713     {
    714         retval = -1;
    715     }
    716 
    717     return retval;
    718 }
    719 
    720 
    721 int calcContainer(Options* inOptions, MSDump_Container* inContainer)
    722 /*
    723 **  Resposible for doing any size calculations based on the offsets known.
    724 **  After this calculation, each sections mUsed will match mSize.
    725 **  After this calculation, all symbols should know how big they are.
    726 */
    727 {
    728     int retval = 0;
    729     unsigned objectLoop = 0;
    730     unsigned sectionLoop = 0;
    731     unsigned symbolLoop = 0;
    732 
    733 
    734     /*
    735     **  Need to sort all symbols by their offsets.
    736     */
    737     for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
    738     {
    739         for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
    740         {
    741             qsort(
    742                 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols,
    743                 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount,
    744                 sizeof(MSDump_Symbol),
    745                 qsortSymOffset
    746                 );
    747         }
    748     }
    749 
    750 
    751     /*
    752     **  Need to go through all symbols and calculate their size.
    753     */
    754     for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
    755     {
    756         for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
    757         {
    758             for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
    759             {
    760                 inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize =
    761                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mLength -
    762                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed -
    763                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mOffset;
    764 
    765                 inContainer->mObjects[objectLoop].mSections[sectionLoop].mUsed +=
    766                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize;
    767             }
    768         }
    769     }
    770 
    771 
    772     return retval;
    773 }
    774 
    775 
    776 int reportContainer(Options* inOptions, MSDump_Container* inContainer)
    777 /*
    778 **  Display all symbols and their data.
    779 **  We'll use a tsv format.
    780 */
    781 {
    782     int retval = 0;
    783     unsigned objectLoop = 0;
    784     unsigned sectionLoop = 0;
    785     unsigned symbolLoop = 0;
    786     int printRes = 0;
    787 
    788     for(objectLoop = 0; 0 == retval && objectLoop < inContainer->mObjectCount; objectLoop++)
    789     {
    790         for(sectionLoop = 0; 0 == retval && sectionLoop < inContainer->mObjects[objectLoop].mSectionCount; sectionLoop++)
    791         {
    792             for(symbolLoop = 0; 0 == retval && symbolLoop < inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbolCount; symbolLoop++)
    793             {
    794                 printRes = fprintf(inOptions->mOutput, "%s\t%s\t%.8X\t%s\n",
    795                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mName,
    796                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mType,
    797                     inContainer->mObjects[objectLoop].mSections[sectionLoop].mSymbols[symbolLoop].mSize,
    798                     inContainer->mObjects[objectLoop].mObject
    799                     );
    800 
    801                 if(0 > printRes)
    802                 {
    803                     retval = __LINE__;
    804                     ERROR_REPORT(retval, inOptions->mOutputName, "Unable to write to file.");
    805                 }
    806             }
    807         }
    808     }
    809 
    810     return retval;
    811 }
    812 
    813 
    814 int dump2symdb(Options* inOptions)
    815 /*
    816 **  Convert the input into the output, respecting the options.
    817 **  Returns 0 on success.
    818 */
    819 {
    820     int retval = 0;
    821     char lineBuffer[0x800];
    822     MSDump_Container container;
    823 
    824     memset(&container, 0, sizeof(container));
    825 
    826     /*
    827     **  Read the file line by line.
    828     */
    829     while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
    830     {
    831         if(0 != container.mReadState.mSkipLines)
    832         {
    833             container.mReadState.mSkipLines--;
    834             continue;
    835         }
    836         retval = processLine(inOptions, &container, lineBuffer);
    837     }
    838 
    839     /*
    840     **  Perform whatever calculations desired.
    841     */
    842     if(0 == retval)
    843     {
    844         retval = calcContainer(inOptions, &container);
    845     }
    846 
    847     /*
    848     **  Output what we know.
    849     */
    850     if(0 == retval)
    851     {
    852         retval = reportContainer(inOptions, &container);
    853     }
    854 
    855     /*
    856     **  Cleanup what we've done.
    857     */
    858     dumpCleanup(&container);
    859 
    860     return retval;
    861 }
    862 
    863 
    864 int initOptions(Options* outOptions, int inArgc, char** inArgv)
    865 /*
    866 **  returns int     0 if successful.
    867 */
    868 {
    869     int retval = 0;
    870     int loop = 0;
    871     int switchLoop = 0;
    872     int match = 0;
    873     const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
    874     Switch* current = NULL;
    875 
    876     /*
    877     **  Set any defaults.
    878     */
    879     memset(outOptions, 0, sizeof(Options));
    880     outOptions->mProgramName = inArgv[0];
    881     outOptions->mInput = stdin;
    882     outOptions->mInputName = strdup("stdin");
    883     outOptions->mOutput = stdout;
    884     outOptions->mOutputName = strdup("stdout");
    885 
    886     if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
    887     {
    888         retval = __LINE__;
    889         ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
    890     }
    891 
    892     /*
    893     **  Go through and attempt to do the right thing.
    894     */
    895     for(loop = 1; loop < inArgc && 0 == retval; loop++)
    896     {
    897         match = 0;
    898         current = NULL;
    899 
    900         for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
    901         {
    902             if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
    903             {
    904                 match = __LINE__;
    905             }
    906             else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
    907             {
    908                 match = __LINE__;
    909             }
    910 
    911             if(match)
    912             {
    913                 if(gSwitches[switchLoop]->mHasValue)
    914                 {
    915                     /*
    916                     **  Attempt to absorb next option to fullfill value.
    917                     */
    918                     if(loop + 1 < inArgc)
    919                     {
    920                         loop++;
    921 
    922                         current = gSwitches[switchLoop];
    923                         current->mValue = inArgv[loop];
    924                     }
    925                 }
    926                 else
    927                 {
    928                     current = gSwitches[switchLoop];
    929                 }
    930 
    931                 break;
    932             }
    933         }
    934 
    935         if(0 == match)
    936         {
    937             outOptions->mHelp = __LINE__;
    938             retval = __LINE__;
    939             ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
    940         }
    941         else if(NULL == current)
    942         {
    943             outOptions->mHelp = __LINE__;
    944             retval = __LINE__;
    945             ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
    946         }
    947         else
    948         {
    949             /*
    950             ** Do something based on address/swtich.
    951             */
    952             if(current == &gInputSwitch)
    953             {
    954                 CLEANUP(outOptions->mInputName);
    955                 if(NULL != outOptions->mInput && stdin != outOptions->mInput)
    956                 {
    957                     fclose(outOptions->mInput);
    958                     outOptions->mInput = NULL;
    959                 }
    960 
    961                 outOptions->mInput = fopen(current->mValue, "r");
    962                 if(NULL == outOptions->mInput)
    963                 {
    964                     retval = __LINE__;
    965                     ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
    966                 }
    967                 else
    968                 {
    969                     outOptions->mInputName = strdup(current->mValue);
    970                     if(NULL == outOptions->mInputName)
    971                     {
    972                         retval = __LINE__;
    973                         ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
    974                     }
    975                 }
    976             }
    977             else if(current == &gOutputSwitch)
    978             {
    979                 CLEANUP(outOptions->mOutputName);
    980                 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
    981                 {
    982                     fclose(outOptions->mOutput);
    983                     outOptions->mOutput = NULL;
    984                 }
    985 
    986                 outOptions->mOutput = fopen(current->mValue, "a");
    987                 if(NULL == outOptions->mOutput)
    988                 {
    989                     retval = __LINE__;
    990                     ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
    991                 }
    992                 else
    993                 {
    994                     outOptions->mOutputName = strdup(current->mValue);
    995                     if(NULL == outOptions->mOutputName)
    996                     {
    997                         retval = __LINE__;
    998                         ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
    999                     }
   1000                 }
   1001             }
   1002             else if(current == &gHelpSwitch)
   1003             {
   1004                 outOptions->mHelp = __LINE__;
   1005             }
   1006             else
   1007             {
   1008                 retval = __LINE__;
   1009                 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
   1010             }
   1011         }
   1012     }
   1013 
   1014     return retval;
   1015 }
   1016 
   1017 
   1018 void cleanOptions(Options* inOptions)
   1019 /*
   1020 **  Clean up any open handles.
   1021 */
   1022 {
   1023     CLEANUP(inOptions->mInputName);
   1024     if(NULL != inOptions->mInput && stdin != inOptions->mInput)
   1025     {
   1026         fclose(inOptions->mInput);
   1027     }
   1028     CLEANUP(inOptions->mOutputName);
   1029     if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
   1030     {
   1031         fclose(inOptions->mOutput);
   1032     }
   1033 
   1034     memset(inOptions, 0, sizeof(Options));
   1035 }
   1036 
   1037 
   1038 void showHelp(Options* inOptions)
   1039 /*
   1040 **  Show some simple help text on usage.
   1041 */
   1042 {
   1043     int loop = 0;
   1044     const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
   1045     const char* valueText = NULL;
   1046 
   1047     printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
   1048     printf("\n");
   1049     printf("arguments:\n");
   1050 
   1051     for(loop = 0; loop < switchCount; loop++)
   1052     {
   1053         if(gSwitches[loop]->mHasValue)
   1054         {
   1055             valueText = " <value>";
   1056         }
   1057         else
   1058         {
   1059             valueText = "";
   1060         }
   1061 
   1062         printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
   1063         printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
   1064         printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
   1065     }
   1066 
   1067     printf("This tool takes the output of \"dumpbin /symbols\" to produce a simple\n");
   1068     printf("tsv db file of symbols and their respective attributes, like size.\n");
   1069 }
   1070 
   1071 
   1072 int main(int inArgc, char** inArgv)
   1073 {
   1074     int retval = 0;
   1075     Options options;
   1076 
   1077     retval = initOptions(&options, inArgc, inArgv);
   1078     if(options.mHelp)
   1079     {
   1080         showHelp(&options);
   1081     }
   1082     else if(0 == retval)
   1083     {
   1084         retval = dump2symdb(&options);
   1085     }
   1086 
   1087     cleanOptions(&options);
   1088     return retval;
   1089 }
   1090 
   1091