Mercurial > hg > octave-lyh
comparison src/debug.cc @ 7082:ac7179f00422
[project @ 2007-10-31 01:24:12 by jwe]
author | jwe |
---|---|
date | Wed, 31 Oct 2007 01:24:12 +0000 |
parents | a1dbe9d80eee |
children | 24fde8abfb90 |
comparison
equal
deleted
inserted
replaced
7081:503001863427 | 7082:ac7179f00422 |
---|---|
17 You should have received a copy of the GNU General Public License | 17 You should have received a copy of the GNU General Public License |
18 along with Octave; see the file COPYING. If not, see | 18 along with Octave; see the file COPYING. If not, see |
19 <http://www.gnu.org/licenses/>. | 19 <http://www.gnu.org/licenses/>. |
20 | 20 |
21 */ | 21 */ |
22 | |
23 #ifdef HAVE_CONFIG_H | 22 #ifdef HAVE_CONFIG_H |
24 #include <config.h> | 23 #include <config.h> |
25 #endif | 24 #endif |
26 | 25 |
27 #include <iostream> | 26 #include <iostream> |
28 #include <fstream> | 27 #include <fstream> |
29 #include <string> | 28 #include <string> |
29 #include <set> | |
30 | |
30 | 31 |
31 #include "defun.h" | 32 #include "defun.h" |
32 #include "error.h" | 33 #include "error.h" |
34 #include "help.h" | |
33 #include "input.h" | 35 #include "input.h" |
34 #include "pager.h" | 36 #include "pager.h" |
35 #include "oct-obj.h" | 37 #include "oct-obj.h" |
36 #include "utils.h" | 38 #include "utils.h" |
37 #include "parse.h" | 39 #include "parse.h" |
38 #include "symtab.h" | 40 #include "symtab.h" |
39 #include "gripes.h" | 41 #include "gripes.h" |
40 #include "ov.h" | 42 #include "ov.h" |
41 #include "ov-usr-fcn.h" | 43 #include "ov-usr-fcn.h" |
42 #include "ov-fcn.h" | 44 #include "ov-fcn.h" |
45 #include "ov-list.h" | |
46 #include "ov-struct.h" | |
43 #include "pt-pr-code.h" | 47 #include "pt-pr-code.h" |
44 #include "pt.h" | 48 #include "pt.h" |
45 #include "pt-bp.h" | 49 #include "pt-bp.h" |
46 #include "pt-stmt.h" | 50 #include "pt-stmt.h" |
47 #include "toplev.h" | 51 #include "toplev.h" |
48 #include "unwind-prot.h" | 52 #include "unwind-prot.h" |
49 #include "variables.h" | 53 #include "variables.h" |
50 | 54 |
55 #include "debug.h" | |
56 | |
57 // Initialize the singleton object | |
58 bp_table *bp_table::instance = NULL; | |
59 | |
51 // Return a pointer to the user-defined function FNAME. If FNAME is | 60 // Return a pointer to the user-defined function FNAME. If FNAME is |
52 // empty, search backward for the first user-defined function in the | 61 // empty, search backward for the first user-defined function in the |
53 // current call stack. | 62 // current call stack. |
54 | |
55 static octave_user_function * | 63 static octave_user_function * |
56 get_user_function (std::string fname = "") | 64 get_user_function (const std::string& fname = "") |
57 { | 65 { |
58 octave_user_function *dbg_fcn = 0; | 66 octave_user_function *dbg_fcn = 0; |
59 | 67 |
60 if (fname == "") | 68 if (fname == "") |
61 dbg_fcn = octave_call_stack::caller_user_function (); | 69 dbg_fcn = octave_call_stack::caller_user_function (); |
69 dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ()); | 77 dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ()); |
70 } | 78 } |
71 else | 79 else |
72 { | 80 { |
73 ptr = lookup_by_name (fname, false); | 81 ptr = lookup_by_name (fname, false); |
74 | |
75 if (ptr && ptr->is_user_function ()) | 82 if (ptr && ptr->is_user_function ()) |
76 { | 83 { |
77 octave_value tmp = ptr->def (); | 84 octave_value tmp = ptr->def (); |
78 dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ()); | 85 dbg_fcn = dynamic_cast<octave_user_function *> (tmp.function_value ()); |
79 } | 86 } |
81 } | 88 } |
82 | 89 |
83 return dbg_fcn; | 90 return dbg_fcn; |
84 } | 91 } |
85 | 92 |
93 static void | |
94 parse_dbfunction_params (const octave_value_list& args, | |
95 std::string& symbol_name, | |
96 intmap& lines) | |
97 { | |
98 octave_idx_type len = 0; | |
99 int nargin = args.length (); | |
100 int idx = 0; | |
101 int list_idx = 0; | |
102 symbol_name = std::string (); | |
103 | |
104 // If we are already in a debugging function | |
105 if (octave_call_stack::caller_user_function () != NULL) | |
106 { | |
107 idx = 0; | |
108 } | |
109 else | |
110 { | |
111 symbol_name = args (0).string_value (); | |
112 if (error_state) | |
113 return; | |
114 idx = 1; | |
115 } | |
116 | |
117 for (int i = idx; i < nargin; i++ ) | |
118 { | |
119 if (args (i).is_string ()) | |
120 len += 1; | |
121 else | |
122 len += args (i).numel (); | |
123 } | |
124 | |
125 lines = intmap(); | |
126 for (int i = idx; i < nargin; i++ ) | |
127 { | |
128 if (args (i).is_string ()) | |
129 { | |
130 int line = atoi (args (i).string_value ().c_str ()); | |
131 if (error_state) | |
132 break; | |
133 lines[list_idx++] = line; | |
134 } | |
135 else | |
136 { | |
137 const NDArray arg = args (i).array_value (); | |
138 | |
139 if (error_state) | |
140 break; | |
141 | |
142 for (octave_idx_type j = 0; j < arg.nelem(); j++) | |
143 { | |
144 int line = static_cast<int> (arg.elem (j)); | |
145 if (error_state) | |
146 break; | |
147 lines[list_idx++] = line; | |
148 } | |
149 | |
150 if (error_state) | |
151 break; | |
152 } | |
153 } | |
154 } | |
155 | |
156 intmap | |
157 bp_table::add_breakpoint (const std::string& fname, | |
158 const intmap& line) | |
159 { | |
160 if (!instance_ok ()) | |
161 return intmap(); | |
162 | |
163 octave_idx_type len = line.size (); | |
164 intmap retval; | |
165 octave_user_function *dbg_fcn = get_user_function (fname); | |
166 | |
167 if (dbg_fcn) | |
168 { | |
169 tree_statement_list *cmds = dbg_fcn->body (); | |
170 for (int i = 0; i < len; i++) | |
171 { | |
172 intmap::const_iterator p = line.find (i); | |
173 if (p != line.end ()) | |
174 { | |
175 int lineno = p->second; | |
176 retval[i] = cmds->set_breakpoint (lineno); | |
177 if (retval[i] != 0) | |
178 instance->bp_map[fname] = dbg_fcn; | |
179 } | |
180 } | |
181 } | |
182 else | |
183 error ("add_breakpoint: unable to find the function requested\n"); | |
184 | |
185 return retval; | |
186 } | |
187 | |
188 | |
189 int | |
190 bp_table::remove_breakpoint (const std::string& fname, | |
191 const intmap& line) | |
192 { | |
193 if (!instance_ok ()) | |
194 return 0; | |
195 | |
196 octave_idx_type len = line.size (); | |
197 int retval = 0; | |
198 | |
199 if (len == 0) | |
200 { | |
201 intmap results = remove_all_breakpoints_in_file (fname); | |
202 retval = results.size (); | |
203 } | |
204 else | |
205 { | |
206 octave_user_function *dbg_fcn = get_user_function (fname); | |
207 if (dbg_fcn) | |
208 { | |
209 tree_statement_list *cmds = dbg_fcn->body (); | |
210 for (int i = 0; i < len; i++) | |
211 { | |
212 intmap::const_iterator p = line.find (i); | |
213 if (p != line.end ()) | |
214 { | |
215 int lineno = p->second; | |
216 cmds->delete_breakpoint (lineno); | |
217 } | |
218 } | |
219 octave_value_list results = cmds->list_breakpoints (); | |
220 if (results.length () == 0) | |
221 instance->bp_map.erase (instance->bp_map.find (fname)); | |
222 retval = results.length (); | |
223 } | |
224 else | |
225 error ("remove_breakpoint: unable to find the function requested\n"); | |
226 } | |
227 return retval; | |
228 } | |
229 | |
230 | |
231 intmap | |
232 bp_table::remove_all_breakpoints_in_file (const std::string& fname) | |
233 { | |
234 if (!instance_ok ()) | |
235 return intmap(); | |
236 | |
237 octave_value_list bkpts; | |
238 intmap retval; | |
239 octave_user_function *dbg_fcn = get_user_function (fname); | |
240 | |
241 if (dbg_fcn) | |
242 { | |
243 tree_statement_list *cmds = dbg_fcn->body (); | |
244 bkpts = cmds->list_breakpoints (); | |
245 for (int i = 0; i < bkpts.length (); i++) | |
246 { | |
247 int lineno = static_cast<int> (bkpts (i).int_value ()); | |
248 cmds->delete_breakpoint (lineno); | |
249 retval[i] = lineno; | |
250 } | |
251 instance->bp_map.erase (instance->bp_map.find (fname)); | |
252 } | |
253 else | |
254 error ("remove_all_breakpoint_in_file: " | |
255 "unable to find the function requested\n"); | |
256 | |
257 return retval; | |
258 } | |
259 | |
260 | |
261 void | |
262 bp_table::remove_all_breakpoints (void) | |
263 { | |
264 if (!instance_ok ()) | |
265 return; | |
266 | |
267 std::map< std::string, octave_user_function* >::iterator it; | |
268 for (it = instance->bp_map.begin (); it != instance->bp_map.end (); it++) | |
269 { | |
270 remove_all_breakpoints_in_file (it->first); | |
271 } | |
272 } | |
273 | |
274 std::string | |
275 do_find_bkpt_list (octave_value_list slist, | |
276 std::string match) | |
277 { | |
278 std::string retval; | |
279 for (int i = 0; i < slist.length (); i++) | |
280 { | |
281 if (slist (i).string_value () == match) | |
282 { | |
283 retval = slist (i).string_value (); | |
284 break; | |
285 } | |
286 } | |
287 return retval; | |
288 } | |
289 | |
290 | |
291 std::map< std::string, intmap> | |
292 bp_table::get_breakpoint_list (const octave_value_list& fname_list) | |
293 { | |
294 std::map<std::string, intmap> retval; | |
295 | |
296 if (!instance_ok ()) | |
297 return retval; | |
298 | |
299 // Iterate through each of the files in the map and get the | |
300 // name and list of breakpoints | |
301 std::map< std::string, octave_user_function* >::iterator it; | |
302 for (it = instance->bp_map.begin (); it != instance->bp_map.end (); it++) | |
303 { | |
304 if (fname_list.length () == 0 || | |
305 do_find_bkpt_list (fname_list, it->first) != "") | |
306 { | |
307 octave_value_list bkpts = it->second->body ()->list_breakpoints (); | |
308 octave_idx_type len = bkpts.length (); | |
309 intmap bkpts_vec; | |
310 for (int i = 0; i < len; i++) | |
311 bkpts_vec[i] = bkpts (i).double_value (); | |
312 retval[ it->first ] = bkpts_vec; | |
313 } | |
314 } | |
315 return retval; | |
316 } | |
317 | |
318 static octave_value | |
319 intmap_to_ov (const intmap& line) | |
320 { | |
321 int idx = 0; | |
322 NDArray retval (dim_vector (1, line.size())); | |
323 for (int i = 0; i < line.size(); i++ ) | |
324 { | |
325 intmap::const_iterator p = line.find (i); | |
326 if (p != line.end ()) | |
327 { | |
328 int lineno = p->second; | |
329 retval (idx++) = lineno; | |
330 } | |
331 } | |
332 retval.resize (dim_vector (1, idx)); | |
333 return retval; | |
334 } | |
86 | 335 |
87 DEFCMD (dbstop, args, , | 336 DEFCMD (dbstop, args, , |
88 "-*- texinfo -*-\n\ | 337 "-*- texinfo -*-\n\ |
89 @deftypefn {Loadable Function} {rline =} dbstop (func, line, @dots{})\n\ | 338 @deftypefn {Loadable Function} {rline =} dbstop (func, line, @dots{})\n\ |
90 Set a breakpoint in a function\n\ | 339 Set a breakpoint in a function\n\ |
99 \n\ | 348 \n\ |
100 The rline returned is the real line that the breakpoint was set at.\n\ | 349 The rline returned is the real line that the breakpoint was set at.\n\ |
101 @seealso{dbclear, dbstatus, dbnext}\n\ | 350 @seealso{dbclear, dbstatus, dbnext}\n\ |
102 @end deftypefn") | 351 @end deftypefn") |
103 { | 352 { |
104 octave_value retval; | 353 intmap retval; |
105 int nargin = args.length (); | |
106 int idx = 0; | |
107 std::string symbol_name = ""; | 354 std::string symbol_name = ""; |
108 | 355 intmap lines; |
109 if (nargin != 1 && args(0).is_string()) | 356 parse_dbfunction_params (args, symbol_name, lines); |
110 { | 357 |
111 symbol_name = args(0).string_value (); | 358 if (!error_state) |
112 idx = 1; | 359 retval = bp_table::add_breakpoint (symbol_name, lines); |
113 } | 360 |
114 | 361 return intmap_to_ov(retval); |
115 octave_user_function *dbg_fcn = get_user_function (symbol_name); | |
116 | |
117 if (dbg_fcn) | |
118 { | |
119 octave_idx_type nsize = 10; | |
120 RowVector results (nsize); | |
121 octave_idx_type nr = 0; | |
122 | |
123 tree_statement_list *cmds = dbg_fcn->body (); | |
124 | |
125 for (int i = idx; i < nargin; i++) | |
126 { | |
127 if (args(i).is_string ()) | |
128 { | |
129 int line = atoi (args(i).string_value ().c_str ()); | |
130 | |
131 if (error_state) | |
132 break; | |
133 | |
134 if (nr == nsize) | |
135 { | |
136 nsize *= 2; | |
137 results.resize (nsize); | |
138 } | |
139 | |
140 results(nr++) = cmds->set_breakpoint (line); | |
141 } | |
142 else | |
143 { | |
144 const NDArray arg = args(i).array_value (); | |
145 | |
146 if (error_state) | |
147 break; | |
148 | |
149 for (octave_idx_type j = 0; j < arg.nelem(); j++) | |
150 { | |
151 int line = static_cast<int> (arg.elem (j)); | |
152 | |
153 if (error_state) | |
154 break; | |
155 | |
156 if (nr == nsize) | |
157 { | |
158 nsize *= 2; | |
159 results.resize (nsize); | |
160 } | |
161 | |
162 results(nr++) = cmds->set_breakpoint (line); | |
163 } | |
164 | |
165 if (error_state) | |
166 break; | |
167 } | |
168 } | |
169 | |
170 if (! error_state) | |
171 { | |
172 results.resize (nr); | |
173 retval = results; | |
174 } | |
175 } | |
176 else | |
177 error ("dbstop: unable to find the function requested\n"); | |
178 | |
179 return retval; | |
180 } | 362 } |
181 | 363 |
182 DEFCMD (dbclear, args, , | 364 DEFCMD (dbclear, args, , |
183 "-*- texinfo -*-\n\ | 365 "-*- texinfo -*-\n\ |
184 @deftypefn {Loadable Function} {} dbclear (func, line, @dots{})\n\ | 366 @deftypefn {Loadable Function} {} dbclear (func, line, @dots{})\n\ |
195 a breakpoint. If you get the wrong line nothing will happen.\n\ | 377 a breakpoint. If you get the wrong line nothing will happen.\n\ |
196 @seealso{dbstop, dbstatus, dbwhere}\n\ | 378 @seealso{dbstop, dbstatus, dbwhere}\n\ |
197 @end deftypefn") | 379 @end deftypefn") |
198 { | 380 { |
199 octave_value retval; | 381 octave_value retval; |
200 int nargin = args.length (); | |
201 int idx = 0; | |
202 std::string symbol_name = ""; | 382 std::string symbol_name = ""; |
203 | 383 intmap lines; |
204 if (nargin != 1 && args(0).is_string()) | 384 parse_dbfunction_params (args, symbol_name, lines); |
205 { | 385 |
206 symbol_name = args(0).string_value (); | 386 if (!error_state) |
207 idx = 1; | 387 bp_table::remove_breakpoint (symbol_name, lines); |
208 } | 388 |
209 | 389 return retval; |
210 octave_user_function *dbg_fcn = get_user_function (symbol_name); | 390 } |
211 | 391 |
212 if (dbg_fcn) | 392 DEFCMD (dbstatus, args, nargout, |
213 { | |
214 tree_statement_list *cmds = dbg_fcn->body (); | |
215 | |
216 for (int i = idx; i < nargin; i++) | |
217 { | |
218 if (args(i).is_string ()) | |
219 { | |
220 int line = atoi (args(i).string_value ().c_str ()); | |
221 | |
222 if (error_state) | |
223 break; | |
224 | |
225 cmds->delete_breakpoint (line); | |
226 } | |
227 else | |
228 { | |
229 const NDArray arg = args(i).array_value (); | |
230 | |
231 if (error_state) | |
232 break; | |
233 | |
234 for (octave_idx_type j = 0; j < arg.nelem (); j++) | |
235 { | |
236 int line = static_cast<int> (arg.elem (j)); | |
237 | |
238 if (error_state) | |
239 break; | |
240 | |
241 cmds->delete_breakpoint (line); | |
242 } | |
243 | |
244 if (error_state) | |
245 break; | |
246 } | |
247 } | |
248 } | |
249 else | |
250 error ("dbclear: unable to find the function requested\n"); | |
251 | |
252 return retval; | |
253 } | |
254 | |
255 DEFCMD (dbstatus, args, , | |
256 "-*- texinfo -*-\n\ | 393 "-*- texinfo -*-\n\ |
257 @deftypefn {Loadable Function} {lst =} dbstatus ([func])\n\ | 394 @deftypefn {Loadable Function} {lst =} dbstatus ([func])\n\ |
258 Return a vector containing the lines on which a function has \n\ | 395 Return a vector containing the lines on which a function has \n\ |
259 breakpoints set.\n\ | 396 breakpoints set.\n\ |
260 @table @code\n\ | 397 @table @code\n\ |
263 mode this should be left out.\n\ | 400 mode this should be left out.\n\ |
264 @end table\n\ | 401 @end table\n\ |
265 @seealso{dbclear, dbwhere}\n\ | 402 @seealso{dbclear, dbwhere}\n\ |
266 @end deftypefn") | 403 @end deftypefn") |
267 { | 404 { |
268 octave_value retval; | 405 Octave_map retval; |
269 | |
270 int nargin = args.length (); | 406 int nargin = args.length (); |
407 octave_value_list fcn_list; | |
408 std::map< std::string, intmap> bp_list; | |
409 std::string symbol_name = ""; | |
271 | 410 |
272 if (nargin != 0 && nargin != 1) | 411 if (nargin != 0 && nargin != 1) |
273 { | 412 { |
274 error ("dbstatus: only zero or one arguements accepted\n"); | 413 error ("dbstatus: only zero or one arguements accepted\n"); |
275 return retval; | 414 return octave_value (); |
276 } | 415 } |
277 | |
278 std::string symbol_name = ""; | |
279 | 416 |
280 if (nargin == 1) | 417 if (nargin == 1) |
281 { | 418 { |
282 if (args(0).is_string ()) | 419 if (args(0).is_string ()) |
283 symbol_name = args(0).string_value (); | 420 { |
421 symbol_name = args (0).string_value (); | |
422 fcn_list (0) = symbol_name; | |
423 bp_list = bp_table::get_breakpoint_list (fcn_list); | |
424 } | |
284 else | 425 else |
285 gripe_wrong_type_arg ("dbstatus", args(0)); | 426 gripe_wrong_type_arg ("dbstatus", args (0)); |
286 } | 427 } |
287 | 428 else |
288 octave_user_function *dbg_fcn = get_user_function (symbol_name); | 429 { |
289 | 430 octave_user_function *dbg_fcn = get_user_function (); |
290 if (dbg_fcn) | 431 if (dbg_fcn) |
291 { | 432 { |
292 tree_statement_list *cmds = dbg_fcn->body (); | 433 symbol_name = dbg_fcn->name (); |
293 | 434 fcn_list (0) = symbol_name; |
294 octave_value_list lst = cmds->list_breakpoints (); | 435 } |
295 | 436 bp_list = bp_table::get_breakpoint_list (fcn_list); |
296 RowVector vec (lst.length (), 0.0); | 437 } |
297 | 438 |
298 for (int i = 0; i < lst.length (); i++) | 439 std::map< std::string, intmap>::iterator it; |
299 { | 440 if (nargout == 1) |
300 vec(i) = lst(i).double_value (); | 441 { |
301 | 442 // Fill in an array for return |
302 if (error_state) | 443 int i = 0; |
303 panic_impossible (); | 444 Cell names (dim_vector (bp_list.size (), 1)); |
304 } | 445 Cell file (dim_vector (bp_list.size (), 1)); |
305 | 446 Cell line (dim_vector (bp_list.size (), 1)); |
306 retval = octave_value (vec); | 447 for (it = bp_list.begin (); it != bp_list.end (); it++) |
307 } | 448 { |
308 else | 449 names (i) = it->first; |
309 error ("dbstatus: unable to find the function you requested\n"); | 450 line (i) = intmap_to_ov(it->second); |
310 | 451 file (i) = do_which (it->first); |
311 return retval; | 452 i++; |
453 } | |
454 retval.assign ("name", names); | |
455 retval.assign ("file", file); | |
456 retval.assign ("line", line); | |
457 return octave_value (retval); | |
458 } | |
459 else | |
460 { | |
461 // Print out the breakpoint information | |
462 for (it = bp_list.begin(); it != bp_list.end(); it++) | |
463 { | |
464 octave_stdout << "Breakpoint in " << it->first << " at line(s) "; | |
465 for (int j = 0; j < it->second.size (); j++) | |
466 if (j < it->second.size()-1) | |
467 octave_stdout << it->second [j] << ", "; | |
468 else | |
469 octave_stdout << it->second [j] << "." << std::endl; | |
470 } | |
471 return octave_value (); | |
472 } | |
312 } | 473 } |
313 | 474 |
314 DEFCMD (dbwhere, , , | 475 DEFCMD (dbwhere, , , |
315 "-*- texinfo -*-\n\ | 476 "-*- texinfo -*-\n\ |
316 @deftypefn {Loadable Function} {} dbwhere ()\n\ | 477 @deftypefn {Loadable Function} {} dbwhere ()\n\ |