Bug 886173 - Preserve playbackRate across pause/play. r=cpearce
[gecko.git] / tools / codesighs / msmap2tsv.c
blobf9cbb8bfdba623f225ddbc7d9331d977cdc505bb
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11 #include <ctype.h>
13 #include "msmap.h"
15 #if defined(_WIN32)
16 #include <windows.h>
17 #include <imagehlp.h>
19 #define F_DEMANGLE 1
20 #define DEMANGLE_STATE_NORMAL 0
21 #define DEMANGLE_STATE_QDECODE 1
22 #define DEMANGLE_STATE_PROLOGUE_1 2
23 #define DEMANGLE_STATE_HAVE_TYPE 3
24 #define DEMANGLE_STATE_DEC_LENGTH 4
25 #define DEMANGLE_STATE_HEX_LENGTH 5
26 #define DEMANGLE_STATE_PROLOGUE_SECONDARY 6
27 #define DEMANGLE_STATE_DOLLAR_1 7
28 #define DEMANGLE_STATE_DOLLAR_2 8
29 #define DEMANGLE_STATE_START 9
30 #define DEMANGLE_STATE_STOP 10
31 #define DEMANGLE_SAFE_CHAR(eval) (isprint(eval) ? eval : ' ')
33 #else
34 #define F_DEMANGLE 0
35 #endif /* WIN32 */
37 #define STRINGIFY(s_) STRINGIFY2(s_)
38 #define STRINGIFY2(s_) #s_
39 #define SYMBOL_BUF_CHARS 511
41 #define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
42 #define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
45 typedef struct __struct_SymDB_Size
47 ** The size of the symbol.
48 ** The size is nested withing a symbols structures to produce a fast
49 ** lookup path.
50 ** The objects are listed in case the client of the symdb needs to
51 ** match the object name in the scenario where multiple symbol
52 ** sizes are present.
54 ** mSize The size of the symbol in these objects.
55 ** mObjects A list of objects containing said symbol.
56 ** mObjectCount Number of objects.
59 unsigned mSize;
60 char** mObjects;
61 unsigned mObjectCount;
63 SymDB_Size;
66 typedef struct __struct_SymDB_Section
68 ** Each section for a symbol has a list of sizes.
69 ** Should there be exactly one size for the symbol, then that
70 ** is the size that should be accepted.
71 ** If there is more than one size, then a match on the object
72 ** should be attempted, held withing each size.
74 ** mName The section name.
75 ** mSizes The varoius sizes of the symbol in this section.
76 ** mSizeCount The number of available sizes.
79 char* mName;
80 SymDB_Size* mSizes;
81 unsigned mSizeCount;
83 SymDB_Section;
86 typedef struct __struct_SymDB_Symbol
88 ** Each symbol has at least one section.
89 ** The section indicates what type of symbol a client may be looking for.
90 ** If there is no match on the section, then the client should not trust
91 ** the symbdb.
93 ** mName The mangled name of the symbol.
94 ** mSections Various sections this symbol belongs to.
95 ** mSectionCount The number of sections.
98 char* mName;
99 SymDB_Section* mSections;
100 unsigned mSectionCount;
102 SymDB_Symbol;
105 #define SYMDB_SYMBOL_GROWBY 0x1000 /* how many sybols to allocate at a time */
108 typedef struct __struct_SymDB_Container
110 ** The symbol DB container object.
111 ** The goal of the symbol DB is to have exactly one SymDB_Symbol for each
112 ** mangled name, no matter how ever many identical mangled names there
113 ** are in the input.
114 ** The input is already expected to be well sorted, futher this leads to
115 ** the ability to binary search for symbol name matches.
117 ** mSymbols The symbols.
118 ** mSymbolCount The number of symbols in the DB.
119 ** mSymbolCapacity The number of symbols we can hold (before realloc).
122 SymDB_Symbol* mSymbols;
123 unsigned mSymbolCount;
124 unsigned mSymbolCapacity;
126 SymDB_Container;
129 typedef struct __struct_Options
131 ** Options to control how we perform.
133 ** mProgramName Used in help text.
134 ** mInput File to read for input.
135 ** Default is stdin.
136 ** mInputName Name of the file.
137 ** mOutput Output file, append.
138 ** Default is stdout.
139 ** mOutputName Name of the file.
140 ** mHelp Whether or not help should be shown.
141 ** mMatchModules Array of strings which the module name should match.
142 ** mMatchModuleCount Number of items in array.
143 ** mSymDBName Symbol DB filename.
144 ** mBatchMode Batch mode.
145 ** When in batch mode, the input file contains a list of
146 ** map files to process.
147 ** Normally the input file is a single map file itself.
150 const char* mProgramName;
151 FILE* mInput;
152 char* mInputName;
153 FILE* mOutput;
154 char* mOutputName;
155 int mHelp;
156 char** mMatchModules;
157 unsigned mMatchModuleCount;
158 char* mSymDBName;
159 SymDB_Container* mSymDB;
160 int mBatchMode;
162 Options;
165 typedef struct __struct_Switch
167 ** Command line options.
170 const char* mLongName;
171 const char* mShortName;
172 int mHasValue;
173 const char* mValue;
174 const char* mDescription;
176 Switch;
178 #define DESC_NEWLINE "\n\t\t"
180 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
181 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
182 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
183 static Switch gMatchModuleSwitch = {"--match-module", "-mm", 1, NULL, "Specify a valid module name." DESC_NEWLINE "Multiple specifications allowed." DESC_NEWLINE "If a module name does not match one of the names specified then no output will occur."};
184 static Switch gSymDBSwitch = {"--symdb", "-sdb", 1, NULL, "Specify a symbol tsv db input file." DESC_NEWLINE "Such a symdb is produced using the tool msdump2symdb." DESC_NEWLINE "This allows better symbol size approximations." DESC_NEWLINE "The symdb file must be pre-sorted."};
185 static Switch gBatchModeSwitch = {"--batch", "-b", 0, NULL, "Runs in batch mode." DESC_NEWLINE "The input file contains a list of map files." DESC_NEWLINE "Normally the input file is a map file itself." DESC_NEWLINE "This eliminates reprocessing the symdb for multiple map files."};
187 static Switch* gSwitches[] = {
188 &gInputSwitch,
189 &gOutputSwitch,
190 &gMatchModuleSwitch,
191 &gSymDBSwitch,
192 &gBatchModeSwitch,
193 &gHelpSwitch
197 typedef struct __struct_MSMap_ReadState
199 ** Keep track of what state we are while reading input.
200 ** This gives the input context in which we absorb the datum.
203 int mHasModule;
205 int mHasTimestamp;
207 int mHasPreferredLoadAddress;
209 int mHasSegmentData;
210 int mSegmentDataSkippedLine;
212 int mHasPublicSymbolData;
213 int mHasPublicSymbolDataSkippedLines;
215 int mHasEntryPoint;
217 int mFoundStaticSymbols;
219 MSMap_ReadState;
222 char* skipWhite(char* inScan)
224 ** Skip whitespace.
227 char* retval = inScan;
229 while(isspace(*retval))
231 retval++;
234 return retval;
237 void trimWhite(char* inString)
239 ** Remove any whitespace from the end of the string.
242 int len = strlen(inString);
244 while(len)
246 len--;
248 if(isspace(*(inString + len)))
250 *(inString + len) = '\0';
252 else
254 break;
260 char* lastWord(char* inString)
262 ** Finds and returns the last word in a string.
263 ** It is assumed no whitespace is at the end of the string.
266 int mod = 0;
267 int len = strlen(inString);
269 while(len)
271 len--;
272 if(isspace(*(inString + len)))
274 mod = 1;
275 break;
279 return inString + len + mod;
283 MSMap_Segment* getSymbolSection(MSMap_Module* inModule, MSMap_Symbol* inoutSymbol)
285 ** Perform a lookup for the section of the symbol.
286 ** The function could cache the value.
289 MSMap_Segment* retval = NULL;
291 if(NULL != inoutSymbol->mSection)
294 ** Use cached value.
296 retval = inoutSymbol->mSection;
298 else
300 unsigned secLoop = 0;
303 ** Go through sections in module to find the match for the symbol.
305 for(secLoop = 0; secLoop < inModule->mSegmentCount; secLoop++)
307 if(inoutSymbol->mPrefix == inModule->mSegments[secLoop].mPrefix)
309 if(inoutSymbol->mOffset >= inModule->mSegments[secLoop].mOffset)
311 if(inoutSymbol->mOffset < (inModule->mSegments[secLoop].mOffset + inModule->mSegments[secLoop].mLength))
314 ** We have the section.
316 retval = &inModule->mSegments[secLoop];
317 break;
324 ** Cache the value for next time.
326 inoutSymbol->mSection = retval;
329 return retval;
333 int readSymDB(const char* inDBName, SymDB_Container** outDB)
335 ** Intialize the symbol DB.
336 ** Only call if the symbol DB should be initialized.
339 int retval = 0;
342 ** Initialize out arguments.
344 if(NULL != outDB)
346 *outDB = NULL;
349 if(NULL != outDB && NULL != inDBName)
351 FILE* symDB = NULL;
353 symDB = fopen(inDBName, "r");
354 if(NULL != symDB)
356 *outDB = (SymDB_Container*)calloc(1, sizeof(SymDB_Container));
357 if(NULL != *outDB)
359 char lineBuf[0x400];
360 char* symbol = NULL;
361 char* section = NULL;
362 char* object = NULL;
363 char* length = NULL;
364 unsigned lengthNum = 0;
365 char* endLength = NULL;
368 ** Read the file line by line.
370 while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), symDB))
372 trimWhite(lineBuf);
375 ** Each line has four arguments. tab separated values (tsv).
376 ** Symbol
377 ** Section
378 ** Length
379 ** Object
382 symbol = skipWhite(lineBuf);
383 if(NULL == symbol)
385 retval = __LINE__;
386 ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
387 break;
390 section = strchr(symbol, '\t');
391 if(NULL == section)
393 retval = __LINE__;
394 ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
395 break;
397 *section = '\0';
398 section++;
400 length = strchr(section, '\t');
401 if(NULL == length)
403 retval = __LINE__;
404 ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
405 break;
407 *length = '\0';
408 length++;
410 object = strchr(length, '\t');
411 if(NULL == object)
413 retval = __LINE__;
414 ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
415 break;
417 *object = '\0';
418 object++;
421 ** Convert the length into a number.
423 errno = 0;
424 lengthNum = strtoul(length, &endLength, 16);
425 if(0 == errno && endLength != length)
427 SymDB_Symbol* dbSymbol = NULL;
428 SymDB_Section* dbSection = NULL;
429 SymDB_Size* dbSize = NULL;
430 char* dbObject = NULL;
431 void* moved = NULL;
434 ** Are we looking at the same symbol as last line?
435 ** This assumes the symdb is pre sorted!!!
437 if(0 != (*outDB)->mSymbolCount)
439 unsigned index = (*outDB)->mSymbolCount - 1;
441 if(0 == strcmp((*outDB)->mSymbols[index].mName, symbol))
443 dbSymbol = &(*outDB)->mSymbols[index];
448 ** May need to create symbol.
450 if(NULL == dbSymbol)
453 ** Could be time to grow the symbol pool.
455 if((*outDB)->mSymbolCount >= (*outDB)->mSymbolCapacity)
457 moved = realloc((*outDB)->mSymbols, sizeof(SymDB_Symbol) * ((*outDB)->mSymbolCapacity + SYMDB_SYMBOL_GROWBY));
458 if(NULL != moved)
460 (*outDB)->mSymbols = (SymDB_Symbol*)moved;
461 memset(&(*outDB)->mSymbols[(*outDB)->mSymbolCapacity], 0, sizeof(SymDB_Symbol) * SYMDB_SYMBOL_GROWBY);
462 (*outDB)->mSymbolCapacity += SYMDB_SYMBOL_GROWBY;
464 else
466 retval = __LINE__;
467 ERROR_REPORT(retval, inDBName, "Unable to grow symbol DB symbol array.");
468 break;
472 if((*outDB)->mSymbolCount < (*outDB)->mSymbolCapacity)
474 dbSymbol = &(*outDB)->mSymbols[(*outDB)->mSymbolCount];
475 (*outDB)->mSymbolCount++;
477 dbSymbol->mName = strdup(symbol);
478 if(NULL == dbSymbol->mName)
480 retval = __LINE__;
481 ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
482 break;
485 else
487 retval = __LINE__;
488 ERROR_REPORT(retval, symbol, "Unable to grow symbol DB for symbol.");
489 break;
494 ** Assume we have the symbol.
496 ** Is this the same section as the last section in the symbol?
497 ** This assumes the symdb was presorted!!!!
499 if(0 != dbSymbol->mSectionCount)
501 unsigned index = dbSymbol->mSectionCount - 1;
503 if(0 == strcmp(dbSymbol->mSections[index].mName, section))
505 dbSection = &dbSymbol->mSections[index];
510 ** May need to create the section.
512 if(NULL == dbSection)
514 moved = realloc(dbSymbol->mSections, sizeof(SymDB_Section) * (dbSymbol->mSectionCount + 1));
515 if(NULL != moved)
517 dbSymbol->mSections = (SymDB_Section*)moved;
518 dbSection = &dbSymbol->mSections[dbSymbol->mSectionCount];
519 dbSymbol->mSectionCount++;
521 memset(dbSection, 0, sizeof(SymDB_Section));
523 dbSection->mName = strdup(section);
524 if(NULL == dbSection->mName)
526 retval = __LINE__;
527 ERROR_REPORT(retval, section, "Unable to duplicate string.");
528 break;
531 else
533 retval = __LINE__;
534 ERROR_REPORT(retval, section, "Unable to grow symbol sections for symbol DB.");
535 break;
540 ** Assume we have the section.
542 ** Is this the same size as the last size?
543 ** This assumes the symdb was presorted!!!
545 if(0 != dbSection->mSizeCount)
547 unsigned index = dbSection->mSizeCount - 1;
549 if(dbSection->mSizes[index].mSize == lengthNum)
551 dbSize = &dbSection->mSizes[index];
556 ** May need to create the size in question.
558 if(NULL == dbSize)
560 moved = realloc(dbSection->mSizes, sizeof(SymDB_Size) * (dbSection->mSizeCount + 1));
561 if(NULL != moved)
563 dbSection->mSizes = (SymDB_Size*)moved;
564 dbSize = &dbSection->mSizes[dbSection->mSizeCount];
565 dbSection->mSizeCount++;
567 memset(dbSize, 0, sizeof(SymDB_Size));
569 dbSize->mSize = lengthNum;
571 else
573 retval = __LINE__;
574 ERROR_REPORT(retval, length, "Unable to grow symbol section sizes for symbol DB.");
575 break;
580 ** Assume we have the size.
582 ** We assume a one to one correllation between size and object.
583 ** Always try to add the new object name.
584 ** As the symdb is assumed to be sorted, the object names should also be in order.
586 moved = realloc(dbSize->mObjects, sizeof(char*) * (dbSize->mObjectCount + 1));
587 if(NULL != moved)
589 dbObject = strdup(object);
591 dbSize->mObjects = (char**)moved;
592 dbSize->mObjects[dbSize->mObjectCount] = dbObject;
593 dbSize->mObjectCount++;
595 if(NULL == dbObject)
597 retval = __LINE__;
598 ERROR_REPORT(retval, object, "Unable to duplicate string.");
599 break;
602 else
604 retval = __LINE__;
605 ERROR_REPORT(retval, object, "Unable to grow symbol section size objects for symbol DB.");
606 break;
609 else
611 retval = __LINE__;
612 ERROR_REPORT(retval, length, "Unable to convert symbol DB length into a number.");
613 break;
617 if(0 == retval && 0 != ferror(symDB))
619 retval = __LINE__;
620 ERROR_REPORT(retval, inDBName, "Unable to read file.");
623 else
625 retval = __LINE__;
626 ERROR_REPORT(retval, inDBName, "Unable to allocate symbol DB.");
629 fclose(symDB);
630 symDB = NULL;
632 else
634 retval = __LINE__;
635 ERROR_REPORT(retval, inDBName, "Unable to open symbol DB.");
638 else
640 retval = __LINE__;
641 ERROR_REPORT(retval, "(NULL)", "Invalid arguments.");
644 return retval;
648 void cleanSymDB(SymDB_Container** inDB)
650 ** Free it all up.
653 if(NULL != inDB && NULL != *inDB)
655 unsigned symLoop = 0;
656 unsigned secLoop = 0;
657 unsigned sizLoop = 0;
658 unsigned objLoop = 0;
660 for(symLoop = 0; symLoop < (*inDB)->mSymbolCount; symLoop++)
662 for(secLoop = 0; secLoop < (*inDB)->mSymbols[symLoop].mSectionCount; secLoop++)
664 for(sizLoop = 0; sizLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizeCount; sizLoop++)
666 for(objLoop = 0; objLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjectCount; objLoop++)
668 CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects[objLoop]);
670 CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects);
672 CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mName);
673 CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes);
675 CLEANUP((*inDB)->mSymbols[symLoop].mName);
676 CLEANUP((*inDB)->mSymbols[symLoop].mSections);
678 CLEANUP((*inDB)->mSymbols);
679 CLEANUP(*inDB);
684 int symDBLookup(const void* inKey, const void* inItem)
686 ** bsearch utility routine to find the symbol in the symdb.
689 int retval = 0;
690 const char* key = (const char*)inKey;
691 const SymDB_Symbol* symbol = (const SymDB_Symbol*)inItem;
693 retval = strcmp(key, symbol->mName);
695 return retval;
699 int fillSymbolSizeFromDB(Options* inOptions, MSMap_Module* inModule, MSMap_Symbol* inoutSymbol, const char* inMangledName)
701 ** If we have a symbol DB, attempt to determine the real size of the symbol
702 ** up front.
703 ** This helps us later in the game to avoid performing size guesses by
704 ** offset.
707 int retval = 0;
710 ** May need to initialize symdb.
712 if(NULL == inOptions->mSymDB && NULL != inOptions->mSymDBName)
714 retval = readSymDB(inOptions->mSymDBName, &inOptions->mSymDB);
718 ** Optional
720 if(0 == retval && NULL != inOptions->mSymDB)
722 void* match = NULL;
725 ** Find the symbol.
727 match = bsearch(inMangledName, inOptions->mSymDB->mSymbols, inOptions->mSymDB->mSymbolCount, sizeof(SymDB_Symbol), symDBLookup);
728 if(NULL != match)
730 SymDB_Symbol* symbol = (SymDB_Symbol*)match;
731 unsigned symDBSize = 0;
732 MSMap_Segment* mapSection = NULL;
735 ** We found the symbol.
737 ** See if it has the section in question.
739 mapSection = getSymbolSection(inModule, inoutSymbol);
740 if(NULL != mapSection)
742 unsigned secLoop = 0;
744 for(secLoop = 0; secLoop < symbol->mSectionCount; secLoop++)
746 if(0 == strcmp(mapSection->mSegment, symbol->mSections[secLoop].mName))
748 SymDB_Section* section = &symbol->mSections[secLoop];
751 ** We have a section match.
752 ** Should there be a single size for the symbol,
753 ** then we just default to that.
754 ** If more than one size, we have to do an
755 ** object match search.
756 ** Should there be no object match, we do nothign.
758 if(1 == section->mSizeCount)
760 symDBSize = section->mSizes[0].mSize;
762 else
764 char* mapObject = NULL;
767 ** Figure out the map object file name.
768 ** Skip any colon.
769 ** If it doesn't have a .obj in it, not worth continuing.
771 mapObject = strrchr(inoutSymbol->mObject, ':');
772 if(NULL == mapObject)
774 mapObject = inoutSymbol->mObject;
776 else
778 mapObject++; /* colon */
781 if(NULL != strstr(mapObject, ".obj"))
783 unsigned sizLoop = 0;
784 unsigned objLoop = 0;
785 SymDB_Size* size = NULL;
787 for(sizLoop = 0; sizLoop < section->mSizeCount; sizLoop++)
789 size = &section->mSizes[sizLoop];
791 for(objLoop = 0; objLoop < size->mObjectCount; objLoop++)
793 if(NULL != strstr(size->mObjects[objLoop], mapObject))
796 ** As we matched the object, in a particular section,
797 ** we'll go with this as the number.
799 symDBSize = size->mSize;
800 break;
805 ** If the object loop broke early, we break too.
807 if(objLoop < size->mObjectCount)
809 break;
815 break;
821 ** Put the size in.
823 inoutSymbol->mSymDBSize = symDBSize;
827 return retval;
831 char* symdup(const char* inSymbol)
833 ** Attempts to demangle the symbol if appropriate.
834 ** Otherwise acts like strdup.
837 char* retval = NULL;
839 #if F_DEMANGLE
841 int isImport = 0;
843 if(0 == strncmp("__imp_", inSymbol, 6))
845 isImport = __LINE__;
846 inSymbol += 6;
849 if('?' == inSymbol[0])
851 char demangleBuf[0x200];
852 DWORD demangleRes = 0;
854 demangleRes = UnDecorateSymbolName(inSymbol, demangleBuf, sizeof(demangleBuf), UNDNAME_COMPLETE);
855 if(0 != demangleRes)
857 if (strcmp(demangleBuf, "`string'") == 0)
860 /* attempt manual demangling of string prefix.. */
862 /* first make sure we have enough space for the
863 updated string - the demangled string will
864 always be shorter than strlen(inSymbol) and the
865 prologue will always be longer than the
866 "string: " that we tack on the front of the string
868 char *curresult = retval = malloc(strlen(inSymbol) + 11);
869 const char *curchar = inSymbol;
871 int state = DEMANGLE_STATE_START;
873 /* the hex state is for stuff like ?$EA which
874 really means hex value 0x40 */
875 char hex_state = 0;
876 char string_is_unicode = 0;
878 /* sometimes we get a null-termination before the
879 final @ sign - in that case, remember that
880 we've seen the whole string */
881 int have_null_char = 0;
883 /* stick our user-readable prefix on */
884 strcpy(curresult, "string: \"");
885 curresult += 9;
887 while (*curchar) {
889 // process current state
890 switch (state) {
892 /* the Prologue states are divided up so
893 that someday we can try to decode
894 the random letters in between the '@'
895 signs. Also, some strings only have 2
896 prologue '@' signs, so we have to
897 figure out how to distinguish between
898 them at some point. */
899 case DEMANGLE_STATE_START:
900 if (*curchar == '@')
901 state = DEMANGLE_STATE_PROLOGUE_1;
902 /* ignore all other states */
903 break;
905 case DEMANGLE_STATE_PROLOGUE_1:
906 switch (*curchar) {
907 case '0':
908 string_is_unicode=0;
909 state = DEMANGLE_STATE_HAVE_TYPE;
910 break;
911 case '1':
912 string_is_unicode=1;
913 state = DEMANGLE_STATE_HAVE_TYPE;
914 break;
916 /* ignore all other characters */
918 break;
920 case DEMANGLE_STATE_HAVE_TYPE:
921 if (*curchar >= '0' && *curchar <= '9') {
922 state = DEMANGLE_STATE_DEC_LENGTH;
923 } else if (*curchar >= 'A' && *curchar <= 'Z') {
924 state = DEMANGLE_STATE_HEX_LENGTH;
926 case DEMANGLE_STATE_DEC_LENGTH:
927 /* decimal lengths don't have the 2nd
928 field
930 if (*curchar == '@')
931 state = DEMANGLE_STATE_NORMAL;
932 break;
934 case DEMANGLE_STATE_HEX_LENGTH:
935 /* hex lengths have a 2nd field
936 (though I have no idea what it is for)
938 if (*curchar == '@')
939 state = DEMANGLE_STATE_PROLOGUE_SECONDARY;
940 break;
942 case DEMANGLE_STATE_PROLOGUE_SECONDARY:
943 if (*curchar == '@')
944 state = DEMANGLE_STATE_NORMAL;
945 break;
947 case DEMANGLE_STATE_NORMAL:
948 switch (*curchar) {
949 case '?':
950 state = DEMANGLE_STATE_QDECODE;
951 break;
952 case '@':
953 state = DEMANGLE_STATE_STOP;
954 break;
955 default:
956 *curresult++ = DEMANGLE_SAFE_CHAR(*curchar);
957 state = DEMANGLE_STATE_NORMAL;
958 break;
960 break;
962 /* found a '?' */
963 case DEMANGLE_STATE_QDECODE:
964 state = DEMANGLE_STATE_NORMAL;
966 /* there are certain shortcuts, like
967 "?3" means ":"
969 switch (*curchar) {
970 case '1':
971 *curresult++ = '/';
972 break;
973 case '2':
974 *curresult++ = '\\';
975 break;
976 case '3':
977 *curresult++ = ':';
978 break;
979 case '4':
980 *curresult++ = '.';
981 break;
982 case '5':
983 *curresult++ = ' ';
984 break;
985 case '6':
986 *curresult++ = '\\';
987 *curresult++ = 'n';
988 break;
989 case '8':
990 *curresult++ = '\'';
991 break;
992 case '9':
993 *curresult++ = '-';
994 break;
996 /* any other arbitrary ASCII value can
997 be stored by prefixing it with ?$
999 case '$':
1000 state = DEMANGLE_STATE_DOLLAR_1;
1002 break;
1004 case DEMANGLE_STATE_DOLLAR_1:
1005 /* first digit of ?$ notation. All digits
1006 are hex, represented starting with the
1007 capital leter 'A' such that 'A' means 0x0,
1008 'B' means 0x1, 'K' means 0xA
1010 hex_state = (*curchar - 'A') * 0x10;
1011 state = DEMANGLE_STATE_DOLLAR_2;
1012 break;
1014 case DEMANGLE_STATE_DOLLAR_2:
1015 /* same mechanism as above */
1016 hex_state += (*curchar - 'A');
1017 if (hex_state) {
1018 *curresult++ = DEMANGLE_SAFE_CHAR(hex_state);
1019 have_null_char = 0;
1021 else {
1022 have_null_char = 1;
1025 state = DEMANGLE_STATE_NORMAL;
1026 break;
1028 case DEMANGLE_STATE_STOP:
1029 break;
1032 curchar++;
1035 /* add the appropriate termination depending
1036 if we completed the string or not */
1037 if (!have_null_char)
1038 strcpy(curresult, "...\"");
1039 else
1040 strcpy(curresult, "\"");
1041 } else {
1042 retval = strdup(demangleBuf);
1045 else
1048 ** fall back to normal.
1050 retval = strdup(inSymbol);
1053 else if('_' == inSymbol[0])
1055 retval = strdup(inSymbol + 1);
1057 else
1059 retval = strdup(inSymbol);
1063 ** May need to rewrite the symbol if an import.
1065 if(NULL != retval && isImport)
1067 const char importPrefix[] = "__declspec(dllimport) ";
1068 char importBuf[0x200];
1069 int printRes = 0;
1071 printRes = _snprintf(importBuf, sizeof(importBuf), "%s%s", importPrefix, retval);
1072 free(retval);
1073 retval = NULL;
1075 if(printRes > 0)
1077 retval = strdup(importBuf);
1081 #else /* F_DEMANGLE */
1082 retval = strdup(inSymbol);
1083 #endif /* F_DEMANGLE */
1085 return retval;
1089 int readmap(Options* inOptions, MSMap_Module* inModule)
1091 ** Read the input line by line, adding it to the module.
1094 int retval = 0;
1095 char lineBuffer[0x400];
1096 char* current = NULL;
1097 MSMap_ReadState fsm;
1098 int len = 0;
1099 int forceContinue = 0;
1101 memset(&fsm, 0, sizeof(fsm));
1104 ** Read the map file line by line.
1105 ** We keep a simple state machine to determine what we're looking at.
1107 while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
1109 if(forceContinue)
1112 ** Used to skip anticipated blank lines.
1114 forceContinue--;
1115 continue;
1118 current = skipWhite(lineBuffer);
1119 trimWhite(current);
1121 len = strlen(current);
1123 if(fsm.mHasModule)
1125 if(fsm.mHasTimestamp)
1127 if(fsm.mHasPreferredLoadAddress)
1129 if(fsm.mHasSegmentData)
1131 if(fsm.mHasPublicSymbolData)
1133 if(fsm.mHasEntryPoint)
1135 if(fsm.mFoundStaticSymbols)
1138 ** A blank line means we've reached the end of all static symbols.
1140 if(len)
1143 ** We're adding a new symbol.
1144 ** Make sure we have room for it.
1146 if(inModule->mSymbolCapacity == inModule->mSymbolCount)
1148 void* moved = NULL;
1150 moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
1151 if(NULL != moved)
1153 inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
1154 inModule->mSymbols = (MSMap_Symbol*)moved;
1156 else
1158 retval = __LINE__;
1159 ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
1163 if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
1165 MSMap_Symbol* theSymbol = NULL;
1166 unsigned index = 0;
1167 int scanRes = 0;
1168 char symbolBuf[SYMBOL_BUF_CHARS + 1];
1170 index = inModule->mSymbolCount;
1171 inModule->mSymbolCount++;
1172 theSymbol = (inModule->mSymbols + index);
1174 memset(theSymbol, 0, sizeof(MSMap_Symbol));
1175 theSymbol->mScope = STATIC;
1177 scanRes = sscanf(current, "%x:%x %" STRINGIFY(SYMBOL_BUF_CHARS) "s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned*)&(theSymbol->mRVABase));
1178 if(4 == scanRes)
1180 theSymbol->mSymbol = symdup(symbolBuf);
1182 if(0 == retval)
1184 if(NULL != theSymbol->mSymbol)
1186 char *last = lastWord(current);
1188 theSymbol->mObject = strdup(last);
1189 if(NULL == theSymbol->mObject)
1191 retval = __LINE__;
1192 ERROR_REPORT(retval, last, "Unable to copy object name.");
1195 else
1197 retval = __LINE__;
1198 ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
1202 else
1204 retval = __LINE__;
1205 ERROR_REPORT(retval, inModule->mModule, "Unable to scan static symbols.");
1209 else
1212 ** All done.
1214 break;
1217 else
1220 ** Static symbols are optional.
1221 ** If no static symbols we're done.
1222 ** Otherwise, set the flag such that it will work more.
1224 if(0 == strcmp(current, "Static symbols"))
1226 fsm.mFoundStaticSymbols = __LINE__;
1227 forceContinue = 1;
1229 else
1232 ** All done.
1234 break;
1238 else
1240 int scanRes = 0;
1242 scanRes = sscanf(current, "entry point at %x:%x", (unsigned*)&(inModule->mEntryPrefix), (unsigned*)&(inModule->mEntryOffset));
1243 if(2 == scanRes)
1245 fsm.mHasEntryPoint = __LINE__;
1246 forceContinue = 1;
1248 else
1250 retval = __LINE__;
1251 ERROR_REPORT(retval, current, "Unable to obtain entry point.");
1255 else
1258 ** Skip the N lines of public symbol data (column headers).
1260 if(2 <= fsm.mHasPublicSymbolDataSkippedLines)
1263 ** A blank line indicates end of public symbols.
1265 if(len)
1268 ** We're adding a new symbol.
1269 ** Make sure we have room for it.
1271 if(inModule->mSymbolCapacity == inModule->mSymbolCount)
1273 void* moved = NULL;
1275 moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
1276 if(NULL != moved)
1278 inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
1279 inModule->mSymbols = (MSMap_Symbol*)moved;
1281 else
1283 retval = __LINE__;
1284 ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
1288 if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
1290 MSMap_Symbol* theSymbol = NULL;
1291 unsigned index = 0;
1292 int scanRes = 0;
1293 char symbolBuf[SYMBOL_BUF_CHARS + 1];
1295 index = inModule->mSymbolCount;
1296 inModule->mSymbolCount++;
1297 theSymbol = (inModule->mSymbols + index);
1299 memset(theSymbol, 0, sizeof(MSMap_Symbol));
1300 theSymbol->mScope = PUBLIC;
1302 scanRes = sscanf(current, "%x:%x %" STRINGIFY(SYMBOL_BUF_CHARS) "s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned *)&(theSymbol->mRVABase));
1303 if(4 == scanRes)
1305 theSymbol->mSymbol = symdup(symbolBuf);
1307 if(NULL != theSymbol->mSymbol)
1309 char *last = lastWord(current);
1311 theSymbol->mObject = strdup(last);
1312 if(NULL != theSymbol->mObject)
1315 ** Finally, attempt to lookup the actual size of the symbol
1316 ** if there is a symbol DB available.
1318 retval = fillSymbolSizeFromDB(inOptions, inModule, theSymbol, symbolBuf);
1320 else
1322 retval = __LINE__;
1323 ERROR_REPORT(retval, last, "Unable to copy object name.");
1326 else
1328 retval = __LINE__;
1329 ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
1332 else
1334 retval = __LINE__;
1335 ERROR_REPORT(retval, inModule->mModule, "Unable to scan public symbols.");
1339 else
1341 fsm.mHasPublicSymbolData = __LINE__;
1344 else
1346 fsm.mHasPublicSymbolDataSkippedLines++;
1350 else
1353 ** Skip the first line of segment data (column headers).
1354 ** Mark that we've begun grabbing segement data.
1356 if(fsm.mSegmentDataSkippedLine)
1359 ** A blank line means end of the segment data.
1361 if(len)
1364 ** We're adding a new segment.
1365 ** Make sure we have room for it.
1367 if(inModule->mSegmentCapacity == inModule->mSegmentCount)
1369 void* moved = NULL;
1371 moved = realloc(inModule->mSegments, sizeof(MSMap_Segment) * (inModule->mSegmentCapacity + MSMAP_SEGMENT_GROWBY));
1372 if(NULL != moved)
1374 inModule->mSegmentCapacity += MSMAP_SEGMENT_GROWBY;
1375 inModule->mSegments = (MSMap_Segment*)moved;
1377 else
1379 retval = __LINE__;
1380 ERROR_REPORT(retval, inModule->mModule, "Unable to grow segments.");
1384 if(0 == retval && inModule->mSegmentCapacity > inModule->mSegmentCount)
1386 MSMap_Segment* theSegment = NULL;
1387 unsigned index = 0;
1388 #define CLASS_BUF_CHARS 15
1389 char classBuf[CLASS_BUF_CHARS + 1];
1390 #define NAME_BUF_CHARS 31
1391 char nameBuf[NAME_BUF_CHARS + 1];
1392 int scanRes = 0;
1394 index = inModule->mSegmentCount;
1395 inModule->mSegmentCount++;
1396 theSegment = (inModule->mSegments + index);
1398 memset(theSegment, 0, sizeof(MSMap_Segment));
1400 scanRes = sscanf(current, "%x:%x %xH %" STRINGIFY(NAME_BUF_CHARS) "s %" STRINGIFY(CLASS_BUF_CHARS) "s", (unsigned*)&(theSegment->mPrefix), (unsigned*)&(theSegment->mOffset), (unsigned*)&(theSegment->mLength), nameBuf, classBuf);
1401 if(5 == scanRes)
1403 if('.' == nameBuf[0])
1405 theSegment->mSegment = strdup(&nameBuf[1]);
1407 else
1409 theSegment->mSegment = strdup(nameBuf);
1412 if(NULL != theSegment->mSegment)
1414 if(0 == strcmp("DATA", classBuf))
1416 theSegment->mClass = DATA;
1418 else if(0 == strcmp("CODE", classBuf))
1420 theSegment->mClass = CODE;
1422 else
1424 retval = __LINE__;
1425 ERROR_REPORT(retval, classBuf, "Unrecognized segment class.");
1428 else
1430 retval = __LINE__;
1431 ERROR_REPORT(retval, nameBuf, "Unable to copy segment name.");
1434 else
1436 retval = __LINE__;
1437 ERROR_REPORT(retval, inModule->mModule, "Unable to scan segments.");
1441 else
1443 fsm.mHasSegmentData = __LINE__;
1446 else
1448 fsm.mSegmentDataSkippedLine = __LINE__;
1452 else
1454 int scanRes = 0;
1457 ** The PLA has a particular format.
1459 scanRes = sscanf(current, "Preferred load address is %x", (unsigned*)&(inModule->mPreferredLoadAddress));
1460 if(1 == scanRes)
1462 fsm.mHasPreferredLoadAddress = __LINE__;
1463 forceContinue = 1;
1465 else
1467 retval = __LINE__;
1468 ERROR_REPORT(retval, current, "Unable to obtain preferred load address.");
1472 else
1474 int scanRes = 0;
1477 ** The timestamp has a particular format.
1479 scanRes = sscanf(current, "Timestamp is %x", (unsigned*)&(inModule->mTimestamp));
1480 if(1 == scanRes)
1482 fsm.mHasTimestamp = __LINE__;
1483 forceContinue = 1;
1485 else
1487 retval = __LINE__;
1488 ERROR_REPORT(retval, current, "Unable to obtain timestamp.");
1492 else
1495 ** The module is on a line by itself.
1497 inModule->mModule = strdup(current);
1498 if(NULL != inModule->mModule)
1500 fsm.mHasModule = __LINE__;
1501 forceContinue = 1;
1503 if(0 != inOptions->mMatchModuleCount)
1505 unsigned matchLoop = 0;
1508 ** If this module name doesn't match, then bail.
1509 ** Compare in a case sensitive manner, exact match only.
1511 for(matchLoop = 0; matchLoop < inOptions->mMatchModuleCount; matchLoop++)
1513 if(0 == strcmp(inModule->mModule, inOptions->mMatchModules[matchLoop]))
1515 break;
1519 if(matchLoop == inOptions->mMatchModuleCount)
1522 ** A match did not occur, bail out of read loop.
1523 ** No error, however.
1525 break;
1529 else
1531 retval = __LINE__;
1532 ERROR_REPORT(retval, current, "Unable to obtain module.");
1537 if(0 == retval && 0 != ferror(inOptions->mInput))
1539 retval = __LINE__;
1540 ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
1543 return retval;
1547 static int qsortRVABase(const void* in1, const void* in2)
1549 ** qsort callback to sort the symbols by their RVABase.
1552 MSMap_Symbol* sym1 = (MSMap_Symbol*)in1;
1553 MSMap_Symbol* sym2 = (MSMap_Symbol*)in2;
1554 int retval = 0;
1556 if(sym1->mRVABase < sym2->mRVABase)
1558 retval = -1;
1560 else if(sym1->mRVABase > sym2->mRVABase)
1562 retval = 1;
1565 return retval;
1569 static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClass, MSMap_SymbolScope inScope, const char* inModule, const char* inSegment, const char* inObject, const char* inSymbol)
1571 ** Output a line of map information separated by tabs.
1572 ** Some items (const char*), if not present, will receive a default value.
1575 int retval = 0;
1578 ** No need to output on no size.
1579 ** This can happen with zero sized segments,
1580 ** or an imported symbol which has multiple names (one will count).
1582 if(0 != inSize)
1584 char objectBuf[0x100];
1585 const char* symScope = NULL;
1586 const char* segClass = NULL;
1587 const char* undefined = "UNDEF";
1590 ** Fill in unspecified values.
1592 if(NULL == inObject)
1594 sprintf(objectBuf, "%s:%s:%s", undefined, inModule, inSegment);
1595 inObject = objectBuf;
1597 if(NULL == inSymbol)
1599 inSymbol = inObject;
1603 ** Convert some enumerations to text.
1605 switch(inClass)
1607 case CODE:
1608 segClass = "CODE";
1609 break;
1610 case DATA:
1611 segClass = "DATA";
1612 break;
1613 default:
1614 retval = __LINE__;
1615 ERROR_REPORT(retval, "", "Unable to determine class for output.");
1616 break;
1619 switch(inScope)
1621 case PUBLIC:
1622 symScope = "PUBLIC";
1623 break;
1624 case STATIC:
1625 symScope = "STATIC";
1626 break;
1627 case UNDEFINED:
1628 symScope = undefined;
1629 break;
1630 default:
1631 retval = __LINE__;
1632 ERROR_REPORT(retval, "", "Unable to determine scope for symbol.");
1633 break;
1636 if(0 == retval)
1638 int printRes = 0;
1640 printRes = fprintf(inOptions->mOutput,
1641 "%.8X\t%s\t%s\t%s\t%s\t%s\t%s\n",
1642 inSize,
1643 segClass,
1644 symScope,
1645 inModule,
1646 inSegment,
1647 inObject,
1648 inSymbol
1651 if(0 > printRes)
1653 retval = __LINE__;
1654 ERROR_REPORT(retval, inOptions->mOutputName, "Unable to output tsv data.");
1659 return retval;
1663 void cleanModule(MSMap_Module* inModule)
1665 unsigned loop = 0;
1667 for(loop = 0; loop < inModule->mSymbolCount; loop++)
1669 CLEANUP(inModule->mSymbols[loop].mObject);
1670 CLEANUP(inModule->mSymbols[loop].mSymbol);
1672 CLEANUP(inModule->mSymbols);
1674 for(loop = 0; loop < inModule->mSegmentCount; loop++)
1676 CLEANUP(inModule->mSegments[loop].mSegment);
1678 CLEANUP(inModule->mSegments);
1680 CLEANUP(inModule->mModule);
1682 memset(inModule, 0, sizeof(MSMap_Module));
1686 int map2tsv(Options* inOptions)
1688 ** Read all input.
1689 ** Output tab separated value data.
1692 int retval = 0;
1693 MSMap_Module module;
1695 memset(&module, 0, sizeof(module));
1698 ** Read in the map file.
1700 retval = readmap(inOptions, &module);
1701 if(0 == retval)
1703 unsigned symLoop = 0;
1704 MSMap_Symbol* symbol = NULL;
1705 unsigned secLoop = 0;
1706 MSMap_Segment* section = NULL;
1707 unsigned size = 0;
1708 unsigned dbSize = 0;
1709 unsigned offsetSize = 0;
1710 unsigned endOffset = 0;
1713 ** Quick sort the symbols via RVABase.
1715 qsort(module.mSymbols, module.mSymbolCount, sizeof(MSMap_Symbol), qsortRVABase);
1718 ** Go through all the symbols (in order by sort).
1719 ** Output their sizes.
1721 for(symLoop = 0; 0 == retval && symLoop < module.mSymbolCount; symLoop++)
1723 symbol = &module.mSymbols[symLoop];
1724 section = getSymbolSection(&module, symbol);
1725 if (!section)
1726 continue;
1729 ** Use the symbol DB size if available.
1731 dbSize = symbol->mSymDBSize;
1734 ** Guess using offsets.
1735 ** Is there a next symbol available? If so, its start offset is the end of this symbol.
1736 ** Otherwise, our section offset + length is the end of this symbol.
1738 ** The trick is, the DB size can not go beyond the offset size, for sanity.
1742 ** Try next symbol, but only if in same section.
1743 ** If still not, use the end of the segment.
1744 ** This implies we were the last symbol in the segment.
1746 if((symLoop + 1) < module.mSymbolCount)
1748 MSMap_Symbol* nextSymbol = NULL;
1749 MSMap_Segment* nextSection = NULL;
1751 nextSymbol = &module.mSymbols[symLoop + 1];
1752 nextSection = getSymbolSection(&module, nextSymbol);
1754 if(section == nextSection)
1756 endOffset = nextSymbol->mOffset;
1758 else
1760 endOffset = section->mOffset + section->mLength;
1763 else
1765 endOffset = section->mOffset + section->mLength;
1769 ** Can now guess at size.
1771 offsetSize = endOffset - symbol->mOffset;
1774 ** Now, determine which size to use.
1775 ** This is really a sanity check as well.
1777 size = offsetSize;
1778 if(0 != dbSize)
1780 if(dbSize < offsetSize)
1782 size = dbSize;
1787 ** Output the symbol with the size.
1789 retval = tsvout(inOptions,
1790 size,
1791 section->mClass,
1792 symbol->mScope,
1793 module.mModule,
1794 section->mSegment,
1795 symbol->mObject,
1796 symbol->mSymbol
1800 ** Make sure we mark this amount of space as used in the section.
1802 section->mUsed += size;
1806 ** Go through the sections, and those whose length is longer than the
1807 ** amount of space used, output dummy filler values.
1809 for(secLoop = 0; 0 == retval && secLoop < module.mSegmentCount; secLoop++)
1811 section = &module.mSegments[secLoop];
1813 if(section && section->mUsed < section->mLength)
1815 retval = tsvout(inOptions,
1816 section->mLength - section->mUsed,
1817 section->mClass,
1818 UNDEFINED,
1819 module.mModule,
1820 section->mSegment,
1821 NULL,
1822 NULL
1829 ** Cleanup.
1831 cleanModule(&module);
1833 return retval;
1837 int initOptions(Options* outOptions, int inArgc, char** inArgv)
1839 ** returns int 0 if successful.
1842 int retval = 0;
1843 int loop = 0;
1844 int switchLoop = 0;
1845 int match = 0;
1846 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
1847 Switch* current = NULL;
1850 ** Set any defaults.
1852 memset(outOptions, 0, sizeof(Options));
1853 outOptions->mProgramName = inArgv[0];
1854 outOptions->mInput = stdin;
1855 outOptions->mInputName = strdup("stdin");
1856 outOptions->mOutput = stdout;
1857 outOptions->mOutputName = strdup("stdout");
1859 if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
1861 retval = __LINE__;
1862 ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
1866 ** Go through and attempt to do the right thing.
1868 for(loop = 1; loop < inArgc && 0 == retval; loop++)
1870 match = 0;
1871 current = NULL;
1873 for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
1875 if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
1877 match = __LINE__;
1879 else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
1881 match = __LINE__;
1884 if(match)
1886 if(gSwitches[switchLoop]->mHasValue)
1889 ** Attempt to absorb next option to fullfill value.
1891 if(loop + 1 < inArgc)
1893 loop++;
1895 current = gSwitches[switchLoop];
1896 current->mValue = inArgv[loop];
1899 else
1901 current = gSwitches[switchLoop];
1904 break;
1908 if(0 == match)
1910 outOptions->mHelp = __LINE__;
1911 retval = __LINE__;
1912 ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
1914 else if(NULL == current)
1916 outOptions->mHelp = __LINE__;
1917 retval = __LINE__;
1918 ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
1920 else
1923 ** Do something based on address/swtich.
1925 if(current == &gInputSwitch)
1927 CLEANUP(outOptions->mInputName);
1928 if(NULL != outOptions->mInput && stdin != outOptions->mInput)
1930 fclose(outOptions->mInput);
1931 outOptions->mInput = NULL;
1934 outOptions->mInput = fopen(current->mValue, "r");
1935 if(NULL == outOptions->mInput)
1937 retval = __LINE__;
1938 ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
1940 else
1942 outOptions->mInputName = strdup(current->mValue);
1943 if(NULL == outOptions->mInputName)
1945 retval = __LINE__;
1946 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
1950 else if(current == &gOutputSwitch)
1952 CLEANUP(outOptions->mOutputName);
1953 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
1955 fclose(outOptions->mOutput);
1956 outOptions->mOutput = NULL;
1959 outOptions->mOutput = fopen(current->mValue, "a");
1960 if(NULL == outOptions->mOutput)
1962 retval = __LINE__;
1963 ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
1965 else
1967 outOptions->mOutputName = strdup(current->mValue);
1968 if(NULL == outOptions->mOutputName)
1970 retval = __LINE__;
1971 ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
1975 else if(current == &gHelpSwitch)
1977 outOptions->mHelp = __LINE__;
1979 else if(current == &gMatchModuleSwitch)
1981 void* moved = NULL;
1984 ** Add the value to the list of allowed module names.
1986 moved = realloc(outOptions->mMatchModules, sizeof(char*) * (outOptions->mMatchModuleCount + 1));
1987 if(NULL != moved)
1989 outOptions->mMatchModules = (char**)moved;
1990 outOptions->mMatchModules[outOptions->mMatchModuleCount] = strdup(current->mValue);
1991 if(NULL != outOptions->mMatchModules[outOptions->mMatchModuleCount])
1993 outOptions->mMatchModuleCount++;
1995 else
1997 retval = __LINE__;
1998 ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
2001 else
2003 retval = __LINE__;
2004 ERROR_REPORT(retval, current->mValue, "Unable to allocate space for string.");
2007 else if(current == &gSymDBSwitch)
2009 CLEANUP(outOptions->mSymDBName);
2010 outOptions->mSymDBName = strdup(current->mValue);
2011 if(NULL == outOptions->mSymDBName)
2013 retval = __LINE__;
2014 ERROR_REPORT(retval, current->mValue, "Unable to duplicate symbol db name.");
2017 else if(current == &gBatchModeSwitch)
2019 outOptions->mBatchMode = __LINE__;
2021 else
2023 retval = __LINE__;
2024 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
2029 return retval;
2033 void cleanOptions(Options* inOptions)
2035 ** Clean up any open handles, et. al.
2038 CLEANUP(inOptions->mInputName);
2039 if(NULL != inOptions->mInput && stdin != inOptions->mInput)
2041 fclose(inOptions->mInput);
2043 CLEANUP(inOptions->mOutputName);
2044 if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
2046 fclose(inOptions->mOutput);
2048 while(0 != inOptions->mMatchModuleCount)
2050 inOptions->mMatchModuleCount--;
2051 CLEANUP(inOptions->mMatchModules[inOptions->mMatchModuleCount]);
2053 CLEANUP(inOptions->mMatchModules);
2055 cleanSymDB(&inOptions->mSymDB);
2057 memset(inOptions, 0, sizeof(Options));
2061 void showHelp(Options* inOptions)
2063 ** Show some simple help text on usage.
2066 int loop = 0;
2067 const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
2068 const char* valueText = NULL;
2070 printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
2071 printf("\n");
2072 printf("arguments:\n");
2074 for(loop = 0; loop < switchCount; loop++)
2076 if(gSwitches[loop]->mHasValue)
2078 valueText = " <value>";
2080 else
2082 valueText = "";
2085 printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
2086 printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
2087 printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
2090 printf("This tool normalizes MS linker .map files for use by other tools.\n");
2094 int batchMode(Options* inOptions)
2096 ** Batch mode means that the input file is actually a list of map files.
2097 ** We simply swap out our input file names while we do this.
2100 int retval = 0;
2101 char lineBuf[0x400];
2102 FILE* realInput = NULL;
2103 char* realInputName = NULL;
2104 FILE* mapFile = NULL;
2105 int finalRes = 0;
2107 realInput = inOptions->mInput;
2108 realInputName = inOptions->mInputName;
2110 while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), realInput))
2112 trimWhite(lineBuf);
2115 ** Skip/allow blank lines.
2117 if('\0' == lineBuf[0])
2119 continue;
2123 ** Override what we believe to be the input for this line.
2125 inOptions->mInputName = lineBuf;
2126 inOptions->mInput = fopen(lineBuf, "r");
2127 if(NULL != inOptions->mInput)
2129 int mapRes = 0;
2132 ** Do it.
2134 mapRes = map2tsv(inOptions);
2137 ** We report the first error that we encounter, but we continue.
2138 ** This is batch mode after all.
2140 if(0 == finalRes)
2142 finalRes = mapRes;
2146 ** Close the input file.
2148 fclose(inOptions->mInput);
2150 else
2152 retval = __LINE__;
2153 ERROR_REPORT(retval, lineBuf, "Unable to open map file.");
2154 break;
2158 if(0 == retval && 0 != ferror(realInput))
2160 retval = __LINE__;
2161 ERROR_REPORT(retval, realInputName, "Unable to read file.");
2165 ** Restore what we've swapped.
2167 inOptions->mInput = realInput;
2168 inOptions->mInputName = realInputName;
2171 ** Report first map file error if there were no other operational
2172 ** problems.
2174 if(0 == retval)
2176 retval = finalRes;
2179 return retval;
2183 int main(int inArgc, char** inArgv)
2185 int retval = 0;
2186 Options options;
2188 retval = initOptions(&options, inArgc, inArgv);
2189 if(options.mHelp)
2191 showHelp(&options);
2193 else if(0 == retval)
2195 if(options.mBatchMode)
2197 retval = batchMode(&options);
2199 else
2201 retval = map2tsv(&options);
2205 cleanOptions(&options);
2206 return retval;