246 lines
5.7 KiB
JavaScript
246 lines
5.7 KiB
JavaScript
|
/*
|
||
|
* 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 <type> [<num>] where
|
||
|
* as node-ctype does this as <type>[<num>].
|
||
|
*/
|
||
|
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;
|