summaryrefslogtreecommitdiff
path: root/read_config_file.c
diff options
context:
space:
mode:
authorAnas Nashif <anas.nashif@intel.com>2012-11-13 07:28:12 -0800
committerAnas Nashif <anas.nashif@intel.com>2012-11-13 07:28:12 -0800
commit59749d048d9e452f049f9151735b5256756919c3 (patch)
tree9b0935c93a3b028fd1dd35a2c632510743e7826f /read_config_file.c
downloadltrace-59749d048d9e452f049f9151735b5256756919c3.tar.gz
ltrace-59749d048d9e452f049f9151735b5256756919c3.tar.bz2
ltrace-59749d048d9e452f049f9151735b5256756919c3.zip
Imported Upstream version 0.5.3upstream/0.5.3
Diffstat (limited to 'read_config_file.c')
-rw-r--r--read_config_file.c680
1 files changed, 680 insertions, 0 deletions
diff --git a/read_config_file.c b/read_config_file.c
new file mode 100644
index 0000000..b4b1b56
--- /dev/null
+++ b/read_config_file.c
@@ -0,0 +1,680 @@
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "common.h"
+
+static int line_no;
+static char *filename;
+static int error_count = 0;
+
+static arg_type_info *parse_type(char **str);
+
+Function *list_of_functions = NULL;
+
+/* Map of strings to type names. These do not need to be in any
+ * particular order */
+static struct list_of_pt_t {
+ char *name;
+ enum arg_type pt;
+} list_of_pt[] = {
+ {
+ "void", ARGTYPE_VOID}, {
+ "int", ARGTYPE_INT}, {
+ "uint", ARGTYPE_UINT}, {
+ "long", ARGTYPE_LONG}, {
+ "ulong", ARGTYPE_ULONG}, {
+ "octal", ARGTYPE_OCTAL}, {
+ "char", ARGTYPE_CHAR}, {
+ "short", ARGTYPE_SHORT}, {
+ "ushort", ARGTYPE_USHORT}, {
+ "float", ARGTYPE_FLOAT}, {
+ "double", ARGTYPE_DOUBLE}, {
+ "addr", ARGTYPE_ADDR}, {
+ "file", ARGTYPE_FILE}, {
+ "format", ARGTYPE_FORMAT}, {
+ "string", ARGTYPE_STRING}, {
+ "array", ARGTYPE_ARRAY}, {
+ "struct", ARGTYPE_STRUCT}, {
+ "enum", ARGTYPE_ENUM}, {
+ NULL, ARGTYPE_UNKNOWN} /* Must finish with NULL */
+};
+
+/* Array of prototype objects for each of the types. The order in this
+ * array must exactly match the list of enumerated values in
+ * common.h */
+static arg_type_info arg_type_prototypes[] = {
+ { ARGTYPE_VOID },
+ { ARGTYPE_INT },
+ { ARGTYPE_UINT },
+ { ARGTYPE_LONG },
+ { ARGTYPE_ULONG },
+ { ARGTYPE_OCTAL },
+ { ARGTYPE_CHAR },
+ { ARGTYPE_SHORT },
+ { ARGTYPE_USHORT },
+ { ARGTYPE_FLOAT },
+ { ARGTYPE_DOUBLE },
+ { ARGTYPE_ADDR },
+ { ARGTYPE_FILE },
+ { ARGTYPE_FORMAT },
+ { ARGTYPE_STRING },
+ { ARGTYPE_STRING_N },
+ { ARGTYPE_ARRAY },
+ { ARGTYPE_ENUM },
+ { ARGTYPE_STRUCT },
+ { ARGTYPE_POINTER },
+ { ARGTYPE_UNKNOWN }
+};
+
+arg_type_info *
+lookup_prototype(enum arg_type at) {
+ if (at >= 0 && at <= ARGTYPE_COUNT)
+ return &arg_type_prototypes[at];
+ else
+ return &arg_type_prototypes[ARGTYPE_COUNT]; /* UNKNOWN */
+}
+
+static arg_type_info *
+str2type(char **str) {
+ struct list_of_pt_t *tmp = &list_of_pt[0];
+
+ while (tmp->name) {
+ if (!strncmp(*str, tmp->name, strlen(tmp->name))
+ && index(" ,()#*;012345[", *(*str + strlen(tmp->name)))) {
+ *str += strlen(tmp->name);
+ return lookup_prototype(tmp->pt);
+ }
+ tmp++;
+ }
+ return lookup_prototype(ARGTYPE_UNKNOWN);
+}
+
+static void
+eat_spaces(char **str) {
+ while (**str == ' ') {
+ (*str)++;
+ }
+}
+
+static char *
+xstrndup(char *str, size_t len) {
+ char *ret = (char *) malloc(len + 1);
+ strncpy(ret, str, len);
+ ret[len] = 0;
+ return ret;
+}
+
+static char *
+parse_ident(char **str) {
+ char *ident = *str;
+
+ if (!isalnum(**str) && **str != '_') {
+ output_line(0, "Syntax error in `%s', line %d: Bad identifier",
+ filename, line_no);
+ error_count++;
+ return NULL;
+ }
+
+ while (**str && (isalnum(**str) || **str == '_')) {
+ ++(*str);
+ }
+
+ return xstrndup(ident, *str - ident);
+}
+
+/*
+ Returns position in string at the left parenthesis which starts the
+ function's argument signature. Returns NULL on error.
+*/
+static char *
+start_of_arg_sig(char *str) {
+ char *pos;
+ int stacked = 0;
+
+ if (!strlen(str))
+ return NULL;
+
+ pos = &str[strlen(str)];
+ do {
+ pos--;
+ if (pos < str)
+ return NULL;
+ while ((pos > str) && (*pos != ')') && (*pos != '('))
+ pos--;
+
+ if (*pos == ')')
+ stacked++;
+ else if (*pos == '(')
+ stacked--;
+ else
+ return NULL;
+
+ } while (stacked > 0);
+
+ return (stacked == 0) ? pos : NULL;
+}
+
+static int
+parse_int(char **str) {
+ char *end;
+ long n = strtol(*str, &end, 0);
+ if (end == *str) {
+ output_line(0, "Syntax error in `%s', line %d: Bad number (%s)",
+ filename, line_no, *str);
+ error_count++;
+ return 0;
+ }
+
+ *str = end;
+ return n;
+}
+
+/*
+ * Input:
+ * argN : The value of argument #N, counting from 1 (arg0 = retval)
+ * eltN : The value of element #N of the containing structure
+ * retval : The return value
+ * 0 : Error
+ * N : The numeric value N, if N > 0
+ *
+ * Output:
+ * > 0 actual numeric value
+ * = 0 return value
+ * < 0 (arg -n), counting from one
+ */
+static int
+parse_argnum(char **str) {
+ int multiplier = 1;
+ int n = 0;
+
+ if (strncmp(*str, "arg", 3) == 0) {
+ (*str) += 3;
+ multiplier = -1;
+ } else if (strncmp(*str, "elt", 3) == 0) {
+ (*str) += 3;
+ multiplier = -1;
+ } else if (strncmp(*str, "retval", 6) == 0) {
+ (*str) += 6;
+ return 0;
+ }
+
+ n = parse_int(str);
+
+ return n * multiplier;
+}
+
+struct typedef_node_t {
+ char *name;
+ arg_type_info *info;
+ struct typedef_node_t *next;
+} *typedefs = NULL;
+
+static arg_type_info *
+lookup_typedef(char **str) {
+ struct typedef_node_t *node;
+ char *end = *str;
+ while (*end && (isalnum(*end) || *end == '_'))
+ ++end;
+ if (end == *str)
+ return NULL;
+
+ for (node = typedefs; node != NULL; node = node->next) {
+ if (strncmp(*str, node->name, end - *str) == 0) {
+ (*str) += strlen(node->name);
+ return node->info;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+parse_typedef(char **str) {
+ char *name;
+ arg_type_info *info;
+ struct typedef_node_t *binding;
+
+ (*str) += strlen("typedef");
+ eat_spaces(str);
+
+ // Grab out the name of the type
+ name = parse_ident(str);
+
+ // Skip = sign
+ eat_spaces(str);
+ if (**str != '=') {
+ output_line(0,
+ "Syntax error in `%s', line %d: expected '=', got '%c'",
+ filename, line_no, **str);
+ error_count++;
+ return;
+ }
+ (*str)++;
+ eat_spaces(str);
+
+ // Parse the type
+ info = parse_type(str);
+
+ // Insert onto beginning of linked list
+ binding = malloc(sizeof(*binding));
+ binding->name = name;
+ binding->info = info;
+ binding->next = typedefs;
+ typedefs = binding;
+}
+
+static size_t
+arg_sizeof(arg_type_info * arg) {
+ if (arg->type == ARGTYPE_CHAR) {
+ return sizeof(char);
+ } else if (arg->type == ARGTYPE_SHORT || arg->type == ARGTYPE_USHORT) {
+ return sizeof(short);
+ } else if (arg->type == ARGTYPE_FLOAT) {
+ return sizeof(float);
+ } else if (arg->type == ARGTYPE_DOUBLE) {
+ return sizeof(double);
+ } else if (arg->type == ARGTYPE_ENUM) {
+ return sizeof(int);
+ } else if (arg->type == ARGTYPE_STRUCT) {
+ return arg->u.struct_info.size;
+ } else if (arg->type == ARGTYPE_POINTER) {
+ return sizeof(void*);
+ } else if (arg->type == ARGTYPE_ARRAY) {
+ if (arg->u.array_info.len_spec > 0)
+ return arg->u.array_info.len_spec * arg->u.array_info.elt_size;
+ else
+ return sizeof(void *);
+ } else {
+ return sizeof(int);
+ }
+}
+
+#undef alignof
+#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
+static size_t
+arg_align(arg_type_info * arg) {
+ struct { char c; char C; } cC;
+ struct { char c; short s; } cs;
+ struct { char c; int i; } ci;
+ struct { char c; long l; } cl;
+ struct { char c; void* p; } cp;
+ struct { char c; float f; } cf;
+ struct { char c; double d; } cd;
+
+ static size_t char_alignment = alignof(C, cC);
+ static size_t short_alignment = alignof(s, cs);
+ static size_t int_alignment = alignof(i, ci);
+ static size_t long_alignment = alignof(l, cl);
+ static size_t ptr_alignment = alignof(p, cp);
+ static size_t float_alignment = alignof(f, cf);
+ static size_t double_alignment = alignof(d, cd);
+
+ switch (arg->type) {
+ case ARGTYPE_LONG:
+ case ARGTYPE_ULONG:
+ return long_alignment;
+ case ARGTYPE_CHAR:
+ return char_alignment;
+ case ARGTYPE_SHORT:
+ case ARGTYPE_USHORT:
+ return short_alignment;
+ case ARGTYPE_FLOAT:
+ return float_alignment;
+ case ARGTYPE_DOUBLE:
+ return double_alignment;
+ case ARGTYPE_ADDR:
+ case ARGTYPE_FILE:
+ case ARGTYPE_FORMAT:
+ case ARGTYPE_STRING:
+ case ARGTYPE_STRING_N:
+ case ARGTYPE_POINTER:
+ return ptr_alignment;
+
+ case ARGTYPE_ARRAY:
+ return arg_align(&arg->u.array_info.elt_type[0]);
+
+ case ARGTYPE_STRUCT:
+ return arg_align(arg->u.struct_info.fields[0]);
+
+ default:
+ return int_alignment;
+ }
+}
+
+static size_t
+align_skip(size_t alignment, size_t offset) {
+ if (offset % alignment)
+ return alignment - (offset % alignment);
+ else
+ return 0;
+}
+
+/* I'm sure this isn't completely correct, but just try to get most of
+ * them right for now. */
+static void
+align_struct(arg_type_info* info) {
+ size_t offset;
+ int i;
+
+ if (info->u.struct_info.size != 0)
+ return; // Already done
+
+ // Compute internal padding due to alignment constraints for
+ // various types.
+ offset = 0;
+ for (i = 0; info->u.struct_info.fields[i] != NULL; i++) {
+ arg_type_info *field = info->u.struct_info.fields[i];
+ offset += align_skip(arg_align(field), offset);
+ info->u.struct_info.offset[i] = offset;
+ offset += arg_sizeof(field);
+ }
+
+ info->u.struct_info.size = offset;
+}
+
+static arg_type_info *
+parse_nonpointer_type(char **str) {
+ arg_type_info *simple;
+ arg_type_info *info;
+
+ if (strncmp(*str, "typedef", 7) == 0) {
+ parse_typedef(str);
+ return lookup_prototype(ARGTYPE_UNKNOWN);
+ }
+
+ simple = str2type(str);
+ if (simple->type == ARGTYPE_UNKNOWN) {
+ info = lookup_typedef(str);
+ if (info)
+ return info;
+ else
+ return simple; // UNKNOWN
+ }
+
+ info = malloc(sizeof(*info));
+ info->type = simple->type;
+
+ /* Code to parse parameterized types will go into the following
+ switch statement. */
+
+ switch (info->type) {
+
+ /* Syntax: array ( type, N|argN ) */
+ case ARGTYPE_ARRAY:
+ (*str)++; // Get past open paren
+ eat_spaces(str);
+ if ((info->u.array_info.elt_type = parse_type(str)) == NULL)
+ return NULL;
+ info->u.array_info.elt_size =
+ arg_sizeof(info->u.array_info.elt_type);
+ (*str)++; // Get past comma
+ eat_spaces(str);
+ info->u.array_info.len_spec = parse_argnum(str);
+ (*str)++; // Get past close paren
+ return info;
+
+ /* Syntax: enum ( keyname=value,keyname=value,... ) */
+ case ARGTYPE_ENUM:{
+ struct enum_opt {
+ char *key;
+ int value;
+ struct enum_opt *next;
+ };
+ struct enum_opt *list = NULL;
+ struct enum_opt *p;
+ int entries = 0;
+ int ii;
+
+ eat_spaces(str);
+ (*str)++; // Get past open paren
+ eat_spaces(str);
+
+ while (**str && **str != ')') {
+ p = (struct enum_opt *) malloc(sizeof(*p));
+ eat_spaces(str);
+ p->key = parse_ident(str);
+ if (error_count) {
+ free(p);
+ return NULL;
+ }
+ eat_spaces(str);
+ if (**str != '=') {
+ free(p->key);
+ free(p);
+ output_line(0,
+ "Syntax error in `%s', line %d: expected '=', got '%c'",
+ filename, line_no, **str);
+ error_count++;
+ return NULL;
+ }
+ ++(*str);
+ eat_spaces(str);
+ p->value = parse_int(str);
+ p->next = list;
+ list = p;
+ ++entries;
+
+ // Skip comma
+ eat_spaces(str);
+ if (**str == ',') {
+ (*str)++;
+ eat_spaces(str);
+ }
+ }
+
+ info->u.enum_info.entries = entries;
+ info->u.enum_info.keys =
+ (char **) malloc(entries * sizeof(char *));
+ info->u.enum_info.values =
+ (int *) malloc(entries * sizeof(int));
+ for (ii = 0, p = NULL; list; ++ii, list = list->next) {
+ if (p)
+ free(p);
+ info->u.enum_info.keys[ii] = list->key;
+ info->u.enum_info.values[ii] = list->value;
+ p = list;
+ }
+ if (p)
+ free(p);
+
+ return info;
+ }
+
+ case ARGTYPE_STRING:
+ if (!isdigit(**str) && **str != '[') {
+ /* Oops, was just a simple string after all */
+ free(info);
+ return simple;
+ }
+
+ info->type = ARGTYPE_STRING_N;
+
+ /* Backwards compatibility for string0, string1, ... */
+ if (isdigit(**str)) {
+ info->u.string_n_info.size_spec = -parse_int(str);
+ return info;
+ }
+
+ (*str)++; // Skip past opening [
+ eat_spaces(str);
+ info->u.string_n_info.size_spec = parse_argnum(str);
+ eat_spaces(str);
+ (*str)++; // Skip past closing ]
+ return info;
+
+ // Syntax: struct ( type,type,type,... )
+ case ARGTYPE_STRUCT:{
+ int field_num = 0;
+ (*str)++; // Get past open paren
+ info->u.struct_info.fields =
+ malloc((MAX_ARGS + 1) * sizeof(void *));
+ info->u.struct_info.offset =
+ malloc((MAX_ARGS + 1) * sizeof(size_t));
+ info->u.struct_info.size = 0;
+ eat_spaces(str); // Empty arg list with whitespace inside
+ while (**str && **str != ')') {
+ if (field_num == MAX_ARGS) {
+ output_line(0,
+ "Error in `%s', line %d: Too many structure elements",
+ filename, line_no);
+ error_count++;
+ return NULL;
+ }
+ eat_spaces(str);
+ if (field_num != 0) {
+ (*str)++; // Get past comma
+ eat_spaces(str);
+ }
+ if ((info->u.struct_info.fields[field_num++] =
+ parse_type(str)) == NULL)
+ return NULL;
+
+ // Must trim trailing spaces so the check for
+ // the closing paren is simple
+ eat_spaces(str);
+ }
+ (*str)++; // Get past closing paren
+ info->u.struct_info.fields[field_num] = NULL;
+ align_struct(info);
+ return info;
+ }
+
+ default:
+ if (info->type == ARGTYPE_UNKNOWN) {
+ output_line(0, "Syntax error in `%s', line %d: "
+ "Unknown type encountered",
+ filename, line_no);
+ free(info);
+ error_count++;
+ return NULL;
+ } else {
+ return info;
+ }
+ }
+}
+
+static arg_type_info *
+parse_type(char **str) {
+ arg_type_info *info = parse_nonpointer_type(str);
+ while (**str == '*') {
+ arg_type_info *outer = malloc(sizeof(*info));
+ outer->type = ARGTYPE_POINTER;
+ outer->u.ptr_info.info = info;
+ (*str)++;
+ info = outer;
+ }
+ return info;
+}
+
+static Function *
+process_line(char *buf) {
+ Function fun;
+ Function *fun_p;
+ char *str = buf;
+ char *tmp;
+ int i;
+ int float_num = 0;
+
+ line_no++;
+ debug(3, "Reading line %d of `%s'", line_no, filename);
+ eat_spaces(&str);
+ fun.return_info = parse_type(&str);
+ if (fun.return_info == NULL)
+ return NULL;
+ if (fun.return_info->type == ARGTYPE_UNKNOWN) {
+ debug(3, " Skipping line %d", line_no);
+ return NULL;
+ }
+ debug(4, " return_type = %d", fun.return_info->type);
+ eat_spaces(&str);
+ tmp = start_of_arg_sig(str);
+ if (!tmp) {
+ output_line(0, "Syntax error in `%s', line %d", filename,
+ line_no);
+ error_count++;
+ return NULL;
+ }
+ *tmp = '\0';
+ fun.name = strdup(str);
+ str = tmp + 1;
+ debug(3, " name = %s", fun.name);
+ fun.params_right = 0;
+ for (i = 0; i < MAX_ARGS; i++) {
+ eat_spaces(&str);
+ if (*str == ')') {
+ break;
+ }
+ if (str[0] == '+') {
+ fun.params_right++;
+ str++;
+ } else if (fun.params_right) {
+ fun.params_right++;
+ }
+ fun.arg_info[i] = parse_type(&str);
+ if (fun.arg_info[i] == NULL) {
+ output_line(0, "Syntax error in `%s', line %d"
+ ": unknown argument type",
+ filename, line_no);
+ error_count++;
+ return NULL;
+ }
+ if (fun.arg_info[i]->type == ARGTYPE_FLOAT)
+ fun.arg_info[i]->u.float_info.float_index = float_num++;
+ else if (fun.arg_info[i]->type == ARGTYPE_DOUBLE)
+ fun.arg_info[i]->u.double_info.float_index = float_num++;
+ eat_spaces(&str);
+ if (*str == ',') {
+ str++;
+ continue;
+ } else if (*str == ')') {
+ continue;
+ } else {
+ if (str[strlen(str) - 1] == '\n')
+ str[strlen(str) - 1] = '\0';
+ output_line(0, "Syntax error in `%s', line %d at ...\"%s\"",
+ filename, line_no, str);
+ error_count++;
+ return NULL;
+ }
+ }
+ fun.num_params = i;
+ fun_p = malloc(sizeof(Function));
+ if (!fun_p) {
+ perror("ltrace: malloc");
+ exit(1);
+ }
+ memcpy(fun_p, &fun, sizeof(Function));
+ return fun_p;
+}
+
+void
+read_config_file(char *file) {
+ FILE *stream;
+ char buf[1024];
+
+ filename = file;
+ stream = fopen(filename, "r");
+ if (!stream) {
+ return;
+ }
+
+ debug(1, "Reading config file `%s'...", filename);
+
+ line_no = 0;
+ while (fgets(buf, 1024, stream)) {
+ Function *tmp;
+
+ error_count = 0;
+ tmp = process_line(buf);
+
+ if (tmp) {
+ debug(2, "New function: `%s'", tmp->name);
+ tmp->next = list_of_functions;
+ list_of_functions = tmp;
+ }
+ }
+ fclose(stream);
+}