From 9ac15436d9d81bdb607dea0bb2bbfedb1d30add0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 1 Aug 2008 13:54:24 +0000 Subject: [PATCH] More docs. Enhance qfprogs qfo debugging. Make sure functions marked as extern don't emit anything. Fixes the segfault when building klik. --- include/QF/progs.h | 2 +- tools/qfcc/include/function.h | 1 + tools/qfcc/include/obj_file.h | 60 ++++++++++++++++++++++++++++++++--- tools/qfcc/include/qfprogs.h | 1 + tools/qfcc/include/reloc.h | 46 +++++++++++++++++---------- tools/qfcc/source/emit.c | 3 +- tools/qfcc/source/function.c | 14 +++++--- tools/qfcc/source/globals.c | 47 ++++++++++++++++++++------- tools/qfcc/source/linker.c | 19 ++++++++--- tools/qfcc/source/obj_file.c | 36 ++++++++++----------- tools/qfcc/source/qc-parse.y | 15 ++++++--- tools/qfcc/source/qfprogs.c | 2 +- 12 files changed, 178 insertions(+), 68 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index d3babb48e..e16a76f43 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -422,7 +422,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define G_EDICTNUM(p,o) NUM_FOR_EDICT(p, G_EDICT (p, o)) -/** Access a a string global, converting it to a C string. Kills the program +/** Access a string global, converting it to a C string. Kills the program if the string is invalid. \par QC type: diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 172868557..62bea4f22 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -85,6 +85,7 @@ struct def_s *get_function_def (const char *name, struct type_s *type, struct expr_s *find_function (struct expr_s *fexpr, struct expr_s *params); void build_scope (function_t *f, struct def_s *func, param_t *params); function_t *new_function (const char *name); +void add_function (function_t *f); function_t *build_code_function (function_t *f, struct expr_s *state_expr, struct expr_s *statements); function_t *build_builtin_function (struct def_s *def, struct expr_s *bi_val); diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index 84e8e3daf..f1c66ff3b 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -211,11 +211,33 @@ typedef struct qfo_func_s { /** Evil source of many headaches. The whole reason I've started writing this documentation. + relocs are always in the order: + referenced relocs + unreferenced relocs + + For \c ref_op_* relocation types, \c ofs is the code section address of the + statement that needs to be adjusted. + + For \c rel_def_* relocation types, + \c ofs refers to the data section address of the word that needs to be + adjusted. + + For \c ref_*_def(_ofs) relocation types, \c def is the index of the + referenced def. + + For \c ref_*_op relocation types, \c def is the address of + the referenced statement. + + For \c ref_*_string relocation types, \c def is + always 0. + + For \c ref_*_field(_ofs) relocation types, \c def is the index of + the referenced field def. */ typedef struct qfo_reloc_s { - pr_int_t ofs; - pr_int_t type; - pr_int_t def; + pr_int_t ofs; ///< offset of the relocation + pr_int_t type; ///< type of the relocation (::reloc_type) + pr_int_t def; ///< "def" this relocation is for } qfo_reloc_t; /** In-memory representation of a QFO object file. @@ -304,7 +326,37 @@ typedef struct qfo_s { \hideinitializer */ -#define QFO_STRING(q, o) G_GETSTR (QFO_var (q, string, o)) +#define QFO_STRING(q, o) QFO_var (q, string, o) + +/** Retrieve a string from the object file, converting it to a C string. + + \param q pointer to ::qfo_t struct + \param s offset into object file string space + \return (char *) + + \hideinitializer +*/ +#define QFO_GETSTR(q, s) ((q)->strings + (s)) + +/** Retrieve a type string from the object file, converting it to a C string. + + \param q pointer to ::qfo_t struct + \param s offset into object file type string space + \return (char *) + + \hideinitializer +*/ +#define QFO_TYPESTR(q, s) ((q)->types + (s)) + +/** Access a string global, converting it to a C string. + + \param q pointer to ::qfo_t struct + \param o offset into object file data space + \return (char *) + + \hideinitializer +*/ +#define QFO_GSTRING(q, o) (QFO_GETSTR (q, (QFO_STRING (q, o)))) /** Access a function variable in the object file. Can be assigned to. diff --git a/tools/qfcc/include/qfprogs.h b/tools/qfcc/include/qfprogs.h index a77bb68a1..21bcedf9b 100644 --- a/tools/qfcc/include/qfprogs.h +++ b/tools/qfcc/include/qfprogs.h @@ -24,6 +24,7 @@ struct dfunction_s *func_find (int st_num); void dump_strings (struct progs_s *pr); void qfo_globals (struct qfo_s *qfo); +void qfo_functions (struct qfo_s *qfo); void qfo_relocs (struct qfo_s *qfo); #endif//__qfprogs_h diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h index 6691e56be..1b91ef161 100644 --- a/tools/qfcc/include/reloc.h +++ b/tools/qfcc/include/reloc.h @@ -32,24 +32,34 @@ #ifndef __reloc_h #define __reloc_h +/** \defgroup qfcc_reloc Relocation handling + \ingroup qfcc +*/ +///@{ + +/** Relocation record types. + Types marked with * are relative and fixed up before the qfo is written. + Types marked with ! are handled by only by the linker. + Types marked with + use pr.relocs +*/ typedef enum { - rel_none, - rel_op_a_def, - rel_op_b_def, - rel_op_c_def, - rel_op_a_op, - rel_op_b_op, - rel_op_c_op, - rel_def_op, - rel_def_def, - rel_def_func, - rel_def_string, - rel_def_field, - rel_op_a_def_ofs, - rel_op_b_def_ofs, - rel_op_c_def_ofs, - rel_def_def_ofs, - rel_def_field_ofs, + rel_none, ///< no relocation + rel_op_a_def, ///< code[ref.ofs].a = def ofs + rel_op_b_def, ///< code[ref.ofs].b = def ofs + rel_op_c_def, ///< code[ref.ofs].c = def ofs + rel_op_a_op, ///< * code[ref.ofs].a = code ofs - ref.ofs + rel_op_b_op, ///< * code[ref.ofs].b = code ofs - ref.ofs + rel_op_c_op, ///< * code[ref.ofs].c = code ofs - ref.ofs + rel_def_op, ///< + data[ref.ofs] = code ofs + rel_def_def, ///< data[ref.ofs] = def ofs + rel_def_func, ///< +(sometimes) data[ref.ofs] = ofs + rel_def_string, ///< + ! data[ref.ofs] = string index + rel_def_field, ///< ! data[ref.ofs] = field def ofs + rel_op_a_def_ofs, ///< code[ref.ofs].a += def ofs + rel_op_b_def_ofs, ///< code[ref.ofs].b += def ofs + rel_op_c_def_ofs, ///< code[ref.ofs].c += def ofs + rel_def_def_ofs, ///< data[ref.ofs] += def ofs + rel_def_field_ofs, ///< data[ref.ofs] += field def ofs } reloc_type; typedef struct reloc_s { @@ -77,4 +87,6 @@ void reloc_def_field (struct def_s *def, int ofs); void reloc_def_field_ofs (struct def_s *def, int ofs); void reloc_def_op (struct ex_label_s *label, int ofs); +///@} + #endif//__reloc_h diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 8d7acd4d4..9db8a9fce 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -49,6 +49,7 @@ static __attribute__ ((used)) const char rcsid[] = #include "debug.h" #include "emit.h" #include "expr.h" +#include "function.h" #include "immediate.h" #include "opcodes.h" #include "options.h" @@ -130,7 +131,7 @@ emit_statement (expr_t *e, opcode_t *op, def_t *var_a, def_t *var_b, error (e, "ice ice baby"); abort (); } - if (options.code.debug) { + if (options.code.debug && current_func->aux) { pr_uint_t line = (e ? e->line : pr.source_line) - lineno_base; if (line != pr.linenos[pr.num_linenos - 1].line) { diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 418fa12e1..e5ca0bd0e 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -395,15 +395,19 @@ new_function (const char *name) function_t *f; ALLOC (1024, function_t, functions, f); + f->s_name = ReuseString (name); + f->s_file = pr.source_file; + return f; +} +void +add_function (function_t *f) +{ *pr.func_tail = f; pr.func_tail = &f->next; f->function_num = pr.num_functions++; - f->s_name = ReuseString (name); - f->s_file = pr.source_file; if (options.code.debug) f->aux = new_auxfunction (); - return f; } function_t * @@ -440,12 +444,12 @@ build_builtin_function (def_t *def, expr_t *bi_val) } f = new_function (def->name); + add_function (f); f->builtin = bi_val->type == ex_integer ? bi_val->e.integer_val : (int)bi_val->e.float_val; f->def = def; - if (!def->external) - reloc_def_func (f, def->ofs); + reloc_def_func (f, def->ofs); build_function (f); finish_function (f); return f; diff --git a/tools/qfcc/source/globals.c b/tools/qfcc/source/globals.c index ab9785471..393639571 100644 --- a/tools/qfcc/source/globals.c +++ b/tools/qfcc/source/globals.c @@ -190,8 +190,9 @@ qfo_globals (qfo_t *qfo) for (i = 0; i < qfo->num_defs; i++) { def = &qfo->defs[i]; - printf ("%-5d %s %s", def->ofs, flags_string (def->flags), - qfo->strings + def->name); + printf ("%-5d %-5d %s %s %s", i, def->ofs, flags_string (def->flags), + QFO_GETSTR (qfo, def->name), + QFO_TYPESTR (qfo, def->full_type)); if (!(def->flags & QFOD_EXTERNAL)) printf (" %d", qfo->data[def->ofs].integer_var); puts (""); @@ -222,8 +223,9 @@ qfo_relocs (qfo_t *qfo) case rel_op_b_def: case rel_op_c_def: def = qfo->defs + reloc->def; - printf (" op.%c %d %d %s", reloc->type - rel_op_a_def + 'a', - reloc->ofs, def->ofs, qfo->strings + def->name); + printf (" op.%c@%d def@%d %s", + reloc->type - rel_op_a_def + 'a', + reloc->ofs, def->ofs, QFO_GETSTR (qfo, def->name)); break; case rel_op_a_op: case rel_op_b_op: @@ -237,41 +239,42 @@ qfo_relocs (qfo_t *qfo) case rel_def_def: def = qfo->defs + reloc->def; printf (" def@%d def@%d %s", reloc->ofs, reloc->def, - qfo->strings + def->name); + QFO_GETSTR (qfo, def->name)); break; case rel_def_func: func = qfo->funcs + reloc->def; printf (" def@%d func@%d %s", reloc->ofs, reloc->def, - qfo->strings + func->name); + QFO_GETSTR (qfo, func->name)); break; case rel_def_string: printf (" def@%d string:`%s'", reloc->ofs, - qfo->strings + qfo->data[reloc->ofs].string_var); + QFO_GSTRING (qfo, reloc->ofs)); break; case rel_def_field: def = qfo->defs + reloc->def; printf (" def@%d def@%d %s", reloc->ofs, reloc->def, - qfo->strings + def->name); + QFO_GETSTR (qfo, def->name)); break; case rel_op_a_def_ofs: case rel_op_b_def_ofs: case rel_op_c_def_ofs: def = qfo->defs + reloc->def; - printf (" op.%c %d %d %s", reloc->type - rel_op_a_def + 'a', - reloc->ofs, def->ofs, qfo->strings + def->name); + printf (" op.%c@%d def@%d %s", + reloc->type - rel_op_a_def_ofs + 'a', + reloc->ofs, def->ofs, QFO_GETSTR (qfo, def->name)); break; case rel_def_def_ofs: def = qfo->defs + reloc->def; printf (" def@%d def@%d+%d %s+%d", reloc->ofs, reloc->def, qfo->data[reloc->ofs].integer_var, - qfo->strings + def->name, + QFO_GETSTR (qfo, def->name), qfo->data[reloc->ofs].integer_var); break; case rel_def_field_ofs: def = qfo->defs + reloc->def; printf (" def@%d def@%d+%d %s+%d", reloc->ofs, reloc->def, qfo->data[reloc->ofs].integer_var, - qfo->strings + def->name, + QFO_GETSTR (qfo, def->name), qfo->data[reloc->ofs].integer_var); break; } @@ -286,3 +289,23 @@ qfo_relocs (qfo_t *qfo) puts (""); } } + +void +qfo_functions (qfo_t *qfo) +{ + qfo_def_t *def; + qfo_func_t *func; + int i; + + for (i = 0; i < qfo->num_funcs; i++) { + func = &qfo->funcs[i]; + def = &qfo->defs[func->def]; + printf ("%-5d %-5d %s %s %d %s", i, def->ofs, + flags_string (def->flags), + QFO_GETSTR (qfo, func->name), func->def, + QFO_GETSTR (qfo, def->name)); + if (!(def->flags & QFOD_EXTERNAL)) + printf (" %d", qfo->data[def->ofs].integer_var); + puts (""); + } +} diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 5dbdc6ef9..0b711262c 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -349,15 +349,18 @@ fixup_def (qfo_t *qfo, qfo_def_t *def, int def_num) pr_int_t i; qfo_reloc_t *reloc; qfo_func_t *func; + const char *full_type = QFO_TYPESTR (qfo, def->full_type); + const char *name = QFO_GETSTR (qfo, def->name); + + def->full_type = strpool_addstr (type_strings, full_type); + def->name = strpool_addstr (strings, name); - def->full_type = strpool_addstr (type_strings, - qfo->types + def->full_type); - def->name = strpool_addstr (strings, qfo->strings + def->name); def->relocs += reloc_base; for (i = 0, reloc = relocs.relocs + def->relocs; i < def->num_relocs; i++, reloc++) reloc->def = def_num; + def->file = strpool_addstr (strings, qfo->strings + def->file); if ((def->flags & (QFOD_LOCAL | QFOD_ABSOLUTE))) @@ -384,6 +387,9 @@ fixup_def (qfo_t *qfo, qfo_def_t *def, int def_num) process_def (def); } +/* Transfer global defs from the object file. Local defs are skipped because + they will be handled by add_funcs. +*/ static void add_defs (qfo_t *qfo) { @@ -392,12 +398,14 @@ add_defs (qfo_t *qfo) for (s = e = qfo->defs; s - qfo->defs < qfo->num_defs; s = e) { int def_num = global_defs.num_defs; qfo_def_t *d; + // find the end of the current chunk of global defs while (e - qfo->defs < qfo->num_defs && !(e->flags & QFOD_LOCAL)) e++; defgroup_add_defs (&global_defs, s, e - s); for (d = global_defs.defs + def_num; def_num < global_defs.num_defs; d++, def_num++) fixup_def (qfo, d, def_num); + // find the beginning of the next chunk of global defs while (e - qfo->defs < qfo->num_defs && (e->flags & QFOD_LOCAL)) e++; } @@ -647,18 +655,21 @@ define_def (const char *name, etype_t basic_type, const char *full_type, val->integer_var = v; memset (&d, 0, sizeof (d)); + d.basic_type = basic_type; d.full_type = strpool_addstr (type_strings, full_type); d.name = strpool_addstr (strings, name); d.ofs = data->size; - d.flags = QFOD_GLOBAL | flags; if (basic_type == ev_field) { d.relocs = relocs.num_relocs; d.num_relocs = 1; } + d.flags = QFOD_GLOBAL | flags; + defspace_adddata (data, val, size); defgroup_add_defs (&global_defs, &d, 1); process_def (global_defs.defs + global_defs.num_defs - 1); + if (basic_type == ev_field) { int def_num = global_defs.num_defs - 1; qfo_def_t *def = global_defs.defs + def_num; diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index cd8c154c3..fa724a3ea 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -79,21 +79,21 @@ count_relocs (reloc_t *reloc) } static void -allocate_stuff (void) +allocate_stuff (pr_info_t *pr) { def_t *def; function_t *func; num_defs = 0; - num_funcs = pr.num_functions - 1; + num_funcs = pr->num_functions - 1; num_relocs = 0; - for (def = pr.scope->head; def; def = def->def_next) { + for (def = pr->scope->head; def; def = def->def_next) { if (def->alias) continue; num_defs++; num_relocs += count_relocs (def->refs); } - for (func = pr.func_head; func; func = func->next) { + for (func = pr->func_head; func; func = func->next) { num_relocs += count_relocs (func->refs); if (func->scope) { num_defs += func->scope->num_defs; @@ -102,7 +102,7 @@ allocate_stuff (void) } } } - num_relocs += count_relocs (pr.relocs); + num_relocs += count_relocs (pr->relocs); if (num_defs) defs = calloc (num_defs, sizeof (qfo_def_t)); if (num_funcs) @@ -182,7 +182,7 @@ write_def (def_t *d, qfo_def_t *def, qfo_reloc_t **reloc) } static void -setup_data (void) +setup_data (pr_info_t *pr) { qfo_def_t *def = defs; def_t *d; @@ -194,10 +194,10 @@ setup_data (void) pr_type_t *var; pr_lineno_t *line; - for (d = pr.scope->head; d; d = d->def_next) + for (d = pr->scope->head; d; d = d->def_next) if (!d->alias) write_def (d, def++, &reloc); - for (f = pr.func_head; f; f = f->next, func++) { + for (f = pr->func_head; f; f = f->next, func++) { func->name = LittleLong (f->s_name); func->file = LittleLong (f->s_file); func->line = LittleLong (f->def->line); @@ -225,25 +225,25 @@ setup_data (void) for (d = f->scope->head; d; d = d->def_next) write_def (d, def++, &reloc); } - for (r = pr.relocs; r; r = r->next) + for (r = pr->relocs; r; r = r->next) if (r->type == rel_def_op) write_one_reloc (r, &reloc, r->label->ofs); else write_one_reloc (r, &reloc, 0); - for (st = pr.code->code; st - pr.code->code < pr.code->size; st++) { + for (st = pr->code->code; st - pr->code->code < pr->code->size; st++) { st->op = LittleLong (st->op); st->a = LittleLong (st->a); st->b = LittleLong (st->b); st->c = LittleLong (st->c); } - for (var = pr.near_data->data; - var - pr.near_data->data < pr.near_data->size; var++) + for (var = pr->near_data->data; + var - pr->near_data->data < pr->near_data->size; var++) var->integer_var = LittleLong (var->integer_var); - if (pr.far_data) - for (var = pr.far_data->data; - var - pr.far_data->data < pr.far_data->size; var++) + if (pr->far_data) + for (var = pr->far_data->data; + var - pr->far_data->data < pr->far_data->size; var++) var->integer_var = LittleLong (var->integer_var); - for (line = pr.linenos; line - pr.linenos < pr.num_linenos; line++) { + for (line = pr->linenos; line - pr->linenos < pr->num_linenos; line++) { line->fa.addr = LittleLong (line->fa.addr); line->line = LittleLong (line->line); } @@ -263,8 +263,8 @@ qfo_from_progs (pr_info_t *pr) qfo_t *qfo; types = strpool_new (); - allocate_stuff (); - setup_data (); + allocate_stuff (pr); + setup_data (pr); round_strings (pr->strings); round_strings (types); diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 707e96c16..fa20c4724 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -524,9 +524,12 @@ func_init builtin_function : /* emtpy */ { - $$ = build_builtin_function ($-1, $0); - build_scope ($$, $$->def, current_params); - flush_scope ($$->scope, 1); + def_t *def = $-1; + if (!def->external) { + $$ = build_builtin_function (def, $0); + build_scope ($$, $$->def, current_params); + flush_scope ($$->scope, 1); + } } ; @@ -716,10 +719,12 @@ begin_function error (0, "%s redefined", $0->name); $$ = current_func = new_function ($0->name); $$->def = $0; - if (!$$->def->external) + if (!$$->def->external) { + add_function ($$); reloc_def_func ($$, $$->def->ofs); + } $$->code = pr.code->size; - if (options.code.debug) { + if (options.code.debug && current_func->aux) { pr_lineno_t *lineno = new_lineno (); $$->aux->source_line = $$->def->line; $$->aux->line_info = lineno - pr.linenos; diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 9833acd41..fd25776e5 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -481,7 +481,7 @@ operation_t operations[] = { {dump_globals, qfo_globals}, // globals {dump_strings, 0}, // strings {dump_fields, 0}, // fields - {dump_functions, 0}, // functions + {dump_functions, qfo_functions}, // functions {dump_lines, 0}, // lines {dump_modules, 0}, // modules {0, qfo_relocs}, // relocs