Not part of any normal build (yet).

Map file parsing tools for a windows build.
Goal will be to use the script to hook up in tinderbox for code size delta tracking.
This commit is contained in:
blythe%netscape.com 2002-10-04 02:33:15 +00:00
parent e0ab272030
commit 5225e70748
6 changed files with 2941 additions and 0 deletions

View File

@ -0,0 +1,42 @@
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s):
# Garrett Arch Blythe
#
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
REQUIRES = $(NULL)
SIMPLECSRCS += \
msmap2tsv.c \
codesighs.c \
maptsvdifftool.c \
$(NULL)
SIMPLE_PROGRAMS = $(SIMPLECSRCS:.c=$(BIN_SUFFIX))
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,142 @@
#!/bin/bash
#
# Assumed to be run from the parent directory of the mozilla source tree.
#
#
# A little help for my friends.
#
if [ "-h" == "$1" ];then
SHOWHELP="1"
fi
if [ "--help" == "$1" ];then
SHOWHELP="1"
fi
if [ "" == "$1" ]; then
SHOWHELP="1"
fi
if [ "" == "$2" ]; then
SHOWHELP="1"
fi
if [ "" == "$3" ]; then
SHOWHELP="1"
fi
#
# Show the help if required.
#
if [ $SHOWHELP ]; then
echo "usage: $0 <save_results> <old_results> <summary>"
echo " <save_results> is a file that will receive the results of this run."
echo " This file can be used in a future run as the old results."
echo " <old_results> is a results file from a previous run."
echo " It is used to diff with current results and come up with a summary"
echo " of changes."
echo " It is OK if the file does not exist, just supply the argument."
echo " <summary> is a file which will contain a human readable report."
echo " This file is most useful by providing more information than the"
echo " normally single digit output of this script."
echo ""
echo "Run this command from the parent directory of the mozilla tree."
echo ""
echo "This command will output two numbers to stdout that will represent"
echo " the total size of all code and data, and a delta from the prior."
echo " the old results."
echo "For much more detail to size drifts refer to the summary report."
exit
fi
#
# Exclude certain path patterns.
# Be sure to modify the grep command below as well.
#
EXCLUDE_PATH_01="/test/"
EXCLUDE_PATH_02="/tests/"
EXCLUDE_PATH_03="/tools/"
EXCLUDE_PATH_04="/config/"
EXCLUDE_PATH_05="IBMNEC.map"
#
# Stash our arguments away.
#
COPYSORTTSV="$1"
OLDTSVFILE="$2"
SUMMARYFILE="$3"
#
# Create our temporary directory.
#
TMPDIR="$TMP/codesighs.$PPID"
mkdir -p $TMPDIR
#
# Find all map files.
#
ALLMAPSFILE="$TMPDIR/allmaps.list"
find ./mozilla -type f -name *.map > $ALLMAPSFILE
#
# Reduce the map files to a revelant set.
#
MAPSFILE="$TMPDIR/maps.list"
grep -v $EXCLUDE_PATH_01 < $ALLMAPSFILE | grep -v $EXCLUDE_PATH_02 | grep -v $EXCLUDE_PATH_03 | grep -v $EXCLUDE_PATH_04 | grep -v $EXCLUDE_PATH_05 > $MAPSFILE
#
# Produce the TSV output.
#
RAWTSVFILE="$TMPDIR/raw.tsv"
xargs -n 1 ./mozilla/dist/bin/msmap2tsv --input < $MAPSFILE > $RAWTSVFILE
#
# Sort the TSV output for useful diffing and eyeballing in general.
#
sort -r $RAWTSVFILE > $COPYSORTTSV
#
# If a historical file was specified, diff it with our sorted tsv values.
# Run it through a tool to summaries the diffs to the module
# level report.
#
rm -f $SUMMARYFILE
DIFFFILE="$TMPDIR/diff.txt"
if [ -e $OLDTSVFILE ]; then
diff $OLDTSVFILE $COPYSORTTSV > $DIFFFILE
./mozilla/dist/bin/maptsvdifftool --input $DIFFFILE >> $SUMMARYFILE
echo "" >> $SUMMARYFILE
echo "" >> $SUMMARYFILE
fi
#
# Generate the module level report from our new data.
#
./mozilla/dist/bin/codesighs --modules --input $COPYSORTTSV >> $SUMMARYFILE
#
# Output our numbers, that will let tinderbox specify everything all
# at once.
# First number is in fact the total size of all code and data in the map
# files parsed.
# Second number, if present, is growth/shrinkage.
#
./mozilla/dist/bin/codesighs --totalonly --input $COPYSORTTSV
if [ -e $DIFFFILE ]; then
./mozilla/dist/bin/maptsvdifftool --totalonly --input $DIFFFILE
fi
#
# Remove our temporary directory.
#
rm -rf $TMPDIR

