backtrace.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. /* Printing of backtraces and error messages
  2. * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002 Free Software Foundation
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2, or (at your option)
  7. * any later version.
  8. *
  9. * This program 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
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; see the file COPYING. If not, write to
  16. * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  17. * Boston, MA 02111-1307 USA
  18. *
  19. * As a special exception, the Free Software Foundation gives permission
  20. * for additional uses of the text contained in its release of GUILE.
  21. *
  22. * The exception is that, if you link the GUILE library with other files
  23. * to produce an executable, this does not by itself cause the
  24. * resulting executable to be covered by the GNU General Public License.
  25. * Your use of that executable is in no way restricted on account of
  26. * linking the GUILE library code into it.
  27. *
  28. * This exception does not however invalidate any other reasons why
  29. * the executable file might be covered by the GNU General Public License.
  30. *
  31. * This exception applies only to the code released by the
  32. * Free Software Foundation under the name GUILE. If you copy
  33. * code from other Free Software Foundation releases into a copy of
  34. * GUILE, as the General Public License permits, the exception does
  35. * not apply to the code that you add in this way. To avoid misleading
  36. * anyone as to the status of such modified files, you must delete
  37. * this exception notice from them.
  38. *
  39. * If you write modifications of your own for GUILE, it is your choice
  40. * whether to permit this exception to apply to your modifications.
  41. * If you do not wish that, delete this exception notice.
  42. *
  43. * The author can be reached at djurfeldt@nada.kth.se
  44. * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN */
  45. #include <stdio.h>
  46. #include <ctype.h>
  47. #include "libguile/_scm.h"
  48. #ifdef HAVE_UNISTD_H
  49. #include <unistd.h>
  50. #endif
  51. #include "libguile/stacks.h"
  52. #include "libguile/srcprop.h"
  53. #include "libguile/struct.h"
  54. #include "libguile/strports.h"
  55. #include "libguile/throw.h"
  56. #include "libguile/fluids.h"
  57. #include "libguile/ports.h"
  58. #include "libguile/strings.h"
  59. #include "libguile/validate.h"
  60. #include "libguile/backtrace.h"
  61. /* {Error reporting and backtraces}
  62. * (A first approximation.)
  63. *
  64. * Note that these functions shouldn't generate errors themselves.
  65. */
  66. #ifndef SCM_RECKLESS
  67. #undef SCM_ASSERT
  68. #define SCM_ASSERT(_cond, _arg, _pos, _subr) \
  69. if (!(_cond)) \
  70. return SCM_BOOL_F;
  71. #endif
  72. SCM scm_the_last_stack_fluid;
  73. static void
  74. display_header (SCM source, SCM port)
  75. {
  76. SCM fname = (SCM_MEMOIZEDP (source)
  77. ? scm_source_property (source, scm_sym_filename)
  78. : SCM_BOOL_F);
  79. if (SCM_STRINGP (fname))
  80. {
  81. scm_prin1 (fname, port, 0);
  82. scm_putc (':', port);
  83. scm_intprint (SCM_INUM (scm_source_property (source, scm_sym_line)) + 1,
  84. 10,
  85. port);
  86. scm_putc (':', port);
  87. scm_intprint (SCM_INUM (scm_source_property (source, scm_sym_column)) + 1,
  88. 10,
  89. port);
  90. }
  91. else
  92. scm_puts ("ERROR", port);
  93. scm_puts (": ", port);
  94. }
  95. void
  96. scm_display_error_message (SCM message, SCM args, SCM port)
  97. {
  98. if (SCM_ROSTRINGP (message) && SCM_NFALSEP (scm_list_p (args)))
  99. {
  100. scm_simple_format (port, message, args);
  101. scm_newline (port);
  102. }
  103. else
  104. {
  105. scm_prin1 (message, port, 0);
  106. scm_putc ('\n', port);
  107. }
  108. }
  109. static void
  110. display_expression (SCM frame,SCM pname,SCM source,SCM port)
  111. {
  112. SCM print_state = scm_make_print_state ();
  113. scm_print_state *pstate = SCM_PRINT_STATE (print_state);
  114. pstate->writingp = 0;
  115. pstate->fancyp = 1;
  116. pstate->level = 2;
  117. pstate->length = 3;
  118. if (SCM_ROSTRINGP (pname))
  119. {
  120. if (SCM_FRAMEP (frame)
  121. && SCM_FRAME_EVAL_ARGS_P (frame))
  122. scm_puts ("While evaluating arguments to ", port);
  123. else
  124. scm_puts ("In procedure ", port);
  125. scm_iprin1 (pname, port, pstate);
  126. if (SCM_MEMOIZEDP (source))
  127. {
  128. scm_puts (" in expression ", port);
  129. pstate->writingp = 1;
  130. scm_iprin1 (scm_unmemoize (source), port, pstate);
  131. }
  132. }
  133. else if (SCM_NIMP (source))
  134. {
  135. scm_puts ("In expression ", port);
  136. pstate->writingp = 1;
  137. scm_iprin1 (scm_unmemoize (source), port, pstate);
  138. }
  139. scm_puts (":\n", port);
  140. scm_free_print_state (print_state);
  141. }
  142. struct display_error_args {
  143. SCM stack;
  144. SCM port;
  145. SCM subr;
  146. SCM message;
  147. SCM args;
  148. SCM rest;
  149. };
  150. static SCM
  151. display_error_body (struct display_error_args *a)
  152. {
  153. SCM current_frame = SCM_BOOL_F;
  154. SCM source = SCM_BOOL_F;
  155. SCM pname = SCM_BOOL_F;
  156. SCM prev_frame = SCM_BOOL_F;
  157. if (SCM_DEBUGGINGP
  158. && SCM_STACKP (a->stack)
  159. && SCM_STACK_LENGTH (a->stack) > 0)
  160. {
  161. current_frame = scm_stack_ref (a->stack, SCM_INUM0);
  162. source = SCM_FRAME_SOURCE (current_frame);
  163. prev_frame = SCM_FRAME_PREV (current_frame);
  164. if (!SCM_MEMOIZEDP (source) && !SCM_FALSEP (prev_frame))
  165. source = SCM_FRAME_SOURCE (prev_frame);
  166. if (SCM_FRAME_PROC_P (current_frame)
  167. && SCM_EQ_P (scm_procedure_p (SCM_FRAME_PROC (current_frame)), SCM_BOOL_T))
  168. pname = scm_procedure_name (SCM_FRAME_PROC (current_frame));
  169. }
  170. if (!SCM_ROSTRINGP (pname))
  171. pname = a->subr;
  172. if (SCM_ROSTRINGP (pname) || SCM_MEMOIZEDP (source))
  173. {
  174. display_header (source, a->port);
  175. display_expression (current_frame, pname, source, a->port);
  176. }
  177. display_header (source, a->port);
  178. scm_display_error_message (a->message, a->args, a->port);
  179. return SCM_UNSPECIFIED;
  180. }
  181. struct display_error_handler_data {
  182. char *mode;
  183. SCM port;
  184. };
  185. /* This is the exception handler for error reporting routines.
  186. Note that it is very important that this handler *doesn't* try to
  187. print more than the error tag, since the error very probably is
  188. caused by an erroneous print call-back routine. If we would
  189. try to print all objects, we would enter an infinite loop. */
  190. static SCM
  191. display_error_handler (struct display_error_handler_data *data,
  192. SCM tag, SCM args)
  193. {
  194. SCM print_state = scm_make_print_state ();
  195. scm_puts ("\nException during displaying of ", data->port);
  196. scm_puts (data->mode, data->port);
  197. scm_puts (": ", data->port);
  198. scm_iprin1 (tag, data->port, SCM_PRINT_STATE (print_state));
  199. scm_putc ('\n', data->port);
  200. return SCM_UNSPECIFIED;
  201. }
  202. SCM_DEFINE (scm_display_error, "display-error", 6, 0, 0,
  203. (SCM stack, SCM port, SCM subr, SCM message, SCM args, SCM rest),
  204. "")
  205. #define FUNC_NAME s_scm_display_error
  206. {
  207. struct display_error_args a;
  208. struct display_error_handler_data data;
  209. a.stack = stack;
  210. a.port = port;
  211. a.subr = subr;
  212. a.message = message;
  213. a.args = args;
  214. a.rest = rest;
  215. data.mode = "error";
  216. data.port = port;
  217. scm_internal_catch (SCM_BOOL_T,
  218. (scm_catch_body_t) display_error_body, &a,
  219. (scm_catch_handler_t) display_error_handler, &data);
  220. return SCM_UNSPECIFIED;
  221. }
  222. #undef FUNC_NAME
  223. typedef struct {
  224. int level;
  225. int length;
  226. } print_params_t;
  227. static int n_print_params = 9;
  228. static print_params_t default_print_params[] = {
  229. { 4, 9 }, { 4, 3 },
  230. { 3, 4 }, { 3, 3 },
  231. { 2, 4 }, { 2, 3 },
  232. { 1, 4 }, { 1, 3 }, { 1, 2 }
  233. };
  234. static print_params_t *print_params = default_print_params;
  235. #ifdef GUILE_DEBUG
  236. SCM_DEFINE (scm_set_print_params_x, "set-print-params!", 1, 0, 0,
  237. (SCM params),
  238. "")
  239. #define FUNC_NAME s_scm_set_print_params_x
  240. {
  241. int i;
  242. int n;
  243. SCM ls;
  244. print_params_t *new_params;
  245. SCM_VALIDATE_NONEMPTYLIST_COPYLEN (2, params, n);
  246. for (ls = params; SCM_NNULLP (ls); ls = SCM_CDR (ls))
  247. SCM_ASSERT (scm_ilength (SCM_CAR (params)) == 2
  248. && SCM_INUMP (SCM_CAAR (ls))
  249. && SCM_INUM (SCM_CAAR (ls)) >= 0
  250. && SCM_INUMP (SCM_CADAR (ls))
  251. && SCM_INUM (SCM_CADAR (ls)) >= 0,
  252. params,
  253. SCM_ARG2,
  254. s_scm_set_print_params_x);
  255. new_params = scm_must_malloc (n * sizeof (print_params_t),
  256. FUNC_NAME);
  257. if (print_params != default_print_params)
  258. scm_must_free (print_params);
  259. print_params = new_params;
  260. for (i = 0; i < n; ++i)
  261. {
  262. print_params[i].level = SCM_INUM (SCM_CAAR (params));
  263. print_params[i].length = SCM_INUM (SCM_CADAR (params));
  264. params = SCM_CDR (params);
  265. }
  266. n_print_params = n;
  267. return SCM_UNSPECIFIED;
  268. }
  269. #undef FUNC_NAME
  270. #endif
  271. static void
  272. indent (int n, SCM port)
  273. {
  274. int i;
  275. for (i = 0; i < n; ++i)
  276. scm_putc (' ', port);
  277. }
  278. static void
  279. display_frame_expr (char *hdr,SCM exp,char *tlr,int indentation,SCM sport,SCM port,scm_print_state *pstate)
  280. {
  281. SCM string;
  282. int i = 0, n;
  283. scm_ptob_descriptor *ptob = scm_ptobs + SCM_PTOBNUM (sport);
  284. do
  285. {
  286. pstate->length = print_params[i].length;
  287. ptob->seek (sport, 0, SEEK_SET);
  288. if (SCM_CONSP (exp))
  289. {
  290. pstate->level = print_params[i].level - 1;
  291. scm_iprlist (hdr, exp, tlr[0], sport, pstate);
  292. scm_puts (&tlr[1], sport);
  293. }
  294. else
  295. {
  296. pstate->level = print_params[i].level;
  297. scm_iprin1 (exp, sport, pstate);
  298. }
  299. ptob->flush (sport);
  300. n = ptob->seek (sport, 0, SEEK_CUR);
  301. ++i;
  302. }
  303. while (indentation + n > SCM_BACKTRACE_WIDTH && i < n_print_params);
  304. ptob->truncate (sport, n);
  305. string = scm_strport_to_string (sport);
  306. /* Remove control characters */
  307. for (i = 0; i < n; ++i)
  308. if (iscntrl (SCM_CHARS (string)[i]))
  309. SCM_CHARS (string)[i] = ' ';
  310. /* Truncate */
  311. if (indentation + n > SCM_BACKTRACE_WIDTH)
  312. {
  313. n = SCM_BACKTRACE_WIDTH - indentation;
  314. SCM_CHARS (string)[n - 1] = '$';
  315. }
  316. scm_lfwrite (SCM_CHARS (string), n, port);
  317. }
  318. static void
  319. display_application (SCM frame,int indentation,SCM sport,SCM port,scm_print_state *pstate)
  320. {
  321. SCM proc = SCM_FRAME_PROC (frame);
  322. SCM name = (SCM_NFALSEP (scm_procedure_p (proc))
  323. ? scm_procedure_name (proc)
  324. : SCM_BOOL_F);
  325. display_frame_expr ("[",
  326. scm_cons (SCM_NFALSEP (name) ? name : proc,
  327. SCM_FRAME_ARGS (frame)),
  328. SCM_FRAME_EVAL_ARGS_P (frame) ? " ..." : "]",
  329. indentation,
  330. sport,
  331. port,
  332. pstate);
  333. }
  334. SCM_DEFINE (scm_display_application, "display-application", 1, 2, 0,
  335. (SCM frame, SCM port, SCM indent),
  336. "")
  337. #define FUNC_NAME s_scm_display_application
  338. {
  339. SCM_VALIDATE_FRAME (1,frame);
  340. if (SCM_UNBNDP (port))
  341. port = scm_cur_outp;
  342. else
  343. SCM_VALIDATE_OPOUTPORT (2,port);
  344. if (SCM_UNBNDP (indent))
  345. indent = SCM_INUM0;
  346. else
  347. SCM_VALIDATE_INUM (3,indent);
  348. if (SCM_FRAME_PROC_P (frame))
  349. /* Display an application. */
  350. {
  351. SCM sport, print_state;
  352. scm_print_state *pstate;
  353. /* Create a string port used for adaptation of printing parameters. */
  354. sport = scm_mkstrport (SCM_INUM0,
  355. scm_make_string (SCM_MAKINUM (240),
  356. SCM_UNDEFINED),
  357. SCM_OPN | SCM_WRTNG,
  358. FUNC_NAME);
  359. /* Create a print state for printing of frames. */
  360. print_state = scm_make_print_state ();
  361. pstate = SCM_PRINT_STATE (print_state);
  362. pstate->writingp = 1;
  363. pstate->fancyp = 1;
  364. display_application (frame, SCM_INUM (indent), sport, port, pstate);
  365. return SCM_BOOL_T;
  366. }
  367. else
  368. return SCM_BOOL_F;
  369. }
  370. #undef FUNC_NAME
  371. static void
  372. display_frame (SCM frame,int nfield,int indentation,SCM sport,SCM port,scm_print_state *pstate)
  373. {
  374. int n, i, j;
  375. /* Announce missing frames? */
  376. if (!SCM_BACKWARDS_P && SCM_FRAME_OVERFLOW_P (frame))
  377. {
  378. indent (nfield + 1 + indentation, port);
  379. scm_puts ("...\n", port);
  380. }
  381. /* Check size of frame number. */
  382. n = SCM_FRAME_NUMBER (frame);
  383. for (i = 0, j = n; j > 0; ++i) j /= 10;
  384. /* Number indentation. */
  385. indent (nfield - (i ? i : 1), port);
  386. /* Frame number. */
  387. scm_iprin1 (SCM_MAKINUM (n), port, pstate);
  388. /* Real frame marker */
  389. scm_putc (SCM_FRAME_REAL_P (frame) ? '*' : ' ', port);
  390. /* Indentation. */
  391. indent (indentation, port);
  392. if (SCM_FRAME_PROC_P (frame))
  393. /* Display an application. */
  394. display_application (frame, nfield + 1 + indentation, sport, port, pstate);
  395. else
  396. /* Display a special form. */
  397. {
  398. SCM source = SCM_FRAME_SOURCE (frame);
  399. SCM copy = (SCM_CONSP (source)
  400. ? scm_source_property (source, scm_sym_copy)
  401. : SCM_BOOL_F);
  402. SCM umcopy = (SCM_MEMOIZEDP (source)
  403. ? scm_unmemoize (source)
  404. : SCM_BOOL_F);
  405. display_frame_expr ("(",
  406. SCM_CONSP (copy) ? copy : umcopy,
  407. ")",
  408. nfield + 1 + indentation,
  409. sport,
  410. port,
  411. pstate);
  412. }
  413. scm_putc ('\n', port);
  414. /* Announce missing frames? */
  415. if (SCM_BACKWARDS_P && SCM_FRAME_OVERFLOW_P (frame))
  416. {
  417. indent (nfield + 1 + indentation, port);
  418. scm_puts ("...\n", port);
  419. }
  420. }
  421. struct display_backtrace_args {
  422. SCM stack;
  423. SCM port;
  424. SCM first;
  425. SCM depth;
  426. };
  427. static SCM
  428. display_backtrace_body(struct display_backtrace_args *a)
  429. #define FUNC_NAME "display_backtrace_body"
  430. {
  431. int n_frames, beg, end, n, i, j;
  432. int nfield, indent_p, indentation;
  433. SCM frame, sport, print_state;
  434. scm_print_state *pstate;
  435. a->port = SCM_COERCE_OUTPORT (a->port);
  436. /* Argument checking and extraction. */
  437. SCM_ASSERT (SCM_STACKP (a->stack),
  438. a->stack,
  439. SCM_ARG1,
  440. s_display_backtrace);
  441. SCM_ASSERT (SCM_OPOUTPORTP (a->port),
  442. a->port,
  443. SCM_ARG2,
  444. s_display_backtrace);
  445. n_frames = SCM_INUM (scm_stack_length (a->stack));
  446. n = SCM_INUMP (a->depth) ? SCM_INUM (a->depth) : SCM_BACKTRACE_DEPTH;
  447. if (SCM_BACKWARDS_P)
  448. {
  449. beg = SCM_INUMP (a->first) ? SCM_INUM (a->first) : 0;
  450. end = beg + n - 1;
  451. if (end >= n_frames)
  452. end = n_frames - 1;
  453. n = end - beg + 1;
  454. }
  455. else
  456. {
  457. if (SCM_INUMP (a->first))
  458. {
  459. beg = SCM_INUM (a->first);
  460. end = beg - n + 1;
  461. if (end < 0)
  462. end = 0;
  463. }
  464. else
  465. {
  466. beg = n - 1;
  467. end = 0;
  468. if (beg >= n_frames)
  469. beg = n_frames - 1;
  470. }
  471. n = beg - end + 1;
  472. }
  473. SCM_ASSERT (beg >= 0 && beg < n_frames, a->first, SCM_ARG3, s_display_backtrace);
  474. SCM_ASSERT (n > 0, a->depth, SCM_ARG4, s_display_backtrace);
  475. /* Create a string port used for adaptation of printing parameters. */
  476. sport = scm_mkstrport (SCM_INUM0,
  477. scm_make_string (SCM_MAKINUM (240), SCM_UNDEFINED),
  478. SCM_OPN | SCM_WRTNG,
  479. FUNC_NAME);
  480. /* Create a print state for printing of frames. */
  481. print_state = scm_make_print_state ();
  482. pstate = SCM_PRINT_STATE (print_state);
  483. pstate->writingp = 1;
  484. pstate->fancyp = 1;
  485. /* First find out if it's reasonable to do indentation. */
  486. if (SCM_BACKWARDS_P)
  487. indent_p = 0;
  488. else
  489. {
  490. indent_p = 1;
  491. frame = scm_stack_ref (a->stack, SCM_MAKINUM (beg));
  492. for (i = 0, j = 0; i < n; ++i)
  493. {
  494. if (SCM_FRAME_REAL_P (frame))
  495. ++j;
  496. if (j > SCM_BACKTRACE_INDENT)
  497. {
  498. indent_p = 0;
  499. break;
  500. }
  501. frame = (SCM_BACKWARDS_P
  502. ? SCM_FRAME_PREV (frame)
  503. : SCM_FRAME_NEXT (frame));
  504. }
  505. }
  506. /* Determine size of frame number field. */
  507. j = SCM_FRAME_NUMBER (scm_stack_ref (a->stack, SCM_MAKINUM (end)));
  508. for (i = 0; j > 0; ++i) j /= 10;
  509. nfield = i ? i : 1;
  510. /* Print frames. */
  511. frame = scm_stack_ref (a->stack, SCM_MAKINUM (beg));
  512. indentation = 1;
  513. display_frame (frame, nfield, indentation, sport, a->port, pstate);
  514. for (i = 1; i < n; ++i)
  515. {
  516. if (indent_p && SCM_FRAME_EVAL_ARGS_P (frame))
  517. ++indentation;
  518. frame = SCM_BACKWARDS_P ? SCM_FRAME_PREV (frame) : SCM_FRAME_NEXT (frame);
  519. display_frame (frame, nfield, indentation, sport, a->port, pstate);
  520. }
  521. return SCM_UNSPECIFIED;
  522. }
  523. #undef FUNC_NAME
  524. SCM_DEFINE (scm_display_backtrace, "display-backtrace", 2, 2, 0,
  525. (SCM stack, SCM port, SCM first, SCM depth),
  526. "")
  527. #define FUNC_NAME s_scm_display_backtrace
  528. {
  529. struct display_backtrace_args a;
  530. struct display_error_handler_data data;
  531. a.stack = stack;
  532. a.port = port;
  533. a.first = first;
  534. a.depth = depth;
  535. data.mode = "backtrace";
  536. data.port = port;
  537. scm_internal_catch (SCM_BOOL_T,
  538. (scm_catch_body_t) display_backtrace_body, &a,
  539. (scm_catch_handler_t) display_error_handler, &data);
  540. return SCM_UNSPECIFIED;
  541. }
  542. #undef FUNC_NAME
  543. SCM_VCELL (scm_has_shown_backtrace_hint_p_var, "has-shown-backtrace-hint?");
  544. SCM_DEFINE (scm_backtrace, "backtrace", 0, 0, 0,
  545. (),
  546. "")
  547. #define FUNC_NAME s_scm_backtrace
  548. {
  549. SCM the_last_stack = scm_fluid_ref (SCM_CDR (scm_the_last_stack_fluid));
  550. if (SCM_NFALSEP (the_last_stack))
  551. {
  552. scm_newline (scm_cur_outp);
  553. scm_puts ("Backtrace:\n", scm_cur_outp);
  554. scm_display_backtrace (the_last_stack,
  555. scm_cur_outp,
  556. SCM_UNDEFINED,
  557. SCM_UNDEFINED);
  558. scm_newline (scm_cur_outp);
  559. if (SCM_FALSEP (SCM_CDR (scm_has_shown_backtrace_hint_p_var))
  560. && !SCM_BACKTRACE_P)
  561. {
  562. scm_puts ("Type \"(debug-enable 'backtrace)\" if you would like "
  563. "a backtrace\n"
  564. "automatically if an error occurs in the future.\n",
  565. scm_cur_outp);
  566. SCM_SETCDR (scm_has_shown_backtrace_hint_p_var, SCM_BOOL_T);
  567. }
  568. }
  569. else
  570. {
  571. scm_puts ("No backtrace available.\n", scm_cur_outp);
  572. }
  573. return SCM_UNSPECIFIED;
  574. }
  575. #undef FUNC_NAME
  576. void
  577. scm_init_backtrace ()
  578. {
  579. SCM f = scm_make_fluid ();
  580. scm_the_last_stack_fluid = scm_sysintern ("the-last-stack", f);
  581. #include "libguile/backtrace.x"
  582. }
  583. /*
  584. Local Variables:
  585. c-file-style: "gnu"
  586. End:
  587. */