1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
16 * The Original Code is msdump2symdb.c code, released
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.
25 * Garrett Arch Blythe, 16-January-2003
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.
39 * ***** END LICENSE BLOCK ***** */
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)
52 typedef struct __struct_Options
54 ** Options to control how we perform.
56 ** mProgramName Used in help text.
57 ** mInput File to read for input.
59 ** mInputName Name of the file.
60 ** mOutput Output file, append.
62 ** mOutputName Name of the file.
63 ** mHelp Whether or not help should be shown.
66 const char* mProgramName
;
76 typedef struct __struct_Switch
78 ** Command line options.
81 const char* mLongName
;
82 const char* mShortName
;
85 const char* mDescription
;
89 #define DESC_NEWLINE "\n\t\t"
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."};
95 static Switch
* gSwitches
[] = {
102 typedef struct __struct_MSDump_Symbol
104 ** Struct to hold infomration on a symbol.
106 ** mSize Size of the symbol once all work is complete.
107 ** mOffset Offset of the symbol in the section.
108 ** mName Symbolic name.
118 typedef struct __struct_MSDump_Section
120 ** Struct for holding information on a section.
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.
134 MSDump_Symbol
* mSymbols
;
135 unsigned mSymbolCount
;
140 typedef struct __struct_MSDump_Object
142 ** Struct for holding object's data.
147 MSDump_Section
* mSections
;
148 unsigned mSectionCount
;
153 typedef struct __struct_MSDump_ReadState
155 ** State flags while reading the input gives us hints on what to do.
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.
163 unsigned mSectionDetails
;
164 MSDump_Object
* mCurrentObject
;
169 typedef struct __struct_MSDump_Container
171 ** Umbrella container for all data encountered.
174 MSDump_ReadState mReadState
;
176 MSDump_Object
* mObjects
;
177 unsigned mObjectCount
;
182 void trimWhite(char* inString
)
184 ** Remove any whitespace from the end of the string.
187 int len
= strlen(inString
);
193 if(isspace(*(inString
+ len
)))
195 *(inString
+ len
) = '\0';
205 const char* skipWhite(const char* inString
)
207 ** Return pointer to first non white space character.
210 const char* retval
= inString
;
212 while('\0' != *retval
&& isspace(*retval
))
221 const char* skipNonWhite(const char* inString
)
223 ** Return pointer to first white space character.
226 const char* retval
= inString
;
228 while('\0' != *retval
&& !isspace(*retval
))
237 void slash2bs(char* inString
)
239 ** Change any forward slash to a backslash.
242 char* slash
= inString
;
244 while(NULL
!= (slash
= strchr(slash
, '/')))
252 const char* skipToArg(const char* inString
, unsigned inArgIndex
)
254 ** Return pointer either to the arg or NULL.
258 const char* retval
= NULL
;
260 while(0 != inArgIndex
&& '\0' != *inString
)
264 inString
= skipWhite(inString
);
267 inString
= skipNonWhite(inString
);
271 if('\0' != *inString
)
280 const char* getLastArg(const char* inString
)
282 ** Return pointer to last arg in string.
285 const char* retval
= NULL
;
289 length
= strlen(inString
);
296 if(0 == isspace(inString
[length
]))
298 sawString
= __LINE__
;
303 if(0 != isspace(inString
[length
]))
305 retval
= inString
+ length
+ 1;
314 int processLine(Options
* inOptions
, MSDump_Container
* inContainer
, const char* inLine
)
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.
326 ** Check to see if we were expecting section details.
328 if(0 != inContainer
->mReadState
.mSectionDetails
)
330 const char* length
= NULL
;
331 unsigned sectionIndex
= 0;
334 ** Detail is a 1 based index....
337 sectionIndex
= inContainer
->mReadState
.mSectionDetails
- 1;
338 inContainer
->mReadState
.mSectionDetails
= 0;
340 if(0 == strncmp(" Section length", inLine
, 18))
342 const char* sectionLength
= NULL
;
343 unsigned numericLength
= 0;
344 char* endScan
= NULL
;
346 sectionLength
= skipWhite(inLine
+ 18);
349 numericLength
= strtoul(sectionLength
, &endScan
, 16);
350 if(0 == errno
&& endScan
!= sectionLength
)
352 inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mLength
= numericLength
;
357 ERROR_REPORT(retval
, inLine
, "Cannot scan for section length.");
363 ERROR_REPORT(retval
, inLine
, "Cannot parse section line.");
367 ** Check for switching object file symbols.
369 else if(0 == strncmp("Dump of file ", inLine
, 13))
371 const char* dupMe
= inLine
+ 13;
383 growth
= realloc(inContainer
->mObjects
, (inContainer
->mObjectCount
+ 1) * sizeof(MSDump_Object
));
386 unsigned int index
= inContainer
->mObjectCount
;
388 inContainer
->mObjectCount
++;
389 inContainer
->mObjects
= growth
;
390 memset(inContainer
->mObjects
+ index
, 0, sizeof(MSDump_Object
));
392 inContainer
->mObjects
[index
].mObject
= dup
;
395 ** Reset the read state for this new object.
397 memset(&inContainer
->mReadState
, 0, sizeof(MSDump_ReadState
));
400 ** Record our current object file.
402 inContainer
->mReadState
.mCurrentObject
= inContainer
->mObjects
+ index
;
405 ** We can skip a few lines.
407 inContainer
->mReadState
.mSkipLines
= 4;
412 ERROR_REPORT(retval
, dup
, "Unable to grow object array.");
419 ERROR_REPORT(retval
, dupMe
, "Unable to copy string.");
424 ** Check for a symbol dump or a section header.
426 else if(isxdigit(*inLine
) && isxdigit(*(inLine
+ 1)) && isxdigit(*(inLine
+ 2)))
428 const char* sectionString
= NULL
;
431 ** Determine the section for this line.
432 ** Ignore DEBUG sections.
434 sectionString
= skipToArg(inLine
, 3);
435 if(NULL
!= sectionString
)
437 if(0 != strncmp(sectionString
, "DEBUG", 5) && 0 != strncmp(sectionString
, "ABS", 3) && 0 != strncmp(sectionString
, "UNDEF", 5))
440 ** MUST start with "SECT"
442 if(0 == strncmp(sectionString
, "SECT", 4))
444 unsigned sectionIndex1
= 0;
446 char *endScan
= NULL
;
451 ** Convert the remaining string to an index.
452 ** It will be 1 based.
455 sectionIndex1
= strtoul(sectionString
, &endScan
, 16);
456 if(0 == errno
&& endScan
!= sectionString
&& 0 != sectionIndex1
)
458 unsigned sectionIndex
= sectionIndex1
- 1;
461 ** Is this a new section? Assumed to be ascending.
462 ** Or is this a symbol in the section?
464 if(sectionIndex1
> inContainer
->mReadState
.mCurrentObject
->mSectionCount
)
466 const char* typeArg
= NULL
;
469 ** New Section, figure out the type.
471 typeArg
= skipToArg(sectionString
, 5);
474 char* typeDup
= NULL
;
477 ** Skip the leading period before duping.
483 typeDup
= strdup(typeArg
);
488 char* nonWhite
= NULL
;
491 ** Terminate the duplicate after the section type.
493 nonWhite
= (char*)skipNonWhite(typeDup
);
500 ** Create more space for the section in the object...
502 moved
= realloc(inContainer
->mReadState
.mCurrentObject
->mSections
, sizeof(MSDump_Section
) * sectionIndex1
);
505 unsigned oldCount
= inContainer
->mReadState
.mCurrentObject
->mSectionCount
;
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
));
512 ** Other section details.
514 inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mType
= typeDup
;
518 ** Mark it so that we look for the length on the next line.
519 ** This happens on next entry into the read state.
521 inContainer
->mReadState
.mSectionDetails
= sectionIndex1
;
526 ERROR_REPORT(retval
, inLine
, "Unable to grow for new section.");
533 ERROR_REPORT(retval
, typeArg
, "Unable to duplicate type.");
539 ERROR_REPORT(retval
, inLine
, "Unable to determine section type.");
545 const char* offsetArg
= NULL
;
546 const char* classArg
= NULL
;
547 unsigned classWords
= 1;
548 const char* symbolArg
= NULL
;
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.
556 offsetArg
= skipToArg(inLine
, 2);
558 classArg
= skipToArg(offsetArg
, 4);
559 if(0 == strncmp(classArg
, "()", 2))
561 classArg
= skipToArg(classArg
, 2);
563 if(0 == strncmp(classArg
, ".bf or.ef", 9))
568 symbolArg
= skipToArg(classArg
, 3 + (classWords
- 1));
571 ** Skip particular lines/items.
574 0 != strncmp(classArg
, "Label", 5) &&
575 0 != strncmp(symbolArg
, ".bf", 3) &&
576 0 != strncmp(symbolArg
, ".lf", 3) &&
577 0 != strncmp(symbolArg
, ".ef", 3)
580 char* endOffsetArg
= NULL
;
584 ** Convert the offset to something meaninful (size).
587 offset
= strtoul(offsetArg
, &endOffsetArg
, 16);
588 if(0 == errno
&& endOffsetArg
!= offsetArg
)
593 ** Increase the size of the symbol array in the section.
594 ** Assumed symbols are unique within each section.
596 moved
= realloc(inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mSymbols
, sizeof(MSDump_Symbol
) * (inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mSymbolCount
+ 1));
599 unsigned symIndex
= 0;
602 ** Record symbol details.
603 ** Assumed symbols are encountered in order for their section (size calc depends on it).
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
));
610 inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mSymbols
[symIndex
].mOffset
= offset
;
613 ** We could allocate smarter here if it ever mattered.
615 inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mSymbols
[symIndex
].mName
= strdup(symbolArg
);
616 if(NULL
!= inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mSymbols
[symIndex
].mName
)
620 trim
= (char*)skipNonWhite(inContainer
->mReadState
.mCurrentObject
->mSections
[sectionIndex
].mSymbols
[symIndex
].mName
);
629 ERROR_REPORT(retval
, inLine
, "Unable to duplicate symbol name.");
635 ERROR_REPORT(retval
, inLine
, "Unable to grow symbol array for section.");
641 ERROR_REPORT(retval
, inLine
, "Unable to convert offset to a number.");
649 ERROR_REPORT(retval
, inLine
, "Unable to determine section index.");
655 ERROR_REPORT(retval
, inLine
, "No match for section prefix.");
662 ERROR_REPORT(retval
, inLine
, "Unable to scan for section.");
670 void dumpCleanup(MSDump_Container
* inContainer
)
672 ** Attempt to be nice and free up what we have allocated.
675 unsigned objectLoop
= 0;
676 unsigned sectionLoop
= 0;
677 unsigned symbolLoop
= 0;
679 for(objectLoop
= 0; objectLoop
< inContainer
->mObjectCount
; objectLoop
++)
681 for(sectionLoop
= 0; sectionLoop
< inContainer
->mObjects
[objectLoop
].mSectionCount
; sectionLoop
++)
683 for(symbolLoop
= 0; symbolLoop
< inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbolCount
; symbolLoop
++)
685 CLEANUP(inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbols
[symbolLoop
].mName
);
687 inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbolCount
= 0;
688 CLEANUP(inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbols
);
689 CLEANUP(inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mType
);
691 inContainer
->mObjects
[objectLoop
].mSectionCount
= 0;
692 CLEANUP(inContainer
->mObjects
[objectLoop
].mSections
);
694 CLEANUP(inContainer
->mObjects
);
695 inContainer
->mObjectCount
= 0;
699 int qsortSymOffset(const void* in1
, const void* in2
)
701 ** qsort callback to sort the symbols by their offset.
704 MSDump_Symbol
* sym1
= (MSDump_Symbol
*)in1
;
705 MSDump_Symbol
* sym2
= (MSDump_Symbol
*)in2
;
708 if(sym1
->mOffset
< sym2
->mOffset
)
712 else if(sym1
->mOffset
> sym2
->mOffset
)
721 int calcContainer(Options
* inOptions
, MSDump_Container
* inContainer
)
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.
729 unsigned objectLoop
= 0;
730 unsigned sectionLoop
= 0;
731 unsigned symbolLoop
= 0;
735 ** Need to sort all symbols by their offsets.
737 for(objectLoop
= 0; 0 == retval
&& objectLoop
< inContainer
->mObjectCount
; objectLoop
++)
739 for(sectionLoop
= 0; 0 == retval
&& sectionLoop
< inContainer
->mObjects
[objectLoop
].mSectionCount
; sectionLoop
++)
742 inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbols
,
743 inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbolCount
,
744 sizeof(MSDump_Symbol
),
752 ** Need to go through all symbols and calculate their size.
754 for(objectLoop
= 0; 0 == retval
&& objectLoop
< inContainer
->mObjectCount
; objectLoop
++)
756 for(sectionLoop
= 0; 0 == retval
&& sectionLoop
< inContainer
->mObjects
[objectLoop
].mSectionCount
; sectionLoop
++)
758 for(symbolLoop
= 0; 0 == retval
&& symbolLoop
< inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbolCount
; symbolLoop
++)
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
;
765 inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mUsed
+=
766 inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbols
[symbolLoop
].mSize
;
776 int reportContainer(Options
* inOptions
, MSDump_Container
* inContainer
)
778 ** Display all symbols and their data.
779 ** We'll use a tsv format.
783 unsigned objectLoop
= 0;
784 unsigned sectionLoop
= 0;
785 unsigned symbolLoop
= 0;
788 for(objectLoop
= 0; 0 == retval
&& objectLoop
< inContainer
->mObjectCount
; objectLoop
++)
790 for(sectionLoop
= 0; 0 == retval
&& sectionLoop
< inContainer
->mObjects
[objectLoop
].mSectionCount
; sectionLoop
++)
792 for(symbolLoop
= 0; 0 == retval
&& symbolLoop
< inContainer
->mObjects
[objectLoop
].mSections
[sectionLoop
].mSymbolCount
; symbolLoop
++)
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
804 ERROR_REPORT(retval
, inOptions
->mOutputName
, "Unable to write to file.");
814 int dump2symdb(Options
* inOptions
)
816 ** Convert the input into the output, respecting the options.
817 ** Returns 0 on success.
821 char lineBuffer
[0x800];
822 MSDump_Container container
;
824 memset(&container
, 0, sizeof(container
));
827 ** Read the file line by line.
829 while(0 == retval
&& NULL
!= fgets(lineBuffer
, sizeof(lineBuffer
), inOptions
->mInput
))
831 if(0 != container
.mReadState
.mSkipLines
)
833 container
.mReadState
.mSkipLines
--;
836 retval
= processLine(inOptions
, &container
, lineBuffer
);
840 ** Perform whatever calculations desired.
844 retval
= calcContainer(inOptions
, &container
);
848 ** Output what we know.
852 retval
= reportContainer(inOptions
, &container
);
856 ** Cleanup what we've done.
858 dumpCleanup(&container
);
864 int initOptions(Options
* outOptions
, int inArgc
, char** inArgv
)
866 ** returns int 0 if successful.
873 const int switchCount
= sizeof(gSwitches
) / sizeof(gSwitches
[0]);
874 Switch
* current
= NULL
;
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");
886 if(NULL
== outOptions
->mOutputName
|| NULL
== outOptions
->mInputName
)
889 ERROR_REPORT(retval
, "stdin/stdout", "Unable to strdup.");
893 ** Go through and attempt to do the right thing.
895 for(loop
= 1; loop
< inArgc
&& 0 == retval
; loop
++)
900 for(switchLoop
= 0; switchLoop
< switchCount
&& 0 == retval
; switchLoop
++)
902 if(0 == strcmp(gSwitches
[switchLoop
]->mLongName
, inArgv
[loop
]))
906 else if(0 == strcmp(gSwitches
[switchLoop
]->mShortName
, inArgv
[loop
]))
913 if(gSwitches
[switchLoop
]->mHasValue
)
916 ** Attempt to absorb next option to fullfill value.
918 if(loop
+ 1 < inArgc
)
922 current
= gSwitches
[switchLoop
];
923 current
->mValue
= inArgv
[loop
];
928 current
= gSwitches
[switchLoop
];
937 outOptions
->mHelp
= __LINE__
;
939 ERROR_REPORT(retval
, inArgv
[loop
], "Unknown command line switch.");
941 else if(NULL
== current
)
943 outOptions
->mHelp
= __LINE__
;
945 ERROR_REPORT(retval
, inArgv
[loop
], "Command line switch requires a value.");
950 ** Do something based on address/swtich.
952 if(current
== &gInputSwitch
)
954 CLEANUP(outOptions
->mInputName
);
955 if(NULL
!= outOptions
->mInput
&& stdin
!= outOptions
->mInput
)
957 fclose(outOptions
->mInput
);
958 outOptions
->mInput
= NULL
;
961 outOptions
->mInput
= fopen(current
->mValue
, "r");
962 if(NULL
== outOptions
->mInput
)
965 ERROR_REPORT(retval
, current
->mValue
, "Unable to open input file.");
969 outOptions
->mInputName
= strdup(current
->mValue
);
970 if(NULL
== outOptions
->mInputName
)
973 ERROR_REPORT(retval
, current
->mValue
, "Unable to strdup.");
977 else if(current
== &gOutputSwitch
)
979 CLEANUP(outOptions
->mOutputName
);
980 if(NULL
!= outOptions
->mOutput
&& stdout
!= outOptions
->mOutput
)
982 fclose(outOptions
->mOutput
);
983 outOptions
->mOutput
= NULL
;
986 outOptions
->mOutput
= fopen(current
->mValue
, "a");
987 if(NULL
== outOptions
->mOutput
)
990 ERROR_REPORT(retval
, current
->mValue
, "Unable to open output file.");
994 outOptions
->mOutputName
= strdup(current
->mValue
);
995 if(NULL
== outOptions
->mOutputName
)
998 ERROR_REPORT(retval
, current
->mValue
, "Unable to strdup.");
1002 else if(current
== &gHelpSwitch
)
1004 outOptions
->mHelp
= __LINE__
;
1009 ERROR_REPORT(retval
, current
->mLongName
, "No handler for command line switch.");
1018 void cleanOptions(Options
* inOptions
)
1020 ** Clean up any open handles.
1023 CLEANUP(inOptions
->mInputName
);
1024 if(NULL
!= inOptions
->mInput
&& stdin
!= inOptions
->mInput
)
1026 fclose(inOptions
->mInput
);
1028 CLEANUP(inOptions
->mOutputName
);
1029 if(NULL
!= inOptions
->mOutput
&& stdout
!= inOptions
->mOutput
)
1031 fclose(inOptions
->mOutput
);
1034 memset(inOptions
, 0, sizeof(Options
));
1038 void showHelp(Options
* inOptions
)
1040 ** Show some simple help text on usage.
1044 const int switchCount
= sizeof(gSwitches
) / sizeof(gSwitches
[0]);
1045 const char* valueText
= NULL
;
1047 printf("usage:\t%s [arguments]\n", inOptions
->mProgramName
);
1049 printf("arguments:\n");
1051 for(loop
= 0; loop
< switchCount
; loop
++)
1053 if(gSwitches
[loop
]->mHasValue
)
1055 valueText
= " <value>";
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
);
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");
1072 int main(int inArgc
, char** inArgv
)
1077 retval
= initOptions(&options
, inArgc
, inArgv
);
1082 else if(0 == retval
)
1084 retval
= dump2symdb(&options
);
1087 cleanOptions(&options
);