563
tools/codesighs/codesighs.c Normal file
View File

@ -0,0 +1,563 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
#define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
typedef struct __struct_Options
/*
** Options to control how we perform.
**
** mProgramName Used in help text.
** mInput File to read for input.
** Default is stdin.
** mInputName Name of the file.
** mOutput Output file, append.
** Default is stdout.
** mOutputName Name of the file.
** mHelp Wether or not help should be shown.
** mModules Output module by module information.
** mTotalOnly Only output one number, the total.
*/
{
const char* mProgramName;
FILE* mInput;
char* mInputName;
FILE* mOutput;
char* mOutputName;
int mHelp;
int mModules;
int mTotalOnly;
}
Options;
typedef struct __struct_Switch
/*
** Command line options.
*/
{
const char* mLongName;
const char* mShortName;
int mHasValue;
const char* mValue;
const char* mDescription;
}
Switch;
#define DESC_NEWLINE "\n\t\t"
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 gModuleSwitch = {"--modules", "-m", 0, NULL, "Output individual module numbers as well."};
static Switch gTotalSwitch = {"--totalonly", "-t", 0, NULL, "Output only one number." DESC_NEWLINE "The total overall size." DESC_NEWLINE "Overrides other output options."};
static Switch* gSwitches[] = {
&gInputSwitch,
&gOutputSwitch,
&gModuleSwitch,
&gTotalSwitch,
&gHelpSwitch
};
typedef struct __struct_SizeStats
/*
** Track totals.
**
** mData Size of data.
** mCode Size of code.
*/
{
unsigned long mData;
unsigned long mCode;
}
SizeStats;
typedef struct __struct_ModuleStats
/*
** Track module level information.
**
** mModule Module name.
** mSize Size of module.
*/
{
char* mModule;
SizeStats mSize;
}
ModuleStats;
typedef enum __enum_SegmentClass
{
CODE,
DATA
}
SegmentClass;
static int moduleCompare(const void* in1, const void* in2)
/*
** qsort helper function.
*/
{
int retval = 0;
const ModuleStats* one = (const ModuleStats*)in1;
const ModuleStats* two = (const ModuleStats*)in2;
unsigned long oneSize = one->mSize.mCode + one->mSize.mData;
unsigned long twoSize = two->mSize.mCode + two->mSize.mData;
if(oneSize < twoSize)
{
retval = 1;
}
else if(oneSize > twoSize)
{
retval = -1;
}
return retval;
}
int codesighs(Options* inOptions)
/*
** Output a simplistic report based on our options.
*/
{
int retval = 0;
char lineBuffer[0x500];
int scanRes = 0;
unsigned long size;
char segClass[0x10];
char scope[0x10];
char module[0x100];
char segment[0x40];
char object[0x100];
char symbol[0x200];
SizeStats overall;
ModuleStats* modules = NULL;
unsigned moduleCount = 0;
memset(&overall, 0, sizeof(overall));
/*
** Read the file line by line, regardless of number of fields.
** We assume tab seperated value formatting, at least 7 lead values:
** size class scope module segment object symbol ....
*/
while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
{
scanRes = sscanf(lineBuffer,
"%x\t%s\t%s\t%s\t%s\t%s\t%s",
&size,
segClass,
scope,
module,
segment,
object,
symbol);
if(7 == scanRes)
{
SegmentClass segmentClass = CODE;
if(0 == strcmp(segClass, "DATA"))
{
segmentClass = DATA;
}
else if(0 == strcmp(segClass, "CODE"))
{
segmentClass = CODE;
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
}
if(0 == retval)
{
/*
** Update overall totals.
*/
if(CODE == segmentClass)
{
overall.mCode += size;
}
else if(DATA == segmentClass)
{
overall.mData += size;
}
/*
** See what else we should be tracking.
*/
if(0 == inOptions->mTotalOnly)
{
if(inOptions->mModules)
{
unsigned index = 0;
/*
** Find the module to modify.
*/
for(index = 0; index < moduleCount; index++)
{
if(0 == strcmp(modules[index].mModule, module))
{
break;
}
}
/*
** If the index is the same as the count, we need to
** add a new module.
*/
if(index == moduleCount)
{
void* moved = NULL;
moved = realloc(modules, sizeof(ModuleStats) * (moduleCount + 1));
if(NULL != moved)
{
modules = (ModuleStats*)moved;
moduleCount++;
memset(modules + index, 0, sizeof(ModuleStats));
modules[index].mModule = strdup(module);
if(NULL == modules[index].mModule)
{
retval = __LINE__;
ERROR_REPORT(retval, module, "Unable to duplicate string.");
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mProgramName, "Unable to allocate module memory.");
}
}
if(0 == retval)
{
if(CODE == segmentClass)
{
modules[index].mSize.mCode += size;
}
else if(DATA == segmentClass)
{
modules[index].mSize.mData += size;
}
}
}
}
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mInputName, "Problem extracting values from file.");
}
}
if(0 == retval && 0 != ferror(inOptions->mInput))
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
}
/*
** If all went well, time to report.
*/
if(0 == retval)
{
if(inOptions->mTotalOnly)
{
fprintf(inOptions->mOutput, "%u\n", overall.mCode + overall.mData);
}
else
{
fprintf(inOptions->mOutput, "Overall Size\n");
fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", overall.mCode + overall.mData);
fprintf(inOptions->mOutput, "\tCode:\t%10u\n", overall.mCode);
fprintf(inOptions->mOutput, "\tData:\t%10u\n", overall.mData);
}
/*
** Check options to see what else we should output.
*/
if(inOptions->mModules && moduleCount)
{
unsigned loop = 0;
/*
** Sort the modules by their size.
*/
qsort(modules, (size_t)moduleCount, sizeof(ModuleStats), moduleCompare);
/*
** Output each one.
** Might as well clean up while we go too.
*/
for(loop = 0; loop < moduleCount; loop++)
{
fprintf(inOptions->mOutput, "\n");
fprintf(inOptions->mOutput, "%s\n", modules[loop].mModule);
fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", modules[loop].mSize.mCode + modules[loop].mSize.mData);
fprintf(inOptions->mOutput, "\tCode:\t%10u\n", modules[loop].mSize.mCode);
fprintf(inOptions->mOutput, "\tData:\t%10u\n", modules[loop].mSize.mData);
CLEANUP(modules[loop].mModule);
}
/*
** Done with modules.
*/
CLEANUP(modules);
moduleCount = 0;
}
}
return retval;
}
int initOptions(Options* outOptions, int inArgc, char** inArgv)
/*
** returns int 0 if successful.
*/
{
int retval = 0;
int loop = 0;
int switchLoop = 0;
int match = 0;
const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
Switch* current = NULL;
/*
** Set any defaults.
*/
memset(outOptions, 0, sizeof(Options));
outOptions->mProgramName = inArgv[0];
outOptions->mInput = stdin;
outOptions->mInputName = strdup("stdin");
outOptions->mOutput = stdout;
outOptions->mOutputName = strdup("stdout");
if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
{
retval = __LINE__;
ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
}
/*
** Go through and attempt to do the right thing.
*/
for(loop = 1; loop < inArgc && 0 == retval; loop++)
{
match = 0;
current = NULL;
for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
{
if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
{
match = __LINE__;
}
else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
{
match = __LINE__;
}
if(match)
{
if(gSwitches[switchLoop]->mHasValue)
{
/*
** Attempt to absorb next option to fullfill value.
*/
if(loop + 1 < inArgc)
{
loop++;
current = gSwitches[switchLoop];
current->mValue = inArgv[loop];
}
}
else
{
current = gSwitches[switchLoop];
}
break;
}
}
if(0 == match)
{
outOptions->mHelp = __LINE__;
retval = __LINE__;
ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
}
else if(NULL == current)
{
outOptions->mHelp = __LINE__;
retval = __LINE__;
ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
}
else
{
/*
** Do something based on address/swtich.
*/
if(current == &gInputSwitch)
{
CLEANUP(outOptions->mInputName);
if(NULL != outOptions->mInput && stdin != outOptions->mInput)
{
fclose(outOptions->mInput);
outOptions->mInput = NULL;
}
outOptions->mInput = fopen(current->mValue, "r");
if(NULL == outOptions->mInput)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
}
else
{
outOptions->mInputName = strdup(current->mValue);
if(NULL == outOptions->mInputName)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
}
}
}
else if(current == &gOutputSwitch)
{
CLEANUP(outOptions->mOutputName);
if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
{
fclose(outOptions->mOutput);
outOptions->mOutput = NULL;
}
outOptions->mOutput = fopen(current->mValue, "a");
if(NULL == outOptions->mOutput)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
}
else
{
outOptions->mOutputName = strdup(current->mValue);
if(NULL == outOptions->mOutputName)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
}
}
}
else if(current == &gHelpSwitch)
{
outOptions->mHelp = __LINE__;
}
else if(current == &gModuleSwitch)
{
outOptions->mModules = __LINE__;
}
else if(current == &gTotalSwitch)
{
outOptions->mTotalOnly = __LINE__;
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, current->mLongName, "No hanlder for command line switch.");
}
}
}
return retval;
}
void cleanOptions(Options* inOptions)
/*
** Clean up any open handles.
*/
{
CLEANUP(inOptions->mInputName);
if(NULL != inOptions->mInput && stdin != inOptions->mInput)
{
fclose(inOptions->mInput);
}
CLEANUP(inOptions->mOutputName);
if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
{
fclose(inOptions->mOutput);
}
memset(inOptions, 0, sizeof(Options));
}
void showHelp(Options* inOptions)
/*
** Show some simple help text on usage.
*/
{
int loop = 0;
const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
const char* valueText = NULL;
printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
printf("\n");
printf("arguments:\n");
for(loop = 0; loop < switchCount; loop++)
{
if(gSwitches[loop]->mHasValue)
{
valueText = " <value>";
}
else
{
valueText = "";
}
printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
}
}
int main(int inArgc, char** inArgv)
{
int retval = 0;
Options options;
retval = initOptions(&options, inArgc, inArgv);
if(options.mHelp)
{
showHelp(&options);
}
else if(0 == retval)
{
retval = codesighs(&options);
}
cleanOptions(&options);
return retval;
}

