📄 gbx_trace.c
字号:
/*************************************************************************** trace.c The debugger (c) 2000-2004 Beno� Minisini <gambas@users.sourceforge.net> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************/#define __GBX_TRACE_C#include "gb_common.h"#include "gb_common_buffer.h"#include "gb_common_case.h"#include <unistd.h>#include <signal.h>#include <fcntl.h>#include "gb_error.h"#include "gbx_type.h"#include "gbx_debug.h"#include "gb_limit.h"#include "gbx_stack.h"#include "gbx_class.h"#include "gbx_exec.h"#include "gbx_local.h"#include "gbx_object.h"#include "gbx_c_application.h"#include "gbx_eval.h"#include "gbx_trace.h"/*#define DEBUG_ME*/PUBLIC TRACE_GLOBAL TRACE = { 0 };PRIVATE TRACE_BREAK *Breakpoint;PRIVATE bool Error;EVAL_INTERFACE EVAL;static int _fdr;static int _fdw;static FILE *_out;static FILE *_in;PUBLIC void TRACE_break_on_next_line(void){ TRACE.stop = TRUE; TRACE.fp = NULL; TRACE.bp = NULL;}PRIVATE void new_line(void){ fprintf(_out, "\n");}PRIVATE void signal_user(int sig){ signal(SIGUSR1, signal_user); #ifdef DEBUG_ME fprintf(stderr, "Got SIGUSR1\n"); #endif /*CAPP_got_signal();*/ TRACE_break_on_next_line();}PRIVATE boolean calc_line_from_position(CLASS *class, FUNCTION *func, PCODE *addr, ushort *line){ int i; ushort pos = addr - func->code; ushort *post; if (func->debug) { post = func->debug->pos; for (i = 0; i < (func->debug->nline - 1); i++) { if (pos >= post[i] && pos < post[i + 1]) { *line = i + func->debug->line; return FALSE; } } /*printf("pos = %d addr=%p func->code=%p\n", pos, addr, func->code);*/ } return TRUE;}PRIVATE boolean calc_position_from_line(CLASS *class, ushort line, FUNCTION **function, PCODE **addr){ int i; ushort pos, pos_after; FUNCTION *func = NULL; FUNC_DEBUG *debug = NULL; for (i = 0; i < class->load->n_func; i++) { func = &class->load->func[i]; debug = func->debug; if (debug && line >= debug->line && line < (debug->line + debug->nline)) break; } if (i >= class->load->n_func) return TRUE; line -= debug->line; for(;;) { pos = debug->pos[line]; pos_after = debug->pos[line + 1]; if (pos != pos_after) break; line++; if (line >= debug->nline) return TRUE; } *function = func; *addr = &func->code[pos]; /*printf("%s.%d -> %04X\n", class->name, line + debug->line, **addr);*/ return FALSE;}PRIVATE bool get_value(const char *sym, long len, GB_VARIANT *ret){ int i; VALUE value; LOCAL_SYMBOL *lp; GLOBAL_SYMBOL *gp; CLASS_VAR *var; char *addr; if (TRACE.fp) { for (i = 0; i < TRACE.fp->debug->n_local; i++) { lp = &TRACE.fp->debug->local[i]; if (len == lp->sym.len && strncasecmp(sym, lp->sym.name, len) == 0) { value = TRACE.bp[lp->value]; goto __FOUND; } } } if (TRACE.cp) { for (i = 0; i < TRACE.cp->load->n_global; i++) { gp = &TRACE.cp->load->global[i]; if (len != gp->sym.len || strncasecmp(sym, gp->sym.name, len) != 0) continue; if (CTYPE_get_kind(gp->ctype) != TK_VARIABLE) continue; if (!CTYPE_is_static(gp->ctype) && TRACE.op) { var = &TRACE.cp->load->dyn[gp->value]; addr = (char *)TRACE.op + var->pos; } else { var = &TRACE.cp->load->stat[gp->value]; addr = (char *)TRACE.cp->stat + var->pos; } VALUE_class_read(TRACE.cp, &value, addr, var->type); goto __FOUND; } } /*printf("Unknown symbol %.*s\n", (int)len, sym); ret->type = GB_T_NULL;*/ return TRUE;__FOUND: /*printf("%.*s =", (int)len, sym); print_value(&value);*/ BORROW(&value); if (value.type == T_ARRAY) value._array.keep = TRUE; else VALUE_conv(&value, T_VARIANT); UNBORROW(&value); *((VALUE *)ret) = value; return FALSE;}PUBLIC void TRACE_init(void){ char path[MAX_PATH]; if (!EXEC_debug) return; LIBRARY_get_interface_by_name("gb.eval", EVAL_INTERFACE_VERSION, &EVAL); if (EXEC_fifo) { sprintf(path, "/tmp/gambas.%d/%d.out", getuid(), getppid()); _fdr = open(path, O_RDONLY); sprintf(path, "/tmp/gambas.%d/%d.in", getuid(), getppid()); _fdw = open(path, O_WRONLY); _in = fdopen(_fdr, "r"); _out = fdopen(_fdw, "w"); if (!_in || !_out) ERROR_panic("Cannot open fifos"); setlinebuf(_in); /*setvbuf(_in, NULL, _IOLBF, 0);*/ setlinebuf(_out); /*setvbuf(_out, NULL, _IOLBF, 0);*/ } else { _in = stdin; _out = stdout; } ARRAY_create(&Breakpoint); signal(SIGUSR1, signal_user); signal(SIGPIPE, SIG_IGN);}/*PUBLIC void TRACE_check_signal(void){ static bool msg = FALSE; struct sigaction action; if (msg) return; sigaction(SIGUSR1, NULL, &action); if (action.sa_handler != signal_user) { fprintf(stderr, "SIGUSR1 handler has changed !\n"); msg = TRUE; } else { fprintf(stderr, "OK\n"); }}*/PUBLIC void TRACE_exit(void){ ARRAY_delete(&Breakpoint); /* if (EXEC_fifo) { fclose(_in); fclose(_out); } */}PRIVATE int find_free_breakpoint(void){ int i; char used[MAX_BREAKPOINT]; memset(used, FALSE, MAX_BREAKPOINT); for (i = 0; i < ARRAY_count(Breakpoint); i++) used[Breakpoint[i].id - 1] = TRUE; for (i = 0; i < MAX_BREAKPOINT; i++) if (!used[i]) return (i + 1); return 0;}PRIVATE boolean set_breakpoint(CLASS *class, ushort line){ PCODE *addr = NULL; TRACE_BREAK *brk; int id; FUNCTION *func; if (ARRAY_count(Breakpoint) >= MAX_BREAKPOINT) { fprintf(_out, "Too many breakpoints (max = %d)\n", MAX_BREAKPOINT); return TRUE; } if (CLASS_is_native(class) || !class->debug) { fprintf(_out, "No debugging information\n"); return TRUE; } if (calc_position_from_line(class, line, &func, &addr)) { fprintf(_out, "Cannot calc position from line number\n"); return TRUE; } if (!PCODE_is_breakpoint(*addr)) { fprintf(_out, "Not a line beginning ?\n"); return TRUE; } if (*addr & 0xFF) { fprintf(_out, "Breakpoint already set\n"); return TRUE; } id = find_free_breakpoint(); if (id == 0) { fprintf(_out, "Cannot create breakpoint\n"); return TRUE; } brk = ARRAY_add(&Breakpoint); brk->id = id; /*brk->func = func;*/ brk->addr = addr; brk->class = class; brk->line = line; *addr = PCODE_BREAKPOINT(id); #ifdef DEBUG_ME fprintf(stderr, "set_breakpoint: %s.%d\n", class->name, line); #endif return FALSE;}PRIVATE boolean unset_breakpoint(CLASS *class, ushort line){ int i; for (i = 0; i < ARRAY_count(Breakpoint); i++) { if (Breakpoint[i].class == class && Breakpoint[i].line == line) { *(Breakpoint[i].addr) = PCODE_BREAKPOINT(0); ARRAY_remove(&Breakpoint, i); #ifdef DEBUG_ME fprintf(stderr, "unset_breakpoint: %s.%d\n", class->name, line); #endif return FALSE; } } fprintf(_out, "Unknown breakpoint\n"); return TRUE;}/*PRIVATE boolean reset_breakpoint(int num){ TRACE_BREAK *tb; if (num < 0 || num >= MAX_BREAKPOINT) return TRUE; tb = &Breakpoint[num]; if (tb->addr == NULL) return TRUE; *(tb->addr) = tb->value; EXEC_stop_next = TRUE; Reset_breakpoint = num; return FALSE;}PUBLIC ushort TRACE_get_current_line(void){ int i; ushort pos = PC - FP->code; if (FP->debug) { for (i = 0; i < (FP->debug->nline - 1); i++) { if (pos >= FP->debug->pos[i] && pos < FP->debug->pos[i + 1]) return i + FP->debug->line; } } return 0;}*/PRIVATE void command_quit(const char *cmd){ exit(1);}PRIVATE void command_go(const char *cmd){ TRACE.stop = FALSE; TRACE.fp = NULL; TRACE.bp = NULL;}PRIVATE void command_step(const char *cmd){ TRACE_break_on_next_line();}PRIVATE void command_next(const char *cmd){ TRACE.stop = TRUE; TRACE.fp = FP; TRACE.bp = BP;}PRIVATE void command_from(const char *cmd){ STACK_CONTEXT *sc = STACK_get_current(); if (sc) { TRACE.stop = TRUE; TRACE.fp = sc->fp; TRACE.bp = sc->bp; } else command_go(cmd);}PRIVATE void command_set_breakpoint(const char *cmd){ char class_name[64]; CLASS *class; ushort line; if (sscanf(cmd, "+%64[^.].%hu", class_name, &line) != 2) fprintf(_out, "Syntax error\n"); else { class = CLASS_find(class_name); CLASS_load_without_init(class); set_breakpoint(class, line); }}PRIVATE void command_unset_breakpoint(const char *cmd){ char class_name[64]; CLASS *class; ushort line; if (sscanf(cmd, "-%64[^.].%hu", class_name, &line) != 2) fprintf(_out, "Syntax error\n"); else { class = CLASS_find(class_name); CLASS_load_without_init(class); unset_breakpoint(class, line); }}PRIVATE void command_where(const char *cmd){ int i; STACK_CONTEXT *context; ushort line; if (CP) fprintf(_out, "%s", TRACE_get_current_position()); else fprintf(_out, "?"); for (i = 0; i < (STACK_frame_count - 1); i++) { context = &STACK_frame[i]; if (context->pc) { line = 0; if (calc_line_from_position(context->cp, context->fp, context->pc, &line)) fprintf(_out, " %s.?.?", context->cp->name); else fprintf(_out, " %s.%s.%d", context->cp->name, context->fp->debug->name, line); } else if (context->cp) fprintf(_out, " ?"); } if (Error) { fprintf(_out, "*"); ERROR_print_at(_out); } else new_line();}PRIVATE void to_string(VALUE *value, char **addr, long *len, boolean *more){ static void *jump[16] = { &&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__FLOAT, &&__DATE, &&__STRING, &&__STRING, &&__VARIANT, &&__ARRAY, &&__STRUCT, &&__FUNCTION, &&__CLASS, &&__NULL }; VALUE conv; *more = FALSE;__CONV: if (TYPE_is_object(value->type)) goto __OBJECT; else goto *jump[value->type];__NULL: *addr = "NULL"; *len = 4; return;__BOOLEAN: if (value->_boolean.value) { *addr = "TRUE"; *len = 4; } else { *addr = "FALSE"; *len = 5; } return;__BYTE:__SHORT:__INTEGER:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -