|
@@ -13,7 +13,10 @@
|
|
|
#include "talloc/talloc.h"
|
|
#include "talloc/talloc.h"
|
|
|
|
|
|
|
|
#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I. -Iccan_tools/libtap/src/"
|
|
#define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I. -Iccan_tools/libtap/src/"
|
|
|
-#define CFLAGS_HDR "-Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Werror -I."
|
|
|
|
|
|
|
+
|
|
|
|
|
+#define IDENT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
|
|
|
|
+ "abcdefghijklmnopqrstuvwxyz" \
|
|
|
|
|
+ "01234567889_"
|
|
|
|
|
|
|
|
static bool verbose = false;
|
|
static bool verbose = false;
|
|
|
static int indent = 0;
|
|
static int indent = 0;
|
|
@@ -166,20 +169,6 @@ lines_from_cmd(const void *ctx, char *format, ...)
|
|
|
return split(ctx, buffer, "\n", NULL);
|
|
return split(ctx, buffer, "\n", NULL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static char *build_obj(const char *cfile)
|
|
|
|
|
-{
|
|
|
|
|
- char *cmd;
|
|
|
|
|
- char *ofile = talloc_strdup(cfile, cfile);
|
|
|
|
|
-
|
|
|
|
|
- ofile[strlen(ofile)-1] = 'c';
|
|
|
|
|
-
|
|
|
|
|
- cmd = talloc_asprintf(ofile, "gcc " CFLAGS " -o %s -c %s",
|
|
|
|
|
- ofile, cfile);
|
|
|
|
|
- if (system(cmd) != 0)
|
|
|
|
|
- errx(1, "Failed to compile %s", cfile);
|
|
|
|
|
- return ofile;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
struct replace
|
|
struct replace
|
|
|
{
|
|
{
|
|
|
struct replace *next;
|
|
struct replace *next;
|
|
@@ -200,11 +189,12 @@ static void __attribute__((noreturn)) usage(void)
|
|
|
|
|
|
|
|
static void add_replace(struct replace **repl, const char *str)
|
|
static void add_replace(struct replace **repl, const char *str)
|
|
|
{
|
|
{
|
|
|
- struct replace *new;
|
|
|
|
|
|
|
+ struct replace *new, *i;
|
|
|
|
|
|
|
|
- /* Don't replace things already CCAN-ized (eg. idempotent wrappers) */
|
|
|
|
|
- if (strstarts(str, "CCAN_") || strstarts(str, "ccan_"))
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ /* Avoid duplicates. */
|
|
|
|
|
+ for (i = *repl; i; i = i->next)
|
|
|
|
|
+ if (streq(i->string, str))
|
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
new = talloc(*repl, struct replace);
|
|
new = talloc(*repl, struct replace);
|
|
|
new->next = *repl;
|
|
new->next = *repl;
|
|
@@ -212,6 +202,17 @@ static void add_replace(struct replace **repl, const char *str)
|
|
|
*repl = new;
|
|
*repl = new;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void add_replace_tok(struct replace **repl, const char *s)
|
|
|
|
|
+{
|
|
|
|
|
+ struct replace *new;
|
|
|
|
|
+ unsigned int len = strspn(s, IDENT_CHARS);
|
|
|
|
|
+
|
|
|
|
|
+ new = talloc(*repl, struct replace);
|
|
|
|
|
+ new->next = *repl;
|
|
|
|
|
+ new->string = talloc_strndup(new, s, len);
|
|
|
|
|
+ *repl = new;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static char *basename(const void *ctx, const char *dir)
|
|
static char *basename(const void *ctx, const char *dir)
|
|
|
{
|
|
{
|
|
|
char *p = strrchr(dir, '/');
|
|
char *p = strrchr(dir, '/');
|
|
@@ -221,20 +222,11 @@ static char *basename(const void *ctx, const char *dir)
|
|
|
return talloc_strdup(ctx, p+1);
|
|
return talloc_strdup(ctx, p+1);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* FIXME: Only does main header, should chase local includes. */
|
|
|
|
|
-static void analyze_headers(const char *dir, struct replace **repl)
|
|
|
|
|
|
|
+static void look_for_macros(char *contents, struct replace **repl)
|
|
|
{
|
|
{
|
|
|
- char *hdr, *contents, *p;
|
|
|
|
|
|
|
+ char *p;
|
|
|
enum { LINESTART, HASH, DEFINE, NONE } state = LINESTART;
|
|
enum { LINESTART, HASH, DEFINE, NONE } state = LINESTART;
|
|
|
|
|
|
|
|
- /* Get hold of header, assume that's it. */
|
|
|
|
|
- hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir));
|
|
|
|
|
- contents = grab_file(dir, hdr);
|
|
|
|
|
- if (!contents)
|
|
|
|
|
- err(1, "Reading %s", hdr);
|
|
|
|
|
-
|
|
|
|
|
- verbose("Looking in %s\n", hdr);
|
|
|
|
|
- verbose_indent();
|
|
|
|
|
/* Look for lines of form #define X */
|
|
/* Look for lines of form #define X */
|
|
|
for (p = contents; *p; p++) {
|
|
for (p = contents; *p; p++) {
|
|
|
if (*p == '\n')
|
|
if (*p == '\n')
|
|
@@ -248,79 +240,160 @@ static void analyze_headers(const char *dir, struct replace **repl)
|
|
|
} else if (state == DEFINE) {
|
|
} else if (state == DEFINE) {
|
|
|
unsigned int len;
|
|
unsigned int len;
|
|
|
|
|
|
|
|
- len = strspn(p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
- "abcdefghijklmnopqrstuvwxyz"
|
|
|
|
|
- "01234567889_");
|
|
|
|
|
|
|
+ len = strspn(p, IDENT_CHARS);
|
|
|
if (len) {
|
|
if (len) {
|
|
|
char *s;
|
|
char *s;
|
|
|
s = talloc_strndup(contents, p, len);
|
|
s = talloc_strndup(contents, p, len);
|
|
|
- verbose("Found %s\n", s);
|
|
|
|
|
- add_replace(repl, s);
|
|
|
|
|
|
|
+ /* Don't wrap idempotent wrappers */
|
|
|
|
|
+ if (!strstarts(s, "CCAN_")) {
|
|
|
|
|
+ verbose("Found %s\n", s);
|
|
|
|
|
+ add_replace(repl, s);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
state = NONE;
|
|
state = NONE;
|
|
|
} else
|
|
} else
|
|
|
state = NONE;
|
|
state = NONE;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- verbose_unindent();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void add_extern_symbols(const char *ofile, struct replace **repl)
|
|
|
|
|
|
|
+/* Blank out preprocessor lines, and eliminate \ */
|
|
|
|
|
+static void preprocess(char *p)
|
|
|
{
|
|
{
|
|
|
- /* Should actually read the elf: this is a hack. */
|
|
|
|
|
- char **line;
|
|
|
|
|
|
|
+ char *s;
|
|
|
|
|
|
|
|
- line = lines_from_cmd(ofile, "nm --defined-only --extern %s", ofile);
|
|
|
|
|
|
|
+ /* We assume backslashes are only used for macros. */
|
|
|
|
|
+ while ((s = strstr(p, "\\\n")) != NULL)
|
|
|
|
|
+ s[0] = s[1] = ' ';
|
|
|
|
|
|
|
|
- /* nm output is of form [hexaddr] [char] [name]\n */
|
|
|
|
|
- for (; *line; line++) {
|
|
|
|
|
- unsigned int cols;
|
|
|
|
|
- char **names = split(ofile, *line, " \t", &cols);
|
|
|
|
|
- if (cols != 3)
|
|
|
|
|
- errx(1, "Unexpected nm line '%s' (%i cols)", *line, cols);
|
|
|
|
|
|
|
+ /* Now eliminate # lines. */
|
|
|
|
|
+ if (p[0] == '#') {
|
|
|
|
|
+ unsigned int i;
|
|
|
|
|
+ for (i = 0; p[i] != '\n'; i++)
|
|
|
|
|
+ p[i] = ' ';
|
|
|
|
|
+ }
|
|
|
|
|
+ while ((s = strstr(p, "\n#")) != NULL) {
|
|
|
|
|
+ unsigned int i;
|
|
|
|
|
+ for (i = 1; s[i] != '\n'; i++)
|
|
|
|
|
+ s[i] = ' ';
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- verbose("Found %s\n", names[2]);
|
|
|
|
|
- add_replace(repl, names[2]);
|
|
|
|
|
|
|
+static char *get_statement(const void *ctx, char **p)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned brackets = 0;
|
|
|
|
|
+ bool seen_brackets = false;
|
|
|
|
|
+ char *answer = talloc_strdup(ctx, "");
|
|
|
|
|
+
|
|
|
|
|
+ for (;;) {
|
|
|
|
|
+ if ((*p)[0] == '/' && (*p)[1] == '/')
|
|
|
|
|
+ *p += strcspn(*p, "\n");
|
|
|
|
|
+ else if ((*p)[0] == '/' && (*p)[1] == '*')
|
|
|
|
|
+ *p = strstr(*p, "*/") + 1;
|
|
|
|
|
+ else {
|
|
|
|
|
+ char c = **p;
|
|
|
|
|
+ if (c == ';' && !brackets) {
|
|
|
|
|
+ (*p)++;
|
|
|
|
|
+ return answer;
|
|
|
|
|
+ }
|
|
|
|
|
+ /* Compress whitespace into a single ' ' */
|
|
|
|
|
+ if (isspace(c)) {
|
|
|
|
|
+ c = ' ';
|
|
|
|
|
+ while (isspace((*p)[1]))
|
|
|
|
|
+ (*p)++;
|
|
|
|
|
+ } else if (c == '{' || c == '(' || c == '[') {
|
|
|
|
|
+ if (c == '(')
|
|
|
|
|
+ seen_brackets = true;
|
|
|
|
|
+ brackets++;
|
|
|
|
|
+ } else if (c == '}' || c == ')' || c == ']')
|
|
|
|
|
+ brackets--;
|
|
|
|
|
+
|
|
|
|
|
+ if (answer[0] != '\0' || c != ' ') {
|
|
|
|
|
+ answer = talloc_realloc(NULL, answer, char,
|
|
|
|
|
+ strlen(answer) + 2);
|
|
|
|
|
+ answer[strlen(answer)+1] = '\0';
|
|
|
|
|
+ answer[strlen(answer)] = c;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (c == '}' && seen_brackets && brackets == 0) {
|
|
|
|
|
+ (*p)++;
|
|
|
|
|
+ return answer;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ (*p)++;
|
|
|
|
|
+ if (**p == '\0')
|
|
|
|
|
+ return NULL;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void get_header_symbols(const char *dir, struct replace **repl)
|
|
|
|
|
|
|
+/* This hack should handle well-formatted code. */
|
|
|
|
|
+static void look_for_definitions(char *contents, struct replace **repl)
|
|
|
{
|
|
{
|
|
|
- char *cmd;
|
|
|
|
|
- char *hfile = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir));
|
|
|
|
|
- char *ofile = talloc_asprintf(dir, "%s.o", hfile);
|
|
|
|
|
|
|
+ char *stmt, *p = contents;
|
|
|
|
|
|
|
|
- /* Horrible hack to get static inlines. */
|
|
|
|
|
- cmd = talloc_asprintf(dir, "gcc " CFLAGS_HDR
|
|
|
|
|
- " -Dstatic= -include %s -o %s -c -x c /dev/null",
|
|
|
|
|
- hfile, ofile);
|
|
|
|
|
- if (system(cmd) != 0)
|
|
|
|
|
- errx(1, "Failed to compile %s", hfile);
|
|
|
|
|
|
|
+ preprocess(contents);
|
|
|
|
|
|
|
|
- add_extern_symbols(ofile, repl);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ while ((stmt = get_statement(contents, &p)) != NULL) {
|
|
|
|
|
+ int i, len;
|
|
|
|
|
|
|
|
-/* FIXME: Better to analyse headers in more depth, rather than recompile. */
|
|
|
|
|
-static void get_exposed_symbols(const char *dir, struct replace **repl)
|
|
|
|
|
-{
|
|
|
|
|
- char **files;
|
|
|
|
|
- unsigned int i;
|
|
|
|
|
|
|
+ /* Definition of struct/union? */
|
|
|
|
|
+ if ((strncmp(stmt, "struct", 5) == 0
|
|
|
|
|
+ || strncmp(stmt, "union", 5) == 0)
|
|
|
|
|
+ && strchr(stmt, '{') && stmt[7] != '{')
|
|
|
|
|
+ add_replace_tok(repl, stmt+7);
|
|
|
|
|
|
|
|
- files = get_dir(dir);
|
|
|
|
|
- for (i = 0; files[i]; i++) {
|
|
|
|
|
- char *ofile;
|
|
|
|
|
- if (!strends(files[i], ".c") || strends(files[i], "/_info.c"))
|
|
|
|
|
|
|
+ /* Definition of var or typedef? */
|
|
|
|
|
+ for (i = strlen(stmt)-1; i >= 0; i--)
|
|
|
|
|
+ if (strspn(stmt+i, IDENT_CHARS) == 0)
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ if (i != strlen(stmt)-1) {
|
|
|
|
|
+ add_replace_tok(repl, stmt+i+1);
|
|
|
continue;
|
|
continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /* This produces file.c -> file.o */
|
|
|
|
|
- ofile = build_obj(files[i]);
|
|
|
|
|
- verbose("Looking in %s\n", ofile);
|
|
|
|
|
- verbose_indent();
|
|
|
|
|
- add_extern_symbols(ofile, repl);
|
|
|
|
|
- unlink(ofile);
|
|
|
|
|
- verbose_unindent();
|
|
|
|
|
|
|
+ /* function or array declaration? */
|
|
|
|
|
+ len = strspn(stmt, IDENT_CHARS "* ");
|
|
|
|
|
+ if (len > 0 && (stmt[len] == '(' || stmt[len] == '[')) {
|
|
|
|
|
+ if (strspn(stmt + len + 1, IDENT_CHARS) != 0) {
|
|
|
|
|
+ for (i = len-1; i >= 0; i--)
|
|
|
|
|
+ if (strspn(stmt+i, IDENT_CHARS) == 0)
|
|
|
|
|
+ break;
|
|
|
|
|
+ if (i != len-1) {
|
|
|
|
|
+ add_replace_tok(repl, stmt+i+1);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ /* Pointer to function? */
|
|
|
|
|
+ len++;
|
|
|
|
|
+ len += strspn(stmt + len, " *");
|
|
|
|
|
+ i = strspn(stmt + len, IDENT_CHARS);
|
|
|
|
|
+ if (i > 0 && stmt[len + i] == ')')
|
|
|
|
|
+ add_replace_tok(repl, stmt+len);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- get_header_symbols(dir, repl);
|
|
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* FIXME: Only does main header, should chase local includes. */
|
|
|
|
|
+static void analyze_headers(const char *dir, struct replace **repl)
|
|
|
|
|
+{
|
|
|
|
|
+ char *hdr, *contents;
|
|
|
|
|
+
|
|
|
|
|
+ /* Get hold of header, assume that's it. */
|
|
|
|
|
+ hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir));
|
|
|
|
|
+ contents = grab_file(dir, hdr);
|
|
|
|
|
+ if (!contents)
|
|
|
|
|
+ err(1, "Reading %s", hdr);
|
|
|
|
|
+
|
|
|
|
|
+ verbose("Looking in %s for macros\n", hdr);
|
|
|
|
|
+ verbose_indent();
|
|
|
|
|
+ look_for_macros(contents, repl);
|
|
|
|
|
+ verbose_unindent();
|
|
|
|
|
+
|
|
|
|
|
+ verbose("Looking in %s for symbols\n", hdr);
|
|
|
|
|
+ verbose_indent();
|
|
|
|
|
+ look_for_definitions(contents, repl);
|
|
|
|
|
+ verbose_unindent();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void write_replacement_file(const char *dir, struct replace **repl)
|
|
static void write_replacement_file(const char *dir, struct replace **repl)
|
|
@@ -472,7 +545,6 @@ static void convert_dir(const char *dir)
|
|
|
name[strlen(name)-1] = '\0';
|
|
name[strlen(name)-1] = '\0';
|
|
|
|
|
|
|
|
analyze_headers(name, &replace);
|
|
analyze_headers(name, &replace);
|
|
|
- get_exposed_symbols(name, &replace);
|
|
|
|
|
write_replacement_file(name, &replace);
|
|
write_replacement_file(name, &replace);
|
|
|
setup_adjust_files(name, replace, &adj);
|
|
setup_adjust_files(name, replace, &adj);
|
|
|
rename_files(adj);
|
|
rename_files(adj);
|