View File

@ -0,0 +1,981 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#define ERROR_REPORT(num, val, msg) fprintf(stderr, "error(%d):\t\"%s\"\t%s\n", (num), (val), (msg));
#define CLEANUP(ptr) do { if(NULL != ptr) { free(ptr); ptr = NULL; } } while(0)
typedef struct __struct_Options
/*
** Options to control how we perform.
**
** mProgramName Used in help text.
** mInput File to read for input.
** Default is stdin.
** mInputName Name of the file.
** mOutput Output file, append.
** Default is stdout.
** mOutputName Name of the file.
** mHelp Wether or not help should be shown.
** mTotalOnly Only output a signle digit.
** mZeroDrift Output zero drift data.
*/
{
const char* mProgramName;
FILE* mInput;
char* mInputName;
FILE* mOutput;
char* mOutputName;
int mHelp;
int mTotalOnly;
int mZeroDrift;
}
Options;
typedef struct __struct_Switch
/*
** Command line options.
*/
{
const char* mLongName;
const char* mShortName;
int mHasValue;
const char* mValue;
const char* mDescription;
}
Switch;
#define DESC_NEWLINE "\n\t\t"
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 gTotalSwitch = {"--totalonly", "-t", 0, NULL, "Only output a single number." DESC_NEWLINE "The cumulative size change." DESC_NEWLINE "Overrides all other output options."};
static Switch gZeroDriftSwitch = {"--zerodrift", "-z", 0, NULL, "Output zero drift data." DESC_NEWLINE "Zero drift data includes all changes, even if they cancel out."};
static Switch gHelpSwitch = {"--help", "-h", 0, NULL, "Information on usage."};
static Switch* gSwitches[] = {
&gInputSwitch,
&gOutputSwitch,
&gTotalSwitch,
&gZeroDriftSwitch,
&gHelpSwitch
};
typedef struct __struct_SizeStats
/*
** Keep track of sizes.
** Use signed integers so that negatives are valid, in which case we shrunk.
*/
{
int mCode;
int mData;
}
SizeStats;
typedef enum __enum_SegmentClass
/*
** What type of data a segment holds.
*/
{
CODE,
DATA
}
SegmentClass;
typedef struct __struct_SymbolStats
/*
** Symbol level stats.
*/
{
char* mSymbol;
int mSize;
}
SymbolStats;
typedef struct __struct_ObjectStats
/*
** Object level stats.
*/
{
char* mObject;
int mSize;
SymbolStats* mSymbols;
unsigned mSymbolCount;
}
ObjectStats;
typedef struct __struct_SegmentStats
/*
** Segment level stats.
*/
{
char* mSegment;
SegmentClass mClass;
int mSize;
ObjectStats* mObjects;
unsigned mObjectCount;
}
SegmentStats;
typedef struct __struct_ModuleStats
/*
** Module level stats.
*/
{
char* mModule;
SizeStats mSize;
SegmentStats* mSegments;
unsigned mSegmentCount;
}
ModuleStats;
static int moduleCompare(const void* in1, const void* in2)
/*
** qsort helper.
*/
{
int retval = 0;
ModuleStats* one = (ModuleStats*)in1;
ModuleStats* two = (ModuleStats*)in2;
int oneSize = (one->mSize.mCode + one->mSize.mData);
int twoSize = (two->mSize.mCode + two->mSize.mData);
if(oneSize < twoSize)
{
retval = 1;
}
else if(oneSize > twoSize)
{
retval = -1;
}
return retval;
}
static int segmentCompare(const void* in1, const void* in2)
/*
** qsort helper.
*/
{
int retval = 0;
SegmentStats* one = (SegmentStats*)in1;
SegmentStats* two = (SegmentStats*)in2;
if(one->mSize < two->mSize)
{
retval = 1;
}
else if(one->mSize > two->mSize)
{
retval = -1;
}
return retval;
}
static int objectCompare(const void* in1, const void* in2)
/*
** qsort helper.
*/
{
int retval = 0;
ObjectStats* one = (ObjectStats*)in1;
ObjectStats* two = (ObjectStats*)in2;
if(one->mSize < two->mSize)
{
retval = 1;
}
else if(one->mSize > two->mSize)
{
retval = -1;
}
return retval;
}
static int symbolCompare(const void* in1, const void* in2)
/*
** qsort helper.
*/
{
int retval = 0;
SymbolStats* one = (SymbolStats*)in1;
SymbolStats* two = (SymbolStats*)in2;
if(one->mSize < two->mSize)
{
retval = 1;
}
else if(one->mSize > two->mSize)
{
retval = -1;
}
return retval;
}
int difftool(Options* inOptions)
/*
** Read a diff file and spit out relevant information.
*/
{
int retval = 0;
char lineBuffer[0x500];
SizeStats overall;
ModuleStats* modules = NULL;
unsigned moduleCount = 0;
unsigned moduleLoop = 0;
ModuleStats* theModule = NULL;
unsigned segmentLoop = 0;
SegmentStats* theSegment = NULL;
unsigned objectLoop = 0;
ObjectStats* theObject = NULL;
unsigned symbolLoop = 0;
SymbolStats* theSymbol = NULL;
memset(&overall, 0, sizeof(overall));
/*
** Read the entire diff file.
** We're only interested in lines beginning with < or >
*/
while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
{
if(('<' == lineBuffer[0] || '>' == lineBuffer[0]) && ' ' == lineBuffer[1])
{
int additive = 0;
char* theLine = &lineBuffer[2];
int scanRes = 0;
int size;
char segClass[0x10];
char scope[0x10];
char module[0x100];
char segment[0x40];
char object[0x100];
char symbol[0x200];
/*
** Figure out if the line adds or subtracts from something.
*/
if('>' == lineBuffer[0])
{
additive = __LINE__;
}
/*
** Scan the line for information.
*/
scanRes = sscanf(theLine,
"%x\t%s\t%s\t%s\t%s\t%s\t%s",
&size,
segClass,
scope,
module,
segment,
object,
symbol);
if(7 == scanRes)
{
SegmentClass segmentClass = DATA;
if(0 == strcmp(segClass, "CODE"))
{
segmentClass = CODE;
}
else if(0 == strcmp(segClass, "DATA"))
{
segmentClass = DATA;
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, segClass, "Unable to determine segment class.");
}
if(0 == retval)
{
/*
** Update our overall totals.
*/
if(CODE == segmentClass)
{
if(additive)
{
overall.mCode += size;
}
else
{
overall.mCode -= size;
}
}
else
{
if(additive)
{
overall.mData += size;
}
else
{
overall.mData -= size;
}
}
/*
** Anything else to track?
*/
if(0 == inOptions->mTotalOnly)
{
unsigned moduleIndex = 0;
/*
** Find, in succession, the following things:
** the module
** the segment
** the object
** the symbol
** Failure to find any one of these means to create it.
*/
for(moduleIndex = 0; moduleIndex < moduleCount; moduleIndex++)
{
if(0 == strcmp(modules[moduleIndex].mModule, module))
{
break;
}
}
if(moduleIndex == moduleCount)
{
void* moved = NULL;
moved = realloc(modules, sizeof(ModuleStats) * (1 + moduleCount));
if(NULL != moved)
{
modules = (ModuleStats*)moved;
moduleCount++;
memset(modules + moduleIndex, 0, sizeof(ModuleStats));
modules[moduleIndex].mModule = strdup(module);
if(NULL == modules[moduleIndex].mModule)
{
retval = __LINE__;
ERROR_REPORT(retval, module, "Unable to duplicate string.");
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase module array.");
}
}
if(0 == retval)
{
unsigned segmentIndex = 0;
ModuleStats* theModule = (modules + moduleIndex);
if(CODE == segmentClass)
{
if(additive)
{
modules[moduleIndex].mSize.mCode += size;
}
else
{
modules[moduleIndex].mSize.mCode -= size;
}
}
else
{
if(additive)
{
modules[moduleIndex].mSize.mData += size;
}
else
{
modules[moduleIndex].mSize.mData -= size;
}
}
for(segmentIndex = 0; segmentIndex < theModule->mSegmentCount; segmentIndex++)
{
if(0 == strcmp(segment, theModule->mSegments[segmentIndex].mSegment))
{
break;
}
}
if(segmentIndex == theModule->mSegmentCount)
{
void* moved = NULL;
moved = realloc(theModule->mSegments, sizeof(SegmentStats) * (theModule->mSegmentCount + 1));
if(NULL != moved)
{
theModule->mSegments = (SegmentStats*)moved;
theModule->mSegmentCount++;
memset(theModule->mSegments + segmentIndex, 0, sizeof(SegmentStats));
theModule->mSegments[segmentIndex].mClass = segmentClass;
theModule->mSegments[segmentIndex].mSegment = strdup(segment);
if(NULL == theModule->mSegments[segmentIndex].mSegment)
{
retval = __LINE__;
ERROR_REPORT(retval, segment, "Unable to duplicate string.");
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase segment array.");
}
}
if(0 == retval)
{
unsigned objectIndex = 0;
SegmentStats* theSegment = (theModule->mSegments + segmentIndex);
if(additive)
{
theSegment->mSize += size;
}
else
{
theSegment->mSize -= size;
}
for(objectIndex = 0; objectIndex < theSegment->mObjectCount; objectIndex++)
{
if(0 == strcmp(object, theSegment->mObjects[objectIndex].mObject))
{
break;
}
}
if(objectIndex == theSegment->mObjectCount)
{
void* moved = NULL;
moved = realloc(theSegment->mObjects, sizeof(ObjectStats) * (1 + theSegment->mObjectCount));
if(NULL != moved)
{
theSegment->mObjects = (ObjectStats*)moved;
theSegment->mObjectCount++;
memset(theSegment->mObjects + objectIndex, 0, sizeof(ObjectStats));
theSegment->mObjects[objectIndex].mObject = strdup(object);
if(NULL == theSegment->mObjects[objectIndex].mObject)
{
retval = __LINE__;
ERROR_REPORT(retval, object, "Unable to duplicate string.");
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase object array.");
}
}
if(0 == retval)
{
unsigned symbolIndex = 0;
ObjectStats* theObject = (theSegment->mObjects + objectIndex);
if(additive)
{
theObject->mSize += size;
}
else
{
theObject->mSize -= size;
}
for(symbolIndex = 0; symbolIndex < theObject->mSymbolCount; symbolIndex++)
{
if(0 == strcmp(symbol, theObject->mSymbols[symbolIndex].mSymbol))
{
break;
}
}
if(symbolIndex == theObject->mSymbolCount)
{
void* moved = NULL;
moved = realloc(theObject->mSymbols, sizeof(SymbolStats) * (1 + theObject->mSymbolCount));
if(NULL != moved)
{
theObject->mSymbols = (SymbolStats*)moved;
theObject->mSymbolCount++;
memset(theObject->mSymbols + symbolIndex, 0, sizeof(SymbolStats));
theObject->mSymbols[symbolIndex].mSymbol = strdup(symbol);
if(NULL == theObject->mSymbols[symbolIndex].mSymbol)
{
retval = __LINE__;
ERROR_REPORT(retval, symbol, "Unable to duplicate string.");
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mProgramName, "Unable to increase symbol array.");
}
}
if(0 == retval)
{
SymbolStats* theSymbol = (theObject->mSymbols + symbolIndex);
if(additive)
{
theSymbol->mSize += size;
}
else
{
theSymbol->mSize -= size;
}
}
}
}
}
}
}
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mInputName, "Unable to scan line data.");
}
}
}
if(0 == retval && 0 != ferror(inOptions->mInput))
{
retval = __LINE__;
ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
}
/*
** If all went well, time to report.
*/
if(0 == retval)
{
if(inOptions->mTotalOnly)
{
fprintf(inOptions->mOutput, "%+d\n", overall.mCode + overall.mData);
}
else
{
fprintf(inOptions->mOutput, "Overall Change in Size\n");
fprintf(inOptions->mOutput, "\tTotal:\t%+11d\n", overall.mCode + overall.mData);
fprintf(inOptions->mOutput, "\tCode:\t%+11d\n", overall.mCode);
fprintf(inOptions->mOutput, "\tData:\t%+11d\n", overall.mData);
}
/*
** Check what else we should output.
*/
if(NULL != modules && moduleCount)
{
const char* segmentType = NULL;
/*
** We're going to sort everything.
*/
qsort(modules, moduleCount, sizeof(ModuleStats), moduleCompare);
for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
{
theModule = modules + moduleLoop;
qsort(theModule->mSegments, theModule->mSegmentCount, sizeof(SegmentStats), segmentCompare);
for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
{
theSegment = theModule->mSegments + segmentLoop;
qsort(theSegment->mObjects, theSegment->mObjectCount, sizeof(ObjectStats), objectCompare);
for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
{
theObject = theSegment->mObjects + objectLoop;
qsort(theObject->mSymbols, theObject->mSymbolCount, sizeof(SymbolStats), symbolCompare);
}
}
}
/*
** Loop through for output.
*/
for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
{
theModule = modules + moduleLoop;
/*
** Skip if there is zero drift, or no net change.
*/
if(0 == inOptions->mZeroDrift && 0 == (theModule->mSize.mCode + theModule->mSize.mCode ))
{
continue;
}
fprintf(inOptions->mOutput, "\n");
fprintf(inOptions->mOutput, "%s\n", theModule->mModule);
fprintf(inOptions->mOutput, "\tTotal:\t%+11d\n", theModule->mSize.mCode + theModule->mSize.mData);
fprintf(inOptions->mOutput, "\tCode:\t%+11d\n", theModule->mSize.mCode);
fprintf(inOptions->mOutput, "\tData:\t%+11d\n", theModule->mSize.mData);
for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
{
theSegment = theModule->mSegments + segmentLoop;
/*
** Skip if there is zero drift, or no net change.
*/
if(0 == inOptions->mZeroDrift && 0 == theSegment->mSize)
{
continue;
}
if(CODE == theSegment->mClass)
{
segmentType = "CODE";
}
else if(DATA == theSegment->mClass)
{
segmentType = "DATA";
}
fprintf(inOptions->mOutput, "\t%+11d\t%s (%s)\n", theSegment->mSize, theSegment->mSegment, segmentType);
for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
{
theObject = theSegment->mObjects + objectLoop;
/*
** Skip if there is zero drift, or no net change.
*/
if(0 == inOptions->mZeroDrift && 0 == theObject->mSize)
{
continue;
}
fprintf(inOptions->mOutput, "\t\t%+11d\t%s\n", theObject->mSize, theObject->mObject);
for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
{
theSymbol = theObject->mSymbols + symbolLoop;
/*
** Skip if there is zero drift, or no net change.
*/
if(0 == inOptions->mZeroDrift && 0 == theSymbol->mSize)
{
continue;
}
fprintf(inOptions->mOutput, "\t\t\t%+11d\t%s\n", theSymbol->mSize, theSymbol->mSymbol);
}
}
}
}
}
}
/*
** Cleanup time.
*/
for(moduleLoop = 0; moduleLoop < moduleCount; moduleLoop++)
{
theModule = modules + moduleLoop;
for(segmentLoop = 0; segmentLoop < theModule->mSegmentCount; segmentLoop++)
{
theSegment = theModule->mSegments + segmentLoop;
for(objectLoop = 0; objectLoop < theSegment->mObjectCount; objectLoop++)
{
theObject = theSegment->mObjects + objectLoop;
for(symbolLoop = 0; symbolLoop < theObject->mSymbolCount; symbolLoop++)
{
theSymbol = theObject->mSymbols + symbolLoop;
CLEANUP(theSymbol->mSymbol);
}
CLEANUP(theObject->mSymbols);
CLEANUP(theObject->mObject);
}
CLEANUP(theSegment->mObjects);
CLEANUP(theSegment->mSegment);
}
CLEANUP(theModule->mSegments);
CLEANUP(theModule->mModule);
}
CLEANUP(modules);
return retval;
}
int initOptions(Options* outOptions, int inArgc, char** inArgv)
/*
** returns int 0 if successful.
*/
{
int retval = 0;
int loop = 0;
int switchLoop = 0;
int match = 0;
const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
Switch* current = NULL;
/*
** Set any defaults.
*/
memset(outOptions, 0, sizeof(Options));
outOptions->mProgramName = inArgv[0];
outOptions->mInput = stdin;
outOptions->mInputName = strdup("stdin");
outOptions->mOutput = stdout;
outOptions->mOutputName = strdup("stdout");
if(NULL == outOptions->mOutputName || NULL == outOptions->mInputName)
{
retval = __LINE__;
ERROR_REPORT(retval, "stdin/stdout", "Unable to strdup.");
}
/*
** Go through and attempt to do the right thing.
*/
for(loop = 1; loop < inArgc && 0 == retval; loop++)
{
match = 0;
current = NULL;
for(switchLoop = 0; switchLoop < switchCount && 0 == retval; switchLoop++)
{
if(0 == strcmp(gSwitches[switchLoop]->mLongName, inArgv[loop]))
{
match = __LINE__;
}
else if(0 == strcmp(gSwitches[switchLoop]->mShortName, inArgv[loop]))
{
match = __LINE__;
}
if(match)
{
if(gSwitches[switchLoop]->mHasValue)
{
/*
** Attempt to absorb next option to fullfill value.
*/
if(loop + 1 < inArgc)
{
loop++;
current = gSwitches[switchLoop];
current->mValue = inArgv[loop];
}
}
else
{
current = gSwitches[switchLoop];
}
break;
}
}
if(0 == match)
{
outOptions->mHelp = __LINE__;
retval = __LINE__;
ERROR_REPORT(retval, inArgv[loop], "Unknown command line switch.");
}
else if(NULL == current)
{
outOptions->mHelp = __LINE__;
retval = __LINE__;
ERROR_REPORT(retval, inArgv[loop], "Command line switch requires a value.");
}
else
{
/*
** Do something based on address/swtich.
*/
if(current == &gInputSwitch)
{
CLEANUP(outOptions->mInputName);
if(NULL != outOptions->mInput && stdin != outOptions->mInput)
{
fclose(outOptions->mInput);
outOptions->mInput = NULL;
}
outOptions->mInput = fopen(current->mValue, "r");
if(NULL == outOptions->mInput)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to open input file.");
}
else
{
outOptions->mInputName = strdup(current->mValue);
if(NULL == outOptions->mInputName)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
}
}
}
else if(current == &gOutputSwitch)
{
CLEANUP(outOptions->mOutputName);
if(NULL != outOptions->mOutput && stdout != outOptions->mOutput)
{
fclose(outOptions->mOutput);
outOptions->mOutput = NULL;
}
outOptions->mOutput = fopen(current->mValue, "a");
if(NULL == outOptions->mOutput)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to open output file.");
}
else
{
outOptions->mOutputName = strdup(current->mValue);
if(NULL == outOptions->mOutputName)
{
retval = __LINE__;
ERROR_REPORT(retval, current->mValue, "Unable to strdup.");
}
}
}
else if(current == &gHelpSwitch)
{
outOptions->mHelp = __LINE__;
}
else if(current == &gTotalSwitch)
{
outOptions->mTotalOnly = __LINE__;
}
else if(current == &gZeroDriftSwitch)
{
outOptions->mZeroDrift = __LINE__;
}
else
{
retval = __LINE__;
ERROR_REPORT(retval, current->mLongName, "No hanlder for command line switch.");
}
}
}
return retval;
}
void cleanOptions(Options* inOptions)
/*
** Clean up any open handles.
*/
{
CLEANUP(inOptions->mInputName);
if(NULL != inOptions->mInput && stdin != inOptions->mInput)
{
fclose(inOptions->mInput);
}
CLEANUP(inOptions->mOutputName);
if(NULL != inOptions->mOutput && stdout != inOptions->mOutput)
{
fclose(inOptions->mOutput);
}
memset(inOptions, 0, sizeof(Options));
}
void showHelp(Options* inOptions)
/*
** Show some simple help text on usage.
*/
{
int loop = 0;
const int switchCount = sizeof(gSwitches) / sizeof(gSwitches[0]);
const char* valueText = NULL;
printf("usage:\t%s [arguments]\n", inOptions->mProgramName);
printf("\n");
printf("arguments:\n");
for(loop = 0; loop < switchCount; loop++)
{
if(gSwitches[loop]->mHasValue)
{
valueText = " <value>";
}
else
{
valueText = "";
}
printf("\t%s%s\n", gSwitches[loop]->mLongName, valueText);
printf("\t %s%s", gSwitches[loop]->mShortName, valueText);
printf(DESC_NEWLINE "%s\n\n", gSwitches[loop]->mDescription);
}
}
int main(int inArgc, char** inArgv)
{
int retval = 0;
Options options;
retval = initOptions(&options, inArgc, inArgv);
if(options.mHelp)
{
showHelp(&options);
}
else if(0 == retval)
{
retval = difftool(&options);
}
cleanOptions(&options);
return retval;
}

106
tools/codesighs/msmap.h Normal file
View File

@ -0,0 +1,106 @@
#if !defined __msmap_H
#define __msmap_H
#if defined(__cplusplus)
extern "C" {
#endif
#if 0
}
#endif
/*
** Used to numerically represent addresses.
*/
typedef unsigned long address;
typedef enum __enum_MSMap_SymbolScope
/*
** Symbol scope.
*/
{
PUBLIC,
STATIC,
UNDEFINED
}
MSMap_SymbolScope;
typedef struct __struct_MSMap_Symbol
/*
** Information about a symbol.
*/
{
address mPrefix;
address mOffset;
char* mSymbol;
address mRVABase;
char* mObject;
MSMap_SymbolScope mScope;
}
MSMap_Symbol;
typedef enum __enum_MSMap_SegmentClass
/*
** Segment class.
*/
{
CODE,
DATA
}
MSMap_SegmentClass;
typedef struct __struct_MSMap_Segment
/*
** Information about a segment.
*/
{
address mPrefix;
address mOffset;
address mLength;
char* mSegment;
MSMap_SegmentClass mClass;
}
MSMap_Segment;
typedef struct __struct_MSMap_Module
/*
** Top level container of the map data.
*/
{
char* mModule;
time_t mTimestamp;
address mPreferredLoadAddress;
MSMap_Segment* mSegments;
unsigned mSegmentCount;
unsigned mSegmentCapacity;
address mEntryPrefix;
address mEntryOffset;
MSMap_Symbol* mSymbols;
unsigned mSymbolCount;
unsigned mSymbolCapacity;
}
MSMap_Module;
/*
** How much to grow our arrays by.
*/
#define MSMAP_SEGMENT_GROWBY 0x10
#define MSMAP_SYMBOL_GROWBY 0x100
#if 0
{
#endif
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif /* __msmap_H */

1107
tools/codesighs/msmap2tsv.c Normal file

File diff suppressed because it is too large Load Diff