debug.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /* Debugging extensions for Guile
  2. * Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2006, 2008 Free Software Foundation
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include "libguile/_scm.h"
  22. #include "libguile/async.h"
  23. #include "libguile/eval.h"
  24. #include "libguile/list.h"
  25. #include "libguile/stackchk.h"
  26. #include "libguile/throw.h"
  27. #include "libguile/macros.h"
  28. #include "libguile/smob.h"
  29. #include "libguile/procprop.h"
  30. #include "libguile/srcprop.h"
  31. #include "libguile/alist.h"
  32. #include "libguile/continuations.h"
  33. #include "libguile/strports.h"
  34. #include "libguile/read.h"
  35. #include "libguile/feature.h"
  36. #include "libguile/dynwind.h"
  37. #include "libguile/modules.h"
  38. #include "libguile/ports.h"
  39. #include "libguile/root.h"
  40. #include "libguile/fluids.h"
  41. #include "libguile/objects.h"
  42. #include "libguile/validate.h"
  43. #include "libguile/debug.h"
  44. /* {Run time control of the debugging evaluator}
  45. */
  46. SCM_DEFINE (scm_debug_options, "debug-options-interface", 0, 1, 0,
  47. (SCM setting),
  48. "Option interface for the debug options. Instead of using\n"
  49. "this procedure directly, use the procedures @code{debug-enable},\n"
  50. "@code{debug-disable}, @code{debug-set!} and @code{debug-options}.")
  51. #define FUNC_NAME s_scm_debug_options
  52. {
  53. SCM ans;
  54. scm_dynwind_begin (0);
  55. scm_dynwind_critical_section (SCM_BOOL_F);
  56. ans = scm_options (setting, scm_debug_opts, SCM_N_DEBUG_OPTIONS, FUNC_NAME);
  57. if (!(1 <= SCM_N_FRAMES && SCM_N_FRAMES <= SCM_MAX_FRAME_SIZE))
  58. {
  59. scm_options (ans, scm_debug_opts, SCM_N_DEBUG_OPTIONS, FUNC_NAME);
  60. SCM_OUT_OF_RANGE (1, setting);
  61. }
  62. SCM_RESET_DEBUG_MODE;
  63. scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
  64. scm_debug_eframe_size = 2 * SCM_N_FRAMES;
  65. scm_dynwind_end ();
  66. return ans;
  67. }
  68. #undef FUNC_NAME
  69. static void
  70. with_traps_before (void *data)
  71. {
  72. int *trap_flag = data;
  73. *trap_flag = SCM_TRAPS_P;
  74. SCM_TRAPS_P = 1;
  75. }
  76. static void
  77. with_traps_after (void *data)
  78. {
  79. int *trap_flag = data;
  80. SCM_TRAPS_P = *trap_flag;
  81. }
  82. static SCM
  83. with_traps_inner (void *data)
  84. {
  85. SCM thunk = SCM_PACK ((scm_t_bits) data);
  86. return scm_call_0 (thunk);
  87. }
  88. SCM_DEFINE (scm_with_traps, "with-traps", 1, 0, 0,
  89. (SCM thunk),
  90. "Call @var{thunk} with traps enabled.")
  91. #define FUNC_NAME s_scm_with_traps
  92. {
  93. int trap_flag;
  94. SCM_VALIDATE_THUNK (1, thunk);
  95. return scm_internal_dynamic_wind (with_traps_before,
  96. with_traps_inner,
  97. with_traps_after,
  98. (void *) SCM_UNPACK (thunk),
  99. &trap_flag);
  100. }
  101. #undef FUNC_NAME
  102. SCM_SYMBOL (scm_sym_procname, "procname");
  103. SCM_SYMBOL (scm_sym_dots, "...");
  104. SCM_SYMBOL (scm_sym_source, "source");
  105. /* {Memoized Source}
  106. */
  107. scm_t_bits scm_tc16_memoized;
  108. static int
  109. memoized_print (SCM obj, SCM port, scm_print_state *pstate)
  110. {
  111. int writingp = SCM_WRITINGP (pstate);
  112. scm_puts ("#<memoized ", port);
  113. SCM_SET_WRITINGP (pstate, 1);
  114. scm_iprin1 (SCM_MEMOIZED_EXP (obj), port, pstate);
  115. SCM_SET_WRITINGP (pstate, writingp);
  116. scm_putc ('>', port);
  117. return 1;
  118. }
  119. SCM_DEFINE (scm_memoized_p, "memoized?", 1, 0, 0,
  120. (SCM obj),
  121. "Return @code{#t} if @var{obj} is memoized.")
  122. #define FUNC_NAME s_scm_memoized_p
  123. {
  124. return scm_from_bool(SCM_MEMOIZEDP (obj));
  125. }
  126. #undef FUNC_NAME
  127. SCM
  128. scm_make_memoized (SCM exp, SCM env)
  129. {
  130. /* *fixme* Check that env is a valid environment. */
  131. SCM_RETURN_NEWSMOB (scm_tc16_memoized, SCM_UNPACK (scm_cons (exp, env)));
  132. }
  133. #ifdef GUILE_DEBUG
  134. /*
  135. * Some primitives for construction of memoized code
  136. *
  137. * - procedure: memcons CAR CDR [ENV]
  138. *
  139. * Construct a pair, encapsulated in a memoized object.
  140. *
  141. * The CAR and CDR can be either normal or memoized. If ENV isn't
  142. * specified, the top-level environment of the current module will
  143. * be assumed. All environments must match.
  144. *
  145. * - procedure: make-iloc FRAME BINDING CDRP
  146. *
  147. * Return an iloc referring to frame no. FRAME, binding
  148. * no. BINDING. If CDRP is non-#f, the iloc is referring to a
  149. * frame consisting of a single pair, with the value stored in the
  150. * CDR.
  151. *
  152. * - procedure: iloc? OBJECT
  153. *
  154. * Return #t if OBJECT is an iloc.
  155. *
  156. * - procedure: mem->proc MEMOIZED
  157. *
  158. * Construct a closure from the memoized lambda expression MEMOIZED
  159. *
  160. * WARNING! The code is not copied!
  161. *
  162. * - procedure: proc->mem CLOSURE
  163. *
  164. * Turn the closure CLOSURE into a memoized object.
  165. *
  166. * WARNING! The code is not copied!
  167. *
  168. * - constant: SCM_IM_AND
  169. * - constant: SCM_IM_BEGIN
  170. * - constant: SCM_IM_CASE
  171. * - constant: SCM_IM_COND
  172. * - constant: SCM_IM_DO
  173. * - constant: SCM_IM_IF
  174. * - constant: SCM_IM_LAMBDA
  175. * - constant: SCM_IM_LET
  176. * - constant: SCM_IM_LETSTAR
  177. * - constant: SCM_IM_LETREC
  178. * - constant: SCM_IM_OR
  179. * - constant: SCM_IM_QUOTE
  180. * - constant: SCM_IM_SET
  181. * - constant: SCM_IM_DEFINE
  182. * - constant: SCM_IM_APPLY
  183. * - constant: SCM_IM_CONT
  184. * - constant: SCM_IM_DISPATCH
  185. */
  186. #include "libguile/variable.h"
  187. #include "libguile/procs.h"
  188. SCM_DEFINE (scm_memcons, "memcons", 2, 1, 0,
  189. (SCM car, SCM cdr, SCM env),
  190. "Return a new memoized cons cell with @var{car} and @var{cdr}\n"
  191. "as members and @var{env} as the environment.")
  192. #define FUNC_NAME s_scm_memcons
  193. {
  194. if (SCM_MEMOIZEDP (car))
  195. {
  196. /*fixme* environments may be two different but equal top-level envs */
  197. if (!SCM_UNBNDP (env) && SCM_MEMOIZED_ENV (car) != env)
  198. SCM_MISC_ERROR ("environment mismatch arg1 <-> arg3",
  199. scm_list_2 (car, env));
  200. else
  201. env = SCM_MEMOIZED_ENV (car);
  202. car = SCM_MEMOIZED_EXP (car);
  203. }
  204. if (SCM_MEMOIZEDP (cdr))
  205. {
  206. if (!SCM_UNBNDP (env) && SCM_MEMOIZED_ENV (cdr) != env)
  207. SCM_MISC_ERROR ("environment mismatch arg2 <-> arg3",
  208. scm_list_2 (cdr, env));
  209. else
  210. env = SCM_MEMOIZED_ENV (cdr);
  211. cdr = SCM_MEMOIZED_EXP (cdr);
  212. }
  213. if (SCM_UNBNDP (env))
  214. env = scm_top_level_env (SCM_TOP_LEVEL_LOOKUP_CLOSURE);
  215. else
  216. SCM_VALIDATE_NULLORCONS (3, env);
  217. return scm_make_memoized (scm_cons (car, cdr), env);
  218. }
  219. #undef FUNC_NAME
  220. SCM_DEFINE (scm_mem_to_proc, "mem->proc", 1, 0, 0,
  221. (SCM obj),
  222. "Convert a memoized object (which must represent a body)\n"
  223. "to a procedure.")
  224. #define FUNC_NAME s_scm_mem_to_proc
  225. {
  226. SCM env;
  227. SCM_VALIDATE_MEMOIZED (1, obj);
  228. env = SCM_MEMOIZED_ENV (obj);
  229. obj = SCM_MEMOIZED_EXP (obj);
  230. return scm_closure (obj, env);
  231. }
  232. #undef FUNC_NAME
  233. SCM_DEFINE (scm_proc_to_mem, "proc->mem", 1, 0, 0,
  234. (SCM obj),
  235. "Convert a procedure to a memoized object.")
  236. #define FUNC_NAME s_scm_proc_to_mem
  237. {
  238. SCM_VALIDATE_CLOSURE (1, obj);
  239. return scm_make_memoized (SCM_CODE (obj), SCM_ENV (obj));
  240. }
  241. #undef FUNC_NAME
  242. #endif /* GUILE_DEBUG */
  243. SCM_DEFINE (scm_i_unmemoize_expr, "unmemoize-expr", 1, 0, 0,
  244. (SCM m),
  245. "Unmemoize the memoized expression @var{m},")
  246. #define FUNC_NAME s_scm_i_unmemoize_expr
  247. {
  248. SCM_VALIDATE_MEMOIZED (1, m);
  249. return scm_i_unmemocopy_expr (SCM_MEMOIZED_EXP (m), SCM_MEMOIZED_ENV (m));
  250. }
  251. #undef FUNC_NAME
  252. SCM_DEFINE (scm_memoized_environment, "memoized-environment", 1, 0, 0,
  253. (SCM m),
  254. "Return the environment of the memoized expression @var{m}.")
  255. #define FUNC_NAME s_scm_memoized_environment
  256. {
  257. SCM_VALIDATE_MEMOIZED (1, m);
  258. return SCM_MEMOIZED_ENV (m);
  259. }
  260. #undef FUNC_NAME
  261. SCM_DEFINE (scm_procedure_name, "procedure-name", 1, 0, 0,
  262. (SCM proc),
  263. "Return the name of the procedure @var{proc}")
  264. #define FUNC_NAME s_scm_procedure_name
  265. {
  266. SCM_VALIDATE_PROC (1, proc);
  267. switch (SCM_TYP7 (proc)) {
  268. case scm_tcs_subrs:
  269. return SCM_SNAME (proc);
  270. default:
  271. {
  272. SCM name = scm_procedure_property (proc, scm_sym_name);
  273. #if 0
  274. /* Source property scm_sym_procname not implemented yet... */
  275. SCM name = scm_source_property (SCM_CAR (SCM_CLOSURE_BODY (proc)), scm_sym_procname);
  276. if (scm_is_false (name))
  277. name = scm_procedure_property (proc, scm_sym_name);
  278. #endif
  279. if (scm_is_false (name) && SCM_CLOSUREP (proc))
  280. name = scm_reverse_lookup (SCM_ENV (proc), proc);
  281. return name;
  282. }
  283. }
  284. }
  285. #undef FUNC_NAME
  286. SCM_DEFINE (scm_procedure_source, "procedure-source", 1, 0, 0,
  287. (SCM proc),
  288. "Return the source of the procedure @var{proc}.")
  289. #define FUNC_NAME s_scm_procedure_source
  290. {
  291. SCM_VALIDATE_NIM (1, proc);
  292. again:
  293. switch (SCM_TYP7 (proc)) {
  294. case scm_tcs_closures:
  295. {
  296. const SCM formals = SCM_CLOSURE_FORMALS (proc);
  297. const SCM body = SCM_CLOSURE_BODY (proc);
  298. const SCM src = scm_source_property (body, scm_sym_copy);
  299. if (scm_is_true (src))
  300. {
  301. return scm_cons2 (scm_sym_lambda, formals, src);
  302. }
  303. else
  304. {
  305. const SCM env = SCM_EXTEND_ENV (formals, SCM_EOL, SCM_ENV (proc));
  306. return scm_cons2 (scm_sym_lambda,
  307. scm_i_finite_list_copy (formals),
  308. scm_i_unmemocopy_body (body, env));
  309. }
  310. }
  311. case scm_tcs_struct:
  312. if (!SCM_I_OPERATORP (proc))
  313. break;
  314. goto procprop;
  315. case scm_tc7_smob:
  316. if (!SCM_SMOB_DESCRIPTOR (proc).apply)
  317. break;
  318. case scm_tcs_subrs:
  319. #ifdef CCLO
  320. case scm_tc7_cclo:
  321. #endif
  322. procprop:
  323. /* It would indeed be a nice thing if we supplied source even for
  324. built in procedures! */
  325. return scm_procedure_property (proc, scm_sym_source);
  326. case scm_tc7_pws:
  327. {
  328. SCM src = scm_procedure_property (proc, scm_sym_source);
  329. if (scm_is_true (src))
  330. return src;
  331. proc = SCM_PROCEDURE (proc);
  332. goto again;
  333. }
  334. default:
  335. ;
  336. }
  337. SCM_WRONG_TYPE_ARG (1, proc);
  338. return SCM_BOOL_F; /* not reached */
  339. }
  340. #undef FUNC_NAME
  341. SCM_DEFINE (scm_procedure_environment, "procedure-environment", 1, 0, 0,
  342. (SCM proc),
  343. "Return the environment of the procedure @var{proc}.")
  344. #define FUNC_NAME s_scm_procedure_environment
  345. {
  346. SCM_VALIDATE_NIM (1, proc);
  347. switch (SCM_TYP7 (proc)) {
  348. case scm_tcs_closures:
  349. return SCM_ENV (proc);
  350. case scm_tcs_subrs:
  351. #ifdef CCLO
  352. case scm_tc7_cclo:
  353. #endif
  354. return SCM_EOL;
  355. default:
  356. SCM_WRONG_TYPE_ARG (1, proc);
  357. /* not reached */
  358. }
  359. }
  360. #undef FUNC_NAME
  361. /* Eval in a local environment. We would like to have the ability to
  362. * evaluate in a specified local environment, but due to the
  363. * memoization this isn't normally possible. We solve it by copying
  364. * the code before evaluating. One solution would be to have eval.c
  365. * generate yet another evaluator. They are not very big actually.
  366. */
  367. SCM_DEFINE (scm_local_eval, "local-eval", 1, 1, 0,
  368. (SCM exp, SCM env),
  369. "Evaluate @var{exp} in its environment. If @var{env} is supplied,\n"
  370. "it is the environment in which to evaluate @var{exp}. Otherwise,\n"
  371. "@var{exp} must be a memoized code object (in which case, its environment\n"
  372. "is implicit).")
  373. #define FUNC_NAME s_scm_local_eval
  374. {
  375. if (SCM_UNBNDP (env))
  376. {
  377. SCM_VALIDATE_MEMOIZED (1, exp);
  378. return scm_i_eval_x (SCM_MEMOIZED_EXP (exp), SCM_MEMOIZED_ENV (exp));
  379. }
  380. return scm_i_eval (exp, env);
  381. }
  382. #undef FUNC_NAME
  383. #if 0
  384. SCM_REGISTER_PROC (s_reverse_lookup, "reverse-lookup", 2, 0, 0, scm_reverse_lookup);
  385. #endif
  386. SCM
  387. scm_reverse_lookup (SCM env, SCM data)
  388. {
  389. while (scm_is_pair (env) && scm_is_pair (SCM_CAR (env)))
  390. {
  391. SCM names = SCM_CAAR (env);
  392. SCM values = SCM_CDAR (env);
  393. while (scm_is_pair (names))
  394. {
  395. if (scm_is_eq (SCM_CAR (values), data))
  396. return SCM_CAR (names);
  397. names = SCM_CDR (names);
  398. values = SCM_CDR (values);
  399. }
  400. if (!scm_is_null (names) && scm_is_eq (values, data))
  401. return names;
  402. env = SCM_CDR (env);
  403. }
  404. return SCM_BOOL_F;
  405. }
  406. SCM
  407. scm_start_stack (SCM id, SCM exp, SCM env)
  408. {
  409. SCM answer;
  410. scm_t_debug_frame vframe;
  411. scm_t_debug_info vframe_vect_body;
  412. vframe.prev = scm_i_last_debug_frame ();
  413. vframe.status = SCM_VOIDFRAME;
  414. vframe.vect = &vframe_vect_body;
  415. vframe.vect[0].id = id;
  416. scm_i_set_last_debug_frame (&vframe);
  417. answer = scm_i_eval (exp, env);
  418. scm_i_set_last_debug_frame (vframe.prev);
  419. return answer;
  420. }
  421. SCM_SYNTAX(s_start_stack, "start-stack", scm_makacro, scm_m_start_stack);
  422. static SCM
  423. scm_m_start_stack (SCM exp, SCM env)
  424. #define FUNC_NAME s_start_stack
  425. {
  426. exp = SCM_CDR (exp);
  427. if (!scm_is_pair (exp)
  428. || !scm_is_pair (SCM_CDR (exp))
  429. || !scm_is_null (SCM_CDDR (exp)))
  430. SCM_WRONG_NUM_ARGS ();
  431. return scm_start_stack (scm_eval_car (exp, env), SCM_CADR (exp), env);
  432. }
  433. #undef FUNC_NAME
  434. /* {Debug Objects}
  435. *
  436. * The debugging evaluator throws these on frame traps.
  437. */
  438. scm_t_bits scm_tc16_debugobj;
  439. static int
  440. debugobj_print (SCM obj, SCM port, scm_print_state *pstate SCM_UNUSED)
  441. {
  442. scm_puts ("#<debug-object ", port);
  443. scm_intprint ((long) SCM_DEBUGOBJ_FRAME (obj), 16, port);
  444. scm_putc ('>', port);
  445. return 1;
  446. }
  447. SCM_DEFINE (scm_debug_object_p, "debug-object?", 1, 0, 0,
  448. (SCM obj),
  449. "Return @code{#t} if @var{obj} is a debug object.")
  450. #define FUNC_NAME s_scm_debug_object_p
  451. {
  452. return scm_from_bool(SCM_DEBUGOBJP (obj));
  453. }
  454. #undef FUNC_NAME
  455. SCM
  456. scm_make_debugobj (scm_t_debug_frame *frame)
  457. {
  458. return scm_cell (scm_tc16_debugobj, (scm_t_bits) frame);
  459. }
  460. /* Undocumented debugging procedure */
  461. #ifdef GUILE_DEBUG
  462. SCM_DEFINE (scm_debug_hang, "debug-hang", 0, 1, 0,
  463. (SCM obj),
  464. "Go into an endless loop, which can be only terminated with\n"
  465. "a debugger.")
  466. #define FUNC_NAME s_scm_debug_hang
  467. {
  468. int go = 0;
  469. while (!go) ;
  470. return SCM_UNSPECIFIED;
  471. }
  472. #undef FUNC_NAME
  473. #endif
  474. void
  475. scm_init_debug ()
  476. {
  477. scm_init_opts (scm_debug_options, scm_debug_opts, SCM_N_DEBUG_OPTIONS);
  478. scm_tc16_memoized = scm_make_smob_type ("memoized", 0);
  479. scm_set_smob_mark (scm_tc16_memoized, scm_markcdr);
  480. scm_set_smob_print (scm_tc16_memoized, memoized_print);
  481. scm_tc16_debugobj = scm_make_smob_type ("debug-object", 0);
  482. scm_set_smob_print (scm_tc16_debugobj, debugobj_print);
  483. #ifdef GUILE_DEBUG
  484. scm_c_define ("SCM_IM_AND", SCM_IM_AND);
  485. scm_c_define ("SCM_IM_BEGIN", SCM_IM_BEGIN);
  486. scm_c_define ("SCM_IM_CASE", SCM_IM_CASE);
  487. scm_c_define ("SCM_IM_COND", SCM_IM_COND);
  488. scm_c_define ("SCM_IM_DO", SCM_IM_DO);
  489. scm_c_define ("SCM_IM_IF", SCM_IM_IF);
  490. scm_c_define ("SCM_IM_LAMBDA", SCM_IM_LAMBDA);
  491. scm_c_define ("SCM_IM_LET", SCM_IM_LET);
  492. scm_c_define ("SCM_IM_LETSTAR", SCM_IM_LETSTAR);
  493. scm_c_define ("SCM_IM_LETREC", SCM_IM_LETREC);
  494. scm_c_define ("SCM_IM_OR", SCM_IM_OR);
  495. scm_c_define ("SCM_IM_QUOTE", SCM_IM_QUOTE);
  496. scm_c_define ("SCM_IM_SET_X", SCM_IM_SET_X);
  497. scm_c_define ("SCM_IM_DEFINE", SCM_IM_DEFINE);
  498. scm_c_define ("SCM_IM_APPLY", SCM_IM_APPLY);
  499. scm_c_define ("SCM_IM_CONT", SCM_IM_CONT);
  500. scm_c_define ("SCM_IM_DISPATCH", SCM_IM_DISPATCH);
  501. #endif
  502. scm_add_feature ("debug-extensions");
  503. #include "libguile/debug.x"
  504. }
  505. /*
  506. Local Variables:
  507. c-file-style: "gnu"
  508. End:
  509. */