6816ee2015-03-15Martin Nilsson /* -*- c -*-
9944b02015-03-08Martin Nilsson || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */ #include "module.h" #include "pike_error.h" #include "interpret.h" #include "pike_embed.h" #include "module_support.h"
da8b642015-03-08Henrik Grubbström (Grubba) #include "builtin_functions.h"
911efc2015-04-30Martin Nilsson #include "gc.h"
415b2e2018-03-05Martin Nilsson #include "opcodes.h"
bf3f1e2018-03-21Tobias S. Josefowitz #include "bignum.h"
da8b642015-03-08Henrik Grubbström (Grubba)  DECLARATIONS
34a6792015-03-08Martin Nilsson 
1fc83b2015-04-10Martin Nilsson /*! @module Debug */
34a6792015-03-08Martin Nilsson /*! @decl int(0..) map_all_objects(function(object:void) cb) *! *! Call cb for all objects that currently exist. The callback will *! not be called with destructed objects as it's argument. *! *! Objects might be missed if @[cb] creates new objects or destroys *! old ones. *! *! This function is only intended to be used for debug purposes. *! *! @returns *! The total number of objects *! *! @seealso
4c73332018-01-18Henrik Grubbström (Grubba)  *! @[next_object()], @[find_all_clones()]
34a6792015-03-08Martin Nilsson  */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN int(0..) map_all_objects(function(object:void) cb)
34a6792015-03-08Martin Nilsson { struct object *o = first_object; INT32 total = 0; while( o ) { struct object *next = o->next; if( o->prog ) { ref_push_object( o ); safe_apply_svalue( Pike_sp-2, 1, 1 ); pop_stack(); } total++; o = next; }
da8b642015-03-08Henrik Grubbström (Grubba)  RETURN total;
34a6792015-03-08Martin Nilsson }
9944b02015-03-08Martin Nilsson 
4c73332018-01-18Henrik Grubbström (Grubba) /*! @decl array(object) find_all_clones(program p, @ *! int(0..1)|void include_subclasses) *! *! Return an array with all objects that are clones of @[p]. *! *! @param p *! Program that the objects should be a clone of. *! *! @param include_subclasses *! If true, include also objects that are clones of programs *! that have inherited @[p]. Note that this adds significant *! overhead. *! *! This function is only intended to be used for debug purposes. *! *! @seealso *! @[map_all_objects()] */ PIKEFUN array(object) find_all_clones(program|function prog, int(0..1)|void include_subclasses) { struct object *o = first_object; struct program *p = program_from_svalue(prog); if (!p) {
40f3152018-02-16Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("Debug.find_all_clones", 1, "program");
4c73332018-01-18Henrik Grubbström (Grubba)  } if (include_subclasses && !include_subclasses->u.integer) { include_subclasses = NULL; } BEGIN_AGGREGATE_ARRAY(10) { for (o = first_object; o; o = o->next) { if (o->prog == p) { ref_push_object(o); DO_AGGREGATE_ARRAY(120); continue; } if (include_subclasses && o->prog && (o->prog->num_inherits > p->num_inherits)) { int e; /* Check if o->prog has inherited p. */ if (o->prog->storage_needed < p->storage_needed) continue;
7120e42018-01-19Henrik Grubbström (Grubba)  for (e = o->prog->num_inherits + 1 - p->num_inherits; e-- > 1;) {
4c73332018-01-18Henrik Grubbström (Grubba)  if (o->prog->inherits[e].prog == p) { /* Found. */ ref_push_object(o); DO_AGGREGATE_ARRAY(120); break; } } } } } END_AGGREGATE_ARRAY; }
6816ee2015-03-15Martin Nilsson /*! @decl int refs(string|array|mapping|multiset|function|object|program o) *! *! Return the number of references @[o] has. *! *! It is mainly meant for debugging the Pike runtime, but can also be *! used to control memory usage. *! *! @note *! Note that the number of references will always be at least one since *! the value is located on the stack when this function is executed. *! *! @seealso
48d1592015-03-16Martin Nilsson  *! @[next()], @[prev()]
6816ee2015-03-15Martin Nilsson  */ PIKEFUN int refs(string|array|mapping|multiset|function|object|program o) {
f9561d2017-11-17Stephen R. van den Berg  if(!REFCOUNTED_TYPE(TYPEOF(*o))) SIMPLE_ARG_TYPE_ERROR("refs", 1, "array|mapping|multiset|object|" "function|program|string|type");
6816ee2015-03-15Martin Nilsson  RETURN o->u.refs[0]; }
48d1592015-03-16Martin Nilsson /*! @decl object next_object(object o) *! @decl object next_object() *! *! Returns the next object from the list of all objects. *! *! All objects are stored in a linked list. *! *! @returns *! If no arguments have been given @[next_object()] will return the first *! object from the list. *! *! If @[o] has been specified the object after @[o] on the list will be *! returned. *! *! @note *! This function is not recomended to use. *! *! @seealso *! @[destruct()] */ PIKEFUN object next_object(void|object o) { if (!o) o = first_object; else o = Pike_sp[-args].u.object->next; while(o && !o->prog) o=o->next; pop_n_elems(args); if(o) ref_push_object(o); else push_int(0); } /*! @decl mixed next(mixed x) *! *! Find the next object/array/mapping/multiset/program or string. *! *! All objects, arrays, mappings, multisets, programs and strings are *! stored in linked lists inside Pike. This function returns the next *! item on the corresponding list. It is mainly meant for debugging *! the Pike runtime, but can also be used to control memory usage. *! *! @seealso *! @[next_object()], @[prev()] */
64226c2015-03-16Martin Nilsson PIKEFUN mixed next(mixed x) rawtype tOr6(tFunc(tStr,tStr), tFunc(tObj,tObj), tFunc(tMapping,tMapping), tFunc(tMultiset,tMultiset), tFunc(tPrg(tObj),tPrg(tObj)), tFunc(tArray,tArray));
48d1592015-03-16Martin Nilsson {
64226c2015-03-16Martin Nilsson  struct svalue tmp = *x;
48d1592015-03-16Martin Nilsson  switch(TYPEOF(tmp)) {
64226c2015-03-16Martin Nilsson  case T_OBJECT: tmp.u.object=tmp.u.object->next; while(tmp.u.object && !tmp.u.object->prog) tmp.u.object=tmp.u.object->next; break;
48d1592015-03-16Martin Nilsson  case T_ARRAY: tmp.u.array=tmp.u.array->next; break; case T_MAPPING: tmp.u.mapping=tmp.u.mapping->next; break; case T_MULTISET:tmp.u.multiset=tmp.u.multiset->next; break; case T_PROGRAM: tmp.u.program=tmp.u.program->next; break; case T_STRING: tmp.u.string=next_pike_string(tmp.u.string); break; default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("next", 1, "object|array|mapping|multiset|program|string");
48d1592015-03-16Martin Nilsson  }
64226c2015-03-16Martin Nilsson 
48d1592015-03-16Martin Nilsson  if(tmp.u.refs)
64226c2015-03-16Martin Nilsson  assign_svalue(Pike_sp-1, &tmp); else
48d1592015-03-16Martin Nilsson  { pop_stack(); push_int(0); } } /*! @decl mixed prev(mixed x) *! *! Find the previous object/array/mapping/multiset or program. *! *! All objects, arrays, mappings, multisets and programs are *! stored in linked lists inside Pike. This function returns the previous *! item on the corresponding list. It is mainly meant for debugging *! the Pike runtime, but can also be used to control memory usage. *! *! @note *! Unlike @[next()] this function does not work on strings. *! *! @seealso *! @[next_object()], @[next()] */
64226c2015-03-16Martin Nilsson PIKEFUN mixed prev(mixed x) rawtype tOr5(tFunc(tObj,tObj), tFunc(tMapping,tMapping), tFunc(tMultiset,tMultiset), tFunc(tPrg(tObj),tPrg(tObj)), tFunc(tArray,tArray));
48d1592015-03-16Martin Nilsson {
64226c2015-03-16Martin Nilsson  struct svalue tmp = *x;
48d1592015-03-16Martin Nilsson  switch(TYPEOF(tmp)) {
64226c2015-03-16Martin Nilsson  case T_OBJECT: tmp.u.object=tmp.u.object->prev; while(tmp.u.object && !tmp.u.object->prog) tmp.u.object=tmp.u.object->prev; break;
48d1592015-03-16Martin Nilsson  case T_ARRAY: tmp.u.array=tmp.u.array->prev; break; case T_MAPPING: tmp.u.mapping=tmp.u.mapping->prev; break; case T_MULTISET:tmp.u.multiset=tmp.u.multiset->prev; break; case T_PROGRAM: tmp.u.program=tmp.u.program->prev; break; default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("prev", 1, "object|array|mapping|multiset|program");
48d1592015-03-16Martin Nilsson  } if(tmp.u.refs)
64226c2015-03-16Martin Nilsson  assign_svalue(Pike_sp-1, &tmp); else
48d1592015-03-16Martin Nilsson  { pop_stack(); push_int(0); } }
9944b02015-03-08Martin Nilsson #ifdef PIKE_DEBUG /* This function is for debugging *ONLY* * do not document please. /Hubbe */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN int leak(array|mapping|multiset|object|function|program|string|type val)
4a9aec2015-03-08Henrik Grubbström (Grubba)  export;
9944b02015-03-08Martin Nilsson { INT32 i;
da8b642015-03-08Henrik Grubbström (Grubba)  if(!REFCOUNTED_TYPE(TYPEOF(*val)))
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("leak", 1, "array|mapping|multiset|object|" "function|program|string|type");
9944b02015-03-08Martin Nilsson 
da8b642015-03-08Henrik Grubbström (Grubba)  add_ref(val->u.dummy); i = val->u.refs[0]; RETURN i;
9944b02015-03-08Martin Nilsson } /*! @decl int(0..) debug(int(0..) level) *! *! Set the run-time debug level. *! *! @returns *! The old debug level will be returned.
da8b642015-03-08Henrik Grubbström (Grubba)  *!
9944b02015-03-08Martin Nilsson  *! @note *! This function is only available if the Pike runtime has been compiled *! with RTL debug. */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN int(0..) debug(int(0..) d)
4a9aec2015-03-08Henrik Grubbström (Grubba)  export;
9944b02015-03-08Martin Nilsson { pop_n_elems(args); push_int(d_flag); d_flag = d; } /*! @decl int(0..) optimizer_debug(int(0..) level) *! *! Set the optimizer debug level. *! *! @returns *! The old optimizer debug level will be returned.
da8b642015-03-08Henrik Grubbström (Grubba)  *!
9944b02015-03-08Martin Nilsson  *! @note *! This function is only available if the Pike runtime has been compiled *! with RTL debug. */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN int(0..) optimizer_debug(int(0..) l)
4a9aec2015-03-08Henrik Grubbström (Grubba)  export;
9944b02015-03-08Martin Nilsson { pop_n_elems(args); push_int(l_flag); l_flag = l; } /*! @decl int(0..) assembler_debug(int(0..) level) *! *! Set the assembler debug level. *! *! @returns *! The old assembler debug level will be returned.
da8b642015-03-08Henrik Grubbström (Grubba)  *!
9944b02015-03-08Martin Nilsson  *! @note *! This function is only available if the Pike runtime has been compiled *! with RTL debug. */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN int(0..) assembler_debug(int(0..) l)
4a9aec2015-03-08Henrik Grubbström (Grubba)  export;
9944b02015-03-08Martin Nilsson { pop_n_elems(args); push_int(a_flag); a_flag = l; } /*! @decl void dump_program_tables(program p, int(0..)|void indent) *! *! Dumps the internal tables for the program @[p] on stderr. *! *! @param p *! Program to dump. *! *! @param indent *! Number of spaces to indent the output. */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN void dump_program_tables(program p, int(0..)|void indent)
9944b02015-03-08Martin Nilsson {
da8b642015-03-08Henrik Grubbström (Grubba)  dump_program_tables(p, indent?indent->u.integer:0);
9944b02015-03-08Martin Nilsson }
928e212015-04-30Martin Nilsson /*! @decl mixed locate_references(string|array|mapping| @
b3e2022015-04-30Martin Nilsson  *! multiset|function|object| @ *! program|type o) *! @belongs Debug *! *! This function is mostly intended for debugging. It will search through *! all data structures in Pike looking for @[o] and print the *! locations on stderr. @[o] can be anything but @expr{int@} or *! @expr{float@}. *! *! @note *! This function only exists if the Pike runtime has been compiled *! with RTL debug. */
928e212015-04-30Martin Nilsson PIKEFUN mixed locate_references(mixed o) rawtype tFunc(tSetvar(1,tMix),tVar(1));
b3e2022015-04-30Martin Nilsson { locate_references(o); }
911efc2015-04-30Martin Nilsson /*! @decl mixed describe(mixed x) *! @belongs Debug *! *! Prints out a description of the thing @[x] to standard error. *! The description contains various internal info associated with *! @[x]. *! *! @note *! This function only exists if the Pike runtime has been compiled *! with RTL debug. */ PIKEFUN mixed describe(mixed x) rawtype tFunc(tSetvar(1,tMix),tVar(1)); { debug_describe_svalue(debug_malloc_pass(&Pike_sp[-1])); }
d1d9402015-04-30Martin Nilsson /*! @decl void gc_set_watch(array|multiset|mapping|object|function|program|string x) *! @belongs Debug *! *! Sets a watch on the given thing, so that the gc will print a *! message whenever it's encountered. Intended to be used together *! with breakpoints to debug the garbage collector. *! *! @note *! This function only exists if the Pike runtime has been compiled *! with RTL debug. */ PIKEFUN void gc_set_watch(array|multiset|mapping|object|function|program|string x) { gc_watch(&Pike_sp[-1]); }
bf10442015-04-30Martin Nilsson /*! @decl void dump_backlog() *! @belongs Debug *! *! Dumps the 1024 latest executed opcodes, along with the source *! code lines, to standard error. The backlog is only collected on *! debug level 1 or higher, set with @[_debug] or with the @tt{-d@} *! argument on the command line. *! *! @note *! This function only exists if the Pike runtime has been compiled *! with RTL debug. */ PIKEFUN void dump_backlog() { dump_backlog(); }
9944b02015-03-08Martin Nilsson #ifdef YYDEBUG /*! @decl int(0..) compiler_trace(int(0..) level) *! *! Set the compiler trace level. *! *! @returns *! The old compiler trace level will be returned.
da8b642015-03-08Henrik Grubbström (Grubba)  *!
9944b02015-03-08Martin Nilsson  *! @note *! This function is only available if the Pike runtime has been compiled *! with RTL debug. */
da8b642015-03-08Henrik Grubbström (Grubba) PIKEFUN int(0..) compiler_trace(int(0..) yyd)
4a9aec2015-03-08Henrik Grubbström (Grubba)  export;
9944b02015-03-08Martin Nilsson { extern int yydebug; pop_n_elems(args); push_int(yydebug); yydebug = yyd; } #endif /* YYDEBUG */
4e5a842015-04-10Martin Nilsson /*! @decl void disassemble(function fun) *! *! Disassemble a Pike function to @[Stdio.stderr]. *! *! @note *! This function is only available if the Pike runtime *! has been compiled with debug enabled. */ PIKEFUN void disassemble(function fun) { if ((TYPEOF(*fun) != T_FUNCTION) || (SUBTYPEOF(*fun) == FUNCTION_BUILTIN)) {
c15eb62016-02-07Martin Nilsson  WERR("Disassembly only supported for functions implemented in Pike.\n");
4e5a842015-04-10Martin Nilsson  } else if (!fun->u.object->prog) {
c15eb62016-02-07Martin Nilsson  WERR("Function in destructed object.\n");
4e5a842015-04-10Martin Nilsson  } else { int f = SUBTYPEOF(*fun); struct reference *ptr = PTR_FROM_INT(fun->u.object->prog, f); struct program *p = PROG_FROM_PTR(fun->u.object->prog, ptr); struct identifier *id = p->identifiers + ptr->identifier_offset; if (id->func.offset >= 0) { struct pike_string *tripples = p->strings[read_program_data(p->program + id->func.offset, -1)]; switch(tripples->size_shift) { #define CASE(SHIFT) \ case SHIFT: \ { \ PIKE_CONCAT(p_wchar, SHIFT) *str = \ PIKE_CONCAT(STR, SHIFT)(tripples); \ int i=0; \ while(i < tripples->len) { \
c15eb62016-02-07Martin Nilsson  WERR("@@@ %d: %s, %d, %d\n", \
4e5a842015-04-10Martin Nilsson  i/3, \ instrs[*str - F_OFFSET]. \ name, \ str[1], str[2]); \ str += 3; \ i += 3; \ } \ } \ break CASE(0); CASE(1); CASE(2); #undef CASE } } else {
c15eb62016-02-07Martin Nilsson  WERR("Prototype.\n");
4e5a842015-04-10Martin Nilsson  } } }
9944b02015-03-08Martin Nilsson #endif /* PIKE_DEBUG */
19a3f32015-03-15Martin Nilsson 
60e07d2015-04-10Martin Nilsson #ifdef DEBUG_MALLOC /*! @decl void reset_dmalloc() *! *! @note *! Only available when compiled with dmalloc. */ PIKEFUN void reset_dmalloc() { reset_debug_malloc(); } extern char * dynamic_location(const char *file, INT_TYPE line); extern char * dmalloc_default_location; /*! @decl void dmalloc_set_name() *! *! @note *! Only available when compiled with dmalloc. */ PIKEFUN void dmalloc_set_name() { dmalloc_default_location=0; } /*! @decl void dmalloc_set_name(string filename, int(1..) linenumber) *! *! @note *! Only available when compiled with dmalloc. */ PIKEFUN void dmalloc_set_name(string filename, int(1..) linenumber) { dmalloc_default_location = dynamic_location(filename->str, linenumber); } extern void list_open_fds(void); /*! @decl void list_open_fds() *! *! @note *! Only available when compiled with dmalloc. */ PIKEFUN void list_open_fds() { list_open_fds(); } /*! @decl void dump_dmalloc_locations(string|array|mapping| @ *! multiset|function|object| @ *! program|type o) *! *! @note *! Only available when compiled with dmalloc. */ PIKEFUN void dump_dmalloc_locations(string|array|mapping|multiset|function|object|program|type o) {
f9561d2017-11-17Stephen R. van den Berg  if(!REFCOUNTED_TYPE(TYPEOF(*o))) SIMPLE_ARG_TYPE_ERROR("refs", 1, "array|mapping|multiset|object|" "function|program|string|type");
60e07d2015-04-10Martin Nilsson  debug_malloc_dump_references (o->u.refs, 2, 1, 0); } #endif /* DEBUG_MALLOC */
c05d7f2015-12-19Tobias S. Josefowitz /*! @decl mapping(string:int) get_program_layout(program p) *! Returns a mapping which describes the layout of compiled machine *! code in the program @expr{p@}. The indices of the returned mapping *! are function names, the values the starting address of the compiled *! function. The total size of the program code is stored with index *! @expr{0@}. */ PIKEFUN mapping get_program_layout(program p) { size_t i; struct mapping *m = allocate_mapping(64); if(p->flags & PROGRAM_FINISHED) { for (i = 0; i < p->num_identifier_references; i++) { struct reference *ref = p->identifier_references + i; struct identifier *id = ID_FROM_PTR(p, ref); if ((id->identifier_flags & IDENTIFIER_TYPE_MASK) == IDENTIFIER_PIKE_FUNCTION && !ref->inherit_offset) { PIKE_OPCODE_T *pc = p->program + id->func.offset; struct svalue sv;
bf3f1e2018-03-21Tobias S. Josefowitz  ulongest_to_svalue_no_free(&sv, (UINT64)PTR_TO_INT(pc));
c05d7f2015-12-19Tobias S. Josefowitz  mapping_string_insert(m, id->name, &sv);
bf3f1e2018-03-21Tobias S. Josefowitz  free_svalue(&sv);
c05d7f2015-12-19Tobias S. Josefowitz  } } { struct svalue key, value; SET_SVAL(key, PIKE_T_INT, NUMBER_NUMBER, integer, 0); SET_SVAL(value, PIKE_T_INT, NUMBER_NUMBER, integer,
0f34312016-08-31Arne Goedeke  p->num_program * sizeof(PIKE_OPCODE_T));
c05d7f2015-12-19Tobias S. Josefowitz  mapping_insert(m, &key, &value); } } RETURN m; } /*! @decl int(0..) map_all_programs(function(program:void) cb) *! *! Call cb for all programs that currently exist. *! *! Programs might be missed if @[cb] creates new programs. *! *! This function is only intended to be used for debug purposes. *! *! @returns *! The total number of programs *! *! @seealso *! @[map_all_objects()] */ PIKEFUN int(0..) map_all_programs(function(program:void) cb) { struct program *p = first_program; INT32 total = 0; while( p ) { struct program *next; if (p->flags & PROGRAM_FINISHED) { add_ref(p); ref_push_program( p ); safe_apply_svalue( Pike_sp-2, 1, 1 ); pop_stack(); total++; next = p->next; sub_ref(p); } else next = p->next; p = next; } RETURN total; }
1fc83b2015-04-10Martin Nilsson /*! @endmodule */
19a3f32015-03-15Martin Nilsson PIKE_MODULE_INIT { INIT; #ifdef PIKE_DEBUG ADD_INT_CONSTANT("HAVE_DEBUG", 1, 0); #endif }
10fe452015-07-01Henrik Grubbström (Grubba)  PIKE_MODULE_EXIT { EXIT; }