- add sources.
[platform/framework/web/crosswalk.git] / src / third_party / codesighs / msmap2tsv.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 msmap2tsv.c code, released
17  * Oct 3, 2002.
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, 03-October-2002
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
47 #include "msmap.h"
48
49 #if defined(_WIN32)
50 #include <windows.h>
51 #include <imagehlp.h>
52
53 #define F_DEMANGLE 1
54 #define DEMANGLE_STATE_NORMAL 0
55 #define DEMANGLE_STATE_QDECODE 1
56 #define DEMANGLE_STATE_PROLOGUE_1 2
57 #define DEMANGLE_STATE_HAVE_TYPE 3
58 #define DEMANGLE_STATE_DEC_LENGTH 4
59 #define DEMANGLE_STATE_HEX_LENGTH 5
60 #define DEMANGLE_STATE_PROLOGUE_SECONDARY 6
61 #define DEMANGLE_STATE_DOLLAR_1 7
62 #define DEMANGLE_STATE_DOLLAR_2 8
63 #define DEMANGLE_STATE_START 9
64 #define DEMANGLE_STATE_STOP 10
65 #define DEMANGLE_SAFE_CHAR(eval)  (isprint(eval) ? eval : ' ')
66
67 #else
68 #define F_DEMANGLE 0
69 #endif /* WIN32 */
70
71
72 #define ERROR_REPORT(num, val, msg)   fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
73 #define CLEANUP(ptr)    do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
74
75
76 typedef struct __struct_SymDB_Size
77 /*
78 **  The size of the symbol.
79 **  The size is nested withing a symbols structures to produce a fast
80 **      lookup path.
81 **  The objects are listed in case the client of the symdb needs to
82 **      match the object name in the scenario where multiple symbol
83 **      sizes are present.
84 **
85 **  mSize           The size of the symbol in these objects.
86 **  mObjects        A list of objects containing said symbol.
87 **  mObjectCount    Number of objects.
88 */
89 {
90     unsigned            mSize;
91     char**              mObjects;
92     unsigned            mObjectCount;
93 }
94 SymDB_Size;
95
96
97 typedef struct __struct_SymDB_Section
98 /*
99 **  Each section for a symbol has a list of sizes.
100 **  Should there be exactly one size for the symbol, then that
101 **      is the size that should be accepted.
102 **  If there is more than one size, then a match on the object
103 **      should be attempted, held withing each size.
104 **
105 **  mName           The section name.
106 **  mSizes          The varoius sizes of the symbol in this section.
107 **  mSizeCount      The number of available sizes.
108 */
109 {
110     char*               mName;
111     SymDB_Size*         mSizes;
112     unsigned            mSizeCount;
113 }
114 SymDB_Section;
115
116
117 typedef struct __struct_SymDB_Symbol
118 /*
119 **  Each symbol has at least one section.
120 **  The section indicates what type of symbol a client may be looking for.
121 **  If there is no match on the section, then the client should not trust
122 **      the symbdb.
123 **
124 **  mName           The mangled name of the symbol.
125 **  mSections       Various sections this symbol belongs to.
126 **  mSectionCount   The number of sections.
127 */
128 {
129     char*               mName;
130     SymDB_Section*      mSections;
131     unsigned            mSectionCount;
132 }
133 SymDB_Symbol;
134
135
136 #define SYMDB_SYMBOL_GROWBY 0x1000 /* how many sybols to allocate at a time */
137
138
139 typedef struct __struct_SymDB_Container
140 /*
141 **  The symbol DB container object.
142 **  The goal of the symbol DB is to have exactly one SymDB_Symbol for each
143 **      mangled name, no matter how ever many identical mangled names there
144 **      are in the input.
145 **  The input is already expected to be well sorted, futher this leads to
146 **      the ability to binary search for symbol name matches.
147 **
148 **  mSymbols        The symbols.
149 **  mSymbolCount    The number of symbols in the DB.
150 **  mSymbolCapacity The number of symbols we can hold (before realloc).
151 */
152 {
153     SymDB_Symbol*       mSymbols;
154     unsigned            mSymbolCount;
155     unsigned            mSymbolCapacity;
156 }
157 SymDB_Container;
158
159
160 typedef struct __struct_Options
161 /*
162 **  Options to control how we perform.
163 **
164 **  mProgramName        Used in help text.
165 **  mInput              File to read for input.
166 **                      Default is stdin.
167 **  mInputName          Name of the file.
168 **  mOutput             Output file, append.
169 **                      Default is stdout.
170 **  mOutputName         Name of the file.
171 **  mHelp               Whether or not help should be shown.
172 **  mMatchModules       Array of strings which the module name should match.
173 **  mMatchModuleCount   Number of items in array.
174 **  mSymDBName          Symbol DB filename.
175 **  mBatchMode          Batch mode.
176 **                      When in batch mode, the input file contains a list of
177 **                          map files to process.
178 **                      Normally the input file is a single map file itself.
179 */
180 {
181     const char* mProgramName;
182     FILE* mInput;
183     char* mInputName;
184     FILE* mOutput;
185     char* mOutputName;
186     int mHelp;
187     char** mMatchModules;
188     unsigned mMatchModuleCount;
189     char* mSymDBName;
190     SymDB_Container* mSymDB;
191     int mBatchMode;
192 }
193 Options;
194
195
196 typedef struct __struct_Switch
197 /*
198 **  Command line options.
199 */
200 {
201     const char* mLongName;
202     const char* mShortName;
203     int mHasValue;
204     const char* mValue;
205     const char* mDescription;
206 }
207 Switch;
208
209 #define DESC_NEWLINE "\n\t\t"
210
211 static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."};
212 static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."};
213 static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
214 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."};
215 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."};
216 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."};
217
218 static Switch* gSwitches[] = {
219         &gInputSwitch,
220         &gOutputSwitch,
221         &gMatchModuleSwitch,
222         &gSymDBSwitch,
223         &gBatchModeSwitch,
224         &gHelpSwitch
225 };
226
227
228 typedef struct __struct_MSMap_ReadState
229 /*
230 **  Keep track of what state we are while reading input.
231 **  This gives the input context in which we absorb the datum.
232 */
233 {
234     int mHasModule;
235
236     int mHasTimestamp;
237
238     int mHasPreferredLoadAddress;
239
240     int mHasSegmentData;
241     int mSegmentDataSkippedLine;
242
243     int mHasPublicSymbolData;
244     int mHasPublicSymbolDataSkippedLines;
245
246     int mHasEntryPoint;
247
248     int mFoundStaticSymbols;
249 }
250 MSMap_ReadState;
251
252
253 char* skipWhite(char* inScan)
254 /*
255 **  Skip whitespace.
256 */
257 {
258     char* retval = inScan;
259
260     while(isspace(*retval))
261     {
262         retval++;
263     }
264
265     return retval;
266 }
267
268 void trimWhite(char* inString)
269 /*
270 **  Remove any whitespace from the end of the string.
271 */
272 {
273     int len = strlen(inString);
274
275     while(len)
276     {
277         len--;
278
279         if(isspace(*(inString + len)))
280         {
281             *(inString + len) = '\0';
282         }
283         else
284         {
285             break;
286         }
287     }
288 }
289
290
291 char* lastWord(char* inString)
292 /*
293 **  Finds and returns the last word in a string.
294 **  It is assumed no whitespace is at the end of the string.
295 */
296 {
297     int mod = 0;
298     int len = strlen(inString);
299
300     while(len)
301     {
302         len--;
303         if(isspace(*(inString + len)))
304         {
305             mod = 1;
306             break;
307         }
308     }
309
310     return inString + len + mod;
311 }
312
313
314 MSMap_Segment* getSymbolSection(MSMap_Module* inModule, MSMap_Symbol* inoutSymbol)
315 /*
316 **  Perform a lookup for the section of the symbol.
317 **  The function could cache the value.
318 */
319 {
320     MSMap_Segment* retval = NULL;
321
322     if(NULL != inoutSymbol->mSection)
323     {
324         /*
325         **  Use cached value.
326         */
327         retval = inoutSymbol->mSection;
328     }
329     else
330     {
331         unsigned secLoop = 0;
332
333         /*
334         **  Go through sections in module to find the match for the symbol.
335         */
336         for(secLoop = 0; secLoop < inModule->mSegmentCount; secLoop++)
337         {
338             if(inoutSymbol->mPrefix == inModule->mSegments[secLoop].mPrefix)
339             {
340                 if(inoutSymbol->mOffset >= inModule->mSegments[secLoop].mOffset)
341                 {
342                     if(inoutSymbol->mOffset < (inModule->mSegments[secLoop].mOffset + inModule->mSegments[secLoop].mLength))
343                     {
344                         /*
345                         **  We have the section.
346                         */
347                         retval = &inModule->mSegments[secLoop];
348                         break;
349                     }
350                 }
351             }
352         }
353
354         /*
355         **  Cache the value for next time.
356         */
357         inoutSymbol->mSection = retval;
358     }
359
360     return retval;
361 }
362
363
364 int readSymDB(const char* inDBName, SymDB_Container** outDB)
365 /*
366 **  Intialize the symbol DB.
367 **  Only call if the symbol DB should be initialized.
368 */
369 {
370     int retval = 0;
371
372     /*
373     **  Initialize out arguments.
374     */
375     if(NULL != outDB)
376     {
377         *outDB = NULL;
378     }
379
380     if(NULL != outDB && NULL != inDBName)
381     {
382         FILE* symDB = NULL;
383
384         symDB = fopen(inDBName, "r");
385         if(NULL != symDB)
386         {
387             *outDB = (SymDB_Container*)calloc(1, sizeof(SymDB_Container));
388             if(NULL != *outDB)
389             {
390                 char lineBuf[0x400];
391                 char* symbol = NULL;
392                 char* section = NULL;
393                 char* object = NULL;
394                 char* length = NULL;
395                 unsigned lengthNum = 0;
396                 char* endLength = NULL;
397                 
398                 /*
399                 **  Read the file line by line.
400                 */
401                 while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), symDB))
402                 {
403                     trimWhite(lineBuf);
404                     
405                     /*
406                     **  Each line has four arguments.  tab separated values (tsv).
407                     **      Symbol
408                     **      Section
409                     **      Length
410                     **      Object
411                     */
412                     
413                     symbol = skipWhite(lineBuf);
414                     if(NULL == symbol)
415                     {
416                         retval = __LINE__;
417                         ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
418                         break;
419                     }
420                     
421                     section = strchr(symbol, '\t');
422                     if(NULL == section)
423                     {
424                         retval = __LINE__;
425                         ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
426                         break;
427                     }
428                     *section = '\0';
429                     section++;
430                     
431                     length = strchr(section, '\t');
432                     if(NULL == length)
433                     {
434                         retval = __LINE__;
435                         ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
436                         break;
437                     }
438                     *length = '\0';
439                     length++;
440                     
441                     object = strchr(length, '\t');
442                     if(NULL == object)
443                     {
444                         retval = __LINE__;
445                         ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB.");
446                         break;
447                     }
448                     *object = '\0';
449                     object++;
450                     
451                     /*
452                     **  Convert the length into a number.
453                     */
454                     errno = 0;
455                     lengthNum = strtoul(length, &endLength, 16);
456                     if(0 == errno && endLength != length)
457                     {
458                         SymDB_Symbol* dbSymbol = NULL;
459                         SymDB_Section* dbSection = NULL;
460                         SymDB_Size* dbSize = NULL;
461                         char* dbObject = NULL;
462                         void* moved = NULL;
463                         
464                         /*
465                         **  Are we looking at the same symbol as last line?
466                         **  This assumes the symdb is pre sorted!!!
467                         */
468                         if(0 != (*outDB)->mSymbolCount)
469                         {
470                             unsigned index = (*outDB)->mSymbolCount - 1;
471                             
472                             if(0 == strcmp((*outDB)->mSymbols[index].mName, symbol))
473                             {
474                                 dbSymbol = &(*outDB)->mSymbols[index];
475                             }
476                         }
477                         
478                         /*
479                         **  May need to create symbol.
480                         */
481                         if(NULL == dbSymbol)
482                         {
483                             /*
484                             **  Could be time to grow the symbol pool.
485                             */
486                             if((*outDB)->mSymbolCount >= (*outDB)->mSymbolCapacity)
487                             {
488                                 moved = realloc((*outDB)->mSymbols, sizeof(SymDB_Symbol) * ((*outDB)->mSymbolCapacity + SYMDB_SYMBOL_GROWBY));
489                                 if(NULL != moved)
490                                 {
491                                     (*outDB)->mSymbols = (SymDB_Symbol*)moved;
492                                     memset(&(*outDB)->mSymbols[(*outDB)->mSymbolCapacity], 0, sizeof(SymDB_Symbol) * SYMDB_SYMBOL_GROWBY);
493                                     (*outDB)->mSymbolCapacity += SYMDB_SYMBOL_GROWBY;
494                                 }
495                                 else
496                                 {
497                                     retval = __LINE__;
498                                     ERROR_REPORT(retval, inDBName, "Unable to grow symbol DB symbol array.");
499                                     break;
500                                 }
501                             }
502
503                             if((*outDB)->mSymbolCount < (*outDB)->mSymbolCapacity)
504                             {
505                                 dbSymbol = &(*outDB)->mSymbols[(*outDB)->mSymbolCount];
506                                 (*outDB)->mSymbolCount++;
507                                 
508                                 dbSymbol->mName = strdup(symbol);
509                                 if(NULL == dbSymbol->mName)
510                                 {
511                                     retval = __LINE__;
512                                     ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
513                                     break;
514                                 }
515                             }
516                             else
517                             {
518                                 retval = __LINE__;
519                                 ERROR_REPORT(retval, symbol, "Unable to grow symbol DB for symbol.");
520                                 break;
521                             }
522                         }
523                         
524                         /*
525                         **  Assume we have the symbol.
526                         **
527                         **  Is this the same section as the last section in the symbol?
528                         **  This assumes the symdb was presorted!!!!
529                         */
530                         if(0 != dbSymbol->mSectionCount)
531                         {
532                             unsigned index = dbSymbol->mSectionCount - 1;
533                             
534                             if(0 == strcmp(dbSymbol->mSections[index].mName, section))
535                             {
536                                 dbSection = &dbSymbol->mSections[index];
537                             }
538                         }
539                         
540                         /*
541                         **  May need to create the section.
542                         */
543                         if(NULL == dbSection)
544                         {
545                             moved = realloc(dbSymbol->mSections, sizeof(SymDB_Section) * (dbSymbol->mSectionCount + 1));
546                             if(NULL != moved)
547                             {
548                                 dbSymbol->mSections = (SymDB_Section*)moved;
549                                 dbSection = &dbSymbol->mSections[dbSymbol->mSectionCount];
550                                 dbSymbol->mSectionCount++;
551                                 
552                                 memset(dbSection, 0, sizeof(SymDB_Section));
553                                 
554                                 dbSection->mName = strdup(section);
555                                 if(NULL == dbSection->mName)
556                                 {
557                                     retval = __LINE__;
558                                     ERROR_REPORT(retval, section, "Unable to duplicate string.");
559                                     break;
560                                 }
561                             }
562                             else
563                             {
564                                 retval = __LINE__;
565                                 ERROR_REPORT(retval, section, "Unable to grow symbol sections for symbol DB.");
566                                 break;
567                             }
568                         }
569                         
570                         /*
571                         **  Assume we have the section.
572                         **
573                         **  Is this the same size as the last size?
574                         **  This assumes the symdb was presorted!!!
575                         */
576                         if(0 != dbSection->mSizeCount)
577                         {
578                             unsigned index = dbSection->mSizeCount - 1;
579                             
580                             if(dbSection->mSizes[index].mSize == lengthNum)
581                             {
582                                 dbSize = &dbSection->mSizes[index];
583                             }
584                         }
585                         
586                         /*
587                         **  May need to create the size in question.
588                         */
589                         if(NULL == dbSize)
590                         {
591                             moved = realloc(dbSection->mSizes, sizeof(SymDB_Size) * (dbSection->mSizeCount + 1));
592                             if(NULL != moved)
593                             {
594                                 dbSection->mSizes = (SymDB_Size*)moved;
595                                 dbSize = &dbSection->mSizes[dbSection->mSizeCount];
596                                 dbSection->mSizeCount++;
597                                 
598                                 memset(dbSize, 0, sizeof(SymDB_Size));
599                                 
600                                 dbSize->mSize = lengthNum;
601                             }
602                             else
603                             {
604                                 retval = __LINE__;
605                                 ERROR_REPORT(retval, length, "Unable to grow symbol section sizes for symbol DB.");
606                                 break;
607                             }
608                         }
609                         
610                         /*
611                         **  Assume we have the size.
612                         **
613                         **  We assume a one to one correllation between size and object.
614                         **  Always try to add the new object name.
615                         **  As the symdb is assumed to be sorted, the object names should also be in order.
616                         */
617                         moved = realloc(dbSize->mObjects, sizeof(char*) * (dbSize->mObjectCount + 1));
618                         if(NULL != moved)
619                         {
620                             dbObject = strdup(object);
621                             
622                             dbSize->mObjects = (char**)moved;
623                             dbSize->mObjects[dbSize->mObjectCount] = dbObject;
624                             dbSize->mObjectCount++;
625                             
626                             if(NULL == dbObject)
627                             {
628                                 retval = __LINE__;
629                                 ERROR_REPORT(retval, object, "Unable to duplicate string.");
630                                 break;
631                             }
632                         }
633                         else
634                         {
635                             retval = __LINE__;
636                             ERROR_REPORT(retval, object, "Unable to grow symbol section size objects for symbol DB.");
637                             break;
638                         }
639                     }
640                     else
641                     {
642                         retval = __LINE__;
643                         ERROR_REPORT(retval, length, "Unable to convert symbol DB length into a number.");
644                         break;
645                     }
646                 }
647             
648                 if(0 == retval && 0 != ferror(symDB))
649                 {
650                     retval = __LINE__;
651                     ERROR_REPORT(retval, inDBName, "Unable to read file.");
652                 }
653             }
654             else
655             {
656                 retval = __LINE__;
657                 ERROR_REPORT(retval, inDBName, "Unable to allocate symbol DB.");
658             }
659
660             fclose(symDB);
661             symDB = NULL;
662         }
663         else
664         {
665             retval = __LINE__;
666             ERROR_REPORT(retval, inDBName, "Unable to open symbol DB.");
667         }
668     }
669     else
670     {
671         retval = __LINE__;
672         ERROR_REPORT(retval, "(NULL)", "Invalid arguments.");
673     }
674
675     return retval;
676 }
677
678
679 void cleanSymDB(SymDB_Container** inDB)
680 /*
681 **  Free it all up.
682 */
683 {
684     if(NULL != inDB && NULL != *inDB)
685     {
686         unsigned symLoop = 0;
687         unsigned secLoop = 0;
688         unsigned sizLoop = 0;
689         unsigned objLoop = 0;
690
691         for(symLoop = 0; symLoop < (*inDB)->mSymbolCount; symLoop++)
692         {
693             for(secLoop = 0; secLoop < (*inDB)->mSymbols[symLoop].mSectionCount; secLoop++)
694             {
695                 for(sizLoop = 0; sizLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizeCount; sizLoop++)
696                 {
697                     for(objLoop = 0; objLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjectCount; objLoop++)
698                     {
699                         CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects[objLoop]);
700                     }
701                     CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects);
702                 }
703                 CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mName);
704                 CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes);
705             }
706             CLEANUP((*inDB)->mSymbols[symLoop].mName);
707             CLEANUP((*inDB)->mSymbols[symLoop].mSections);
708         }
709         CLEANUP((*inDB)->mSymbols);
710         CLEANUP(*inDB);
711     }
712 }
713
714
715 int symDBLookup(const void* inKey, const void* inItem)
716 /*
717 **  bsearch utility routine to find the symbol in the symdb.
718 */
719 {
720     int retval = 0;
721     const char* key = (const char*)inKey;
722     const SymDB_Symbol* symbol = (const SymDB_Symbol*)inItem;
723
724     retval = strcmp(key, symbol->mName);
725
726     return retval;
727 }
728
729
730 int fillSymbolSizeFromDB(Options* inOptions, MSMap_Module* inModule, MSMap_Symbol* inoutSymbol, const char* inMangledName)
731 /*
732 **  If we have a symbol DB, attempt to determine the real size of the symbol
733 **      up front.
734 **  This helps us later in the game to avoid performing size guesses by
735 **      offset.
736 */
737 {
738     int retval = 0;
739
740     /*
741     **  May need to initialize symdb.
742     */
743     if(NULL == inOptions->mSymDB && NULL != inOptions->mSymDBName)
744     {
745         retval = readSymDB(inOptions->mSymDBName, &inOptions->mSymDB);
746     }
747
748     /*
749     **  Optional
750     */
751     if(0 == retval && NULL != inOptions->mSymDB)
752     {
753         void* match = NULL;
754
755         /*
756         **  Find the symbol.
757         */
758         match = bsearch(inMangledName, inOptions->mSymDB->mSymbols, inOptions->mSymDB->mSymbolCount, sizeof(SymDB_Symbol), symDBLookup);
759         if(NULL != match)
760         {
761             SymDB_Symbol* symbol = (SymDB_Symbol*)match;
762             unsigned symDBSize = 0;
763             MSMap_Segment* mapSection = NULL;
764
765             /*
766             **  We found the symbol.
767             **
768             **  See if it has the section in question.
769             */
770             mapSection = getSymbolSection(inModule, inoutSymbol);
771             if(NULL != mapSection)
772             {
773                 unsigned secLoop = 0;
774
775                 for(secLoop = 0; secLoop < symbol->mSectionCount; secLoop++)
776                 {
777                     if(0 == strcmp(mapSection->mSegment, symbol->mSections[secLoop].mName))
778                     {
779                         SymDB_Section* section = &symbol->mSections[secLoop];
780
781                         /*
782                         **  We have a section match.
783                         **  Should there be a single size for the symbol,
784                         **      then we just default to that.
785                         **  If more than one size, we have to do an
786                         **      object match search.
787                         **  Should there be no object match, we do nothign.
788                         */
789                         if(1 == section->mSizeCount)
790                         {
791                             symDBSize = section->mSizes[0].mSize;
792                         }
793                         else
794                         {
795                             char* mapObject = NULL;
796                             
797                             /*
798                             **  Figure out the map object file name.
799                             **  Skip any colon.
800                             **  If it doesn't have a .obj in it, not worth continuing.
801                             */
802                             mapObject = strrchr(inoutSymbol->mObject, ':');
803                             if(NULL == mapObject)
804                             {
805                                 mapObject = inoutSymbol->mObject;
806                             }
807                             else
808                             {
809                                 mapObject++; /* colon */
810                             }
811
812                             if(NULL != strstr(mapObject, ".obj"))
813                             {
814                                 unsigned sizLoop = 0;
815                                 unsigned objLoop = 0;
816                                 SymDB_Size* size = NULL;
817
818                                 for(sizLoop = 0; sizLoop < section->mSizeCount; sizLoop++)
819                                 {
820                                     size = &section->mSizes[sizLoop];
821                                     
822                                     for(objLoop = 0; objLoop < size->mObjectCount; objLoop++)
823                                     {
824                                         if(NULL != strstr(size->mObjects[objLoop], mapObject))
825                                         {
826                                             /*
827                                             **  As we matched the object, in a particular section,
828                                             **      we'll go with this as the number.
829                                             */
830                                             symDBSize = size->mSize;
831                                             break;
832                                         }
833                                     }
834                                     
835                                     /*
836                                     **  If the object loop broke early, we break too.
837                                     */
838                                     if(objLoop < size->mObjectCount)
839                                     {
840                                         break;
841                                     }
842                                 }
843                             }
844                         }
845
846                         break;
847                     }
848                 }
849             }
850
851             /*
852             **  Put the size in.
853             */
854             inoutSymbol->mSymDBSize = symDBSize;
855         }
856     }
857
858     return retval;
859 }
860
861
862 char* symdup(const char* inSymbol)
863 /*
864 **  Attempts to demangle the symbol if appropriate.
865 **  Otherwise acts like strdup.
866 */
867 {
868     char* retval = NULL;
869
870 #if F_DEMANGLE
871     {
872         int isImport = 0;
873
874         if(0 == strncmp("__imp_", inSymbol, 6))
875         {
876             isImport = __LINE__;
877             inSymbol += 6;
878         }
879
880         if('?' == inSymbol[0])
881         {
882             char demangleBuf[0x200];
883             DWORD demangleRes = 0;
884             
885             demangleRes = UnDecorateSymbolName(inSymbol, demangleBuf, sizeof(demangleBuf), UNDNAME_COMPLETE);
886             if(0 != demangleRes)
887             {
888                 if (strcmp(demangleBuf, "`string'") == 0)
889                 {
890                     
891                     /* attempt manual demangling of string prefix.. */
892
893                     /* first make sure we have enough space for the
894                        updated string - the demangled string will
895                        always be shorter than strlen(inSymbol) and the
896                        prologue will always be longer than the
897                        "string: " that we tack on the front of the string
898                     */
899                     char *curresult = retval = malloc(strlen(inSymbol) + 11);
900                     const char *curchar = inSymbol;
901                     
902                     int state = DEMANGLE_STATE_START;
903
904                     /* the hex state is for stuff like ?$EA which
905                        really means hex value 0x40 */
906                     char hex_state = 0;
907                     char string_is_unicode = 0;
908
909                     /* sometimes we get a null-termination before the
910                        final @ sign - in that case, remember that
911                        we've seen the whole string */
912                     int have_null_char = 0;
913
914                     /* stick our user-readable prefix on */
915                     strcpy(curresult, "string: \"");
916                     curresult += 9;
917                     
918                     while (*curchar) {
919                         
920                         // process current state
921                         switch (state) {
922
923                             /* the Prologue states are divided up so
924                                that someday we can try to decode
925                                the random letters in between the '@'
926                                signs. Also, some strings only have 2
927                                prologue '@' signs, so we have to
928                                figure out how to distinguish between
929                                them at some point. */
930                         case DEMANGLE_STATE_START:
931                             if (*curchar == '@')
932                                 state = DEMANGLE_STATE_PROLOGUE_1;
933                             /* ignore all other states */
934                             break;
935
936                         case DEMANGLE_STATE_PROLOGUE_1:
937                             switch (*curchar) {
938                             case '0':
939                                 string_is_unicode=0;
940                                 state = DEMANGLE_STATE_HAVE_TYPE;
941                                 break;
942                             case '1':
943                                 string_is_unicode=1;
944                                 state = DEMANGLE_STATE_HAVE_TYPE;
945                                 break;
946
947                                 /* ignore all other characters */
948                             }
949                             break;
950
951                         case DEMANGLE_STATE_HAVE_TYPE:
952                             if (*curchar >= '0' && *curchar <= '9') {
953                                 state = DEMANGLE_STATE_DEC_LENGTH;
954                             } else if (*curchar >= 'A' && *curchar <= 'Z') {
955                                 state = DEMANGLE_STATE_HEX_LENGTH;
956                             }
957                         case DEMANGLE_STATE_DEC_LENGTH:
958                             /* decimal lengths don't have the 2nd
959                                field
960                             */
961                             if (*curchar == '@')
962                                 state = DEMANGLE_STATE_NORMAL;
963                             break;
964                             
965                         case DEMANGLE_STATE_HEX_LENGTH:
966                             /* hex lengths have a 2nd field
967                                (though I have no idea what it is for)
968                             */
969                             if (*curchar == '@')
970                                 state = DEMANGLE_STATE_PROLOGUE_SECONDARY;
971                             break;
972
973                         case DEMANGLE_STATE_PROLOGUE_SECONDARY:
974                             if (*curchar == '@')
975                                 state = DEMANGLE_STATE_NORMAL;
976                             break;
977                         
978                         case DEMANGLE_STATE_NORMAL:
979                             switch (*curchar) {
980                             case '?':
981                                 state = DEMANGLE_STATE_QDECODE;
982                                 break;
983                             case '@':
984                                 state = DEMANGLE_STATE_STOP;
985                                 break;
986                             default:
987                                 *curresult++ = DEMANGLE_SAFE_CHAR(*curchar);
988                                 state = DEMANGLE_STATE_NORMAL;
989                                 break;
990                             }
991                             break;
992
993                             /* found a '?' */
994                         case DEMANGLE_STATE_QDECODE:
995                             state = DEMANGLE_STATE_NORMAL;
996
997                             /* there are certain shortcuts, like
998                                "?3" means ":"
999                             */
1000                             switch (*curchar) {
1001                             case '1':
1002                                 *curresult++ = '/';
1003                                 break;
1004                             case '2':
1005                                 *curresult++ = '\\';
1006                                 break;
1007                             case '3':
1008                                 *curresult++ = ':';
1009                                 break;
1010                             case '4':
1011                                 *curresult++ = '.';
1012                                 break;
1013                             case '5':
1014                                 *curresult++ = ' ';
1015                                 break;
1016                             case '6':
1017                                 *curresult++ = '\\';
1018                                 *curresult++ = 'n';
1019                                 break;
1020                             case '8':
1021                                 *curresult++ = '\'';
1022                                 break;
1023                             case '9':
1024                                 *curresult++ = '-';
1025                                 break;
1026
1027                                 /* any other arbitrary ASCII value can
1028                                    be stored by prefixing it with ?$
1029                                 */
1030                             case '$':
1031                                 state = DEMANGLE_STATE_DOLLAR_1;
1032                             }
1033                             break;
1034                             
1035                         case DEMANGLE_STATE_DOLLAR_1:
1036                             /* first digit of ?$ notation. All digits
1037                                are hex, represented starting with the
1038                                capital leter 'A' such that 'A' means 0x0,
1039                                'B' means 0x1, 'K' means 0xA
1040                             */
1041                             hex_state = (*curchar - 'A') * 0x10;
1042                             state = DEMANGLE_STATE_DOLLAR_2;
1043                             break;
1044
1045                         case DEMANGLE_STATE_DOLLAR_2:
1046                             /* same mechanism as above */
1047                             hex_state += (*curchar - 'A');
1048                             if (hex_state) {
1049                                 *curresult++ = DEMANGLE_SAFE_CHAR(hex_state);
1050                                 have_null_char = 0;
1051                             }
1052                             else {
1053                                 have_null_char = 1;
1054                             }
1055                             
1056                             state = DEMANGLE_STATE_NORMAL;
1057                             break;
1058
1059                         case DEMANGLE_STATE_STOP:
1060                             break;
1061                         }
1062
1063                         curchar++;
1064                     }
1065                     
1066                     /* add the appropriate termination depending
1067                        if we completed the string or not */
1068                     if (!have_null_char)
1069                         strcpy(curresult, "...\"");
1070                     else
1071                         strcpy(curresult, "\"");
1072                 } else {
1073                     retval = strdup(demangleBuf);
1074                 }
1075             }
1076             else
1077             {
1078                 /*
1079                 ** fall back to normal.
1080                 */
1081                 retval = strdup(inSymbol);
1082             }
1083         }
1084         else if('_' == inSymbol[0])
1085         {
1086             retval = strdup(inSymbol + 1);
1087         }
1088         else
1089         {
1090             retval = strdup(inSymbol);
1091         }
1092
1093         /*
1094         **  May need to rewrite the symbol if an import.
1095         */
1096         if(NULL != retval && isImport)
1097         {
1098             const char importPrefix[] = "__declspec(dllimport) ";
1099             char importBuf[0x200];
1100             int printRes = 0;
1101
1102             printRes = _snprintf(importBuf, sizeof(importBuf), "%s%s", importPrefix, retval);
1103             free(retval);
1104             retval = NULL;
1105
1106             if(printRes > 0)
1107             {
1108                 retval = strdup(importBuf);
1109             }
1110         }
1111     }
1112 #else /* F_DEMANGLE */
1113     retval = strdup(inSymbol);
1114 #endif  /* F_DEMANGLE */
1115
1116     return retval;
1117 }
1118
1119
1120 int readmap(Options* inOptions, MSMap_Module* inModule)
1121 /*
1122 **  Read the input line by line, adding it to the module.
1123 */
1124 {
1125     int retval = 0;
1126     char lineBuffer[0x400];
1127     char* current = NULL;
1128     MSMap_ReadState fsm;
1129     int len = 0;
1130     int forceContinue = 0;
1131     
1132     memset(&fsm, 0, sizeof(fsm));
1133     
1134     /*
1135     **  Read the map file line by line.
1136     **  We keep a simple state machine to determine what we're looking at.
1137     */
1138     while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
1139     {
1140         if(forceContinue)
1141         {
1142             /*
1143             **  Used to skip anticipated blank lines.
1144             */
1145             forceContinue--;
1146             continue;
1147         }
1148
1149         current = skipWhite(lineBuffer);
1150         trimWhite(current);
1151         
1152         len = strlen(current);
1153         
1154         if(fsm.mHasModule)
1155         {
1156             if(fsm.mHasTimestamp)
1157             {
1158                 if(fsm.mHasPreferredLoadAddress)
1159                 {
1160                     if(fsm.mHasSegmentData)
1161                     {
1162                         if(fsm.mHasPublicSymbolData)
1163                         {
1164                             if(fsm.mHasEntryPoint)
1165                             {
1166                                 if(fsm.mFoundStaticSymbols)
1167                                 {
1168                                     /*
1169                                     **  A blank line means we've reached the end of all static symbols.
1170                                     */
1171                                     if(len)
1172                                     {
1173                                        /*
1174                                         **  We're adding a new symbol.
1175                                         **  Make sure we have room for it.
1176                                         */
1177                                         if(inModule->mSymbolCapacity == inModule->mSymbolCount)
1178                                         {
1179                                             void* moved = NULL;
1180                                             
1181                                             moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
1182                                             if(NULL != moved)
1183                                             {
1184                                                 inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
1185                                                 inModule->mSymbols = (MSMap_Symbol*)moved;
1186                                             }
1187                                             else
1188                                             {
1189                                                 retval = __LINE__;
1190                                                 ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
1191                                             }
1192                                         }
1193                                         
1194                                         if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
1195                                         {
1196                                             MSMap_Symbol* theSymbol = NULL;
1197                                             unsigned index = 0;
1198                                             int scanRes = 0;
1199                                             char symbolBuf[0x200];
1200                                             
1201                                             index = inModule->mSymbolCount;
1202                                             inModule->mSymbolCount++;
1203                                             theSymbol = (inModule->mSymbols + index);
1204                                             
1205                                             memset(theSymbol, 0, sizeof(MSMap_Symbol));
1206                                             theSymbol->mScope = STATIC;
1207                                             
1208                                             scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned*)&(theSymbol->mRVABase));
1209                                             if(4 == scanRes)
1210                                             {
1211                                                 theSymbol->mSymbol = symdup(symbolBuf);
1212
1213                                                 if(0 == retval)
1214                                                 {
1215                                                     if(NULL != theSymbol->mSymbol)
1216                                                     {
1217                                                         char *last = lastWord(current);
1218                                                         
1219                                                         theSymbol->mObject = strdup(last);
1220                                                         if(NULL == theSymbol->mObject)
1221                                                         {
1222                                                             retval = __LINE__;
1223                                                             ERROR_REPORT(retval, last, "Unable to copy object name.");
1224                                                         }
1225                                                     }
1226                                                     else
1227                                                     {
1228                                                         retval = __LINE__;
1229                                                         ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
1230                                                     }
1231                                                 }
1232                                             }
1233                                             else
1234                                             {
1235                                                 retval = __LINE__;
1236                                                 ERROR_REPORT(retval, inModule->mModule, "Unable to scan static symbols.");
1237                                             }
1238                                         }
1239                                     }
1240                                     else
1241                                     {
1242                                         /*
1243                                         **  All done.
1244                                         */
1245                                         break;
1246                                     }
1247                                 }
1248                                 else
1249                                 {
1250                                     /*
1251                                     **  Static symbols are optional.
1252                                     **  If no static symbols we're done.
1253                                     **  Otherwise, set the flag such that it will work more.
1254                                     */
1255                                     if(0 == strcmp(current, "Static symbols"))
1256                                     {
1257                                         fsm.mFoundStaticSymbols = __LINE__;
1258                                         forceContinue = 1;
1259                                     }
1260                                     else
1261                                     {
1262                                         /*
1263                                         **  All done.
1264                                         */
1265                                         break;
1266                                     }
1267                                 }
1268                             }
1269                             else
1270                             {
1271                                 int scanRes = 0;
1272                                 
1273                                 scanRes = sscanf(current, "entry point at %x:%x", (unsigned*)&(inModule->mEntryPrefix), (unsigned*)&(inModule->mEntryOffset));
1274                                 if(2 == scanRes)
1275                                 {
1276                                     fsm.mHasEntryPoint = __LINE__;
1277                                     forceContinue = 1;
1278                                 }
1279                                 else
1280                                 {
1281                                     retval = __LINE__;
1282                                     ERROR_REPORT(retval, current, "Unable to obtain entry point.");
1283                                 }
1284                             }
1285                         }
1286                         else
1287                         {
1288                             /*
1289                             **  Skip the N lines of public symbol data (column headers).
1290                             */
1291                             if(2 <= fsm.mHasPublicSymbolDataSkippedLines)
1292                             {
1293                                 /*
1294                                 **  A blank line indicates end of public symbols. 
1295                                 */
1296                                 if(len)
1297                                 {
1298                                     /*
1299                                     **  We're adding a new symbol.
1300                                     **  Make sure we have room for it.
1301                                     */
1302                                     if(inModule->mSymbolCapacity == inModule->mSymbolCount)
1303                                     {
1304                                         void* moved = NULL;
1305                                         
1306                                         moved = realloc(inModule->mSymbols, sizeof(MSMap_Symbol) * (inModule->mSymbolCapacity + MSMAP_SYMBOL_GROWBY));
1307                                         if(NULL != moved)
1308                                         {
1309                                             inModule->mSymbolCapacity += MSMAP_SYMBOL_GROWBY;
1310                                             inModule->mSymbols = (MSMap_Symbol*)moved;
1311                                         }
1312                                         else
1313                                         {
1314                                             retval = __LINE__;
1315                                             ERROR_REPORT(retval, inModule->mModule, "Unable to grow symbols.");
1316                                         }
1317                                     }
1318                                     
1319                                     if(0 == retval && inModule->mSymbolCapacity > inModule->mSymbolCount)
1320                                     {
1321                                         MSMap_Symbol* theSymbol = NULL;
1322                                         unsigned index = 0;
1323                                         int scanRes = 0;
1324                                         char symbolBuf[0x200];
1325                                         
1326                                         index = inModule->mSymbolCount;
1327                                         inModule->mSymbolCount++;
1328                                         theSymbol = (inModule->mSymbols + index);
1329                                         
1330                                         memset(theSymbol, 0, sizeof(MSMap_Symbol));
1331                                         theSymbol->mScope = PUBLIC;
1332                                         
1333                                         scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned *)&(theSymbol->mRVABase));
1334                                         if(4 == scanRes)
1335                                         {
1336                                             theSymbol->mSymbol = symdup(symbolBuf);
1337
1338                                             if(NULL != theSymbol->mSymbol)
1339                                             {
1340                                                 char *last = lastWord(current);
1341                                                 
1342                                                 theSymbol->mObject = strdup(last);
1343                                                 if(NULL != theSymbol->mObject)
1344                                                 {
1345                                                     /*
1346                                                     **  Finally, attempt to lookup the actual size of the symbol
1347                                                     **      if there is a symbol DB available.
1348                                                     */
1349                                                     retval = fillSymbolSizeFromDB(inOptions, inModule, theSymbol, symbolBuf);
1350                                                 }
1351                                                 else
1352                                                 {
1353                                                     retval = __LINE__;
1354                                                     ERROR_REPORT(retval, last, "Unable to copy object name.");
1355                                                 }
1356                                             }
1357                                             else
1358                                             {
1359                                                 retval = __LINE__;
1360                                                 ERROR_REPORT(retval, symbolBuf, "Unable to copy symbol name.");
1361                                             }
1362                                         }
1363                                         else
1364                                         {
1365                                             retval = __LINE__;
1366                                             ERROR_REPORT(retval, inModule->mModule, "Unable to scan public symbols.");
1367                                         }
1368                                     }
1369                                 }
1370                                 else
1371                                 {
1372                                     fsm.mHasPublicSymbolData = __LINE__;
1373                                 }
1374                             }
1375                             else
1376                             {
1377                                 fsm.mHasPublicSymbolDataSkippedLines++;
1378                             }
1379                         }
1380                     }
1381                     else
1382                     {
1383                         /*
1384                         **  Skip the first line of segment data (column headers).
1385                         **  Mark that we've begun grabbing segement data.
1386                         */
1387                         if(fsm.mSegmentDataSkippedLine)
1388                         {
1389                             /*
1390                             **  A blank line means end of the segment data.
1391                             */
1392                             if(len)
1393                             {
1394                                 /*
1395                                 **  We're adding a new segment.
1396                                 **  Make sure we have room for it.
1397                                 */
1398                                 if(inModule->mSegmentCapacity == inModule->mSegmentCount)
1399                                 {
1400                                     void* moved = NULL;
1401                                     
1402                                     moved = realloc(inModule->mSegments, sizeof(MSMap_Segment) * (inModule->mSegmentCapacity + MSMAP_SEGMENT_GROWBY));
1403                                     if(NULL != moved)
1404                                     {
1405                                         inModule->mSegmentCapacity += MSMAP_SEGMENT_GROWBY;
1406                                         inModule->mSegments = (MSMap_Segment*)moved;
1407                                     }
1408                                     else
1409                                     {
1410                                         retval = __LINE__;
1411                                         ERROR_REPORT(retval, inModule->mModule, "Unable to grow segments.");
1412                                     }
1413                                 }
1414                                 
1415                                 if(0 == retval && inModule->mSegmentCapacity > inModule->mSegmentCount)
1416                                 {
1417                                     MSMap_Segment* theSegment = NULL;
1418                                     unsigned index = 0;
1419                                     char classBuf[0x10];
1420                                     char nameBuf[0x20];
1421                                     int scanRes = 0;
1422                                     
1423                                     index = inModule->mSegmentCount;
1424                                     inModule->mSegmentCount++;
1425                                     theSegment = (inModule->mSegments + index);
1426                                     
1427                                     memset(theSegment, 0, sizeof(MSMap_Segment));
1428                                     
1429                                     scanRes = sscanf(current, "%x:%x %xH %s %s", (unsigned*)&(theSegment->mPrefix), (unsigned*)&(theSegment->mOffset), (unsigned*)&(theSegment->mLength), nameBuf, classBuf);
1430                                     if(5 == scanRes)
1431                                     {
1432                                         if('.' == nameBuf[0])
1433                                         {
1434                                             theSegment->mSegment = strdup(&nameBuf[1]);
1435                                         }
1436                                         else
1437                                         {
1438                                             theSegment->mSegment = strdup(nameBuf);
1439                                         }
1440
1441                                         if(NULL != theSegment->mSegment)
1442                                         {
1443                                             if(0 == strcmp("DATA", classBuf))
1444                                             {
1445                                                 theSegment->mClass = DATA;
1446                                             }
1447                                             else if(0 == strcmp("CODE", classBuf))
1448                                             {
1449                                                 theSegment->mClass = CODE;
1450                                             }
1451                                             else
1452                                             {
1453                                                 retval = __LINE__;
1454                                                 ERROR_REPORT(retval, classBuf, "Unrecognized segment class.");
1455                                             }
1456                                         }
1457                                         else
1458                                         {
1459                                             retval = __LINE__;
1460                                             ERROR_REPORT(retval, nameBuf, "Unable to copy segment name.");
1461                                         }
1462                                     }
1463                                     else
1464                                     {
1465                                         retval = __LINE__;
1466                                         ERROR_REPORT(retval, inModule->mModule, "Unable to scan segments.");
1467                                     }
1468                                 }
1469                             }
1470                             else
1471                             {
1472                                 fsm.mHasSegmentData = __LINE__;
1473                             }
1474                         }
1475                         else
1476                         {
1477                             fsm.mSegmentDataSkippedLine = __LINE__;
1478                         }
1479                     }
1480                 }
1481                 else
1482                 {
1483                     int scanRes = 0;
1484                     
1485                     /*
1486                     **  The PLA has a particular format.
1487                     */
1488                     scanRes = sscanf(current, "Preferred load address is %x", (unsigned*)&(inModule->mPreferredLoadAddress));
1489                     if(1 == scanRes)
1490                     {
1491                         fsm.mHasPreferredLoadAddress = __LINE__;
1492                         forceContinue = 1;
1493                     }
1494                     else
1495                     {
1496                         retval = __LINE__;
1497                         ERROR_REPORT(retval, current, "Unable to obtain preferred load address.");
1498                     }
1499                 }
1500             }
1501             else
1502             {
1503                 int scanRes = 0;
1504                 
1505                 /*
1506                 **  The timestamp has a particular format.
1507                 */
1508                 scanRes = sscanf(current, "Timestamp is %x", (unsigned*)&(inModule->mTimestamp));
1509                 if(1 == scanRes)
1510                 {
1511                     fsm.mHasTimestamp = __LINE__;
1512                     forceContinue = 1;
1513                 }
1514                 else
1515                 {
1516                     retval = __LINE__;
1517                     ERROR_REPORT(retval, current, "Unable to obtain timestamp.");
1518                 }
1519             }
1520         }
1521         else
1522         {
1523             /*
1524             **  The module is on a line by itself.
1525             */
1526             inModule->mModule = strdup(current);
1527             if(NULL != inModule->mModule)
1528             {
1529                 fsm.mHasModule = __LINE__;
1530                 forceContinue = 1;
1531
1532                 if(0 != inOptions->mMatchModuleCount)
1533                 {
1534                     unsigned matchLoop = 0;
1535                     
1536                     /*
1537                     **  If this module name doesn't match, then bail.
1538                     **  Compare in a case sensitive manner, exact match only.
1539                     */
1540                     for(matchLoop = 0; matchLoop < inOptions->mMatchModuleCount; matchLoop++)
1541                     {
1542                         if(0 == strcmp(inModule->mModule, inOptions->mMatchModules[matchLoop]))
1543                         {
1544                             break;
1545                         }
1546                     }
1547                     
1548                     if(matchLoop == inOptions->mMatchModuleCount)
1549                     {
1550                         /*
1551                         **  A match did not occur, bail out of read loop.
1552                         **  No error, however.
1553                         */
1554                         break;
1555                     }
1556                 }
1557             }
1558             else
1559             {
1560                 retval = __LINE__;
1561                 ERROR_REPORT(retval, current, "Unable to obtain module.");
1562             }
1563         }
1564     }
1565     
1566     if(0 == retval && 0 != ferror(inOptions->mInput))
1567     {
1568         retval = __LINE__;
1569         ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
1570     }
1571     
1572     return retval;
1573 }
1574
1575
1576 static int qsortRVABase(const void* in1, const void* in2)
1577 /*
1578 **  qsort callback to sort the symbols by their RVABase.
1579 */
1580 {
1581     MSMap_Symbol* sym1 = (MSMap_Symbol*)in1;
1582     MSMap_Symbol* sym2 = (MSMap_Symbol*)in2;
1583     int retval = 0;
1584
1585     if(sym1->mRVABase < sym2->mRVABase)
1586     {
1587         retval = -1;
1588     }
1589     else if(sym1->mRVABase > sym2->mRVABase)
1590     {
1591         retval = 1;
1592     }
1593
1594     return retval;
1595 }
1596
1597
1598 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)
1599 /*
1600 **  Output a line of map information separated by tabs.
1601 **  Some items (const char*), if not present, will receive a default value.
1602 */
1603 {
1604     int retval = 0;
1605
1606     /*
1607     **  No need to output on no size.
1608     **  This can happen with zero sized segments,
1609     **      or an imported symbol which has multiple names (one will count).
1610     */
1611     if(0 != inSize)
1612     {
1613         char objectBuf[0x100];
1614         const char* symScope = NULL;
1615         const char* segClass = NULL;
1616         const char* undefined = "UNDEF";
1617         
1618         /*
1619         **  Fill in unspecified values.
1620         */
1621         if(NULL == inObject)
1622         {
1623             sprintf(objectBuf, "%s:%s:%s", undefined, inModule, inSegment);
1624             inObject = objectBuf;
1625         }
1626         if(NULL == inSymbol)
1627         {
1628             inSymbol = inObject;
1629         }
1630         
1631         /*
1632         **  Convert some enumerations to text.
1633         */
1634         switch(inClass)
1635         {
1636         case CODE:
1637             segClass = "CODE";
1638             break;
1639         case DATA:
1640             segClass = "DATA";
1641             break;
1642         default:
1643             retval = __LINE__;
1644             ERROR_REPORT(retval, "", "Unable to determine class for output.");
1645             break;
1646         }
1647         
1648         switch(inScope)
1649         {
1650         case PUBLIC:
1651             symScope = "PUBLIC";
1652             break;
1653         case STATIC:
1654             symScope = "STATIC";
1655             break;
1656         case UNDEFINED:
1657             symScope = undefined;
1658             break;
1659         default:
1660             retval = __LINE__;
1661             ERROR_REPORT(retval, "", "Unable to determine scope for symbol.");
1662             break;
1663         }
1664         
1665         if(0 == retval)
1666         {
1667             int printRes = 0;
1668             
1669             printRes = fprintf(inOptions->mOutput,
1670                 "%.8X\t%s\t%s\t%s\t%s\t%s\t%s\n",
1671                 inSize,
1672                 segClass,
1673                 symScope,
1674                 inModule,
1675                 inSegment,
1676                 inObject,
1677                 inSymbol
1678                 );
1679
1680             if(0 > printRes)
1681             {
1682                 retval = __LINE__;
1683                 ERROR_REPORT(retval, inOptions->mOutputName, "Unable to output tsv data.");
1684             }
1685         }
1686     }
1687
1688     return retval;
1689 }
1690
1691
1692 void cleanModule(MSMap_Module* inModule)
1693 {
1694     unsigned loop = 0;
1695
1696     for(loop = 0; loop < inModule->mSymbolCount; loop++)
1697     {
1698         CLEANUP(inModule->mSymbols[loop].mObject);
1699         CLEANUP(inModule->mSymbols[loop].mSymbol);
1700     }
1701     CLEANUP(inModule->mSymbols);
1702
1703     for(loop = 0; loop < inModule->mSegmentCount; loop++)
1704     {
1705         CLEANUP(inModule->mSegments[loop].mSegment);
1706     }
1707     CLEANUP(inModule->mSegments);
1708
1709     CLEANUP(inModule->mModule);
1710
1711     memset(inModule, 0, sizeof(MSMap_Module));
1712 }
1713
1714
1715 int map2tsv(Options* inOptions)
1716 /*
1717 **  Read all input.
1718 **  Output tab separated value data.
1719 */
1720 {
1721     int retval = 0;
1722     MSMap_Module module;
1723
1724     memset(&module, 0, sizeof(module));
1725
1726     /*
1727     **  Read in the map file.
1728     */
1729     retval = readmap(inOptions, &module);
1730     if(0 == retval)
1731     {
1732         unsigned symLoop = 0;
1733         MSMap_Symbol* symbol = NULL;
1734         unsigned secLoop = 0;
1735         MSMap_Segment* section = NULL;
1736         unsigned size = 0;
1737         unsigned dbSize = 0;
1738         unsigned offsetSize = 0;
1739         unsigned endOffset = 0;
1740
1741         /*
1742         **  Quick sort the symbols via RVABase.
1743         */
1744         qsort(module.mSymbols, module.mSymbolCount, sizeof(MSMap_Symbol), qsortRVABase);
1745
1746         /*
1747         **  Go through all the symbols (in order by sort).
1748         **  Output their sizes.
1749         */
1750         for(symLoop = 0; 0 == retval && symLoop < module.mSymbolCount; symLoop++)
1751         {
1752             symbol = &module.mSymbols[symLoop];
1753             section = getSymbolSection(&module, symbol);
1754             if (!section)
1755                 continue;
1756
1757             /*
1758             **  Use the symbol DB size if available.
1759             */
1760             dbSize = symbol->mSymDBSize;
1761
1762             /*
1763             **  Guess using offsets.
1764             **  Is there a next symbol available?  If so, its start offset is the end of this symbol.
1765             **  Otherwise, our section offset + length is the end of this symbol.
1766             **
1767             **  The trick is, the DB size can not go beyond the offset size, for sanity.
1768             */
1769             
1770             /*
1771             **  Try next symbol, but only if in same section.
1772             **  If still not, use the end of the segment.
1773             **  This implies we were the last symbol in the segment.
1774             */
1775             if((symLoop + 1) < module.mSymbolCount)
1776             {
1777                 MSMap_Symbol* nextSymbol = NULL;
1778                 MSMap_Segment* nextSection = NULL;
1779                 
1780                 nextSymbol = &module.mSymbols[symLoop + 1];
1781                 nextSection = getSymbolSection(&module, nextSymbol);
1782                 
1783                 if(section == nextSection)
1784                 {
1785                     endOffset = nextSymbol->mOffset;
1786                 }
1787                 else
1788                 {
1789                     endOffset = section->mOffset + section->mLength;
1790                 }
1791             }
1792             else
1793             {
1794                 endOffset = section->mOffset + section->mLength;
1795             }
1796
1797             /*
1798             **  Can now guess at size.
1799             */
1800             offsetSize = endOffset - symbol->mOffset;
1801
1802             /*
1803             **  Now, determine which size to use.
1804             **  This is really a sanity check as well.
1805             */
1806             size = offsetSize;
1807             if(0 != dbSize)
1808             {
1809                 if(dbSize < offsetSize)
1810                 {
1811                     size = dbSize;
1812                 }
1813             }
1814
1815             /*
1816             **  Output the symbol with the size.
1817             */
1818             retval = tsvout(inOptions,
1819                 size,
1820                 section->mClass,
1821                 symbol->mScope,
1822                 module.mModule,
1823                 section->mSegment,
1824                 symbol->mObject,
1825                 symbol->mSymbol
1826                 );
1827
1828             /*
1829             **  Make sure we mark this amount of space as used in the section.
1830             */
1831             section->mUsed += size;
1832         }
1833
1834         /*
1835         **  Go through the sections, and those whose length is longer than the
1836         **      amount of space used, output dummy filler values.
1837         */
1838         for(secLoop = 0; 0 == retval && secLoop < module.mSegmentCount; secLoop++)
1839         {
1840             section = &module.mSegments[secLoop];
1841
1842             if(section && section->mUsed < section->mLength)
1843             {
1844                 retval = tsvout(inOptions,
1845                     section->mLength - section->mUsed,
1846                     section->mClass,
1847                     UNDEFINED,
1848                     module.mModule,
1849                     section->mSegment,
1850                     NULL,
1851                     NULL
1852                     );
1853             }
1854         }
1855     }
1856
1857     /*
1858     **  Cleanup.
1859     */
1860     cleanModule(&module);
1861
1862     return retval;
1863 }
1864
1865
1866 int initOptions(Options* outOptions, int inArgc, char** inArgv)
1867 /*
1868 **  returns int     0 if successful.
1869 */
1870 {
1871     int retval = 0;
1872     int loop = 0;
1873     int switchLoop = 0;
1874     int match = 0;
1875     const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
1876     Switch* current = NULL;
1877
1878     /*
1879     **  Set any defaults.
1880     */
1881     memset(outOptions, 0, sizeof(Options));
1882     outOptions->mProgramName = inArgv[0];
1883     outOptions->mInput = stdin;
1884     outOptions->mInputName = strdup("stdin");
1885     outOptions->mOutput = stdout;
1886     outOptions->mOutputName = strdup("stdout");
1887
1888     if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
1889     {
1890         retval = __LINE__;
1891         ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
1892     }
1893
1894     /*
1895     **  Go through and attempt to do the right thing.
1896     */
1897     for(loop = 1; loop < inArgc && 0 == retval; loop++)
1898     {
1899         match = 0;
1900         current = NULL;
1901
1902         for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
1903         {
1904             if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
1905             {
1906                 match = __LINE__;
1907             }
1908             else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
1909             {
1910                 match = __LINE__;
1911             }
1912
1913             if(match)
1914             {
1915                 if(gSwitches[switchLoop]->mHasValue)
1916                 {
1917                     /*
1918                     **  Attempt to absorb next option to fullfill value.
1919                     */
1920                     if(loop + 1 < inArgc)
1921                     {
1922                         loop++;
1923
1924                         current = gSwitches[switchLoop];
1925                         current->mValue = inArgv[loop];
1926                     }
1927                 }
1928                 else
1929                 {
1930                     current = gSwitches[switchLoop];
1931                 }
1932
1933                 break;
1934             }
1935         }
1936
1937         if(0 == match)
1938         {
1939             outOptions->mHelp = __LINE__;
1940             retval = __LINE__;
1941             ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
1942         }
1943         else if(NULL == current)
1944         {
1945             outOptions->mHelp = __LINE__;
1946             retval = __LINE__;
1947             ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
1948         }
1949         else
1950         {
1951             /*
1952             ** Do something based on address/swtich.
1953             */
1954             if(current == &gInputSwitch)
1955             {
1956                 CLEANUP(outOptions->mInputName);
1957                 if(NULL != outOptions->mInput && stdin != outOptions->mInput)
1958                 {
1959                     fclose(outOptions->mInput);
1960                     outOptions->mInput = NULL;
1961                 }
1962
1963                 outOptions->mInput = fopen(current->mValue, "r");
1964                 if(NULL == outOptions->mInput)
1965                 {
1966                     retval = __LINE__;
1967                     ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
1968                 }
1969                 else
1970                 {
1971                     outOptions->mInputName = strdup(current->mValue);
1972                     if(NULL == outOptions->mInputName)
1973                     {
1974                         retval = __LINE__;
1975                         ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
1976                     }
1977                 }
1978             }
1979             else if(current == &gOutputSwitch)
1980             {
1981                 CLEANUP(outOptions->mOutputName);
1982                 if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
1983                 {
1984                     fclose(outOptions->mOutput);
1985                     outOptions->mOutput = NULL;
1986                 }
1987
1988                 outOptions->mOutput = fopen(current->mValue, "a");
1989                 if(NULL == outOptions->mOutput)
1990                 {
1991                     retval = __LINE__;
1992                     ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
1993                 }
1994                 else
1995                 {
1996                     outOptions->mOutputName = strdup(current->mValue);
1997                     if(NULL == outOptions->mOutputName)
1998                     {
1999                         retval = __LINE__;
2000                         ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
2001                     }
2002                 }
2003             }
2004             else if(current == &gHelpSwitch)
2005             {
2006                 outOptions->mHelp = __LINE__;
2007             }
2008             else if(current == &gMatchModuleSwitch)
2009             {
2010                 void* moved = NULL;
2011
2012                 /*
2013                 **  Add the value to the list of allowed module names.
2014                 */
2015                 moved = realloc(outOptions->mMatchModules, sizeof(char*) * (outOptions->mMatchModuleCount + 1));
2016                 if(NULL != moved)
2017                 {
2018                     outOptions->mMatchModules = (char**)moved;
2019                     outOptions->mMatchModules[outOptions->mMatchModuleCount] = strdup(current->mValue);
2020                     if(NULL != outOptions->mMatchModules[outOptions->mMatchModuleCount])
2021                     {
2022                         outOptions->mMatchModuleCount++;
2023                     }
2024                     else
2025                     {
2026                         retval = __LINE__;
2027                         ERROR_REPORT(retval, current->mValue, "Unable to duplicate string.");
2028                     }
2029                 }
2030                 else
2031                 {
2032                     retval = __LINE__;
2033                     ERROR_REPORT(retval, current->mValue, "Unable to allocate space for string.");
2034                 }
2035             }
2036             else if(current == &gSymDBSwitch)
2037             {
2038                 CLEANUP(outOptions->mSymDBName);
2039                 outOptions->mSymDBName = strdup(current->mValue);
2040                 if(NULL == outOptions->mSymDBName)
2041                 {
2042                     retval = __LINE__;
2043                     ERROR_REPORT(retval, current->mValue, "Unable to duplicate symbol db name.");
2044                 }
2045             }
2046             else if(current == &gBatchModeSwitch)
2047             {
2048                 outOptions->mBatchMode = __LINE__;
2049             }
2050             else
2051             {
2052                 retval = __LINE__;
2053                 ERROR_REPORT(retval, current->mLongName, "No handler for command line switch.");
2054             }
2055         }
2056     }
2057
2058     return retval;
2059 }
2060
2061
2062 void cleanOptions(Options* inOptions)
2063 /*
2064 **  Clean up any open handles, et. al.
2065 */
2066 {
2067     CLEANUP(inOptions->mInputName);
2068     if(NULL != inOptions->mInput && stdin != inOptions->mInput)
2069     {
2070         fclose(inOptions->mInput);
2071     }
2072     CLEANUP(inOptions->mOutputName);
2073     if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
2074     {
2075         fclose(inOptions->mOutput);
2076     }
2077     while(0 != inOptions->mMatchModuleCount)
2078     {
2079         inOptions->mMatchModuleCount--;
2080         CLEANUP(inOptions->mMatchModules[inOptions->mMatchModuleCount]);
2081     }
2082     CLEANUP(inOptions->mMatchModules);
2083
2084     cleanSymDB(&inOptions->mSymDB);
2085
2086     memset(inOptions, 0, sizeof(Options));
2087 }
2088
2089
2090 void showHelp(Options* inOptions)
2091 /*
2092 **  Show some simple help text on usage.
2093 */
2094 {
2095     int loop = 0;
2096     const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
2097     const char* valueText = NULL;
2098
2099     printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
2100     printf("\n");
2101     printf("arguments:\n");
2102
2103     for(loop = 0; loop < switchCount; loop++)
2104     {
2105         if(gSwitches[loop]->mHasValue)
2106         {
2107             valueText = " <value>";
2108         }
2109         else
2110         {
2111             valueText = "";
2112         }
2113
2114         printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
2115         printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
2116         printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
2117     }
2118
2119     printf("This tool normalizes MS linker .map files for use by other tools.\n");
2120 }
2121
2122
2123 int batchMode(Options* inOptions)
2124 /*
2125 **  Batch mode means that the input file is actually a list of map files.
2126 **  We simply swap out our input file names while we do this.
2127 */
2128 {
2129     int retval = 0;
2130     char lineBuf[0x400];
2131     FILE* realInput = NULL;
2132     char* realInputName = NULL;
2133     FILE* mapFile = NULL;
2134     int finalRes = 0;
2135
2136     realInput = inOptions->mInput;
2137     realInputName = inOptions->mInputName;
2138
2139     while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), realInput))
2140     {
2141         trimWhite(lineBuf);
2142
2143         /*
2144         **  Skip/allow blank lines.
2145         */
2146         if('\0' == lineBuf[0])
2147         {
2148             continue;
2149         }
2150
2151         /*
2152         **  Override what we believe to be the input for this line.
2153         */
2154         inOptions->mInputName = lineBuf;
2155         inOptions->mInput = fopen(lineBuf, "r");
2156         if(NULL != inOptions->mInput)
2157         {
2158             int mapRes = 0;
2159
2160             /*
2161             **  Do it.
2162             */
2163             mapRes = map2tsv(inOptions);
2164
2165             /*
2166             **  We report the first error that we encounter, but we continue.
2167             **  This is batch mode after all.
2168             */
2169             if(0 == finalRes)
2170             {
2171                 finalRes = mapRes;
2172             }
2173             
2174             /*
2175             **  Close the input file.
2176             */
2177             fclose(inOptions->mInput);
2178         }
2179         else
2180         {
2181             retval = __LINE__;
2182             ERROR_REPORT(retval, lineBuf, "Unable to open map file.");
2183             break;
2184         }
2185     }
2186
2187     if(0 == retval && 0 != ferror(realInput))
2188     {
2189         retval = __LINE__;
2190         ERROR_REPORT(retval, realInputName, "Unable to read file.");
2191     }
2192
2193     /*
2194     **  Restore what we've swapped.
2195     */
2196     inOptions->mInput = realInput;
2197     inOptions->mInputName = realInputName;
2198
2199     /*
2200     **  Report first map file error if there were no other operational
2201     **      problems.
2202     */
2203     if(0 == retval)
2204     {
2205         retval = finalRes;
2206     }
2207
2208     return retval;
2209 }
2210
2211
2212 int main(int inArgc, char** inArgv)
2213 {
2214     int retval = 0;
2215     Options options;
2216
2217     retval = initOptions(&options, inArgc, inArgv);
2218     if(options.mHelp)
2219     {
2220         showHelp(&options);
2221     }
2222     else if(0 == retval)
2223     {
2224         if(options.mBatchMode)
2225         {
2226             retval = batchMode(&options);
2227         }
2228         else
2229         {
2230             retval = map2tsv(&options);
2231         }
2232     }
2233
2234     cleanOptions(&options);
2235     return retval;
2236 }
2237