@bugsplat/elfy
Version:
Tiny utility for parsing ELF/SELF files.
114 lines • 4.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ElfFile = void 0;
const promises_1 = require("node:fs/promises");
const file_header_1 = require("./file-header");
const section_header_1 = require("./section-header");
class ElfFile {
constructor(fileHandle) {
this.fileHandle = fileHandle;
}
static async create(path) {
const fileHandle = await (0, promises_1.open)(path, 'r');
return new ElfFile(fileHandle);
}
[Symbol.dispose]() {
this.dispose();
}
dispose() {
this.fileHandle?.close();
}
async tryReadSection(name) {
let section = undefined;
let success = true;
try {
section = await this.readSection(name);
}
catch {
success = false;
}
return {
success,
section,
};
}
async readSection(name) {
if (!this.header) {
this.header = await this.readFileHeader();
}
if (!this.stringTable) {
this.stringTable = await this.createStringTable();
}
const index = this.stringTable.indexOf(name);
const found = index !== -1;
if (!found) {
throw new Error(`Section ${name} not found`);
}
const header = await this.readSectionHeader(index);
const { sectionOffset, sectionSize } = header;
const { buffer, bytesRead } = await this.fileHandle.read(Buffer.alloc(Number(sectionSize)), 0, Number(sectionSize), Number(sectionOffset));
if (bytesRead !== Number(sectionSize)) {
throw new Error(`Could not read section ${name}`);
}
return buffer;
}
async createStringTable() {
const { stringTableIndex } = this.header;
const stringTableHeader = await this.readSectionHeader(stringTableIndex);
const { sectionOffset, sectionSize } = stringTableHeader;
const { buffer, bytesRead } = await this.fileHandle.read(Buffer.alloc(Number(sectionSize)), 0, Number(sectionSize), Number(sectionOffset));
if (bytesRead !== Number(sectionSize)) {
throw new Error('Could not read string table');
}
const stringTable = [];
// The section names in the strings table aren't necessarily in the same order as the corresponding sections.
// Read all the section headers to find the true order of the sections.
for (let i = 0; i < this.header.sectionHeaderEntryCount; i++) {
const { sectionNameOffset } = await this.readSectionHeader(i);
const nextNull = buffer.indexOf(0x00, sectionNameOffset);
const name = buffer.subarray(sectionNameOffset, nextNull).toString('utf-8');
stringTable.push(name);
}
return stringTable;
}
async readSectionHeader(i) {
const { sectionHeaderOffset, sectionHeaderEntrySize } = this.header;
const headerStart = Number(sectionHeaderOffset) + i * sectionHeaderEntrySize;
const { buffer, bytesRead } = await this.fileHandle.read(Buffer.alloc(sectionHeaderEntrySize), 0, sectionHeaderEntrySize, headerStart);
if (bytesRead !== sectionHeaderEntrySize) {
throw new Error('Could not read section header');
}
const sectionNameOffset = buffer.readUInt32LE(0);
const sectionType = buffer.readUInt32LE(4);
const sectionFlags = buffer.readBigUInt64LE(8);
const sectionLoadAddress = buffer.readBigUInt64LE(16);
const sectionOffset = buffer.readBigUInt64LE(24);
const sectionSize = buffer.readBigUInt64LE(32);
const sectionLink = buffer.readUInt32LE(40);
const sectionInfo = buffer.readUInt32LE(44);
const sectionAlignment = buffer.readBigUInt64LE(48);
const sectionEntrySize = buffer.readBigUInt64LE(56);
return new section_header_1.ElfSectionHeader(sectionNameOffset, sectionType, sectionFlags, sectionLoadAddress, sectionOffset, sectionSize, sectionLink, sectionInfo, sectionAlignment, sectionEntrySize);
}
async readFileHeader() {
const { buffer, bytesRead } = await this.fileHandle.read(Buffer.alloc(file_header_1.lengthOf64BitElfHeader), 0, file_header_1.lengthOf64BitElfHeader, 0);
if (bytesRead !== file_header_1.lengthOf64BitElfHeader) {
throw new Error('Could not read ELF header');
}
return file_header_1.ElfFileHeader.parse(buffer);
}
}
exports.ElfFile = ElfFile;
function splitBuffer(buffer, delimiter) {
const parts = [];
let start = 0;
let index = 0;
// Believe it or not, according to elfsharp the first part is indeed empty
while ((index = buffer.indexOf(delimiter, start)) !== -1) {
parts.push(buffer.subarray(start, index));
start = index + 1;
}
parts.push(buffer.subarray(start));
return parts;
}
//# sourceMappingURL=elf.js.map