mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
279 lines
8.1 KiB
279 lines
8.1 KiB
// This program updates the line number information in the symbol table of
|
|
// a COFF object based on a set of line number deltas specified in an input
|
|
// file.
|
|
// This program expects two arguments on the command line. The first is
|
|
// the name of the object file and the second is the name of the file containing
|
|
// the line number deltas. The format of this file is that it contains some
|
|
// number of lines of the following form:
|
|
// <source file name>,<first line number>,<delta>,<last line number>
|
|
// Note that if the source file name is not specified, then the last source
|
|
// file name seen will be used. Also, this program assumes that this input
|
|
// file will contain only one appearance of any give source file name.
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
// Data structure to hold a list of line number deltas for a particular
|
|
// source file.
|
|
typedef struct tagLINEDELTAS {
|
|
int begLine; // First line to which to apply the delta.
|
|
int lastLine; // Last line to which to apply the delta.
|
|
int delta; // The actual delta to use.
|
|
struct tagLINEDELTAS *next;
|
|
} LINEDELTAS;
|
|
|
|
// Data structure to hold line number deltas for a number of source files.
|
|
typedef struct tagDELTAS {
|
|
struct tagDELTAS *next;
|
|
char *fileName; // Name of file which the deltas apply to.
|
|
LINEDELTAS *lineDeltas; // List of line number deltas for the file.
|
|
} DELTAS;
|
|
|
|
// Function prototypes:
|
|
static DELTAS *ReadDeltas(char *);
|
|
static int PatchLineNumbers(char *, DELTAS *);
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
DELTAS *deltas;
|
|
|
|
if (argc != 3) {
|
|
printf("Usage: %s <object name> <line number deltas file name>",
|
|
argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
// Read in the line number deltas file and build up a data structure
|
|
// to store the information which it contains.
|
|
deltas = ReadDeltas(argv[2]);
|
|
|
|
if (deltas == NULL)
|
|
return 1;
|
|
|
|
// Update the line numbers in the COFF symbol table in the specified object
|
|
// according to the line number delta information.
|
|
return PatchLineNumbers(argv[1], deltas);
|
|
}
|
|
|
|
static DELTAS *
|
|
ReadDeltas(char *fileName)
|
|
{
|
|
FILE *fp;
|
|
char buf[_MAX_PATH * 2], *p;
|
|
int beg, delta, end, i;
|
|
DELTAS *deltas = NULL;
|
|
DELTAS *tmpDelta;
|
|
LINEDELTAS *tmpLine;
|
|
|
|
if ((fp = fopen(fileName, "r")) == NULL) {
|
|
printf("Unable to open %s for reading\n", fileName);
|
|
return NULL;
|
|
}
|
|
|
|
// Read in one set of line number delta information at a time.
|
|
while(fgets(buf, _MAX_PATH * 2, fp) != NULL) {
|
|
|
|
// Skip to the first comma.
|
|
for(i = 0, p = buf; *p != ','; p++, i++) {
|
|
if (*p == '\0') {
|
|
printf("Bad input string %s\n", buf);
|
|
return NULL;
|
|
}
|
|
}
|
|
p++; // Skip the comma.
|
|
|
|
// Extract the line number information.
|
|
sscanf(p, "%d,%d,%d", &beg, &delta, &end);
|
|
|
|
// Check to see if we got a new source file name or if we should
|
|
// use the previous one.
|
|
if (i != 0) {
|
|
|
|
// We have a new file name, so create a new file delta record
|
|
// and initialize it appropriately.
|
|
tmpDelta = (DELTAS *) malloc(sizeof(DELTAS));
|
|
tmpDelta->fileName = malloc(i + 1);
|
|
memcpy(tmpDelta->fileName, buf, i);
|
|
tmpDelta->fileName[i] = '\0';
|
|
tmpDelta->lineDeltas = NULL;
|
|
tmpDelta->next = deltas;
|
|
deltas = tmpDelta;
|
|
|
|
} else {
|
|
|
|
// We better already have a file delta record.
|
|
if (deltas == NULL) {
|
|
puts("Failed to get a source file name");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Allocate a new line number delta record and add it to the current
|
|
// file delta record.
|
|
tmpLine = (LINEDELTAS *) malloc(sizeof(LINEDELTAS));
|
|
tmpLine->begLine = beg;
|
|
tmpLine->lastLine = end;
|
|
tmpLine->delta = delta;
|
|
tmpLine->next = deltas->lineDeltas;
|
|
deltas->lineDeltas = tmpLine;
|
|
}
|
|
|
|
fclose(fp);
|
|
return deltas;
|
|
}
|
|
|
|
// Coff object specific defines:
|
|
#define SYMTAB_OFFSET_LOCATION 8 // offset in object of symtab location
|
|
#define IMAGE_SIZEOF_SYMBOL 18 // size of an entry in the COFF symbol table
|
|
#define IMAGE_SYM_CLASS_FILE 103 // storage class for a file name directive
|
|
#define IMAGE_SYM_CLASS_FUNCTION 101 // storage class for a line number record
|
|
|
|
static int
|
|
PatchLineNumbers(char *objName, DELTAS *deltas)
|
|
{
|
|
FILE *fp;
|
|
char headerBuff[8], *buf, *curr;
|
|
int symTabLoc, symTabEntries, symTabSize;
|
|
int i, lineNum;
|
|
char class, numAux, fileBuff[_MAX_PATH], *p;
|
|
DELTAS *currDelta = NULL;
|
|
LINEDELTAS *lines;
|
|
int changed = 0;
|
|
|
|
if ((fp = fopen(objName, "r+b")) == NULL) {
|
|
printf("Unable to open %s for reading and writing\n", objName);
|
|
return 1;
|
|
}
|
|
|
|
// Seek to the location containing the location of the symbol table.
|
|
if (fseek(fp, SYMTAB_OFFSET_LOCATION, SEEK_SET) != 0) {
|
|
puts("Failed to seek to the desired position in the object header");
|
|
return 1;
|
|
}
|
|
|
|
// Read in the symbol table location as well as the number of entries.
|
|
if (fread(headerBuff, 1, 8, fp) != 8) {
|
|
puts("Failed to read in necessary header info");
|
|
return 1;
|
|
}
|
|
symTabLoc = *((int *) headerBuff);
|
|
symTabEntries = *((int *) (headerBuff + 4));
|
|
|
|
// Seek to the location of the COFF symbol table.
|
|
if (fseek(fp, symTabLoc, SEEK_SET) != 0) {
|
|
puts("Failed to seek to the location of the COFF symbol table");
|
|
return 1;
|
|
}
|
|
|
|
// Allocate a buffer large enough to hold the entire COFF symbol table
|
|
// and read it in all at once.
|
|
symTabSize = symTabEntries * IMAGE_SIZEOF_SYMBOL;
|
|
buf = malloc(symTabSize);
|
|
if (fread(buf, 1, symTabSize, fp) != symTabSize) {
|
|
puts("Failed to read in COFF symbol table");
|
|
return 1;
|
|
}
|
|
|
|
// Examine one entry of the COFF symbol table at a time looking for
|
|
// file name directives and line number records while skipping over
|
|
// other records.
|
|
curr = buf;
|
|
for(i = 0; i < symTabEntries; curr += IMAGE_SIZEOF_SYMBOL, i++) {
|
|
|
|
// Get the storage class of this symbol and the number of auxiliary
|
|
// records which follow it.
|
|
class = *(curr + 16);
|
|
numAux = *(curr + 17);
|
|
|
|
// Check to see if this is a file name directive.
|
|
if (class == IMAGE_SYM_CLASS_FILE) {
|
|
if (numAux == 0) {
|
|
puts("Bogus COFF symbol record");
|
|
return 1;
|
|
}
|
|
|
|
// Read in the file name.
|
|
p = fileBuff;
|
|
while(numAux > 0) {
|
|
i++;
|
|
curr += IMAGE_SIZEOF_SYMBOL;
|
|
memcpy(p, curr, IMAGE_SIZEOF_SYMBOL);
|
|
p += IMAGE_SIZEOF_SYMBOL;
|
|
numAux--;
|
|
}
|
|
*p = '\0'; // Make sure the file name is null terminated.
|
|
|
|
// Check to see if this is a source file for which we have
|
|
// line number delta records.
|
|
for(currDelta = deltas; currDelta; currDelta = currDelta->next) {
|
|
if (strcmp(currDelta->fileName, fileBuff) == 0)
|
|
break;
|
|
}
|
|
|
|
// Otherwise, check to see if this is a line number record.
|
|
} else if (class == IMAGE_SYM_CLASS_FUNCTION) {
|
|
// Skip over .lf records.
|
|
if (numAux == 0)
|
|
continue;
|
|
if (numAux != 1) {
|
|
puts("Bogus COFF symbol record");
|
|
return 1;
|
|
}
|
|
i++;
|
|
curr += IMAGE_SIZEOF_SYMBOL;
|
|
|
|
// Examine the auxiliary symbol to see if the line number specified
|
|
// therein is in any range of line numbers which need to have
|
|
// deltas applied to them. Don't need to do anything if there are
|
|
// no deltas to be applied for the current source file name.
|
|
if (currDelta != NULL) {
|
|
|
|
// Extract the line number.
|
|
lineNum = (int) *((unsigned short *) (curr + 4));
|
|
|
|
// Search the list of line number ranges to see if the line
|
|
// number falls in between any of them.
|
|
for(lines = currDelta->lineDeltas; lines; lines = lines->next) {
|
|
if (lineNum >= lines->begLine && lineNum <= lines->lastLine)
|
|
break;
|
|
}
|
|
|
|
// If the line number does need a delta applied to it, then
|
|
// do so and store the result back in the buffer.
|
|
if (lines != NULL) {
|
|
lineNum += lines->delta;
|
|
*((unsigned short *) (curr + 4)) = (unsigned short) lineNum;
|
|
changed = 1; // Flag that the buffer has changed.
|
|
}
|
|
}
|
|
|
|
// Otherwise, just skip this symbol and its auxiliary records.
|
|
} else {
|
|
if (numAux != 0) {
|
|
if (numAux != 1) {
|
|
puts("Bogus COFF symbol record");
|
|
return 1;
|
|
}
|
|
i++;
|
|
curr += IMAGE_SIZEOF_SYMBOL;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the buffer has been modified, then we need to write it back out.
|
|
if (changed) {
|
|
// Seek to the location of the COFF symbol table.
|
|
if (fseek(fp, symTabLoc, SEEK_SET) != 0) {
|
|
puts("Failed to seek to the location of the COFF symbol table");
|
|
return 1;
|
|
}
|
|
if (fwrite(buf, 1, symTabSize, fp) != symTabSize) {
|
|
puts("Failed to write out updated version of COFF symbol table");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
return 0;
|
|
}
|