зеркало из https://github.com/mozilla/pjs.git
not part of build
Enable usage of codesighs on linux.
This commit is contained in:
Родитель
b0e0f669e8
Коммит
a836ea1d3d
|
@ -31,8 +31,9 @@ REQUIRES = $(NULL)
|
|||
|
||||
SIMPLECSRCS += \
|
||||
msmap2tsv.c \
|
||||
nm2tsv.c \
|
||||
codesighs.c \
|
||||
maptsvdifftool.c \
|
||||
maptsvdifftool.c \
|
||||
$(NULL)
|
||||
|
||||
SIMPLE_PROGRAMS = $(SIMPLECSRCS:.c=$(BIN_SUFFIX))
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla 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/MPL/
|
||||
#
|
||||
# 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 autosummary.linx.bash code, released
|
||||
# Oct 10, 2002.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Netscape
|
||||
# Communications Corporation. Portions created by Netscape are
|
||||
# Copyright (C) 2002 Netscape Communications Corporation. All
|
||||
# Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Garrett Arch Blythe, 10-October-2002
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the
|
||||
# terms of the GNU Public License (the "GPL"), in which case the
|
||||
# provisions of the GPL are applicable instead of those above.
|
||||
# If you wish to allow use of your version of this file only
|
||||
# under the terms of the GPL and not to allow others to use your
|
||||
# version of this file under the MPL, indicate your decision by
|
||||
# deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this
|
||||
# file under either the MPL or the GPL.
|
||||
#
|
||||
|
||||
#
|
||||
# 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 on size drifts refer to the summary report."
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# Exclude certain path patterns.
|
||||
# Be sure to modify the grep command below as well.
|
||||
#
|
||||
EXCLUDE_PATTERN_01="test"
|
||||
|
||||
|
||||
#
|
||||
# Stash our arguments away.
|
||||
#
|
||||
COPYSORTTSV="$1"
|
||||
OLDTSVFILE="$2"
|
||||
SUMMARYFILE="$3"
|
||||
|
||||
|
||||
#
|
||||
# Create our temporary directory.
|
||||
#
|
||||
TMPDIR="/tmp/codesighs.$PPID"
|
||||
mkdir -p $TMPDIR
|
||||
|
||||
|
||||
#
|
||||
# Find all relevant files.
|
||||
#
|
||||
ALLFILES="$TMPDIR/allfiles.list"
|
||||
find ./mozilla/dist/bin -not -type d > $ALLFILES
|
||||
|
||||
|
||||
#
|
||||
# Reduce the files to a revelant set.
|
||||
#
|
||||
THEFILES="$TMPDIR/files.list"
|
||||
grep -vi $EXCLUDE_PATTERN_01 < $ALLFILES > $THEFILES
|
||||
|
||||
|
||||
#
|
||||
# Produce the cumulative nm output.
|
||||
# We are very particular on what switches to use.
|
||||
# nm --format=bsd --size-sort --print-file-name
|
||||
#
|
||||
NMRESULTS="$TMPDIR/nm.txt"
|
||||
xargs -n 1 nm --format=bsd --size-sort --print-file-name < $THEFILES > $NMRESULTS 2> /dev/null
|
||||
|
||||
|
||||
#
|
||||
# Produce the TSV output.
|
||||
#
|
||||
RAWTSVFILE="$TMPDIR/raw.tsv"
|
||||
./mozilla/dist/bin/nm2tsv --input $NMRESULTS > $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
|
|
@ -161,6 +161,29 @@ static int moduleCompare(const void* in1, const void* in2)
|
|||
}
|
||||
|
||||
|
||||
void trimWhite(char* inString)
|
||||
/*
|
||||
** Remove any whitespace from the end of the string.
|
||||
*/
|
||||
{
|
||||
int len = strlen(inString);
|
||||
|
||||
while(len)
|
||||
{
|
||||
len--;
|
||||
|
||||
if(isspace(*(inString + len)))
|
||||
{
|
||||
*(inString + len) = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int codesighs(Options* inOptions)
|
||||
/*
|
||||
** Output a simplistic report based on our options.
|
||||
|
@ -175,7 +198,7 @@ int codesighs(Options* inOptions)
|
|||
char module[0x100];
|
||||
char segment[0x40];
|
||||
char object[0x100];
|
||||
char symbol[0x200];
|
||||
char* symbol;
|
||||
SizeStats overall;
|
||||
ModuleStats* modules = NULL;
|
||||
unsigned moduleCount = 0;
|
||||
|
@ -189,20 +212,23 @@ int codesighs(Options* inOptions)
|
|||
*/
|
||||
while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
|
||||
{
|
||||
trimWhite(lineBuffer);
|
||||
|
||||
scanRes = sscanf(lineBuffer,
|
||||
"%x\t%s\t%s\t%s\t%s\t%s\t%s",
|
||||
&size,
|
||||
"%x\t%s\t%s\t%s\t%s\t%s\t",
|
||||
(unsigned*)&size,
|
||||
segClass,
|
||||
scope,
|
||||
module,
|
||||
segment,
|
||||
object,
|
||||
symbol);
|
||||
object);
|
||||
|
||||
if(7 == scanRes)
|
||||
if(6 == scanRes)
|
||||
{
|
||||
SegmentClass segmentClass = CODE;
|
||||
|
||||
symbol = strchr(lineBuffer, '\t') + 1;
|
||||
|
||||
if(0 == strcmp(segClass, "DATA"))
|
||||
{
|
||||
segmentClass = DATA;
|
||||
|
@ -315,14 +341,14 @@ int codesighs(Options* inOptions)
|
|||
{
|
||||
if(inOptions->mTotalOnly)
|
||||
{
|
||||
fprintf(inOptions->mOutput, "%u\n", overall.mCode + overall.mData);
|
||||
fprintf(inOptions->mOutput, "%u\n", (unsigned)(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);
|
||||
fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(overall.mCode + overall.mData));
|
||||
fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)overall.mCode);
|
||||
fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)overall.mData);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -345,9 +371,9 @@ int codesighs(Options* inOptions)
|
|||
{
|
||||
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);
|
||||
fprintf(inOptions->mOutput, "\tTotal:\t%10u\n", (unsigned)(modules[loop].mSize.mCode + modules[loop].mSize.mData));
|
||||
fprintf(inOptions->mOutput, "\tCode:\t%10u\n", (unsigned)modules[loop].mSize.mCode);
|
||||
fprintf(inOptions->mOutput, "\tData:\t%10u\n", (unsigned)modules[loop].mSize.mData);
|
||||
|
||||
CLEANUP(modules[loop].mModule);
|
||||
}
|
||||
|
|
|
@ -270,6 +270,29 @@ static int symbolCompare(const void* in1, const void* in2)
|
|||
}
|
||||
|
||||
|
||||
void trimWhite(char* inString)
|
||||
/*
|
||||
** Remove any whitespace from the end of the string.
|
||||
*/
|
||||
{
|
||||
int len = strlen(inString);
|
||||
|
||||
while(len)
|
||||
{
|
||||
len--;
|
||||
|
||||
if(isspace(*(inString + len)))
|
||||
{
|
||||
*(inString + len) = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int difftool(Options* inOptions)
|
||||
/*
|
||||
** Read a diff file and spit out relevant information.
|
||||
|
@ -297,6 +320,8 @@ int difftool(Options* inOptions)
|
|||
*/
|
||||
while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
|
||||
{
|
||||
trimWhite(lineBuffer);
|
||||
|
||||
if(('<' == lineBuffer[0] || '>' == lineBuffer[0]) && ' ' == lineBuffer[1])
|
||||
{
|
||||
int additive = 0;
|
||||
|
@ -308,7 +333,7 @@ int difftool(Options* inOptions)
|
|||
char module[0x100];
|
||||
char segment[0x40];
|
||||
char object[0x100];
|
||||
char symbol[0x200];
|
||||
char* symbol = NULL;
|
||||
|
||||
/*
|
||||
** Figure out if the line adds or subtracts from something.
|
||||
|
@ -323,19 +348,20 @@ int difftool(Options* inOptions)
|
|||
** Scan the line for information.
|
||||
*/
|
||||
scanRes = sscanf(theLine,
|
||||
"%x\t%s\t%s\t%s\t%s\t%s\t%s",
|
||||
&size,
|
||||
"%x\t%s\t%s\t%s\t%s\t%s\t",
|
||||
(unsigned*)&size,
|
||||
segClass,
|
||||
scope,
|
||||
module,
|
||||
segment,
|
||||
object,
|
||||
symbol);
|
||||
object);
|
||||
|
||||
if(7 == scanRes)
|
||||
if(6 == scanRes)
|
||||
{
|
||||
SegmentClass segmentClass = DATA;
|
||||
|
||||
symbol = strrchr(theLine, '\t') + 1;
|
||||
|
||||
if(0 == strcmp(segClass, "CODE"))
|
||||
{
|
||||
segmentClass = CODE;
|
||||
|
|
|
@ -274,7 +274,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule)
|
|||
memset(theSymbol, 0, sizeof(MSMap_Symbol));
|
||||
theSymbol->mScope = STATIC;
|
||||
|
||||
scanRes = sscanf(current, "%x:%x %s %x", &(theSymbol->mPrefix), &(theSymbol->mOffset), symbolBuf, &(theSymbol->mRVABase));
|
||||
scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned*)&(theSymbol->mRVABase));
|
||||
if(4 == scanRes)
|
||||
{
|
||||
theSymbol->mSymbol = strdup(symbolBuf);
|
||||
|
@ -335,7 +335,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule)
|
|||
{
|
||||
int scanRes = 0;
|
||||
|
||||
scanRes = sscanf(current, "entry point at %x:%x", &(inModule->mEntryPrefix), &(inModule->mEntryOffset));
|
||||
scanRes = sscanf(current, "entry point at %x:%x", (unsigned*)&(inModule->mEntryPrefix), (unsigned*)&(inModule->mEntryOffset));
|
||||
if(2 == scanRes)
|
||||
{
|
||||
fsm.mHasEntryPoint = __LINE__;
|
||||
|
@ -395,7 +395,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule)
|
|||
memset(theSymbol, 0, sizeof(MSMap_Symbol));
|
||||
theSymbol->mScope = PUBLIC;
|
||||
|
||||
scanRes = sscanf(current, "%x:%x %s %x", &(theSymbol->mPrefix), &(theSymbol->mOffset), symbolBuf, &(theSymbol->mRVABase));
|
||||
scanRes = sscanf(current, "%x:%x %s %x", (unsigned*)&(theSymbol->mPrefix), (unsigned*)&(theSymbol->mOffset), symbolBuf, (unsigned *)&(theSymbol->mRVABase));
|
||||
if(4 == scanRes)
|
||||
{
|
||||
theSymbol->mSymbol = strdup(symbolBuf);
|
||||
|
@ -482,7 +482,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule)
|
|||
|
||||
memset(theSegment, 0, sizeof(MSMap_Segment));
|
||||
|
||||
scanRes = sscanf(current, "%x:%x %xH %s %s", &(theSegment->mPrefix), &(theSegment->mOffset), &(theSegment->mLength), nameBuf, classBuf);
|
||||
scanRes = sscanf(current, "%x:%x %xH %s %s", (unsigned*)&(theSegment->mPrefix), (unsigned*)&(theSegment->mOffset), (unsigned*)&(theSegment->mLength), nameBuf, classBuf);
|
||||
if(5 == scanRes)
|
||||
{
|
||||
if('.' == nameBuf[0])
|
||||
|
@ -541,7 +541,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule)
|
|||
/*
|
||||
** The PLA has a particular format.
|
||||
*/
|
||||
scanRes = sscanf(current, "Preferred load address is %x", &(inModule->mPreferredLoadAddress));
|
||||
scanRes = sscanf(current, "Preferred load address is %x", (unsigned*)&(inModule->mPreferredLoadAddress));
|
||||
if(1 == scanRes)
|
||||
{
|
||||
fsm.mHasPreferredLoadAddress = __LINE__;
|
||||
|
@ -561,7 +561,7 @@ int readmap(Options* inOptions, MSMap_Module* inModule)
|
|||
/*
|
||||
** The timestamp has a particular format.
|
||||
*/
|
||||
scanRes = sscanf(current, "Timestamp is %x", &(inModule->mTimestamp));
|
||||
scanRes = sscanf(current, "Timestamp is %x", (unsigned*)&(inModule->mTimestamp));
|
||||
if(1 == scanRes)
|
||||
{
|
||||
fsm.mHasTimestamp = __LINE__;
|
||||
|
@ -711,8 +711,8 @@ static int tsvout(Options* inOptions, unsigned inSize, MSMap_SegmentClass inClas
|
|||
{
|
||||
printRes = fprintf(inOptions->mOutput,
|
||||
"\t%.4X:%.8X",
|
||||
inPrefix,
|
||||
inOffset
|
||||
(unsigned)inPrefix,
|
||||
(unsigned)inOffset
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,496 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla 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/MPL/
|
||||
*
|
||||
* 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 nm2tsv.c code, released
|
||||
* Oct 10, 2002.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 2002 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Garrett Arch Blythe, 10-October-2002
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the MPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#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.
|
||||
*/
|
||||
{
|
||||
const char* mProgramName;
|
||||
FILE* mInput;
|
||||
char* mInputName;
|
||||
FILE* mOutput;
|
||||
char* mOutputName;
|
||||
int mHelp;
|
||||
}
|
||||
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* gSwitches[] = {
|
||||
&gInputSwitch,
|
||||
&gOutputSwitch,
|
||||
&gHelpSwitch
|
||||
};
|
||||
|
||||
|
||||
char* scanWhite(char* inScan)
|
||||
/*
|
||||
** Scan for whitespace.
|
||||
*/
|
||||
{
|
||||
char* retval = inScan;
|
||||
|
||||
while('\0' != *retval && 0 == isspace(*retval))
|
||||
{
|
||||
retval++;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void trimWhite(char* inString)
|
||||
/*
|
||||
** Remove any whitespace from the end of the string.
|
||||
*/
|
||||
{
|
||||
int len = strlen(inString);
|
||||
|
||||
while(len)
|
||||
{
|
||||
len--;
|
||||
|
||||
if(isspace(*(inString + len)))
|
||||
{
|
||||
*(inString + len) = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int nm2tsv(Options* inOptions)
|
||||
/*
|
||||
** Read all input.
|
||||
** Output tab seperated value data.
|
||||
**
|
||||
** We expect our data to be in a particular format.
|
||||
** nm --format=bsd --size-sort --print-file-name
|
||||
*/
|
||||
{
|
||||
int retval = 0;
|
||||
char lineBuffer[0x400];
|
||||
char* module = NULL;
|
||||
char* size = NULL;
|
||||
char* type = NULL;
|
||||
char* symbol = NULL;
|
||||
|
||||
/*
|
||||
** Read in the nm file.
|
||||
*/
|
||||
while(0 == retval && NULL != fgets(lineBuffer, sizeof(lineBuffer), inOptions->mInput))
|
||||
{
|
||||
trimWhite(lineBuffer);
|
||||
|
||||
/*
|
||||
** Find the various peices of information we'll be looking for.
|
||||
*/
|
||||
size = strchr(lineBuffer, ':');
|
||||
if(NULL != size)
|
||||
{
|
||||
*size = '\0';
|
||||
size++;
|
||||
|
||||
module = strrchr(lineBuffer, '/');
|
||||
if(NULL == module)
|
||||
{
|
||||
module = lineBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
*module = '\0';
|
||||
module++;
|
||||
}
|
||||
|
||||
type = scanWhite(size);
|
||||
*type = '\0';
|
||||
type++;
|
||||
|
||||
symbol = type + 1;
|
||||
*symbol = '\0';
|
||||
symbol++;
|
||||
|
||||
/*
|
||||
** Skip certain types.
|
||||
*/
|
||||
switch(*type)
|
||||
{
|
||||
case '-':
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Simply output the data with a little more interpretation.
|
||||
** First is size.
|
||||
*/
|
||||
fprintf(inOptions->mOutput, "%s\t", size);
|
||||
|
||||
/*
|
||||
** Type, CODE or DATA
|
||||
*/
|
||||
switch(toupper(*type))
|
||||
{
|
||||
case 'T': /* text (code) */
|
||||
case 'V': /* weak object */
|
||||
case 'W': /* weak symbol */
|
||||
fprintf(inOptions->mOutput, "CODE\t");
|
||||
break;
|
||||
default:
|
||||
fprintf(inOptions->mOutput, "DATA\t");
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Scope, PUBLIC, STATIC, or UNDEF
|
||||
*/
|
||||
if(islower(*type))
|
||||
{
|
||||
fprintf(inOptions->mOutput, "STATIC\t");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(*type)
|
||||
{
|
||||
case '?':
|
||||
fprintf(inOptions->mOutput, "UNDEF\t");
|
||||
break;
|
||||
default:
|
||||
fprintf(inOptions->mOutput, "PUBLIC\t");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Module name, segment.
|
||||
*/
|
||||
fprintf(inOptions->mOutput, "%s\t", module);
|
||||
fprintf(inOptions->mOutput, "%c\t", toupper(*type));
|
||||
|
||||
/*
|
||||
** Origin
|
||||
*/
|
||||
fprintf(inOptions->mOutput, "UNDEF:%s:%c\t", module, toupper(*type));
|
||||
|
||||
/*
|
||||
** Symbol is last.
|
||||
*/
|
||||
fprintf(inOptions->mOutput, "%s\n", symbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = __LINE__;
|
||||
ERROR_REPORT(retval, lineBuffer, "Malformed input line.");
|
||||
}
|
||||
}
|
||||
|
||||
if(0 == retval && 0 != ferror(inOptions->mInput))
|
||||
{
|
||||
retval = __LINE__;
|
||||
ERROR_REPORT(retval, inOptions->mInputName, "Unable to read file.");
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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 = nm2tsv(&options);
|
||||
}
|
||||
|
||||
cleanOptions(&options);
|
||||
return retval;
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче