diff --git a/tools/codesighs/autosummary.win.bash b/tools/codesighs/autosummary.win.bash index 72c7d0fded8f..911f52f48b34 100755 --- a/tools/codesighs/autosummary.win.bash +++ b/tools/codesighs/autosummary.win.bash @@ -94,11 +94,18 @@ SUMMARYFILE="$3" MYTMPDIR=`mktemp -d ./codesighs.tmp.XXXXXXXX` +# +# Find the types of files we are interested in. +# +ONEFINDPASS="$MYTMPDIR/onefind.list" +find ./mozilla -type f -name "*.obj" -or -name "*.map" > $ONEFINDPASS + + # # Find all object files. # ALLOBJSFILE="$MYTMPDIR/allobjs.list" -find ./mozilla -type f -name "*.obj" > $ALLOBJSFILE +grep -i "\.obj$" < $ONEFINDPASS > $ALLOBJSFILE # @@ -119,14 +126,14 @@ SYMDBFILE="$MYTMPDIR/symdb.tsv" # Find all map files. # ALLMAPSFILE="$MYTMPDIR/allmaps.list" -find ./mozilla -type f -name "*.map" > $ALLMAPSFILE +grep -i "\.map$" < $ONEFINDPASS > $ALLMAPSFILE # # Produce the TSV output. # RAWTSVFILE="$MYTMPDIR/raw.tsv" -xargs -n 1 ./mozilla/dist/bin/msmap2tsv --symdb $SYMDBFILE --input < $ALLMAPSFILE > $RAWTSVFILE 2> /dev/null +./mozilla/dist/bin/msmap2tsv --symdb $SYMDBFILE --batch < $ALLMAPSFILE > $RAWTSVFILE 2> /dev/null # diff --git a/tools/codesighs/basesummary.win.bash b/tools/codesighs/basesummary.win.bash index a06c9e9eb135..4725803108ef 100755 --- a/tools/codesighs/basesummary.win.bash +++ b/tools/codesighs/basesummary.win.bash @@ -99,11 +99,39 @@ SUMMARYFILE="$3" MYTMPDIR=`mktemp -d ./codesighs.tmp.XXXXXXXX` +# +# Find the types of files we are interested in. +# +ONEFINDPASS="$MYTMPDIR/onefind.list" +find ./mozilla -type f -name "*.obj" -or -name "*.map" > $ONEFINDPASS + + +# +# Find all object files. +# +ALLOBJSFILE="$MYTMPDIR/allobjs.list" +grep -i "\.obj$" < $ONEFINDPASS > $ALLOBJSFILE + + +# +# Get a dump of the symbols in every object file. +# +ALLOBJSYMSFILE="$MYTMPDIR/allobjsyms.list" +xargs -n 1 dumpbin.exe /symbols < $ALLOBJSFILE > $ALLOBJSYMSFILE 2> /dev/null + + +# +# Produce the symdb for the symbols in all object files. +# +SYMDBFILE="$MYTMPDIR/symdb.tsv" +./mozilla/dist/bin/msdump2symdb --input $ALLOBJSYMSFILE | sort > $SYMDBFILE 2> /dev/null + + # # Find all map files. # ALLMAPSFILE="$MYTMPDIR/allmaps.list" -find ./mozilla -type f -name "*.map" > $ALLMAPSFILE +grep -i "\.map$" < $ONEFINDPASS > $ALLMAPSFILE # @@ -115,11 +143,12 @@ RELEVANTSETFILE="$MYTMPDIR/relevant.set" grep -v '\;' < $MANIFEST | sed 's/.*\\//' | grep '\.[eEdD][xXlL][eElL]' | sed 's/\.[eEdD][xXlL][eElL]//' > $RELEVANTSETFILE RELEVANTARG=`xargs -n 1 echo --match-module < $RELEVANTSETFILE` + # # Produce the TSV output. # RAWTSVFILE="$MYTMPDIR/raw.tsv" -xargs -n 1 ./mozilla/dist/bin/msmap2tsv $RELEVANTARG --input < $ALLMAPSFILE > $RAWTSVFILE +./mozilla/dist/bin/msmap2tsv --symdb $SYMDBFILE --batch $RELEVANTARG < $ALLMAPSFILE > $RAWTSVFILE 2> /dev/null # diff --git a/tools/codesighs/msdump2symdb.c b/tools/codesighs/msdump2symdb.c index b4941fc73f40..98268c51b0ad 100755 --- a/tools/codesighs/msdump2symdb.c +++ b/tools/codesighs/msdump2symdb.c @@ -468,7 +468,15 @@ int processLine(Options* inOptions, MSDump_Container* inContainer, const char* i { char* typeDup = NULL; + /* + ** Skip the leading period before duping. + */ + if('.' == *typeArg) + { + typeArg++; + } typeDup = strdup(typeArg); + if(NULL != typeDup) { void* moved = NULL; diff --git a/tools/codesighs/msmap.h b/tools/codesighs/msmap.h index 8a5cee6f834a..7bbf072d5343 100644 --- a/tools/codesighs/msmap.h +++ b/tools/codesighs/msmap.h @@ -63,22 +63,6 @@ typedef enum __enum_MSMap_SymbolScope MSMap_SymbolScope; -typedef struct __struct_MSMap_Symbol -/* -** Information about a symbol. -*/ -{ - address mPrefix; - address mOffset; - char* mSymbol; - address mRVABase; - char* mObject; - MSMap_SymbolScope mScope; - unsigned mSymDBSize; -} -MSMap_Symbol; - - typedef enum __enum_MSMap_SegmentClass /* ** Segment class. @@ -98,12 +82,30 @@ typedef struct __struct_MSMap_Segment address mPrefix; address mOffset; address mLength; + address mUsed; char* mSegment; MSMap_SegmentClass mClass; } MSMap_Segment; +typedef struct __struct_MSMap_Symbol +/* +** Information about a symbol. +*/ +{ + address mPrefix; + address mOffset; + char* mSymbol; + address mRVABase; + char* mObject; + MSMap_SymbolScope mScope; + unsigned mSymDBSize; + MSMap_Segment* mSection; +} +MSMap_Symbol; + + typedef struct __struct_MSMap_Module /* ** Top level container of the map data. diff --git a/tools/codesighs/msmap2tsv.c b/tools/codesighs/msmap2tsv.c index c432a45f9890..745c08d2e093 100644 --- a/tools/codesighs/msmap2tsv.c +++ b/tools/codesighs/msmap2tsv.c @@ -127,6 +127,9 @@ typedef struct __struct_SymDB_Symbol SymDB_Symbol; +#define SYMDB_SYMBOL_GROWBY 0x1000 /* how many sybols to allocate at a time */ + + typedef struct __struct_SymDB_Container /* ** The symbol DB container object. @@ -138,10 +141,12 @@ typedef struct __struct_SymDB_Container ** ** mSymbols The symbols. ** mSymbolCount The number of symbols in the DB. +** mSymbolCapacity The number of symbols we can hold (before realloc). */ { SymDB_Symbol* mSymbols; unsigned mSymbolCount; + unsigned mSymbolCapacity; } SymDB_Container; @@ -158,10 +163,13 @@ typedef struct __struct_Options ** Default is stdout. ** mOutputName Name of the file. ** mHelp Wether or not help should be shown. -** mAddress Wether or not to output addresses. ** mMatchModules Array of strings which the module name should match. ** mMatchModuleCount Number of items in array. ** mSymDBName Symbol DB filename. +** mBatchMode Batch mode. +** When in batch mode, the input file contains a list of +** map files to process. +** Normally the input file is a single map file itself. */ { const char* mProgramName; @@ -170,11 +178,11 @@ typedef struct __struct_Options FILE* mOutput; char* mOutputName; int mHelp; - int mAddresses; char** mMatchModules; unsigned mMatchModuleCount; char* mSymDBName; SymDB_Container* mSymDB; + int mBatchMode; } Options; @@ -197,16 +205,16 @@ Switch; static Switch gInputSwitch = {"--input", "-i", 1, NULL, "Specify input file." DESC_NEWLINE "stdin is default."}; static Switch gOutputSwitch = {"--output", "-o", 1, NULL, "Specify output file." DESC_NEWLINE "Appends if file exists." DESC_NEWLINE "stdout is default."}; static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."}; -static Switch gAddressesSwitch = {"--addresses", "-a", 0, NULL, "Output segment addresses." DESC_NEWLINE "Helps reveal symbol ordering." DESC_NEWLINE "Lack of simplifies size diffing."}; 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."}; 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."}; +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."}; static Switch* gSwitches[] = { &gInputSwitch, &gOutputSwitch, - &gAddressesSwitch, &gMatchModuleSwitch, &gSymDBSwitch, + &gBatchModeSwitch, &gHelpSwitch }; @@ -297,6 +305,55 @@ char* lastWord(char* inString) } +MSMap_Segment* getSymbolSection(MSMap_Module* inModule, MSMap_Symbol* inoutSymbol) +/* +** Perform a lookup for the section of the symbol. +** The function could cache the value. +*/ +{ + MSMap_Segment* retval = NULL; + + if(NULL != inoutSymbol->mSection) + { + /* + ** Use cached value. + */ + retval = inoutSymbol->mSection; + } + else + { + unsigned secLoop = 0; + + /* + ** Go through sections in module to find the match for the symbol. + */ + for(secLoop = 0; secLoop < inModule->mSegmentCount; secLoop++) + { + if(inoutSymbol->mPrefix == inModule->mSegments[secLoop].mPrefix) + { + if(inoutSymbol->mOffset >= inModule->mSegments[secLoop].mOffset) + { + if(inoutSymbol->mOffset < (inModule->mSegments[secLoop].mOffset + inModule->mSegments[secLoop].mLength)) + { + /* + ** We have the section. + */ + retval = &inModule->mSegments[secLoop]; + } + } + } + } + + /* + ** Cache the value for next time. + */ + inoutSymbol->mSection = retval; + } + + return retval; +} + + int readSymDB(const char* inDBName, SymDB_Container** outDB) /* ** Intialize the symbol DB. @@ -315,9 +372,292 @@ int readSymDB(const char* inDBName, SymDB_Container** outDB) if(NULL != outDB && NULL != inDBName) { - /* - ** TODO - */ + FILE* symDB = NULL; + + symDB = fopen(inDBName, "r"); + if(NULL != symDB) + { + *outDB = (SymDB_Container*)calloc(1, sizeof(SymDB_Container)); + if(NULL != *outDB) + { + char lineBuf[0x400]; + char* symbol = NULL; + char* section = NULL; + char* object = NULL; + char* length = NULL; + unsigned lengthNum = 0; + char* endLength = NULL; + + /* + ** Read the file line by line. + */ + while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), symDB)) + { + trimWhite(lineBuf); + + /* + ** Each line has four arguments. tab seperated values (tsv). + ** Symbol + ** Section + ** Length + ** Object + */ + + symbol = skipWhite(lineBuf); + if(NULL == symbol) + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB."); + break; + } + + section = strchr(symbol, '\t'); + if(NULL == section) + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB."); + break; + } + *section = '\0'; + section++; + + length = strchr(section, '\t'); + if(NULL == length) + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB."); + break; + } + *length = '\0'; + length++; + + object = strchr(length, '\t'); + if(NULL == object) + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "File does not appear to be a symbol DB."); + break; + } + *object = '\0'; + object++; + + /* + ** Convert the length into a number. + */ + errno = 0; + lengthNum = strtoul(length, &endLength, 16); + if(0 == errno && endLength != length) + { + SymDB_Symbol* dbSymbol = NULL; + SymDB_Section* dbSection = NULL; + SymDB_Size* dbSize = NULL; + char* dbObject = NULL; + void* moved = NULL; + + /* + ** Are we looking at the same symbol as last line? + ** This assumes the symdb is pre sorted!!! + */ + if(0 != (*outDB)->mSymbolCount) + { + unsigned index = (*outDB)->mSymbolCount - 1; + + if(0 == strcmp((*outDB)->mSymbols[index].mName, symbol)) + { + dbSymbol = &(*outDB)->mSymbols[index]; + } + } + + /* + ** May need to create symbol. + */ + if(NULL == dbSymbol) + { + /* + ** Could be time to grow the symbol pool. + */ + if((*outDB)->mSymbolCount >= (*outDB)->mSymbolCapacity) + { + moved = realloc((*outDB)->mSymbols, sizeof(SymDB_Symbol) * ((*outDB)->mSymbolCapacity + SYMDB_SYMBOL_GROWBY)); + if(NULL != moved) + { + (*outDB)->mSymbols = (SymDB_Symbol*)moved; + memset(&(*outDB)->mSymbols[(*outDB)->mSymbolCapacity], 0, sizeof(SymDB_Symbol) * SYMDB_SYMBOL_GROWBY); + (*outDB)->mSymbolCapacity += SYMDB_SYMBOL_GROWBY; + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "Unable to grow symbol DB symbol array."); + break; + } + } + + if((*outDB)->mSymbolCount < (*outDB)->mSymbolCapacity) + { + dbSymbol = &(*outDB)->mSymbols[(*outDB)->mSymbolCount]; + (*outDB)->mSymbolCount++; + + dbSymbol->mName = strdup(symbol); + if(NULL == dbSymbol->mName) + { + retval = __LINE__; + ERROR_REPORT(retval, symbol, "Unable to duplicate string."); + break; + } + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, symbol, "Unable to grow symbol DB for symbol."); + break; + } + } + + /* + ** Assume we have the symbol. + ** + ** Is this the same section as the last section in the symbol? + ** This assumes the symdb was presorted!!!! + */ + if(0 != dbSymbol->mSectionCount) + { + unsigned index = dbSymbol->mSectionCount - 1; + + if(0 == strcmp(dbSymbol->mSections[index].mName, section)) + { + dbSection = &dbSymbol->mSections[index]; + } + } + + /* + ** May need to create the section. + */ + if(NULL == dbSection) + { + moved = realloc(dbSymbol->mSections, sizeof(SymDB_Section) * (dbSymbol->mSectionCount + 1)); + if(NULL != moved) + { + dbSymbol->mSections = (SymDB_Section*)moved; + dbSection = &dbSymbol->mSections[dbSymbol->mSectionCount]; + dbSymbol->mSectionCount++; + + memset(dbSection, 0, sizeof(SymDB_Section)); + + dbSection->mName = strdup(section); + if(NULL == dbSection->mName) + { + retval = __LINE__; + ERROR_REPORT(retval, section, "Unable to duplicate string."); + break; + } + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, section, "Unable to grow symbol sections for symbol DB."); + break; + } + } + + /* + ** Assume we have the section. + ** + ** Is this the same size as the last size? + ** This assumes the symdb was presorted!!! + */ + if(0 != dbSection->mSizeCount) + { + unsigned index = dbSection->mSizeCount - 1; + + if(dbSection->mSizes[index].mSize == lengthNum) + { + dbSize = &dbSection->mSizes[index]; + } + } + + /* + ** May need to create the size in question. + */ + if(NULL == dbSize) + { + moved = realloc(dbSection->mSizes, sizeof(SymDB_Size) * (dbSection->mSizeCount + 1)); + if(NULL != moved) + { + dbSection->mSizes = (SymDB_Size*)moved; + dbSize = &dbSection->mSizes[dbSection->mSizeCount]; + dbSection->mSizeCount++; + + memset(dbSize, 0, sizeof(SymDB_Size)); + + dbSize->mSize = lengthNum; + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, length, "Unable to grow symbol section sizes for symbol DB."); + break; + } + } + + /* + ** Assume we have the size. + ** + ** We assume a one to one correllation between size and object. + ** Always try to add the new object name. + ** As the symdb is assumed to be sorted, the object names should also be in order. + */ + moved = realloc(dbSize->mObjects, sizeof(char*) * (dbSize->mObjectCount + 1)); + if(NULL != moved) + { + dbObject = strdup(object); + + dbSize->mObjects = (char**)moved; + dbSize->mObjects[dbSize->mObjectCount] = dbObject; + dbSize->mObjectCount++; + + if(NULL == dbObject) + { + retval = __LINE__; + ERROR_REPORT(retval, object, "Unable to duplicate string."); + break; + } + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, object, "Unable to grow symbol section size objects for symbol DB."); + break; + } + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, length, "Unable to convert symbol DB length into a number."); + break; + } + } + + if(0 == retval && 0 != ferror(symDB)) + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "Unable to read file."); + } + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "Unable to allocate symbol DB."); + } + + fclose(symDB); + symDB = NULL; + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, inDBName, "Unable to open symbol DB."); + } } else { @@ -329,7 +669,58 @@ int readSymDB(const char* inDBName, SymDB_Container** outDB) } -int fillSymbolSizeFromDB(Options* inOptions, MSMap_Symbol* inoutSymbol, const char* inMangledName) +void cleanSymDB(SymDB_Container** inDB) +/* +** Free it all up. +*/ +{ + if(NULL != inDB && NULL != *inDB) + { + unsigned symLoop = 0; + unsigned secLoop = 0; + unsigned sizLoop = 0; + unsigned objLoop = 0; + + for(symLoop = 0; symLoop < (*inDB)->mSymbolCount; symLoop++) + { + for(secLoop = 0; secLoop < (*inDB)->mSymbols[symLoop].mSectionCount; secLoop++) + { + for(sizLoop = 0; sizLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizeCount; sizLoop++) + { + for(objLoop = 0; objLoop < (*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjectCount; objLoop++) + { + CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects[objLoop]); + } + CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes[sizLoop].mObjects); + } + CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mName); + CLEANUP((*inDB)->mSymbols[symLoop].mSections[secLoop].mSizes); + } + CLEANUP((*inDB)->mSymbols[symLoop].mName); + CLEANUP((*inDB)->mSymbols[symLoop].mSections); + } + CLEANUP((*inDB)->mSymbols); + CLEANUP(*inDB); + } +} + + +int symDBLookup(const void* inKey, const void* inItem) +/* +** bsearch utility routine to find the symbol in the symdb. +*/ +{ + int retval = 0; + const char* key = (const char*)inKey; + const SymDB_Symbol* symbol = (const SymDB_Symbol*)inItem; + + retval = strcmp(key, symbol->mName); + + return retval; +} + + +int fillSymbolSizeFromDB(Options* inOptions, MSMap_Module* inModule, MSMap_Symbol* inoutSymbol, const char* inMangledName) /* ** If we have a symbol DB, attempt to determine the real size of the symbol ** up front. @@ -352,9 +743,109 @@ int fillSymbolSizeFromDB(Options* inOptions, MSMap_Symbol* inoutSymbol, const ch */ if(0 == retval && NULL != inOptions->mSymDB) { + void* match = NULL; + /* - ** TODO + ** Find the symbol. */ + match = bsearch(inMangledName, inOptions->mSymDB->mSymbols, inOptions->mSymDB->mSymbolCount, sizeof(SymDB_Symbol), symDBLookup); + if(NULL != match) + { + SymDB_Symbol* symbol = (SymDB_Symbol*)match; + unsigned symDBSize = 0; + MSMap_Segment* mapSection = NULL; + + /* + ** We found the symbol. + ** + ** See if it has the section in question. + */ + mapSection = getSymbolSection(inModule, inoutSymbol); + if(NULL != mapSection) + { + unsigned secLoop = 0; + + for(secLoop = 0; secLoop < symbol->mSectionCount; secLoop++) + { + if(0 == strcmp(mapSection->mSegment, symbol->mSections[secLoop].mName)) + { + SymDB_Section* section = &symbol->mSections[secLoop]; + + /* + ** We have a section match. + ** Should there be a single size for the symbol, + ** then we just default to that. + ** If more than one size, we have to do an + ** object match search. + ** Should there be no object match, we do nothign. + */ + if(1 == section->mSizeCount) + { + symDBSize = section->mSizes[0].mSize; + } + else + { + char* mapObject = NULL; + + /* + ** Figure out the map object file name. + ** Skip any colon. + ** If it doesn't have a .obj in it, not worth continuing. + */ + mapObject = strrchr(inoutSymbol->mObject, ':'); + if(NULL == mapObject) + { + mapObject = inoutSymbol->mObject; + } + else + { + mapObject++; /* colon */ + } + + if(NULL != strstr(mapObject, ".obj")) + { + unsigned sizLoop = 0; + unsigned objLoop = 0; + SymDB_Size* size = NULL; + + for(sizLoop = 0; sizLoop < section->mSizeCount; sizLoop++) + { + size = §ion->mSizes[sizLoop]; + + for(objLoop = 0; objLoop < size->mObjectCount; objLoop++) + { + if(NULL != strstr(size->mObjects[objLoop], mapObject)) + { + /* + ** As we matched the object, in a particular section, + ** we'll go with this as the number. + */ + symDBSize = size->mSize; + break; + } + } + + /* + ** If the object loop broke early, we break too. + */ + if(objLoop < size->mObjectCount) + { + break; + } + } + } + } + + break; + } + } + } + + /* + ** Put the size in. + */ + inoutSymbol->mSymDBSize = symDBSize; + } } return retval; @@ -848,7 +1339,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule) ** Finally, attempt to lookup the actual size of the symbol ** if there is a symbol DB available. */ - retval = fillSymbolSizeFromDB(inOptions, theSymbol, symbolBuf); + retval = fillSymbolSizeFromDB(inOptions, inModule, theSymbol, symbolBuf); } else { @@ -1097,7 +1588,7 @@ static int qsortRVABase(const void* in1, const void* in2) } -static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClass, MSMap_SymbolScope inScope, const char* inModule, const char* inSegment, address inPrefix, address inOffset, const char* inObject, const char* inSymbol) +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) /* ** Output a line of map information seperated by tabs. ** Some items (const char*), if not present, will receive a default value. @@ -1169,7 +1660,7 @@ static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClas int printRes = 0; printRes = fprintf(inOptions->mOutput, - "%.8X\t%s\t%s\t%s\t%s\t%s\t%s", + "%.8X\t%s\t%s\t%s\t%s\t%s\t%s\n", inSize, segClass, symScope, @@ -1179,20 +1670,6 @@ static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClas inSymbol ); - if(0 <= printRes && inOptions->mAddresses) - { - printRes = fprintf(inOptions->mOutput, - "\t%.4X:%.8X", - (unsigned)inPrefix, - (unsigned)inOffset - ); - } - - if(0 <= printRes) - { - printRes = fprintf(inOptions->mOutput, "\n"); - } - if(0 > printRes) { retval = __LINE__; @@ -1245,13 +1722,14 @@ int map2tsv(Options* inOptions) retval = readmap(inOptions, &module); if(0 == retval) { - unsigned segLoop = 0; - MSMap_Segment* segment = NULL; unsigned symLoop = 0; MSMap_Symbol* symbol = NULL; - MSMap_Symbol* firstSymbol = NULL; - MSMap_Symbol* matchSymbol = NULL; - MSMap_Symbol* prevSymbol = NULL; + unsigned secLoop = 0; + MSMap_Segment* section = NULL; + unsigned size = 0; + unsigned dbSize = 0; + unsigned offsetSize = 0; + unsigned endOffset = 0; /* ** Quick sort the symbols via RVABase. @@ -1259,118 +1737,110 @@ int map2tsv(Options* inOptions) qsort(module.mSymbols, module.mSymbolCount, sizeof(MSMap_Symbol), qsortRVABase); /* - ** Go through each segment in order: - ** Output symbols and sizes, already in order. - ** Make up symbol names for those missing symbols, - ** or for blank spots at the beginning of a segment. + ** Go through all the symbols (in order by sort). + ** Output their sizes. */ - for(segLoop = 0; 0 == retval && segLoop < module.mSegmentCount; segLoop++) + for(symLoop = 0; 0 == retval && symLoop < module.mSymbolCount; symLoop++) { - segment = (module.mSegments + segLoop); - firstSymbol = NULL; - matchSymbol = NULL; - prevSymbol = NULL; + symbol = &module.mSymbols[symLoop]; + section = getSymbolSection(&module, symbol); - for(symLoop = 0; 0 == retval && symLoop < module.mSymbolCount; symLoop++) + /* + ** Use the symbol DB size if available. + */ + dbSize = symbol->mSymDBSize; + + /* + ** Guess using offsets. + ** Is there a next symbol available? If so, it's start offset is the end of this symbol. + ** Otherwise, our section offset + length is the end of this symbol. + ** + ** The trick is, the DB size can not go beyond the offset size, for sanity. + */ + + /* + ** Try next symbol, but only if in same section. + ** If still not, use the end of the segment. + ** This implies we were the last symbol in the segment. + */ + if((symLoop + 1) < module.mSymbolCount) { - symbol = (module.mSymbols + symLoop); - - /* - ** Symbol must fall in range of segment for consideration. - */ - if(symbol->mPrefix == segment->mPrefix) + MSMap_Symbol* nextSymbol = NULL; + MSMap_Segment* nextSection = NULL; + + nextSymbol = &module.mSymbols[symLoop + 1]; + nextSection = getSymbolSection(&module, nextSymbol); + + if(section == nextSection) { - if(symbol->mOffset >= segment->mOffset) - { - if(symbol->mOffset < (segment->mOffset + segment->mLength)) - { - /* - ** Matched. - */ - prevSymbol = matchSymbol; - matchSymbol = symbol; + endOffset = nextSymbol->mOffset; + } + else + { + endOffset = section->mOffset + section->mLength; + } + } + else + { + endOffset = section->mOffset + section->mLength; + } - if(NULL == firstSymbol) - { - firstSymbol = matchSymbol; + /* + ** Can now guess at size. + */ + offsetSize = endOffset - symbol->mOffset; - /* - ** Check to see if we need to output a dummy - ** to start the segment. - */ - if(0 == retval && firstSymbol->mOffset != segment->mOffset) - { - retval = tsvout(inOptions, - firstSymbol->mOffset - segment->mOffset, - segment->mClass, - UNDEFINED, - module.mModule, - segment->mSegment, - segment->mPrefix, - segment->mOffset, - NULL, - NULL - ); - } - } - - /* - ** Can now output previous symbol as can calculate size. - */ - if(0 == retval && NULL != prevSymbol) - { - retval = tsvout(inOptions, - matchSymbol->mOffset - prevSymbol->mOffset, - segment->mClass, - prevSymbol->mScope, - module.mModule, - segment->mSegment, - prevSymbol->mPrefix, - prevSymbol->mOffset, - prevSymbol->mObject, - prevSymbol->mSymbol - ); - } - } - } + /* + ** Now, determine which size to use. + ** This is really a sanity check as well. + */ + size = offsetSize; + if(0 != dbSize) + { + if(dbSize < offsetSize) + { + size = dbSize; } } /* - ** If there was no symbol, output a fake one for the entire segment. - ** Otherwise, there is always one final match which we must output - ** taking up the remainder of the segment. + ** Output the symbol with the size. */ - if(0 == retval) + retval = tsvout(inOptions, + size, + section->mClass, + symbol->mScope, + module.mModule, + section->mSegment, + symbol->mObject, + symbol->mSymbol + ); + + /* + ** Make sure we mark this amount of space as used in the section. + */ + section->mUsed += size; + } + + /* + ** Go through the sections, and those whose length is longer than the + ** amount of space used, output dummy filler values. + */ + for(secLoop = 0; 0 == retval && secLoop < module.mSegmentCount; secLoop++) + { + section = &module.mSegments[secLoop]; + + if(section->mUsed < section->mLength) { - if(NULL == firstSymbol) - { - retval = tsvout(inOptions, - segment->mLength, - segment->mClass, - UNDEFINED, - module.mModule, - segment->mSegment, - segment->mPrefix, - segment->mOffset, - NULL, - NULL - ); - } - else - { - retval = tsvout(inOptions, - (segment->mOffset + segment->mLength) - matchSymbol->mOffset, - segment->mClass, - matchSymbol->mScope, - module.mModule, - segment->mSegment, - matchSymbol->mPrefix, - matchSymbol->mOffset, - matchSymbol->mObject, - matchSymbol->mSymbol - ); - } + retval = tsvout(inOptions, + section->mLength - section->mUsed, + section->mClass, + UNDEFINED, + module.mModule, + section->mSegment, + NULL, + NULL + ); } } } @@ -1522,10 +1992,6 @@ int initOptions(Options* outOptions, int inArgc, char** inArgv) } } } - else if(current == &gAddressesSwitch) - { - outOptions->mAddresses = __LINE__; - } else if(current == &gHelpSwitch) { outOptions->mHelp = __LINE__; @@ -1568,6 +2034,10 @@ int initOptions(Options* outOptions, int inArgc, char** inArgv) ERROR_REPORT(retval, current->mValue, "Unable to duplicate symbol db name."); } } + else if(current == &gBatchModeSwitch) + { + outOptions->mBatchMode = __LINE__; + } else { retval = __LINE__; @@ -1582,7 +2052,7 @@ int initOptions(Options* outOptions, int inArgc, char** inArgv) void cleanOptions(Options* inOptions) /* -** Clean up any open handles. +** Clean up any open handles, et. al. */ { CLEANUP(inOptions->mInputName); @@ -1602,6 +2072,8 @@ void cleanOptions(Options* inOptions) } CLEANUP(inOptions->mMatchModules); + cleanSymDB(&inOptions->mSymDB); + memset(inOptions, 0, sizeof(Options)); } @@ -1639,6 +2111,95 @@ void showHelp(Options* inOptions) } +int batchMode(Options* inOptions) +/* +** Batch mode means that the input file is actually a list of map files. +** We simply swap out our input file names while we do this. +*/ +{ + int retval = 0; + char lineBuf[0x400]; + FILE* realInput = NULL; + char* realInputName = NULL; + FILE* mapFile = NULL; + int finalRes = 0; + + realInput = inOptions->mInput; + realInputName = inOptions->mInputName; + + while(0 == retval && NULL != fgets(lineBuf, sizeof(lineBuf), realInput)) + { + trimWhite(lineBuf); + + /* + ** Skip/allow blank lines. + */ + if('\0' == lineBuf[0]) + { + continue; + } + + /* + ** Override what we believe to be the input for this line. + */ + inOptions->mInputName = lineBuf; + inOptions->mInput = fopen(lineBuf, "r"); + if(NULL != inOptions->mInput) + { + int mapRes = 0; + + /* + ** Do it. + */ + mapRes = map2tsv(inOptions); + + /* + ** We report the first error that we encounter, but we continue. + ** This is batch mode after all. + */ + if(0 == finalRes) + { + finalRes = mapRes; + } + + /* + ** Close the input file. + */ + fclose(inOptions->mInput); + } + else + { + retval = __LINE__; + ERROR_REPORT(retval, lineBuf, "Unable to open map file."); + break; + } + } + + if(0 == retval && 0 != ferror(realInput)) + { + retval = __LINE__; + ERROR_REPORT(retval, realInputName, "Unable to read file."); + } + + /* + ** Restore what we've swapped. + */ + inOptions->mInput = realInput; + inOptions->mInputName = realInputName; + + /* + ** Report first map file error if there were no other operational + ** problems. + */ + if(0 == retval) + { + retval = finalRes; + } + + return retval; +} + + int main(int inArgc, char** inArgv) { int retval = 0; @@ -1651,7 +2212,14 @@ int main(int inArgc, char** inArgv) } else if(0 == retval) { - retval = map2tsv(&options); + if(options.mBatchMode) + { + retval = batchMode(&options); + } + else + { + retval = map2tsv(&options); + } } cleanOptions(&options);