- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / codesighs / msdump2symdb.c
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