/* * Copyright (c) 2004 - 2007, Nils R. Weller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Various debugging output functions */ #include "debug.h" #include "decl.h" #include "icode.h" #include "type.h" #include "defs.h" #include "token.h" #include "expr.h" #include "reg.h" #include "subexpr.h" #include "functions.h" #include "debug.h" #include "scope.h" #include "backend.h" #include #include #include "n_libc.h" #define DOTABS(ntabs) do { \ int i; \ for (i = 0; i < ntabs; ++i) putchar('\t'); \ } while (0) void debug_do_print_type(struct type *decty, int mode, int tabs) { char *p; char *name = decty->name? decty->name: ""; DOTABS(tabs); printf("Read "); switch (mode) { case DECL_CAST: printf("cast"); break; case DECL_NOINIT: printf("declaration of %s without initializer", name); break; case DECL_CONSTINIT: printf("declaration of %s with constant initializer", name); break; case DECL_VARINIT: printf("declaration of %s with variable initializer", name); break; case DECL_FUNCARG: printf("function argument"); break; case DECL_STRUCT: printf("structure member %s", name); break; case 0: puts("KLUDGE XXX :->"); break; } printf(" of type:\n"); p = type_to_text(decty); printf("\t%s\n", p); free(p); } void debug_do_print_conv( struct type *old1, struct type *old2, int op, struct type *newt) { char *p; struct operator *operator; operator = &operators[LOOKUP_OP2(op)]; printf("The resulting type of ...\n"); p = type_to_text(old1); printf(" (%s)\n", p); free(p); printf("%s\n", operator->name); p = type_to_text(old2); printf(" (%s)\n", p); free(p); p = type_to_text(newt); printf("... is: %s\n", p); free(p); } /* * Expression parsing */ void debug_do_print_icode_list(struct icode_list *list) { struct icode_instr *ip; struct vreg *vr; if (list == NULL) { printf("expr_to_icode() failed\n"); return; } printf("Intermediate instruction list:\n"); for (ip = list->head; ip != NULL; ip = ip->next) { putchar('\t'); switch (ip->type) { case INSTR_SEQPOINT: printf("(Sequence point)\n"); break; case INSTR_DEBUG: printf("DEBUG: %s\n", (char *)ip->dat); break; case INSTR_LABEL: printf("%s:\n", (char *)ip->dat); break; case INSTR_JUMP: printf("JMP\n"); break; case INSTR_CMP: printf("CMP\n"); break; case INSTR_BR_EQUAL: printf("BREQUAL\n"); break; case INSTR_BR_NEQUAL: printf("BRNEQUAL\n"); break; case INSTR_BR_GREATER: printf("BRGREATER\n"); break; case INSTR_BR_SMALLER: printf("BRSMALLER\n"); break; case INSTR_BR_GREATEREQ: printf("BRGREATEREQ\n"); break; case INSTR_BR_SMALLEREQ: printf("BRSMALLEREQ\n"); break; case INSTR_CALL: printf("CALL %s\n", (char *)ip->dat); break; case INSTR_LOAD: printf("LOAD %s = [%p]\n", ip->src_pregs[0]->name, ip->src_vreg); break; case INSTR_INC: printf("INC\n"); break; case INSTR_ADD: printf("ADD\n"); break; case INSTR_DIV: printf("DIV\n"); break; case INSTR_MUL: printf("MUL\n"); break; case INSTR_PUSH: printf("PUSH\n"); break; case INSTR_SUB: printf("SUB\n"); break; case INSTR_ADDROF: printf("ADDROF %s = [%p]\n", ((struct reg *)ip->dat)->name, ip->src_vreg); break; case INSTR_INDIR: printf("[INDIR] "); break; case INSTR_FREESTACK: printf("ADD ESP, %d\n", (int)*(size_t *)ip->dat); break; case INSTR_STORE: if (ip->src_vreg != NULL) { printf("STORE [%p", ip->src_vreg); vr = ip->src_vreg; if (vr->var_backed != NULL) { printf(":%s", vr->var_backed->dtype->name); } printf("] = [%p]\n", ip->dest_vreg); } else { printf("STORE = [%p]\n", ip->dest_vreg); } break; case INSTR_WRITEBACK: printf("WRITEBACK\n"); break; case INSTR_RET: printf("RET\n"); break; default: printf("Illegal instruction (core dumped) " "(only kidding)\n"); printf("Code is %d\n", ip->type); break; } } } void debug_do_print_s_expr(struct s_expr *ex, int tabs) { (void) ex; DOTABS(tabs); printf("Sub-expression:\n"); DOTABS(tabs); putchar('\n'); } void debug_do_print_expr(struct expr *ex) { printf("Expression:\n"); do { if (ex->data != NULL) { debug_do_print_s_expr(ex->data, 1); } if (ex->left != NULL) { printf("Left:\n"); debug_do_print_expr(ex->left); } if (ex->op != 0) { printf(" ... connected thru %d ...\n", ex->op); } } while ((ex = ex->right) != NULL); printf("--- END ---\n"); } static char tree_map[24][80]; #define POS(x, y) (x + ((sizeof(x) / 2) + pos * 10)) static void do_debug_print_tree(struct expr *ex, int line, int pos) { char *p; if (line >= 24) { puts("Expression too long"); exit(EXIT_FAILURE); } p = POS(tree_map[line], pos); if (ex->op) { p[ sprintf(p, "<%d>", ex->op) ] = ' '; } else { p[ sprintf(p, "s_expr") ] = ' '; } ++line; if (ex->left) { p = POS(tree_map[line], pos) - 2; p[ sprintf(p, "/ ") ] = ' '; do_debug_print_tree(ex->left, line+1, pos - 1); } if (ex->right) { p = POS(tree_map[line], pos) + 2; p[ sprintf(p, " \\") ] = ' '; do_debug_print_tree(ex->right, line+1, pos + 1); } } void debug_do_print_tree(struct expr *ex) { int i; for (i = 0; i < 24; ++i) { memset(tree_map[i], ' ', sizeof tree_map[i]); tree_map[i][79] = 0; } do_debug_print_tree(ex, 0, 0); tree_map[5][0] = '*'; for (i = 0; i < 24; ++i) { printf("%s\n", tree_map[i]); } } void debug_do_print_function(struct function *f) { printf("Read function `%s'\n", f->proto->dtype->name); debug_do_print_type(f->proto->dtype, DECL_NOINIT, 1); } /* * Note that the cast and function call operators are not handled * because they are ambiguous */ void debug_do_print_eval_op(struct token *t) { char *p = "an unknown something"; (void) t; (void) p; if (t->type == TOK_ARRAY_OPEN) { p = "array subscript operator"; } else if (t->type == TOK_OPERATOR) { switch (*(int *)t->data) { case TOK_OP_INCPOST: p = "postifx increment operator"; break; case TOK_OP_DECPOST: p = "postfix decrement operator"; break; case TOK_OP_STRUMEMB: p = ". operator"; break; case TOK_OP_STRUPMEMB: p = "-> operator"; break; case TOK_OP_DEREF: p = "dereferecing operator"; break; case TOK_OP_UPLUS: p = "unary plus operator"; break; case TOK_OP_UMINUS: p = "unary minus operator"; break; case TOK_OP_ADDR: p = "address-of operator"; break; case TOK_OP_INCPRE: p = "prefix increment operator"; break; case TOK_OP_DECPRE: p = "prefix decrement operator"; break; default: p = "unknown operator"; } } printf("get_sub_expr(): evaluating %s\n", p); } void debug_do_print_static_var_defs(void) { struct decl *dp; printf("Static initialized variables:\n"); for (dp = static_init_vars; dp != NULL; dp = dp->next) { printf("%s\n", dp->dtype->name); } printf("Static uninitialized variables:\n"); for (dp = static_uninit_vars; dp != NULL; dp = dp->next) { printf("%s\n", dp->dtype->name); } } void debug_print_vreg_backing(struct vreg *vr) { static int tab = ' '; printf("%c%p->var_backed = %p\n", tab, vr, vr->var_backed); printf("%c%p->from_const = %p\n", tab, vr, vr->from_const); printf("%c%p->from_ptr = %p\n", tab, vr, vr->from_ptr); printf("%c%p->parent = %p\n", tab, vr, vr->parent); printf("%c%p->stack_addr = %p\n", tab, vr, vr->stack_addr); printf("%c%p->preg = %p ", tab, vr, vr->pregs[0]); if (vr->pregs[0] != NULL) { printf("[%s->vreg = %p]", vr->pregs[0]->name, vr->pregs[0]->vreg); } if (tab == ' ') tab = '\t'; else tab = ' '; putchar('\n'); } static void debug_do_print_vreg(struct vreg *vr) { printf("[vr %p: ", vr); if (vr->var_backed) { printf("%s", vr->var_backed->dtype->name); } else if (vr->memberdecl) { if (vr->memberdecl->dtype) { printf(". %s", vr->memberdecl->dtype->name); } else { printf(". %lu", (unsigned long)vr->memberdecl->offset); } } else if (vr->from_const) { printf("(const)"); } else if (vr->from_ptr) { printf("*ptr"); } else if (vr->pregs[0] && vr->pregs[0]->vreg == vr) { printf("%s", vr->pregs[0]->name); } else if (vr->stack_addr == NULL) { printf("INVALID"); } else { printf("(anonstack)"); } printf(",%lu bytes,type=%d] ", (unsigned long)vr->size, vr->type->code); } static void debug_do_print_preg(struct reg *r) { printf("[reg %s] ", r->name); } void debug_do_log_regstuff(struct reg *r, struct vreg *vr, int flag) { static int seqno; printf("%d", seqno++); switch (flag) { case DEBUG_LOG_FAULTIN: putchar('\t'); debug_do_print_vreg(vr); printf("-> "); debug_do_print_preg(r); break; case DEBUG_LOG_REVIVE: putchar('\t'); printf("REVIVING "); debug_do_print_vreg(vr); printf("["); debug_do_print_preg(r); printf("]"); break; case DEBUG_LOG_ALLOCGPR: putchar('\t'); printf("ALLOC %s ", r->name); if (r->vreg != NULL && r->vreg->pregs[0] == r) { printf("[was mapped "); debug_do_print_vreg(r->vreg); printf("] "); } if (backend->debug_print_gprs != NULL) { putchar('\n'); backend->debug_print_gprs(); } break; case DEBUG_LOG_FREEGPR: putchar('\t'); printf("FREE %s ", r->name); if (r->vreg != NULL && r->vreg->pregs[0] == r) { printf("[was mapped "); debug_do_print_vreg(r->vreg); printf("] "); } break; case DEBUG_LOG_FAILEDALLOC: putchar('\t'); printf("FAILED GPR ALLOC ATTEMPT\n"); if (backend->debug_print_gprs != NULL) { putchar('\n'); backend->debug_print_gprs(); } break; default: printf("Bad log flag %d\n", flag); abort(); } putchar('\n'); }