aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/mapfiles/map-file.ts40
-rw-r--r--lib/pe32-support.ts (renamed from lib/pe32-support.js)69
-rw-r--r--test/map-file-tests.js74
3 files changed, 94 insertions, 89 deletions
diff --git a/lib/mapfiles/map-file.ts b/lib/mapfiles/map-file.ts
index 6c7e97de0..adf05b6b3 100644
--- a/lib/mapfiles/map-file.ts
+++ b/lib/mapfiles/map-file.ts
@@ -33,7 +33,7 @@ type SegmentOffset = {
segmentLength: number;
};
-type Segment = {
+export type Segment = {
segment: string;
addressInt: number;
address: string;
@@ -103,7 +103,7 @@ export class MapFileReader {
}
}
- getLineInfoByAddress(segment: string | boolean, address: number) {
+ getLineInfoByAddress(segment: string | undefined, address: number): LineNumber | undefined {
for (let idx = 0; idx < this.lineNumbers.length; idx++) {
const lineInfo = this.lineNumbers[idx];
if (!segment && lineInfo.addressInt === address) {
@@ -113,7 +113,7 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
getSegmentOffset(segment: string): number {
@@ -157,7 +157,7 @@ export class MapFileReader {
});
}
- getSegmentInfoByUnitName(unitName: string) {
+ getSegmentInfoByUnitName(unitName: string): Segment | undefined {
for (let idx = 0; idx < this.segments.length; idx++) {
const info = this.segments[idx];
if (info.unitName === unitName) {
@@ -165,10 +165,10 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
- getICodeSegmentInfoByUnitName(unitName: string) {
+ getICodeSegmentInfoByUnitName(unitName: string): Segment | undefined {
for (let idx = 0; idx < this.isegments.length; idx++) {
const info = this.isegments[idx];
if (info.unitName === unitName) {
@@ -176,10 +176,10 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
- getSegmentIdByUnitName(unitName: string) {
+ getSegmentIdByUnitName(unitName: string): number | undefined {
const info = this.getSegmentInfoByUnitName(unitName);
if (info) {
return info.id;
@@ -191,7 +191,7 @@ export class MapFileReader {
/**
* Get Segment info for exact address
*/
- getSegmentInfoByStartingAddress(segment: string | boolean, address: number) {
+ getSegmentInfoByStartingAddress(segment: string | undefined, address: number): Segment | undefined {
for (let idx = 0; idx < this.segments.length; idx++) {
const info = this.segments[idx];
if (!segment && info.addressInt === address) {
@@ -201,13 +201,13 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
/**
* Get Segment info for the segment where the given address is in
*/
- getSegmentInfoAddressIsIn(segment: string | boolean, address: number) {
+ getSegmentInfoAddressIsIn(segment: string | undefined, address: number): Segment | undefined {
for (let idx = 0; idx < this.segments.length; idx++) {
const info = this.segments[idx];
if (!segment && address >= info.addressInt && address < info.addressInt + info.segmentLength) {
@@ -221,13 +221,13 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
/**
* Get Segment info for the segment where the given address is in
*/
- getSegmentInfoAddressWithoutOffsetIsIn(segment: string, address: number) {
+ getSegmentInfoAddressWithoutOffsetIsIn(segment: string, address: number): Segment | undefined {
for (let idx = 0; idx < this.segments.length; idx++) {
const info = this.segments[idx];
if (
@@ -239,10 +239,10 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
- getSymbolAt(segment: string, address: number) {
+ getSymbolAt(segment: string | undefined, address: number): Segment | undefined {
for (let idx = 0; idx < this.namedAddresses.length; idx++) {
const info = this.namedAddresses[idx];
if (!segment && info.addressInt === address) {
@@ -252,11 +252,11 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
- getSymbolBefore(segment: string, address: number) {
- let maxNamed: false | Segment = false;
+ getSymbolBefore(segment: string, address: number): Segment | undefined {
+ let maxNamed: Segment | undefined;
for (let idx = 0; idx < this.namedAddresses.length; idx++) {
const info = this.namedAddresses[idx];
@@ -274,7 +274,7 @@ export class MapFileReader {
return maxNamed;
}
- getSymbolInfoByName(name: string) {
+ getSymbolInfoByName(name: string): Segment | undefined {
for (let idx = 0; idx < this.namedAddresses.length; idx++) {
const info = this.namedAddresses[idx];
if (info.displayName === name) {
@@ -282,7 +282,7 @@ export class MapFileReader {
}
}
- return false;
+ return undefined;
}
addressToObject(segment: string, address: string): LineNumber {
diff --git a/lib/pe32-support.js b/lib/pe32-support.ts
index f0cec5c7e..fa3d468b0 100644
--- a/lib/pe32-support.js
+++ b/lib/pe32-support.ts
@@ -22,14 +22,25 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
+import {MapFileReader, Segment} from './mapfiles/map-file';
+
export class PELabelReconstructor {
- /**
- *
- * @param {Array} asmLines
- * @param {boolean} dontLabelUnmappedAddresses
- * @param {MapFileReader} mapFileReader
- */
- constructor(asmLines, dontLabelUnmappedAddresses, mapFileReader, needsReconstruction = true) {
+ public readonly asmLines: string[];
+ private readonly addressesToLabel: string[];
+ private readonly dontLabelUnmappedAddresses: boolean;
+ private readonly needsReconstruction: boolean;
+ private readonly mapFileReader: MapFileReader;
+ private readonly addressRegex: RegExp;
+ private readonly jumpRegex: RegExp;
+ private readonly callRegex: RegExp;
+ private readonly int3Regex: RegExp;
+
+ constructor(
+ asmLines: string[],
+ dontLabelUnmappedAddresses: boolean,
+ mapFileReader: MapFileReader,
+ needsReconstruction = true,
+ ) {
this.asmLines = asmLines;
this.addressesToLabel = [];
this.dontLabelUnmappedAddresses = dontLabelUnmappedAddresses;
@@ -47,7 +58,7 @@ export class PELabelReconstructor {
* Start reconstructing labels using the mapfile and remove unneccessary assembly
*
*/
- run(/*unitName*/) {
+ run(_unitName?: string) {
this.mapFileReader.run();
//this.deleteEverythingBut(unitName);
@@ -86,12 +97,10 @@ export class PELabelReconstructor {
/**
* Remove any assembly or data that isn't part of the given unit
- *
- * @param {string} unitName
*/
- deleteEverythingBut(unitName) {
+ deleteEverythingBut(unitName: string) {
if (this.needsReconstruction) {
- let unitAddressSpaces = this.mapFileReader.getReconstructedUnitAddressSpace(unitName);
+ const unitAddressSpaces = this.mapFileReader.getReconstructedUnitAddressSpace(unitName);
for (let idx = 0; idx < this.mapFileReader.reconstructedSegments.length; idx++) {
const info = this.mapFileReader.reconstructedSegments[idx];
@@ -146,12 +155,7 @@ export class PELabelReconstructor {
}
}
- /**
- *
- * @param {number} beginAddress
- * @param {number} endAddress
- */
- deleteLinesBetweenAddresses(beginAddress, endAddress) {
+ deleteLinesBetweenAddresses(beginAddress: number, endAddress?: number) {
let startIdx = -1;
let linesRemoved = false;
let lineIdx = 0;
@@ -185,19 +189,16 @@ export class PELabelReconstructor {
/**
* Replaces an address used in a jmp or call instruction by its label.
* Does not replace an address if it has an offset.
- *
- * @param {int} lineIdx
- * @param {regex} regex
*/
- addAddressAsLabelAndReplaceLine(lineIdx, regex) {
+ addAddressAsLabelAndReplaceLine(lineIdx: number, regex: RegExp) {
const line = this.asmLines[lineIdx];
- let matches = line.match(regex);
+ const matches = line.match(regex);
if (matches) {
const address = matches[3];
if (!address.includes('+') && !address.includes('-')) {
let labelName = 'L' + address;
- const namedAddr = this.mapFileReader.getSymbolAt(false, parseInt(address, 16));
- if (namedAddr) {
+ const namedAddr = this.mapFileReader.getSymbolAt(undefined, parseInt(address, 16));
+ if (namedAddr && namedAddr.displayName) {
labelName = namedAddr.displayName;
}
@@ -225,7 +226,7 @@ export class PELabelReconstructor {
* if an address doesn't have a mapped name, it is called <Laddress>
*/
insertLabels() {
- let currentSegment = false;
+ let currentSegment: Segment | undefined;
let segmentChanged = false;
let lineIdx = 0;
@@ -237,21 +238,21 @@ export class PELabelReconstructor {
const addressStr = matches[1];
const address = parseInt(addressStr, 16);
- const segmentInfo = this.mapFileReader.getSegmentInfoByStartingAddress(false, address);
+ const segmentInfo = this.mapFileReader.getSegmentInfoByStartingAddress(undefined, address);
if (segmentInfo) {
currentSegment = segmentInfo;
segmentChanged = true;
}
- let namedAddr = false;
- let labelLine = false;
+ let namedAddr: Segment | undefined;
+ let labelLine: string | undefined;
const isReferenced = this.addressesToLabel.indexOf(addressStr);
if (isReferenced === -1) {
// we might have missed the reference to this address,
// but if it's listed as a symbol, we should still label it.
// todo: the call might be in <.itext>, should we include that part of the assembly?
- namedAddr = this.mapFileReader.getSymbolAt(false, address);
+ namedAddr = this.mapFileReader.getSymbolAt(undefined, address);
if (namedAddr) {
labelLine = matches[1] + ' <' + namedAddr.displayName + '>:';
@@ -261,7 +262,7 @@ export class PELabelReconstructor {
} else {
labelLine = matches[1] + ' <L' + addressStr + '>:';
- namedAddr = this.mapFileReader.getSymbolAt(false, address);
+ namedAddr = this.mapFileReader.getSymbolAt(undefined, address);
if (namedAddr) {
labelLine = matches[1] + ' <' + namedAddr.displayName + '>:';
}
@@ -272,11 +273,11 @@ export class PELabelReconstructor {
}
}
- const lineInfo = this.mapFileReader.getLineInfoByAddress(false, address);
- if (lineInfo && currentSegment.unitName) {
+ const lineInfo = this.mapFileReader.getLineInfoByAddress(undefined, address);
+ if (lineInfo && currentSegment && currentSegment.unitName) {
this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':' + lineInfo.lineNumber);
lineIdx++;
- } else if (segmentChanged) {
+ } else if (segmentChanged && currentSegment) {
this.asmLines.splice(lineIdx, 0, '/app/' + currentSegment.unitName + ':0');
lineIdx++;
}
diff --git a/test/map-file-tests.js b/test/map-file-tests.js
index 838bd9e72..57f8c6821 100644
--- a/test/map-file-tests.js
+++ b/test/map-file-tests.js
@@ -25,9 +25,13 @@
import {MapFileReaderDelphi} from '../lib/mapfiles/map-file-delphi';
import {MapFileReaderVS} from '../lib/mapfiles/map-file-vs';
+import {chai} from './utils';
+
+const expect = chai.expect;
+
describe('Map setup', function () {
it('VS-map preferred load address', function () {
- const reader = new MapFileReaderVS();
+ const reader = new MapFileReaderVS('');
reader.preferredLoadAddress.should.equal(0x400000, 'default load address');
reader.tryReadingPreferredAddress(' Preferred load address is 00400000');
@@ -40,27 +44,27 @@ describe('Map setup', function () {
describe('Code Segments', function () {
it('One normal Delphi-Map segment', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingCodeSegmentInfo(' 0001:00002838 00000080 C=CODE S=.text G=(none) M=output ACBP=A9');
reader.segments.length.should.equal(1);
let info = reader.getSegmentInfoByStartingAddress('0001', 0x2838);
info.unitName.should.equal('output.pas');
- info = reader.getSegmentInfoByStartingAddress(false, reader.getSegmentOffset('0001') + 0x2838);
+ info = reader.getSegmentInfoByStartingAddress(undefined, reader.getSegmentOffset('0001') + 0x2838);
info.unitName.should.equal('output.pas');
- info = reader.getSegmentInfoByStartingAddress('0001', '2838');
- info.should.equal(false, 'Address should not be a Start for any segment');
+ info = reader.getSegmentInfoByStartingAddress('0001', 0x1234);
+ expect(info, 'Address should not be a Start for any segment').to.be.undefined;
info = reader.getSegmentInfoAddressIsIn('0001', 0x2838 + 0x10);
info.unitName.should.equal('output.pas');
- info = reader.getSegmentInfoAddressIsIn(false, reader.getSegmentOffset('0001') + 0x2838 + 0x10);
+ info = reader.getSegmentInfoAddressIsIn(undefined, reader.getSegmentOffset('0001') + 0x2838 + 0x10);
info.unitName.should.equal('output.pas');
info = reader.getSegmentInfoAddressIsIn('0001', reader.getSegmentOffset('0001') + 0x2838 + 0x80 + 1);
- info.should.equal(false, 'Address should not be in any segment');
+ expect(info, 'Address should not be in any segment').to.be.undefined;
info = reader.getSegmentInfoByUnitName('output.pas');
info.unitName.should.equal('output.pas');
@@ -68,37 +72,37 @@ describe('Code Segments', function () {
});
it('Not include this segment', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingCodeSegmentInfo(' 0002:000000B0 00000023 C=ICODE S=.itext G=(none) M=output ACBP=A9');
reader.segments.length.should.equal(0);
});
it('ICode/IText segments', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingCodeSegmentInfo(' 0002:000000B0 00000023 C=ICODE S=.itext G=(none) M=output ACBP=A9');
reader.isegments.length.should.equal(1);
});
it('One normal VS-Map segment', function () {
- const reader = new MapFileReaderVS();
+ const reader = new MapFileReaderVS('');
reader.tryReadingCodeSegmentInfo(' 0001:00002838 00000080H .text$mn CODE');
reader.segments.length.should.equal(1);
let info = reader.getSegmentInfoByStartingAddress('0001', 0x2838);
info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838);
- info = reader.getSegmentInfoByStartingAddress(false, 0x403838);
+ info = reader.getSegmentInfoByStartingAddress(undefined, 0x403838);
info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838);
- info = reader.getSegmentInfoAddressIsIn(false, reader.getSegmentOffset('0001') + 0x2838 + 0x10);
+ info = reader.getSegmentInfoAddressIsIn(undefined, reader.getSegmentOffset('0001') + 0x2838 + 0x10);
info.addressInt.should.equal(reader.getSegmentOffset('0001') + 0x2838);
info = reader.getSegmentInfoAddressIsIn('0001', reader.getSegmentOffset('0001') + 0x2837);
- info.should.equal(false);
+ expect(info).to.be.undefined;
});
it('Repair VS-Map code segment info', function () {
- const reader = new MapFileReaderVS();
+ const reader = new MapFileReaderVS('');
reader.tryReadingCodeSegmentInfo(' 0002:00000000 00004c73H .text$mn CODE');
reader.tryReadingNamedAddress(
' 0002:000007f0 _main 004117f0 f ConsoleApplication1.obj',
@@ -109,58 +113,58 @@ describe('Code Segments', function () {
reader.getSegmentOffset('0002').should.equal(0x411000);
- info = reader.getSegmentInfoByStartingAddress(false, 0x411000);
+ info = reader.getSegmentInfoByStartingAddress(undefined, 0x411000);
info.unitName.should.equal('ConsoleApplication1.obj');
});
});
describe('Symbol info', function () {
it('Delphi-Map symbol test', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingNamedAddress(' 0001:00002838 Square');
reader.namedAddresses.length.should.equal(1);
let info = reader.getSymbolAt('0001', 0x2838);
- info.should.not.equal(false, 'Symbol Square should have been returned 1');
+ info.should.not.equal(undefined, 'Symbol Square should have been returned 1');
info.displayName.should.equal('Square');
- info = reader.getSymbolAt(false, reader.getSegmentOffset('0001') + 0x2838);
- info.should.not.equal(false, 'Symbol Square should have been returned 2');
+ info = reader.getSymbolAt(undefined, reader.getSegmentOffset('0001') + 0x2838);
+ info.should.not.equal(undefined, 'Symbol Square should have been returned 2');
info.displayName.should.equal('Square');
});
it('Delphi-Map D2009 symbol test', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingNamedAddress(' 0001:00002C4C output.MaxArray');
reader.namedAddresses.length.should.equal(1);
let info = reader.getSymbolAt('0001', 0x2c4c);
- info.should.not.equal(false, 'Symbol MaxArray should have been returned');
+ info.should.not.equal(undefined, 'Symbol MaxArray should have been returned');
info.displayName.should.equal('output.MaxArray');
-
- info = reader.getSymbolAt(false, reader.getSegmentOffset('0001') + 0x2c4c);
- info.should.not.equal(false, 'Symbol MaxArray should have been returned');
+ //todo should not be undefined
+ info = reader.getSymbolAt(undefined, reader.getSegmentOffset('0001') + 0x2c4c);
+ info.should.not.equal(undefined, 'Symbol MaxArray should have been returned');
info.displayName.should.equal('output.MaxArray');
});
it('VS-Map symbol test', function () {
- const reader = new MapFileReaderVS();
+ const reader = new MapFileReaderVS('');
reader.tryReadingNamedAddress(
' 0002:000006b0 ??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ 004116b0 f i ConsoleApplication1.obj',
);
reader.namedAddresses.length.should.equal(1);
let info = reader.getSymbolAt('0002', 0x6b0);
- info.should.not.equal(false, 'Symbol start_verify_argument should have been returned 1');
+ info.should.not.equal(undefined, 'Symbol start_verify_argument should have been returned 1');
info.displayName.should.equal('??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ');
- info = reader.getSymbolAt(false, 0x4116b0);
- info.should.not.equal(false, 'Symbol start_verify_argument should have been returned 2');
+ info = reader.getSymbolAt(undefined, 0x4116b0);
+ info.should.not.equal(undefined, 'Symbol start_verify_argument should have been returned 2');
info.displayName.should.equal('??$__vcrt_va_start_verify_argument_type@QBD@@YAXXZ');
});
it('Delphi-Map Duplication prevention', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingNamedAddress(' 0001:00002838 Square');
reader.namedAddresses.length.should.equal(1);
@@ -171,23 +175,23 @@ describe('Symbol info', function () {
describe('Delphi-Map Line number info', function () {
it('No line', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingLineNumbers('').should.equal(false);
});
it('One line', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader.tryReadingLineNumbers(' 17 0001:000028A4').should.equal(true);
let lineInfo = reader.getLineInfoByAddress('0001', 0x28a4);
lineInfo.lineNumber.should.equal(17);
- lineInfo = reader.getLineInfoByAddress(false, reader.getSegmentOffset('0001') + 0x28a4);
+ lineInfo = reader.getLineInfoByAddress(undefined, reader.getSegmentOffset('0001') + 0x28a4);
lineInfo.lineNumber.should.equal(17);
});
it('Multiple lines', function () {
- const reader = new MapFileReaderDelphi();
+ const reader = new MapFileReaderDelphi('');
reader
.tryReadingLineNumbers(' 12 0001:00002838 13 0001:0000283B 14 0001:00002854 15 0001:00002858')
.should.equal(true);
@@ -244,7 +248,7 @@ describe('VS-Map load test', function () {
describe('VS-Map address checking', function () {
it('Normal defined spaces', function () {
- const reader = new MapFileReaderVS();
+ const reader = new MapFileReaderVS('');
const mainAddresses = [
{startAddress: 1, startAddressHex: '00000001', endAddress: 10, endAddressHex: '0000000A'},
@@ -259,7 +263,7 @@ describe('VS-Map address checking', function () {
});
it('Overlapping regions', function () {
- const reader = new MapFileReaderVS();
+ const reader = new MapFileReaderVS('');
const mainAddresses = [
{startAddress: 1, startAddressHex: '00000001', endAddress: 10, endAddressHex: '0000000A'},