Skip to content

Instantly share code, notes, and snippets.

@landonf
Last active January 5, 2016 18:33
Show Gist options
  • Save landonf/fda9c2d9e5e8ef765ba7 to your computer and use it in GitHub Desktop.
Save landonf/fda9c2d9e5e8ef765ba7 to your computer and use it in GitHub Desktop.
Super hacked together SPROM definition extraction code, using ObjC libclang wrapper written for ObjectDoc https://github.com/landonf/objectdoc
// Created by Landon Fuller on 12/31/15.
// Copyright (c) 2015 Landon Fuller. All rights reserved.
//
#include <stdio.h>
#include <err.h>
#include <getopt.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <iostream>
#include <iomanip>
#import <ObjectDoc/ObjectDoc.h>
#import <ObjectDoc/PLClang.h>
extern "C" {
#include "bcm/bcmsrom_tbl.h"
}
using namespace std;
static uint32_t compute_literal_u32(PLClangTranslationUnit *tu, NSArray *tokens);
static id<NSObject> get_literal(PLClangTranslationUnit *tu, PLClangToken *t);
/** A symbolic constant definition */
struct symbolic_constant {
PLClangTranslationUnit *tu;
PLClangToken *token;
std::string name() const { return token.spelling.UTF8String; }
};
/** A symbolic offset definition */
struct symbolic_offset {
PLClangTranslationUnit *tu;
NSArray *tokens;
uint16_t raw_value;
size_t raw_byte_offset;
NSString *virtual_base = nil;
symbolic_offset() {}
symbolic_offset(PLClangTranslationUnit *_tu, NSArray *_tokens) : tu(_tu), tokens(_tokens) {
raw_value = compute_literal_u32(tu, tokens);
/** bcmsrom offsets assume 16-bit pointer arithmetic */
raw_byte_offset = raw_value * sizeof(uint16_t);
}
vector<string> referenced_constants () {
vector<string> ret;
if (virtual_base)
ret.push_back(virtual_base.UTF8String);
for (PLClangToken *t in tokens) {
switch (t.kind) {
case PLClangTokenKindIdentifier:
ret.push_back(t.spelling.UTF8String);
break;
default:
break;
}
}
return ret;
}
std::string byte_adjusted_string_rep () {
NSMutableArray *strs = [NSMutableArray array];
if (virtual_base != nil) {
[strs addObject: virtual_base];
[strs addObject: @"+"];
}
for (PLClangToken *t in tokens) {
switch (t.kind) {
case PLClangTokenKindIdentifier:
case PLClangTokenKindPunctuation:
[strs addObject: t.spelling];
break;
case PLClangTokenKindLiteral: {
NSNumber *n = (NSNumber *) get_literal(tu, t);
u_int off = [n unsignedIntValue];
NSString *soff = [NSString stringWithFormat: @"%u", off*2];
[strs addObject: soff];
break;
} default:
errx(EXIT_FAILURE, "unsupported token %s", t.description.UTF8String);
}
}
return [strs componentsJoinedByString:@""].UTF8String;
}
bool isSimple() const {
return (tokens.count == 1);
};
};
namespace std {
std::string to_string(const struct symbolic_offset &off) {
std::string ret;
ret = [off.tokens componentsJoinedByString: @" "].UTF8String;
return ret;
}
}
/* A parsed SPROM record from the vendor header file */
struct nvar {
NSString *name;
uint32_t revmask;
uint32_t flags;
symbolic_offset off;
uint32_t valmask;
nvar () {}
nvar (NSString *n,
uint32_t _revmask,
uint32_t _flags,
symbolic_offset _off,
uint32_t _valmask) : name(n), revmask(_revmask), flags(_flags), off(_off), valmask(_valmask) {}
size_t byte_off() const {
size_t offset = off.raw_byte_offset;
if (!(valmask & 0xFF00))
offset += sizeof(uint8_t);
return offset;
}
size_t width() const {
size_t w = 4;
if (!(valmask & 0xFF000000))
w -= 1;
if (!(valmask & 0x00FF0000))
w -= 1;
if (!(valmask & 0x0000FF00))
w -= 1;
if (!(valmask & 0x000000FF))
w -= 1;
return w;
}
};
/*
* A copy of our output target's types, modified to support generating
* output code, allow use of std::vector instead of C arrays, etc.
*/
/** NVRAM primitive data types */
typedef enum {
BHND_NVRAM_DT_UINT, /**< unsigned integer */
BHND_NVRAM_DT_SINT, /**< signed integer */
BHND_NVRAM_DT_MAC48, /**< MAC-48 address */
BHND_NVRAM_DT_LEDDC, /**< LED PWM duty-cycle */
BHND_NVRAM_DT_CCODE, /**< country code format (2-3 ASCII chars) */
} bhnd_nvram_dt;
/** NVRAM data type string representations */
typedef enum {
BHND_NVRAM_SFMT_HEX, /**< hex string format */
BHND_NVRAM_SFMT_SDEC, /**< signed decimal format */
BHND_NVRAM_SFMT_MACADDR, /**< mac address (canonical form, hex octets,
seperated with ':') */
BHND_NVRAM_SFMT_ASCII /**< ASCII string */
} bhnd_nvram_sfmt;
/** NVRAM variable flags */
enum {
BHND_NVRAM_VF_DFLT = 0,
BHND_NVRAM_VF_ARRAY = (1<<0), /**< variable is an array */
BHND_NVRAM_VF_MFGINT = (1<<1), /**< mfg-internal variable; should not be externally visible */
BHND_NVRAM_VF_IGNALL1 = (1<<2) /**< hide variable if its value has all bits set. */
};
#define BHND_SPROMREV_MAX UINT16_MAX /**< maximum supported SPROM revision */
/** SPROM revision compatibility declaration */
struct bhnd_sprom_compat {
uint16_t first; /**< first compatible SPROM revision */
uint16_t last; /**< last compatible SPROM revision, or BHND_SPROMREV_MAX */
};
/** SPROM value segment descriptor */
struct bhnd_sprom_vseg {
size_t offset; /**< byte offset within SPROM */
size_t width; /**< 1, 2, or 4 bytes */
uint32_t mask; /**< mask to be applied to the value */
ssize_t shift; /**< shift to be applied to the value on extraction. if negative, left shift. if positive, right shift. */
const char *width_str () const {
switch (width) {
case 1:
return "u8";
case 2:
return "u16";
case 4:
return "u32";
default:
errx(EXIT_FAILURE, "Unsupported width: %zu", width);
}
}
bool has_default_mask () const {
switch (width) {
case 1:
return (mask == 0xFF);
case 2:
return (mask == 0xFFFF);
case 4:
return (mask == 0xFFFFFFFF);
default:
errx(EXIT_FAILURE, "Unsupported width: %zu", width);
}
}
bool has_default_shift () const {
return (shift == 0);
}
bool has_defaults () const {
return (has_default_mask() && has_default_shift());
}
};
/** SPROM value descriptor */
struct bhnd_sprom_value {
std::vector<bhnd_sprom_vseg> segs; /**< segment(s) containing this value */
};
/** SPROM-specific variable definition */
struct bhnd_sprom_var {
const bhnd_sprom_compat compat; /**< sprom compatibility declaration */
std::vector<bhnd_sprom_value> values; /**< value descriptor(s) */
};
/** NVRAM variable definition */
struct bhnd_nvram_var {
std::string name; /**< variable name */
bhnd_nvram_dt type; /**< base data type */
bhnd_nvram_sfmt fmt; /**< string format */
uint32_t flags; /**< BHND_NVRAM_VF_* flags */
size_t array_len; /**< array element count (if BHND_NVRAM_VF_ARRAY) */
std::vector<bhnd_sprom_var> sprom_descs; /**< SPROM-specific variable descriptors */
bool operator < (const bhnd_nvram_var &other) const {
return ([@(name.c_str()) compare:@(other.name.c_str()) options:NSNumericSearch] == NSOrderedAscending);
}
};
static id<NSObject> get_literal(PLClangTranslationUnit *tu, PLClangToken *t);
static PLClangToken *
resolve_pre(PLClangTranslationUnit *tu, PLClangToken *t) {
PLClangCursor *def;
if (t.cursor.referencedCursor != nil)
def = t.cursor.referencedCursor;
else
def = t.cursor;
NSArray *tokens = [tu tokensForSourceRange: def.extent];
if (tokens.count < 2)
errx(EXIT_FAILURE, "macro def %s unsupported token count %lu", t.spelling.UTF8String, (unsigned long)tokens.count);
return tokens[1];
}
static id<NSObject>
get_literal(PLClangTranslationUnit *tu, PLClangToken *t) {
if (t.kind == PLClangTokenKindIdentifier && t.cursor.isPreprocessing)
return get_literal(tu, resolve_pre(tu, t));
if (t.kind != PLClangTokenKindLiteral)
return nil;
NSString *s = t.spelling;
NSScanner *sc = [NSScanner scannerWithString: s];
switch (t.cursor.kind) {
case PLClangCursorKindMacroDefinition:
case PLClangCursorKindIntegerLiteral: {
unsigned long long ull;
if ([s hasPrefix: @"0x"]) {
[sc scanHexLongLong: &ull];
} else if ([s hasPrefix: @"0"] && ![s isEqual: @"0"]) {
// TODO
errx(EXIT_FAILURE, "octal not supported srry");
} else {
[sc scanUnsignedLongLong: &ull];
}
return [NSNumber numberWithUnsignedLongLong: ull];
}
case PLClangCursorKindStringLiteral: {
NSString *lit = t.spelling;
lit = [lit substringFromIndex: 1];
lit = [lit substringToIndex: lit.length - 1];
return lit;
}
default:
return nil;
}
}
static uint32_t
compute_literal_u32(PLClangTranslationUnit *tu, NSArray *tokens)
{
uint32_t v = 0;
char op = '\0';
if (tokens.count == 0)
errx(EXIT_FAILURE, "empty token list");
for (__strong PLClangToken *t in tokens) {
if (t.kind == PLClangTokenKindIdentifier)
t = resolve_pre(tu, t);
switch (t.kind) {
case PLClangTokenKindLiteral: {
NSNumber *n = (NSNumber *) get_literal(tu, t);
uint32_t nv = (uint32_t) [n unsignedIntegerValue];
switch (op) {
case '\0':
v = nv;
break;
case '|':
v |= nv;
break;
case '+':
v += nv;
break;
case '-':
v -= nv;
break;
default:
errx(EXIT_FAILURE, "unsupported op %c", op);
}
break;
}
case PLClangTokenKindPunctuation:
op = t.spelling.UTF8String[0];
break;
default:
errx(EXIT_FAILURE, "Unsupported token type!");
}
}
return v;
}
static bool
extract_struct(PLClangTranslationUnit *tu, PLClangCursor *c, nvar *nout) {
NSMutableArray *tokens = [[tu tokensForSourceRange: c.extent] mutableCopy];
if (tokens.count == 0)
errx(EXIT_FAILURE, "zero length");
PLClangToken *sep = tokens.lastObject;
if (sep.kind == PLClangTokenKindPunctuation && ([sep.spelling isEqual: @","] || [sep.spelling isEqual: @"}"])) {
sep = nil;
[tokens removeLastObject];
}
if (tokens.count < 2)
errx(EXIT_FAILURE, "invalid length");
PLClangToken *start = tokens.firstObject;
PLClangToken *end = tokens.lastObject;
if (start.kind != PLClangTokenKindPunctuation || end.kind != PLClangTokenKindPunctuation)
errx(EXIT_FAILURE, "not an initializer");
if (![start.spelling isEqual: @"{"] || ![end.spelling isEqual: @"}"])
errx(EXIT_FAILURE, "not an initializer");
[tokens removeObjectAtIndex: 0];
[tokens removeLastObject];
NSMutableArray *grouped = [NSMutableArray array];
NSMutableArray *curgroup = [NSMutableArray array];
for (PLClangToken *t in [tokens copy]) {
if (t.kind == PLClangTokenKindPunctuation && [t.spelling isEqualToString: @","]) {
[grouped addObject: curgroup];
curgroup = [NSMutableArray array];
} else {
[curgroup addObject: t];
}
}
[grouped addObject: curgroup];
if (grouped.count != 5)
errx(EXIT_FAILURE, "invalid length");
PLClangToken *nameToken = tokens.firstObject;
/* Skip terminating entry */
if (nameToken.kind == PLClangTokenKindIdentifier && [nameToken.spelling isEqual: @"NULL"])
return false;
NSString *name = (NSString *) get_literal(tu, nameToken);
uint32_t revmask = compute_literal_u32(tu, grouped[1]);
uint32_t flags = compute_literal_u32(tu, grouped[2]);
symbolic_offset off(tu, (NSArray *) grouped[3]);
uint32_t valmask = compute_literal_u32(tu, grouped[4]);
*nout = nvar(name, revmask, flags, off, valmask);
return true;
}
static const char *dtstr (bhnd_nvram_dt dt) {
switch (dt) {
case BHND_NVRAM_DT_UINT: return "uint";
case BHND_NVRAM_DT_SINT: return "sint";
case BHND_NVRAM_DT_MAC48: return "mac48";
case BHND_NVRAM_DT_LEDDC: return "led";
case BHND_NVRAM_DT_CCODE: return "cc";
}
}
static const char *sfmtstr (bhnd_nvram_sfmt sfmt) {
switch (sfmt) {
case BHND_NVRAM_SFMT_HEX: return "hex";
case BHND_NVRAM_SFMT_SDEC: return "sdec";
case BHND_NVRAM_SFMT_MACADDR: return "macaddr";
case BHND_NVRAM_SFMT_ASCII: return "ascii";
}
}
class Extractor {
private:
PLClangSourceIndex *idx;
PLClangTranslationUnit *tu;
NSDictionary *api;
/**
* Coalesce unnecessary continuations in nvars
*/
shared_ptr<vector<nvar>> coalesce (shared_ptr<vector<nvar>> &nvars) {
auto clean_nvars = make_shared<vector<nvar>>();
for (size_t i = 0; i < nvars->size(); i++) {
const nvar &n = (*nvars)[i];
std::string name = n.name.UTF8String;
uint32_t flags = n.flags;
uint16_t offset = n.byte_off();
size_t width = n.width();
uint32_t valmask = n.valmask;
/* Unify unnecessary continuations */
const nvar *c = &n;
while (c->flags & SRFL_MORE) {
i++;
c = &(*nvars)[i];
/* Can't unify sparse continuations */
if (c->byte_off() != offset + width) {
warnx("%s: sparse continuation (%zx, %hu, %zu)", name.c_str(), c->byte_off(), offset, width);
i--;
break;
}
if (c->revmask != 0 && c->revmask != n.revmask)
errx(EXIT_FAILURE, "%s: continuation has non-matching revmask", name.c_str());
if (c->valmask != 0xFFFF)
errx(EXIT_FAILURE, "%s: unsupported valmask", name.c_str());
width += c->width();
valmask <<= c->width()*8;
valmask |= c->valmask;
flags &= ~SRFL_MORE;
}
clean_nvars->emplace_back(n.name, n.revmask, flags, n.off, valmask);
}
return clean_nvars;
}
/* Return the cursors composing the given array's initializers */
NSArray *get_array_inits (PLClangCursor *tbl) {
NSMutableArray *result = [NSMutableArray array];
[tbl visitChildrenUsingBlock:^PLClangCursorVisitResult(PLClangCursor *cursor) {
if (cursor.kind != PLClangCursorKindInitializerListExpression)
return PLClangCursorVisitContinue;
[cursor visitChildrenUsingBlock: ^PLClangCursorVisitResult(PLClangCursor *cursor) {
if (cursor.kind == PLClangCursorKindInitializerListExpression)
[result addObject: cursor];
return PLClangCursorVisitContinue;
}];
return PLClangCursorVisitContinue;
}];
return result;
}
shared_ptr<vector<nvar>> extract_nvars (NSString *symbol) {
auto nvars = std::make_shared<std::vector<nvar>>();
/* Fetch all sromvars */
PLClangCursor *tbl = api[symbol];
if (tbl == nil)
errx(EXIT_FAILURE, "missing %s", symbol.UTF8String);
for (PLClangCursor *init in get_array_inits(tbl)) {
nvar n;
if (extract_struct(tu, init, &n))
nvars->push_back(n);
}
/* Coalesce continuations */
return coalesce(nvars);
}
NSArray *get_tokens (PLClangCursor *cursor) {
return [tu tokensForSourceRange: cursor.extent];
}
int _depth = 0;
int dprintf(const char *fmt, ...) {
va_list vap;
for (int i = 0; i < _depth; i++)
printf("\t");
va_start(vap, fmt);
int r = vprintf(fmt, vap);
va_end(vap);
return r;
}
void output_vars (const vector<shared_ptr<bhnd_nvram_var>> &vars) {
for (const auto &v : vars) {
if (v->flags & BHND_NVRAM_VF_MFGINT)
printf("private ");
dprintf("%s %s", dtstr(v->type), v->name.c_str());
if (v->flags & BHND_NVRAM_VF_ARRAY)
printf("[]");
printf(" {\n");
_depth++;
if (v->fmt != BHND_NVRAM_SFMT_HEX)
dprintf("sfmt\t%s\n", sfmtstr(v->fmt));
if (v->flags & BHND_NVRAM_VF_IGNALL1)
dprintf("all1\tignore\n");
for (const auto &t : v->sprom_descs) {
dprintf("revs ");
if (t.compat.last == BHND_SPROMREV_MAX)
printf(">= %u", t.compat.first);
else if (t.compat.first == t.compat.last)
printf("%u", t.compat.first);
else
printf("%u-%u", t.compat.first, t.compat.last);
size_t vlines = 0;
for (const auto &val : t.values) {
for (__unused const auto &seg : val.segs) {
vlines++;
}
}
if (vlines <= 1) {
printf("\t{ ");
} else {
printf(" {\n");
_depth++;
}
size_t vali = 0;
for (const auto &val : t.values) {
for (size_t i = 0; i < val.segs.size(); i++) {
const auto &seg = val.segs[i];
if (vlines > 1)
dprintf("");
printf("%s 0x%04zX", seg.width_str(), seg.offset);
if (!seg.has_defaults()) {
printf(" (");
if (!seg.has_default_mask()) {
printf("&0x%X", seg.mask);
if (!seg.has_default_shift())
printf(", ");
}
if (!seg.has_default_shift()) {
if (seg.shift < 0)
printf("<<%zu", -seg.shift);
else
printf(">>%zu", seg.shift);
}
printf(")");
}
if (i+1 != val.segs.size())
printf(" |\n");
else if (vlines > 1 && vali+1 != t.values.size())
printf(",\n");
}
vali++;
}
if (vlines <= 1)
printf(" }\n");
else {
printf("\n");
_depth--;
dprintf("}\n");
}
}
_depth--;
dprintf("}\n\n");
}
}
vector<shared_ptr<bhnd_nvram_var>> convert_nvars (shared_ptr<vector<nvar>> &nvars) {
unordered_map<string, shared_ptr<bhnd_nvram_var>> var_table;
vector<shared_ptr<bhnd_nvram_var>> vars;
unordered_set<string> consts;
for (size_t i = 0; i < nvars->size(); i++) {
nvar *n = &(*nvars)[i];
/* Record symbolic constants that we'll need to preserve */
auto refconst = n->off.referenced_constants();
for (const auto &rc : refconst) {
if (consts.count(rc) == 0)
consts.insert(rc);
}
std::string name = n->name.UTF8String;
uint32_t revmask = n->revmask;
uint32_t flags = n->flags;
if (name.length() == 0)
errx(EXIT_FAILURE, "variable has zero-length name");
/* Generate the basic bhnd_nvram_var record */
auto v = std::make_shared<bhnd_nvram_var>();
v->name = name;
/* Determine fmt and type */
if (flags & SRFL_CCODE) {
v->type = BHND_NVRAM_DT_CCODE;
v->fmt = BHND_NVRAM_SFMT_ASCII;
} else if (flags & SRFL_ETHADDR) {
v->type = BHND_NVRAM_DT_MAC48;
v->fmt = BHND_NVRAM_SFMT_MACADDR;
} else if (flags & SRFL_LEDDC) {
v->type = BHND_NVRAM_DT_LEDDC;
v->fmt = BHND_NVRAM_SFMT_HEX;
} else if (flags & SRFL_PRSIGN) {
v->type = BHND_NVRAM_DT_SINT;
v->fmt = BHND_NVRAM_SFMT_SDEC;
} else if (flags & SRFL_PRHEX) {
v->type = BHND_NVRAM_DT_UINT;
v->fmt = BHND_NVRAM_SFMT_HEX;
} else {
/* Default behavior */
v->type = BHND_NVRAM_DT_UINT;
v->fmt = BHND_NVRAM_SFMT_HEX;
}
/* Apply flags */
v->flags = 0;
if (flags & SRFL_NOFFS)
v->flags |= BHND_NVRAM_VF_IGNALL1;
if (flags & SRFL_ARRAY)
v->flags |= BHND_NVRAM_VF_ARRAY;
if (flags & SRFL_NOVAR)
v->flags |= BHND_NVRAM_VF_MFGINT;
/* Compare against previous variable with this name, or
* register the new variable */
if (var_table.count(name) == 0) {
vars.push_back(v);
var_table.insert({name, v});
} else {
auto orig = var_table.at(name);
if (orig->type != v->type)
errx(EXIT_FAILURE, "%s: type mismatch (%u vs %u)", name.c_str(), orig->type, v->type);
if (orig->fmt != v->fmt)
errx(EXIT_FAILURE, "fmt mismatch");
if (orig->flags != v->flags) {
/* VF_ARRAY mismatch is OK, but nothing else is */
if ((orig->flags & ~BHND_NVRAM_VF_ARRAY) != (v->flags & ~BHND_NVRAM_VF_ARRAY))
errx(EXIT_FAILURE, "%s: flag mismatch (0x%X vs. 0x%X)", name.c_str(), orig->flags, v->flags);
/* Promote to an array */
orig->flags |= BHND_NVRAM_VF_ARRAY;
}
v = orig;
}
/* Handle array/sparse continuation records */
std::vector<bhnd_sprom_value> vals;
bhnd_sprom_value base_val;
bhnd_sprom_vseg base_seg = {
n->byte_off(),
n->width(),
n->valmask,
static_cast<ssize_t>(__builtin_ctz(n->valmask))
};
base_val.segs.push_back(base_seg);
size_t more_width = n->width();
while (n->flags & SRFL_MORE) {
i++;
n = &(*nvars)[i];
base_val.segs.push_back({
n->byte_off(),
n->width(),
n->valmask,
static_cast<ssize_t>(__builtin_ctz(n->valmask) - (more_width * 8))
});
more_width += n->width();
}
vals.push_back(base_val);
while (n->flags & SRFL_ARRAY) {
bhnd_sprom_value val;
i++;
n = &(*nvars)[i];
val.segs.push_back({
n->byte_off(),
n->width(),
n->valmask,
static_cast<ssize_t>(__builtin_ctz(n->valmask))
});
more_width = n->width();
while (n->flags & SRFL_MORE) {
i++;
n = &(*nvars)[i];
val.segs.push_back({
n->byte_off(),
n->width(),
n->valmask,
static_cast<ssize_t>(__builtin_ctz(n->valmask) - (more_width * 8))
});
more_width += n->width();
}
vals.push_back(val);
}
int ctz = __builtin_ctz(revmask);
uint16_t first_ver = (1UL << ctz);
uint16_t last_ver = revmask | (((~revmask) << (sizeof(revmask)*8 - ctz)) >> (sizeof(revmask)*8 - ctz));
v->sprom_descs.push_back({{first_ver, last_ver}, vals});
}
return vars;
}
public:
Extractor(int argc, char * const argv[]) {
NSError *error;
NSString *input;
int optchar;
static struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
while ((optchar = getopt_long(argc, argv, "h", longopts, NULL)) != -1) {
switch (optchar) {
case 'h':
// TODO
break;
case 'i':
input = @(optarg);
break;
default:
fprintf(stderr, "unhandled option -%c\n", optchar);
break;
}
}
argc -= optind;
argv += optind;
auto args = [NSMutableArray array];
for (u_int i = 0; i < argc; i++) {
[args addObject: @(argv[i])];
}
idx = [PLClangSourceIndex indexWithOptions: PLClangIndexCreationDisplayDiagnostics];
tu = [idx addTranslationUnitWithSourcePath: input
compilerArguments: args
options: PLClangTranslationUnitCreationDetailedPreprocessingRecord
error:&error];
if (tu == nil)
errx(EXIT_FAILURE, "%s", error.description.UTF8String);
if (tu.didFail)
errx(EXIT_FAILURE, "parse failed");
/* Map symbol names to their definitions */
auto symbols = [NSMutableDictionary dictionary];
[tu.cursor visitChildrenUsingBlock:^PLClangCursorVisitResult(PLClangCursor *cursor) {
if (cursor.location.isInSystemHeader || cursor.location.path == nil)
return PLClangCursorVisitContinue;
if (cursor.displayName.length == 0)
return PLClangCursorVisitContinue;
if (cursor.isReference)
return PLClangCursorVisitContinue;
symbols[cursor.displayName] = cursor;
switch (cursor.kind) {
case PLClangCursorKindObjCInterfaceDeclaration:
case PLClangCursorKindObjCCategoryDeclaration:
case PLClangCursorKindObjCProtocolDeclaration:
case PLClangCursorKindEnumDeclaration:
return PLClangCursorVisitRecurse;
default:
break;
}
return PLClangCursorVisitContinue;
}];
api = symbols;
/* Output all PCI sromvars */
auto nvars = extract_nvars(@"pci_sromvars");
auto vars = convert_nvars(nvars);
output_vars(vars);
/* Output the per-path vars */
auto path_nvars = extract_nvars(@"perpath_pci_sromvars");
auto path_vars = convert_nvars(path_nvars);
struct pathcfg {
NSString *path_pfx;
NSString *path_num;
const char *revdesc;
} pathcfgs[] = {
{ @"SROM4_PATH", @"MAX_PATH_SROM", "revs 4-7" },
{ @"SROM8_PATH", @"MAX_PATH_SROM", "revs 8-10" },
{ @"SROM11_PATH", @"MAX_PATH_SROM_11", "revs >= 11" },
{ nil, nil }
};
printf("#\n"
"# Any variables defined within a `struct` block will be interpreted relative to\n"
"# the provided array of SPROM base addresses; this is used to define\n"
"# a common layout defined at the given base addresses.\n"
"#\n"
"# To produce SPROM variable names matching those used in the Broadcom HND\n"
"# ASCII 'key=value\\0' NVRAM, the index number of the variable's\n"
"# struct instance will be appended (e.g., given a variable of noiselvl5ga, the\n"
"# generated variable instances will be named noiselvl5ga0, noiselvl5ga1,\n"
"# noiselvl5ga2, noiselvl5ga3 ...)\n"
"#\n");
printf("struct pathvars[] {\n");
_depth++;
for (auto cfg = pathcfgs; cfg->path_pfx != nil; cfg++) {
PLClangCursor *maxCursor = api[cfg->path_num];
if (maxCursor == nil)
errx(EXIT_FAILURE, "missing %s", cfg->path_num.UTF8String);
uint32_t max = compute_literal_u32(tu, get_tokens(maxCursor));
dprintf("%s\t[", cfg->revdesc);
for (uint32_t i = 0; i < max; i++) {
NSString *path = [NSString stringWithFormat: @"%@%u", cfg->path_pfx, i];
PLClangCursor *c = api[path];
if (c == nil)
errx(EXIT_FAILURE, "missing %s", path.UTF8String);
uint32_t offset = compute_literal_u32(tu, get_tokens(c));
printf("0x%04zX", offset*sizeof(uint16_t));
if (i+1 != max)
printf(", ");
}
printf("]\n");
}
printf("\n");
output_vars(path_vars);
_depth--;
dprintf("}\n");
#if 0
auto path_nvars = generate_path_vars();
nvars->reserve(nvars->size() + path_nvars->size());
nvars->insert(nvars->end(), path_nvars->begin(), path_nvars->end());
sort(vars.begin(), vars.end(), [](const shared_ptr<bhnd_nvram_var> &lhs, const shared_ptr<bhnd_nvram_var> &rhs) {
return *lhs < *rhs;
});
#endif
}
};
int
main (int argc, char * const argv[])
{
@autoreleasepool {
Extractor(argc, argv);
return (0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment