UNPKG

@bugsplat/sysvelf

Version:

An Executable and Linkable Format (ELF) parser.

243 lines (212 loc) 7.45 kB
/** * Module dependencies. */ var fs = require('fs') , EndianBuffer = require('endian-buffer').Buffer , Encoding = require('./constants/encoding') /** * `Elf32` constructor. * * @api protected */ function Elf32(filename, enc) { this.filename = filename; this.enc = enc; } /** * Read the segment identified by `type` from the ELF. * * @param {Number} type * @param {Function} cb * @api public */ Elf32.prototype.readSegment = function(type, cb) { var self = this; fs.open(this.filename, 'r', function(err, fd) { if (err) { return cb(err); } // wrap `cb` to close the file descriptor function done(err, buf) { fs.close(fd, function(cerr) { if (cerr) { return cb(cerr); } return cb(err, buf); }); } // find program header with specified `type` var ph; for (var i = 0, len = self.pheaders.length; i < len; ++i) { if (self.pheaders[i].type === type) { ph = self.pheaders[i]; break; } } if (!ph) { return done(new Error('No program header with type: ' + type)); } var buf = new Buffer(ph.filesz); fs.read(fd, buf, 0, ph.filesz, ph.offset, function(err, bytesRead) { if (err) { return done(err); } return done(null, buf); }); }); } /** * Read the section identified by `name` from the ELF. * * @param {String} name * @param {Function} cb * @api public */ Elf32.prototype.readSection = function(name, cb) { var self = this; fs.open(this.filename, 'r', function(err, fd) { if (err) { return cb(err); } // wrap `cb` to close the file descriptor function done(err, buf) { fs.close(fd, function(cerr) { if (cerr) { return cb(cerr); } return cb(err, buf); }); } // find section header with specified `name` var sh; for (var i = 0, len = self.sheaders.length; i < len; ++i) { if (self.sheaders[i].name === name) { sh = self.sheaders[i]; break; } } if (!sh) { return done(new Error('No section header with name: ' + name)); } var buf = new Buffer(sh.size); fs.read(fd, buf, 0, sh.size, sh.offset, function(err, bytesRead) { if (err) { return done(err); } return done(null, buf); }); }); } /** * Load a 32-bit ELF file. * * References: * - [System V Application Binary Interface](http://www.sco.com/developers/devspecs/gabi41.pdf) * * @param {Number} fd * @param {Function} cb * @api protected */ Elf32.prototype.load = function(fd, cb) { var self = this; var endian = this.enc == Encoding.LSB ? 'le' : 'be'; // Read the ELF header, minus the identification portion. // // The format of the header is specified by the System V Application Binary // Interface, section 4 (pg. 48). For an online copy of this document, // visit: http://www.sco.com/developers/devspecs/gabi41.pdf var header = new EndianBuffer(36, endian); fs.read(fd, header.buffer, 0, 36, null, function(err, bytesRead) { if (err) { return cb(err); } self.type = header.readUInt16(0); self.machine = header.readUInt16(2); self.version = header.readUInt32(4); self.entry = header.readUInt32(8); self.phoff = header.readUInt32(12); self.shoff = header.readUInt32(16); self.flags = header.readUInt32(20); self.ehsize = header.readUInt16(24); self.phentsize = header.readUInt16(26); self.phnum = header.readUInt16(28); self.shentsize = header.readUInt16(30); self.shnum = header.readUInt16(32); self.shstrndx = header.readUInt16(34); self.pheaders = []; self.sheaders = []; // Parse the ELF's section header table. // // The section header table consists of an array of section header // structures. The format of these structures is specified by the System V // Application Binary Interface, section 4 (pg. 54). function parseSHT(cb) { if (self.shoff === 0) { return cb(); } // no section header table (function iter(i, err) { if (err) { return cb(err); } if (i >= self.shnum) { return cb(); } // done var pos = self.shoff + (self.shentsize * i); var entry = new EndianBuffer(self.shentsize, endian); fs.read(fd, entry.buffer, 0, self.shentsize, pos, function(err, bytesRead) { if (err) { return iter(i + 1, err); } var sh = {}; sh.namendx = entry.readUInt32(0); sh.type = entry.readUInt32(4); sh.flags = entry.readUInt32(8); sh.addr = entry.readUInt32(12); sh.offset = entry.readUInt32(16); sh.size = entry.readUInt32(20); sh.link = entry.readUInt32(24); sh.info = entry.readUInt32(28); sh.addralign = entry.readUInt32(32); sh.entsize = entry.readUInt32(36); self.sheaders.push(sh); return iter(i + 1); }); })(0); } // Parse the ELF's section header string table, associating sections headers // with their corresponding names. // // The format of the string table is specified by the System V Application // Binary Interface, section 4 (pg. 65). function parseSHStrTab(cb) { if (self.shoff === 0) { return cb(); } // no section header table var strsh = self.sheaders[self.shstrndx]; var strsec = new Buffer(strsh.size); fs.read(fd, strsec, 0, strsh.size, strsh.offset, function(err, bytesRead) { if (err) { return cb(err); } for (var i = 0, len = self.sheaders.length; i < len; ++i) { var sh = self.sheaders[i] , start = sh.namendx , end = sh.namendx; if (sh.namendx === 0) { continue; } while (strsec[end] !== 0) { ++end; } sh.name = strsec.slice(start, end).toString(); } return cb(); }); } // Parse the ELF's program header table. // // The program header table consists of an array of program header // structures. The format of these structures is specified by the System V // Application Binary Interface, section 5 (pg. 75). function parsePHT(cb) { if (self.phoff === 0) { return cb(); } // no program header table (function iter(i, err) { if (err) { return cb(err); } if (i >= self.phnum) { return cb(); } // done var pos = self.phoff + (self.phentsize * i); var entry = new EndianBuffer(self.phentsize, endian); fs.read(fd, entry.buffer, 0, self.phentsize, pos, function(err, bytesRead) { if (err) { return iter(i + 1, err); } var ph = {}; self.pheaders.push(ph); ph.type = entry.readUInt32(0); ph.offset = entry.readUInt32(4); ph.vaddr = entry.readUInt32(8); ph.paddr = entry.readUInt32(12); ph.filesz = entry.readUInt32(16); ph.memsz = entry.readUInt32(20); ph.flags = entry.readUInt32(24); ph.align = entry.readUInt32(28); return iter(i + 1); }); })(0); } parseSHT(function(err) { if (err) { return cb(err); } parseSHStrTab(function(err) { if (err) { return cb(err); } parsePHT(function(err) { if (err) { return cb(err); } return cb(); }); }); }); }); } module.exports = Elf32;