wireshark/wiretap/ct-compile.c

488 lines
11 KiB
C

/* ct-compile.c
------------
Compile-time filter-compiler for Wiretap
*/
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "ct-compile.h"
#ifdef HAVE_GLIB10
#include "glib-new.h"
#endif
#define LINE_SIZE 1024
GHashTable *field_hash;
GHashTable *protocol_hash;
char *protocol_name = NULL;
int rt_iteration;
extern struct field_info working_field; /* in ct-grammar.y */
char *ftype_text[] = {
"NONE",
"BOOLEAN",
"ETHER",
"IPv4ADDR",
"UINT8",
"UINT16",
"UINT32",
"BYTE"
};
char *ctype_text[] = {
"NONE",
"ANDMASK",
"BYTECMP",
"EITHEROF"
};
static
int many_list_subtype(struct field_info *val);
/* Called by main() to initialize the global variables that ct-compile.c
* worries about. */
void compiler_init(void)
{
field_hash = g_hash_table_new(g_str_hash, g_str_equal);
protocol_hash = g_hash_table_new(g_str_hash, g_str_equal);
field_info_init(&working_field);
}
/* takes a pointer to a field_info struct that the parser built,
* makes a copy of the struct, and adds it to our list of fields */
void field_info_add(struct field_info *fi, char *protocol)
{
struct field_info *new_fi;
/* Make a duplicate of the field_info struct, destroying
* the pointers of the old struct in the process. */
new_fi = g_memdup(fi, sizeof(struct field_info));
new_fi->name = fi->name;
new_fi->short_name = fi->short_name;
new_fi->description = fi->description;
new_fi->many_list = fi->many_list;
new_fi->aliases = fi->aliases;
fi->name = NULL;
fi->short_name = NULL;
fi->description = NULL;
fi->many_list = NULL;
fi->aliases = NULL;
/* Find the parent */
new_fi->parent = g_hash_table_lookup(protocol_hash, protocol);
if (!new_fi)
g_print("Cannot find parent protocol %s for field %s\n",
protocol, new_fi->name);
g_hash_table_insert(field_hash, new_fi->name, new_fi);
g_print("field_info_add added %s (%s) \n\t"
"ftype=%s, off=%d, len=%d, val=%d, ctype=%s\n",
new_fi->name,
new_fi->description,
ftype_text[new_fi->field_type], new_fi->offset,
new_fi->length, new_fi->value,
ctype_text[new_fi->computation_type]);
}
/* initialize a field_info struct */
void field_info_init(struct field_info *fi)
{
/* put NULLs in the fields that field_info_zero assumes
* that a non-NULL value corresponds to allocated memory. */
fi->name = NULL;
fi->description = NULL;
fi->aliases = NULL;
fi->many_list = NULL;
field_info_zero(fi);
}
/* zero out the values of an existing field_info struct */
void field_info_zero(struct field_info *fi)
{
if (fi->name)
free(fi->name);
if (fi->short_name)
free(fi->short_name);
if (fi->description)
free(fi->description);
fi->field_type = 0;
fi->computation_type = CTYPE_NONE;
fi->offset = 0;
fi->length = 0;
fi->value = 0;
fi->parent = NULL;
if (fi->aliases)
g_slist_free(fi->aliases);
if (fi->many_list)
g_slist_free(fi->many_list);
fi->aliases = g_slist_alloc();
fi->many_list = g_slist_alloc();
}
void show_aliases(gpointer alias, gpointer field)
{
if (alias)
g_print("%s ", ((GString*)alias)->str);
}
/* add alias(es) to this field */
void field_info_add_alias(char *field_name, GSList *aliases)
{
struct field_info *fi;
fi = g_hash_table_lookup(field_hash, field_name);
if (!fi) {
g_print("Could not find field %s to alias.\n", field_name);
return;
}
g_slist_concat(fi->aliases, aliases);
g_print("(%s) added aliases: ", fi->name);
g_slist_foreach(fi->aliases, show_aliases, NULL);
g_print("\n");
}
/* Given a list of GStrings of field_names, return a list of field_info
* pointers */
GSList* field_info_list(GSList *field_names, char *protocol)
{
GSList *new_list;
char *protocol_dot;
protocol_dot = g_strjoin("", protocol, ".", NULL);
g_slist_foreach(field_names, field_info_list_func1, protocol_dot);
new_list = g_slist_alloc();
g_slist_foreach(field_names, field_info_list_func2, new_list);
return new_list;
}
void field_info_list_func1(gpointer node, gpointer protocol)
{
if(node)
g_string_prepend((GString*)node, (char*)protocol);
}
void field_info_list_func2(gpointer node, gpointer new_list)
{
if (node)
g_slist_append(new_list,
g_hash_table_lookup(field_hash,
((GString*)node)->str));
/* if (node)
g_print("info_list added %s\n", ((GString*)node)->str);*/
}
/* add a protocol to the hash */
void protocol_layer_add(char *name, char *description)
{
struct protocol_layer *new_pr;
new_pr = g_malloc(sizeof(struct protocol_layer));
new_pr->name = g_strdup(name);
new_pr->description = g_strdup(description);
g_hash_table_insert(protocol_hash, new_pr->name, new_pr);
g_print("protocol_layer_add added %s (%s)\n",
new_pr->name,
new_pr->description);
}
/* Creates rt-scanner.l from rt-scanner-skel.l */
void write_rt_lex(void)
{
char buf[LINE_SIZE];
FILE *in, *out;
if (!(in = fopen("rt-scanner-skel.l", "r"))) {
g_error("Could not open rt-scanner-skel.l for reading.");
exit(1);
}
if (!(out = fopen("rt-scanner.l", "w"))) {
g_error("Could not open rt-scanner.l for writing.");
exit(1);
}
while(fgets(buf, LINE_SIZE, in)) {
if (strcmp(buf, "/* ct-compile: lex tokens */\n") == 0) {
write_rt_lex_tokens(out);
continue;
}
else {
fprintf(out, "%s", buf);
}
}
fclose(in);
fclose(out);
}
void write_rt_lex_tokens(FILE *out)
{
g_hash_table_foreach(field_hash, rt_lex_tokens, out);
}
void rt_lex_tokens(gpointer key, gpointer value, gpointer out)
{
char *upcase;
if (!value) {
g_print("key %s has no value.\n", (char*)key);
return;
}
protocol_name = ((struct field_info*) value)->parent->name;
if (((struct field_info*) value)->aliases) {
g_slist_foreach(((struct field_info*) value)->aliases,
rt_lex_tokens_aliases, out);
}
upcase = rt_lex_token_upcase(((struct field_info*)value)->name);
fprintf((FILE*)out, "%s\\.%s\t return %s;\n", protocol_name,
((struct field_info*) value)->short_name,
upcase);
free(upcase);
}
char* rt_lex_token_upcase(char *text)
{
char *new_text;
char *p;
new_text = g_strdup(text);
g_strup(new_text);
/* s/\./_/g */
for (p = new_text; *p; p++) {
if (*p == '.') {
*p = '_';
}
}
return new_text;
}
void rt_lex_tokens_aliases(gpointer node, gpointer out)
{
if (node) {
fprintf((FILE*)out, "%s\\.%s\t|\n",
protocol_name,
((GString*) node)->str);
}
}
/* Creates rt-grammar.y from rt-grammar-skel.y */
void write_rt_yacc(void)
{
char buf[LINE_SIZE];
FILE *in, *out;
if (!(in = fopen("rt-grammar-skel.y", "r"))) {
g_error("Could not open rt-grammar-skel.y for reading.");
exit(1);
}
if (!(out = fopen("rt-grammar.y", "w"))) {
g_error("Could not open rt-scanner.l for writing.");
exit(1);
}
while(fgets(buf, LINE_SIZE, in)) {
if (strcmp(buf, "/* ct-compile: bytecmp_table */\n") == 0) {
write_rt_bytecmp_table(out);
continue;
}
else if (strcmp(buf, "/* ct-compile: eitherof_table */\n") == 0) {
write_rt_eitherof_table(out);
continue;
}
else if (strcmp(buf, "/* ct-compile: yacc tokens */\n") == 0) {
write_rt_yacc_tokens(out);
continue;
}
else if (strcmp(buf, "/* ct-compile: bytecmp_lval */\n") == 0) {
write_rt_bytecmp_lval(out);
continue;
}
else {
fprintf(out, "%s", buf);
}
}
fclose(in);
fclose(out);
}
/* ------------------------- BYTECMP_TABLE -------------------- */
void write_rt_bytecmp_table(FILE *out)
{
fprintf(out, "bytecmp_info bytecmp_table[] = {\n");
g_hash_table_foreach(field_hash, rt_bytecmp_table, out);
fprintf(out, "\t{ 0, 0, 0, 0 }\n};\n");
}
void rt_bytecmp_table(gpointer key, gpointer value, gpointer out)
{
char *upcase;
struct field_info *val = (struct field_info*) value;
if (!val) {
g_print("key %s has no value.\n", (char*)key);
return;
}
/* return now if we're not dealing with a bytecmp field */
if (val->computation_type == CTYPE_EITHEROF) {
if (many_list_subtype(val) != CTYPE_BYTECMP)
return;
}
else if (val->computation_type != CTYPE_BYTECMP) {
return;
}
upcase = rt_lex_token_upcase(((struct field_info*)value)->name);
fprintf((FILE*)out, "\t{ %s, %d, %d, %d },\n",
upcase, val->computation_type, val->offset, val->length);
free(upcase);
}
static
int many_list_subtype(struct field_info *val)
{
struct field_info *fi;
gchar *field1;
if (!val->many_list)
return 0;
field1 = ((GString*)g_slist_nth_data(val->many_list, 1))->str;
fi = g_hash_table_lookup(field_hash, field1);
if (!fi)
return 0;
return fi->computation_type;;
}
/* ------------------- EITHEROF_TABLE ------------------------ */
void write_rt_eitherof_table(FILE *out)
{
fprintf(out, "eitherof_info eitherof_table[] = {\n");
g_hash_table_foreach(field_hash, rt_eitherof_table, out);
fprintf(out, "\t{ 0, 0, 0, 0 }\n};\n");
}
void rt_eitherof_table(gpointer key, gpointer value, gpointer out)
{
char *upcase_field, *upcase_field1, *upcase_field2;
struct field_info *val = (struct field_info*) value;
if (!val) {
g_print("key %s has no value.\n", (char*)key);
return;
}
if (val->computation_type != CTYPE_EITHEROF) {
return;
}
upcase_field = rt_lex_token_upcase(((struct field_info*)value)->name);
g_print("EITHEROF checking %s\n", upcase_field);
if (val->many_list) {
g_print("getting fields\n");
upcase_field1 = ((GString*)g_slist_nth_data(val->many_list, 1))->str;
g_print("got field1 %s\n", upcase_field1);
upcase_field2 = ((GString*)g_slist_nth_data(val->many_list, 2))->str;
g_print("got field2 %s\n", upcase_field2);
upcase_field1 = rt_lex_token_upcase(upcase_field1);
g_print("got field1 %s\n", upcase_field1);
upcase_field2 = rt_lex_token_upcase(upcase_field2);
g_print("got field2 %s\n", upcase_field2);
}
else
return;
fprintf((FILE*)out, "\t{ %s, %d, %s, %s },\n",
upcase_field, val->computation_type,
upcase_field1, upcase_field2);
free(upcase_field);
free(upcase_field1);
free(upcase_field2);
}
/* ---------------------- YACC_TOKENS ---------------------------- */
void write_rt_yacc_tokens(FILE *out)
{
g_hash_table_foreach(field_hash, rt_yacc_tokens, out);
}
void rt_yacc_tokens(gpointer key, gpointer value, gpointer out)
{
char *upcase;
struct field_info *val = (struct field_info*) value;
if (!val) {
g_print("key %s has no value.\n", (char*)key);
return;
}
upcase = rt_lex_token_upcase(((struct field_info*)value)->name);
fprintf((FILE*)out, "%%token <d>\t%s\n", upcase);
free(upcase);
}
/* ------------------------ BYTECMP_LVAL -------------------------- */
void write_rt_bytecmp_lval(FILE *out)
{
rt_iteration = 0;
g_hash_table_foreach(field_hash, rt_bytecmp_lval, out);
fprintf(out, "\t;\n");
}
void rt_bytecmp_lval(gpointer key, gpointer value, gpointer out)
{
char *upcase;
struct field_info *val = (struct field_info*) value;
if (!val) {
g_print("key %s has no value.\n", (char*)key);
return;
}
if (val->computation_type == CTYPE_EITHEROF) {
if (many_list_subtype(val) != CTYPE_BYTECMP)
return;
}
else if (val->computation_type != CTYPE_BYTECMP) {
return;
}
if (rt_iteration == 0) {
fprintf(out, "bytecmp_lval:\t");
}
else {
fprintf(out,"\t|\t");
}
upcase = rt_lex_token_upcase(((struct field_info*)value)->name);
fprintf((FILE*)out, "\t%s { $$ = %s; }\n",
upcase, upcase);
free(upcase);
rt_iteration++;
}