/* * ctf.js * * Understand and parse all of the different JSON formats of CTF data and * translate that into a series of node-ctype friendly pieces. The reason for * the abstraction is to handle different changes in the file format. * * We have to be careful here that we don't end up using a name that is already * a built in type. */ var mod_assert = require('assert'); var ASSERT = mod_assert.ok; var ctf_versions = [ '1.0' ]; var ctf_entries = [ 'integer', 'float', 'typedef', 'struct' ]; var ctf_deftypes = [ 'int8_t', 'uint8_t', 'int16_t', 'uint16_t', 'int32_t', 'uint32_t', 'float', 'double' ]; function ctfParseInteger(entry, ctype) { var name, sign, len, type; name = entry['name']; if (!('signed' in entry['integer'])) throw (new Error('Malformed CTF JSON: integer missing ' + 'signed value')); if (!('length' in entry['integer'])) throw (new Error('Malformed CTF JSON: integer missing ' + 'length value')); sign = entry['integer']['signed']; len = entry['integer']['length']; type = null; if (sign && len == 1) type = 'int8_t'; else if (len == 1) type = 'uint8_t'; else if (sign && len == 2) type = 'int16_t'; else if (len == 2) type = 'uint16_t'; else if (sign && len == 4) type = 'int32_t'; else if (len == 4) type = 'uint32_t'; else if (sign && len == 8) type = 'int64_t'; else if (len == 8) type = 'uint64_t'; if (type === null) throw (new Error('Malformed CTF JSON: integer has ' + 'unsupported length and sign - ' + len + '/' + sign)); /* * This means that this is the same as one of our built in types. If * that's the case defining it would be an error. So instead of trying * to typedef it, we'll return here. */ if (name == type) return; if (name == 'char') { ASSERT(type == 'int8_t'); return; } ctype.typedef(name, type); } function ctfParseFloat(entry, ctype) { var name, len; name = entry['name']; if (!('length' in entry['float'])) throw (new Error('Malformed CTF JSON: float missing ' + 'length value')); len = entry['float']['length']; if (len != 4 && len != 8) throw (new Error('Malformed CTF JSON: float has invalid ' + 'length value')); if (len == 4) { if (name == 'float') return; ctype.typedef(name, 'float'); } else if (len == 8) { if (name == 'double') return; ctype.typedef(name, 'double'); } } function ctfParseTypedef(entry, ctype) { var name, type, ii; name = entry['name']; if (typeof (entry['typedef']) != 'string') throw (new Error('Malformed CTF JSON: typedef value in not ' + 'a string')); type = entry['typedef']; /* * We need to ensure that we're not looking at type that's one of our * built in types. Traditionally in C a uint32_t would be a typedef to * some kind of integer. However, those size types are built ins. */ for (ii = 0; ii < ctf_deftypes.length; ii++) { if (name == ctf_deftypes[ii]) return; } ctype.typedef(name, type); } function ctfParseStruct(entry, ctype) { var name, type, ii, val, index, member, push; member = []; if (!Array.isArray(entry['struct'])) throw (new Error('Malformed CTF JSON: struct value is not ' + 'an array')); for (ii = 0; ii < entry['struct'].length; ii++) { val = entry['struct'][ii]; if (!('name' in val)) throw (new Error('Malformed CTF JSON: struct member ' + 'missing name')); if (!('type' in val)) throw (new Error('Malformed CTF JSON: struct member ' + 'missing type')); if (typeof (val['name']) != 'string') throw (new Error('Malformed CTF JSON: struct member ' + 'name isn\'t a string')); if (typeof (val['type']) != 'string') throw (new Error('Malformed CTF JSON: struct member ' + 'type isn\'t a string')); /* * CTF version 2 specifies array names as [] where * as node-ctype does this as []. */ name = val['name']; type = val['type']; index = type.indexOf(' ['); if (index != -1) { type = type.substring(0, index) + type.substring(index + 1, type.length); } push = {}; push[name] = { 'type': type }; member.push(push); } name = entry['name']; ctype.typedef(name, member); } function ctfParseEntry(entry, ctype) { var ii, found; if (!('name' in entry)) throw (new Error('Malformed CTF JSON: entry missing "name" ' + 'section')); for (ii = 0; ii < ctf_entries.length; ii++) { if (ctf_entries[ii] in entry) found++; } if (found === 0) throw (new Error('Malformed CTF JSON: found no entries')); if (found >= 2) throw (new Error('Malformed CTF JSON: found more than one ' + 'entry')); if ('integer' in entry) { ctfParseInteger(entry, ctype); return; } if ('float' in entry) { ctfParseFloat(entry, ctype); return; } if ('typedef' in entry) { ctfParseTypedef(entry, ctype); return; } if ('struct' in entry) { ctfParseStruct(entry, ctype); return; } ASSERT(false, 'shouldn\'t reach here'); } function ctfParseJson(json, ctype) { var version, ii; ASSERT(json); ASSERT(ctype); if (!('metadata' in json)) throw (new Error('Invalid CTF JSON: missing metadata section')); if (!('ctf2json_version' in json['metadata'])) throw (new Error('Invalid CTF JSON: missing ctf2json_version')); version = json['metadata']['ctf2json_version']; for (ii = 0; ii < ctf_versions.length; ii++) { if (ctf_versions[ii] == version) break; } if (ii == ctf_versions.length) throw (new Error('Unsuported ctf2json_version: ' + version)); if (!('data' in json)) throw (new Error('Invalid CTF JSON: missing data section')); if (!Array.isArray(json['data'])) throw (new Error('Malformed CTF JSON: data section is not ' + 'an array')); for (ii = 0; ii < json['data'].length; ii++) ctfParseEntry(json['data'][ii], ctype); } exports.ctfParseJson = ctfParseJson;