gambas-source-code/main/gbx/gbx_debug.c

598 lines
12 KiB
C
Raw Normal View History

/***************************************************************************
gbx_debug.c
(c) 2000-2012 Benoît 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 2, 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., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __GBX_DEBUG_C
#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_common_case.h"
#include <stdarg.h>
#include "gb_buffer.h"
#include "gb_array.h"
#include "gb_error.h"
#include "gbx_exec.h"
#include "gbx_api.h"
#include "gbx_class.h"
#include "gbx_c_array.h"
#include "gbx_project.h"
#include "gbx_stack.h"
#include "gbx_subr.h"
#include "gbx_debug.h"
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
DEBUG_INTERFACE DEBUG;
DEBUG_INFO *DEBUG_info = NULL;
static bool 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;
}
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
const char *DEBUG_get_position(CLASS *cp, FUNCTION *fp, PCODE *pc)
{
#if DEBUG_MEMORY
static char buffer[256];
#endif
ushort line = 0;
if (!cp || !pc)
return "?";
if (fp != NULL && fp->debug)
calc_line_from_position(cp, fp, pc, &line);
#if DEBUG_MEMORY
snprintf(buffer, sizeof(buffer), "%s.%s.%d",
cp ? cp->name : "?",
(fp && fp->debug) ? fp->debug->name : "?",
line);
return buffer;
#else
snprintf(COMMON_buffer, COMMON_BUF_MAX, "%.64s.%.64s.%d",
cp ? cp->name : "?",
(fp && fp->debug) ? fp->debug->name : "?",
line);
return COMMON_buffer;
#endif
}
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
const char *DEBUG_get_current_position(void)
{
return DEBUG_get_position(CP, FP, PC);
}
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
void DEBUG_init(void)
{
if (!EXEC_debug)
return;
COMPONENT_load(COMPONENT_create("gb.debug"));
LIBRARY_get_interface_by_name("gb.debug", DEBUG_INTERFACE_VERSION, &DEBUG);
DEBUG_info = DEBUG.Init((GB_DEBUG_INTERFACE *)(void *)GAMBAS_DebugApi, EXEC_fifo, EXEC_fifo_name);
if (!DEBUG_info)
ERROR_panic("Cannot initializing debug mode");
if (EXEC_profile)
{
EXEC_profile_instr = TRUE;
DEBUG.Profile.Init(EXEC_profile_path);
}
}
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
void DEBUG_exit(void)
{
if (!EXEC_debug)
return;
DEBUG.Exit();
if (EXEC_profile)
DEBUG.Profile.Exit();
}
void DEBUG_enter_event_loop(void)
{
if (EXEC_profile)
DEBUG.Profile.Begin(NULL, NULL);
}
void DEBUG_leave_event_loop(void)
{
if (EXEC_profile)
DEBUG.Profile.End(NULL, NULL);
}
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
void DEBUG_where(void)
{
//static bool breakpoint = FALSE;
const char *where = DEBUG_get_current_position();
/*if (!breakpoint && !strcmp(where, "FForm._new.97"))
{
breakpoint = TRUE;
BREAKPOINT();
}*/
fprintf(stderr, "%s: ", where);
}
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
bool DEBUG_get_value(const char *sym, int len, GB_VARIANT *ret)
{
int i;
VALUE value;
LOCAL_SYMBOL *lp;
GLOBAL_SYMBOL *gp;
CLASS_VAR *var;
char *addr;
CLASS *class;
void *ref;
if (DEBUG_info->fp)
{
for (i = 0; i < DEBUG_info->fp->debug->n_local; i++)
{
lp = &DEBUG_info->fp->debug->local[i];
if (len == lp->sym.len && strncasecmp(sym, lp->sym.name, len) == 0)
{
value = DEBUG_info->bp[lp->value];
goto __FOUND;
}
}
}
if (DEBUG_info->cp)
{
for (i = 0; i < DEBUG_info->cp->load->n_global; i++)
{
gp = &DEBUG_info->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)
{
if (!CTYPE_is_static(gp->ctype) && DEBUG_info->op)
{
var = &DEBUG_info->cp->load->dyn[gp->value];
addr = (char *)DEBUG_info->op + var->pos;
ref = DEBUG_info->op;
}
else
{
var = &DEBUG_info->cp->load->stat[gp->value];
addr = (char *)DEBUG_info->cp->stat + var->pos;
ref = DEBUG_info->cp;
}
VALUE_class_read(DEBUG_info->cp, &value, addr, var->type, ref);
goto __FOUND;
}
else if (CTYPE_get_kind(gp->ctype) == TK_CONST)
{
VALUE_class_constant(DEBUG_info->cp, &value, gp->value);
goto __FOUND;
}
}
}
//class = CLASS_look_global(sym, len);
class = CLASS_look(sym, len);
if (class)
{
if (class->auto_create && class->instance)
{
value._object.class = class;
value._object.object = class->instance;
value._object.super = NULL;
}
else
{
value.type = T_CLASS;
value._class.class = class;
[CONFIGURATION] * NEW: Upgrade libtool autoconf macros and libltdl sources to the 1.5.26 version. [DEVELOPMENT ENVIRONMENT] * BUG: Control and window dimensions can go up to 4096x4096 pixels. * BUG: When unchecking GUI components in a project, the edited forms are automatically closed. * BUG: Do not use the form icon on form class editors when refreshing the project. * BUG: In the icon editor, filling with a transparent color won't enter an infinite loop anymore. * BUG: Selecting the "Collection" word while debugging does not crash the IDE anymore. * NEW: Pressing Escape now closes a debugging window. * BUG: The 'Minimize on run' option works correctly now. [INTERPRETER] * BUG: SUPER now works inside overriden static methods. [GB.DB.ODBC] * BUG: Handle ODBC drivers that can return the number of records in a query better. [GB.DEBUG] * BUG: If there is an I/O error between a debugged process and the IDE, the process is aborted. * BUG: Evaluating a class name returns better information now. [GB.EVAL] * BUG: Highlight.Analyze correctly handle code lines having non ASCII characters inside. [GB.FORM] * BUG: The Balloon does not take the focus anymore. [GB.FORM.MDI] * NEW: Starting to enhance the Action class to provide shortcuts and toolbar configuration dialog. Does nothing at the moment! [GB.GTK] * BUG: Fix a leak in font objects management. * BUG: Picture.Load() yet loads an image, but internally converts it to a pixmap. It speeds up following draws based on this picture. * BUG: Startup forms hidden at design time are not shown automatically anymore. * NEW: The Action class is now shared with gb.qt by using a symbolic link. [GB.IMAGE.INFO] * NEW: New component to get information about an image file without having to fully load it. [GB.QT] * BUG: Disable automatic extra indent of Labels. * BUG: Startup forms hidden at design time are not shown automatically anymore. * BUG: Don't allow widgets to be destroyed while processing non-input events. git-svn-id: svn://localhost/gambas/trunk@1747 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-12-28 20:01:39 +01:00
value._class.super = NULL;
}
goto __FOUND;
}
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_variant(&value);
UNBORROW(&value);
*((VALUE *)ret) = value;
return FALSE;
}
int DEBUG_set_value(const char *sym, int len, VALUE *value)
{
int i;
LOCAL_SYMBOL *lp;
GLOBAL_SYMBOL *gp;
CLASS_VAR *var;
char *addr;
VALUE *where;
bool ret = GB_DEBUG_SET_OK;
TRY
{
if (DEBUG_info->fp)
{
for (i = 0; i < DEBUG_info->fp->debug->n_local; i++)
{
lp = &DEBUG_info->fp->debug->local[i];
if (len == lp->sym.len && strncasecmp(sym, lp->sym.name, len) == 0)
{
where = &DEBUG_info->bp[lp->value];
VALUE_conv(value, where->type);
RELEASE(where);
*where = *value;
BORROW(where);
goto __FOUND;
}
}
}
if (DEBUG_info->cp)
{
for (i = 0; i < DEBUG_info->cp->load->n_global; i++)
{
gp = &DEBUG_info->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)
{
if (!CTYPE_is_static(gp->ctype) && DEBUG_info->op)
{
var = &DEBUG_info->cp->load->dyn[gp->value];
addr = (char *)DEBUG_info->op + var->pos;
}
else
{
var = &DEBUG_info->cp->load->stat[gp->value];
addr = (char *)DEBUG_info->cp->stat + var->pos;
}
VALUE_class_write(DEBUG_info->cp, value, addr, var->type);
goto __FOUND;
}
}
}
ret = GB_DEBUG_SET_READ_ONLY;
__FOUND:
0;
}
CATCH
{
ret = GB_DEBUG_SET_ERROR;
EXEC_set_native_error(TRUE);
}
END_TRY
return ret;
}
int DEBUG_get_object_access_type(void *object, CLASS *class, int *count)
{
CLASS_DESC *desc;
CLASS_DESC_METHOD *dm;
char type;
int access = GB_DEBUG_ACCESS_NORMAL;
//fprintf(stderr, "DEBUG_can_be_used_like_an_array: %p %s ?\n", object, class->name);
if (!object)
goto __NORMAL;
if (class == CLASS_Class || OBJECT_is_class(object))
{
class = (CLASS *)object;
object = NULL;
CLASS_load(class);
}
dm = CLASS_get_special_desc(class, SPEC_GET);
if (!dm)
{
//fprintf(stderr, "No _get method\n");
goto __NORMAL;
}
if (dm->npmin != 1 || dm->npmax != 1)
{
//fprintf(stderr, "No _get(Arg AS Integer) method\n");
goto __NORMAL;
}
if (*dm->signature == T_INTEGER)
access = GB_DEBUG_ACCESS_ARRAY;
else if (*dm->signature == T_STRING)
access = GB_DEBUG_ACCESS_COLLECTION;
else
goto __NORMAL;
desc = CLASS_get_symbol_desc(class, "Count");
if (!desc)
goto __NORMAL;
type = CLASS_DESC_get_type(desc);
// The two only possible cases:
// A static read-only property, and object == NULL
// or a dynamic read-only property, and object != NULL
if (!((type == 'r' && object) || (type == 'R' && !object)))
goto __NORMAL;
TRY
{
if (desc->property.native)
{
if (EXEC_call_native(desc->property.read, object, desc->property.type, 0))
access = GB_DEBUG_ACCESS_NORMAL;
}
else
{
EXEC.class = desc->property.class;
EXEC.object = object;
EXEC.nparam = 0;
EXEC.native = FALSE;
EXEC.index = (int)(intptr_t)desc->property.read;
//EXEC.func = &class->load->func[(int)desc->property.read];
EXEC_function_keep();
TEMP = *RP;
UNBORROW(RP);
RP->type = T_VOID;
}
if (access != GB_DEBUG_ACCESS_NORMAL)
{
VALUE_conv_integer(&TEMP);
*count = TEMP._integer.value;
}
}
CATCH
{
access = GB_DEBUG_ACCESS_NORMAL;
}
END_TRY
// For collection-like objects, check _next and Key property
if (access == GB_DEBUG_ACCESS_COLLECTION)
{
dm = CLASS_get_special_desc(class, SPEC_NEXT);
if (!dm)
goto __NORMAL;
desc = CLASS_get_symbol_desc(class, "Key");
if (!desc || CLASS_DESC_get_type(desc) != type)
goto __NORMAL;
}
return access;
__NORMAL:
return GB_DEBUG_ACCESS_NORMAL;
}
void DEBUG_print_backtrace(STACK_BACKTRACE *bt)
{
int i, n;
bool stop;
STACK_BACKTRACE *NO_WARNING(end);
//STACK_CONTEXT *sc = (STACK_CONTEXT *)(STACK_base + STACK_size) - err->bt_count;
//fprintf(stderr, "0: %s\n", DEBUG_get_position(err->cp, err->fp, err->pc));
for (i = 0, n = 0, stop = FALSE; !stop; i++)
{
//fprintf(stderr, "%d: %s\n", i, DEBUG_get_position(bt[i].cp, bt[i].fp, bt[i].pc));
if (STACK_backtrace_is_end(&bt[i]))
{
stop = TRUE;
end = &bt[i];
STACK_backtrace_clear_end(end);
}
if (bt[i].pc)
{
n++;
fprintf(stderr, "%d: %s\n", n, DEBUG_get_position(bt[i].cp, bt[i].fp, bt[i].pc));
}
}
STACK_backtrace_set_end(end);
}
GB_ARRAY DEBUG_get_string_array_from_backtrace(STACK_BACKTRACE *bt)
{
GB_ARRAY array;
int i, n, size;
STACK_BACKTRACE *end;
for (i = 0, size = 0;; i++)
{
if (bt[i].pc)
size++;
if (STACK_backtrace_is_end(&bt[i]))
{
end = &bt[i];
STACK_backtrace_clear_end(end);
break;
}
}
GB_ArrayNew(&array, GB_T_STRING, size);
//*((char **)GB_ArrayGet(array, 0)) = STRING_new_zero(DEBUG_get_position(err->cp, err->fp, err->pc));
for (i = 0, n = 0; n < size; i++)
{
if (!bt[i].pc)
continue;
*((char **)GB_ArrayGet(array, n)) = STRING_new_zero(DEBUG_get_position(bt[i].cp, bt[i].fp, bt[i].pc));
n++;
}
STACK_backtrace_set_end(end);
return array;
}
GB_CLASS DEBUG_find_class(const char *name)
{
CLASS *class;
CLASS *save = CP;
// As the startup class is automatically exported, this is the only way for the debugger to find it.
if (PROJECT_class && !strcmp(name, PROJECT_class->name))
return (GB_CLASS)PROJECT_class;
CP = NULL;
class = CLASS_find(name);
CP = save;
return (GB_CLASS)class;
}
void DEBUG_enum_keys(void *object, char **key)
{
static CLASS_DESC *desc;
static CENUM *cenum = NULL;
CENUM *old;
CLASS *class;
bool err = FALSE;
char *str;
int len;
old = EXEC_enum;
class = OBJECT_class(object);
if (class == CLASS_Class)
{
class = (CLASS *)object;
object = NULL;
}
TRY
{
if (!cenum)
{
desc = CLASS_get_symbol_desc(class, "Key");
cenum = CENUM_create(object ? object : class);
EXEC_enum = cenum;
EXEC_special(SPEC_FIRST, class, object, 0, TRUE);
EXEC_enum = old;
if (cenum->stop)
{
err = TRUE;
goto __END;
}
}
EXEC_enum = cenum;
err = EXEC_special(SPEC_NEXT, class, object, 0, TRUE);
EXEC_enum = old;
if (err || cenum->stop)
{
err = TRUE;
goto __END;
}
if (desc->property.native)
{
EXEC_call_native(desc->property.read, object, desc->property.type, 0);
SUBR_get_string_len(&TEMP, &str, &len);
}
else
{
EXEC.class = desc->property.class;
EXEC.object = object;
EXEC.nparam = 0;
EXEC.native = FALSE;
EXEC.index = (int)(intptr_t)desc->property.read;
EXEC_function_keep();
SUBR_get_string_len(RP, &str, &len);
}
STRING_free(key);
*key = STRING_new(str, len);
__END:
if (err)
{
OBJECT_UNREF(cenum, "DEBUG_enum_keys");
STRING_free(key);
}
}
CATCH
{
OBJECT_UNREF(cenum, "DEBUG_enum_keys");
STRING_free(key);
}
END_TRY
}