1 /*
2 * Copyright 2015 Steven Watanabe
3 * Distributed under the Boost Software License, Version 1.0.
4 * (See accompanying file LICENSE_1_0.txt or copy at
5 * http://www.boost.org/LICENSE_1_0.txt)
6 */
7
8 #include "debugger.h"
9 #include "constants.h"
10 #include "jam_strings.h"
11 #include "pathsys.h"
12 #include "cwd.h"
13 #include "function.h"
14 #include <assert.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <limits.h>
20 #include <signal.h>
21 #include <ctype.h>
22
23 #ifdef NT
24 #include <windows.h>
25 #include <io.h>
26 #include <fcntl.h>
27 #else
28 #include <errno.h>
29 #include <sys/wait.h>
30 #include <unistd.h>
31 #endif
32
33 #undef debug_on_enter_function
34 #undef debug_on_exit_function
35
36 struct breakpoint
37 {
38 OBJECT * file;
39 OBJECT * bound_file;
40 int line;
41 int status;
42 };
43
44 #define BREAKPOINT_ENABLED 1
45 #define BREAKPOINT_DISABLED 2
46 #define BREAKPOINT_DELETED 3
47
48 static struct breakpoint * breakpoints;
49 static int num_breakpoints;
50 static int breakpoints_capacity;
51
52 #define DEBUG_NO_CHILD 0
53 #define DEBUG_RUN 1
54 #define DEBUG_STEP 2
55 #define DEBUG_NEXT 3
56 #define DEBUG_FINISH 4
57 #define DEBUG_STOPPED 5
58
59 #define DEBUG_MSG_BREAKPOINT 1
60 #define DEBUG_MSG_END_STEPPING 2
61 #define DEBUG_MSG_SETUP 3
62 #define DEBUG_MSG_DONE 32
63
64 static int debug_state;
65 static int debug_depth;
66 static OBJECT * debug_file;
67 static int debug_line;
68 static FRAME * debug_frame;
69 LIST * debug_print_result;
70 static int current_token;
71 static int debug_selected_frame_number;
72
73 /* Commands are read from this stream. */
74 static FILE * command_input;
75 /* Where to send output from commands. */
76 static FILE * command_output;
77 /* Only valid in the parent. Reads command output from the child. */
78 static FILE * command_child;
79
80 struct command_elem
81 {
82 const char * key;
83 void (*command)( int, const char * * );
84 };
85
86 static struct command_elem * command_array;
87
88 static void debug_listen( void );
89 static int read_command( void );
90 static int is_same_file( OBJECT * file1, OBJECT * file2 );
91 static void debug_mi_format_token( void );
92 static OBJECT * make_absolute_path( OBJECT * filename );
93
debug_string_write(FILE * out,const char * data)94 static void debug_string_write( FILE * out, const char * data )
95 {
96 fprintf( out, "%s", data );
97 fputc( '\0', out );
98 }
99
debug_string_read(FILE * in)100 static char * debug_string_read( FILE * in )
101 {
102 string buf[ 1 ];
103 int ch;
104 char * result;
105 string_new( buf );
106 while( ( ch = fgetc( in ) ) > 0 )
107 {
108 string_push_back( buf, (char)ch );
109 }
110 result = strdup( buf->value );
111 string_free( buf );
112 return result;
113 }
114
debug_object_write(FILE * out,OBJECT * data)115 static void debug_object_write( FILE * out, OBJECT * data )
116 {
117 debug_string_write( out, object_str( data ) );
118 }
119
debug_object_read(FILE * in)120 static OBJECT * debug_object_read( FILE * in )
121 {
122 string buf[ 1 ];
123 int ch;
124 OBJECT * result;
125 string_new( buf );
126 while( ( ch = fgetc( in ) ) > 0 )
127 {
128 string_push_back( buf, (char)ch );
129 }
130 result = object_new( buf->value );
131 string_free( buf );
132 return result;
133 }
134
debug_int_write(FILE * out,int i)135 static void debug_int_write( FILE * out, int i )
136 {
137 fprintf( out, "%d", i );
138 fputc( '\0', out );
139 }
140
debug_int_read(FILE * in)141 static int debug_int_read( FILE * in )
142 {
143 OBJECT * str = debug_object_read( in );
144 int result = atoi( object_str( str ) );
145 object_free( str );
146 return result;
147 }
148
debug_list_write(FILE * out,LIST * l)149 static void debug_list_write( FILE * out, LIST * l )
150 {
151 LISTITER iter = list_begin( l ), end = list_end( l );
152 fprintf( out, "%d\n", list_length( l ) );
153 for ( ; iter != end; iter = list_next( iter ) )
154 {
155 debug_object_write( out, list_item( iter ) );
156 }
157 }
158
debug_list_read(FILE * in)159 static LIST * debug_list_read( FILE * in )
160 {
161 int len;
162 int i;
163 LIST * result = L0;
164 int ret = fscanf( in, "%d", &len );
165 if (ret == 1)
166 {
167 int ch = fgetc( in );
168 if (ch > 0) assert( ch == '\n' );
169 for ( i = 0; i < len; ++i )
170 {
171 result = list_push_back( result, debug_object_read( in ) );
172 }
173 }
174 return result;
175 }
176
debug_lol_write(FILE * out,LOL * lol)177 static void debug_lol_write( FILE * out, LOL * lol )
178 {
179 int i;
180 debug_int_write( out, lol->count );
181 for ( i = 0; i < lol->count; ++i )
182 {
183 debug_list_write( out, lol_get( lol, i ) );
184 }
185 }
186
debug_lol_read(FILE * in,LOL * lol)187 static void debug_lol_read( FILE * in, LOL * lol )
188 {
189 int count, i;
190 lol_init( lol );
191 count = debug_int_read( in );
192 for ( i = 0; i < count; ++i )
193 {
194 lol_add( lol, debug_list_read( in ) );
195 }
196 }
197
debug_format_rulename(string * out,FRAME * frame)198 static void debug_format_rulename ( string * out, FRAME * frame )
199 {
200 const char * pos = strchr( frame->rulename, '.' );
201 if ( frame->module->class_module && pos )
202 {
203 string_copy( out, object_str( frame->module->name ) );
204 string_push_back( out, '.' );
205 string_append( out, pos + 1 );
206 }
207 else
208 {
209 string_copy( out, frame->rulename );
210 }
211 }
212
debug_frame_write(FILE * out,FRAME * frame)213 static void debug_frame_write( FILE * out, FRAME * frame )
214 {
215 string rulename_buffer [ 1 ];
216 OBJECT * fullname = constant_builtin;
217 OBJECT * file = frame->file;
218 if ( file == NULL ) file = constant_builtin;
219 else fullname = make_absolute_path( frame->file );
220 debug_format_rulename( rulename_buffer, frame );
221 debug_object_write( out, file );
222 debug_int_write( out, frame->line );
223 debug_object_write( out, fullname );
224 debug_lol_write( out, frame->args );
225 debug_string_write( out, rulename_buffer->value );
226 object_free( fullname );
227 string_free( rulename_buffer );
228 }
229
230 /*
231 * The information passed to the debugger for
232 * a frame is slightly different from the FRAME
233 * struct.
234 */
235 typedef struct _frame_info
236 {
237 OBJECT * file;
238 int line;
239 OBJECT * fullname;
240 LOL args[ 1 ];
241 char * rulename;
242 } FRAME_INFO;
243
debug_frame_info_free(FRAME_INFO * frame)244 static void debug_frame_info_free( FRAME_INFO * frame )
245 {
246 object_free( frame->file );
247 object_free( frame->fullname );
248 lol_free( frame->args );
249 free( frame->rulename );
250 }
251
debug_frame_read(FILE * in,FRAME_INFO * frame)252 static void debug_frame_read( FILE * in, FRAME_INFO * frame )
253 {
254 frame->file = debug_object_read( in );
255 frame->line = debug_int_read( in );
256 frame->fullname = debug_object_read( in );
257 debug_lol_read( in, frame->args );
258 frame->rulename = debug_string_read( in );
259 }
260
add_breakpoint(struct breakpoint elem)261 static int add_breakpoint( struct breakpoint elem )
262 {
263 if ( num_breakpoints == breakpoints_capacity )
264 {
265 int new_capacity = breakpoints_capacity * 2;
266 if ( new_capacity == 0 ) new_capacity = 1;
267 breakpoints = ( struct breakpoint * )realloc( breakpoints, new_capacity * sizeof( struct breakpoint ) );
268 breakpoints_capacity = new_capacity;
269 }
270 breakpoints[ num_breakpoints++ ] = elem;
271 return num_breakpoints;
272 }
273
add_line_breakpoint(OBJECT * file,int line)274 static int add_line_breakpoint( OBJECT * file, int line )
275 {
276 struct breakpoint elem;
277 elem.file = file;
278 elem.bound_file = NULL;
279 elem.line = line;
280 elem.status = BREAKPOINT_ENABLED;
281 return add_breakpoint( elem );
282 }
283
add_function_breakpoint(OBJECT * name)284 static int add_function_breakpoint( OBJECT * name )
285 {
286 struct breakpoint elem;
287 elem.file = name;
288 elem.bound_file = object_copy( name );
289 elem.line = -1;
290 elem.status = BREAKPOINT_ENABLED;
291 return add_breakpoint( elem );
292 }
293
294 /*
295 * Checks whether there is an active breakpoint at the
296 * specified location. Returns the breakpoint id
297 * or -1 if none is found.
298 */
handle_line_breakpoint(OBJECT * file,int line)299 static int handle_line_breakpoint( OBJECT * file, int line )
300 {
301 int i;
302 if ( file == NULL ) return 0;
303 for ( i = 0; i < num_breakpoints; ++i )
304 {
305 if ( breakpoints[ i ].bound_file == NULL && is_same_file( breakpoints[ i ].file, file ) )
306 {
307 breakpoints[ i ].bound_file = object_copy( file );
308 }
309 if ( breakpoints[ i ].status == BREAKPOINT_ENABLED &&
310 breakpoints[ i ].bound_file != NULL &&
311 object_equal( breakpoints[ i ].bound_file, file ) &&
312 breakpoints[ i ].line == line )
313 {
314 return i + 1;
315 }
316 }
317 return 0;
318 }
319
handle_function_breakpoint(OBJECT * name)320 static int handle_function_breakpoint( OBJECT * name )
321 {
322 return handle_line_breakpoint( name, -1 );
323 }
324
make_absolute_path(OBJECT * filename)325 static OBJECT * make_absolute_path( OBJECT * filename )
326 {
327 PATHNAME path1[ 1 ];
328 string buf[ 1 ];
329 OBJECT * result;
330 const char * root = object_str( cwd() );
331 path_parse( object_str( filename ), path1 );
332 path1->f_root.ptr = root;
333 path1->f_root.len = int32_t(strlen( root ));
334 string_new( buf );
335 path_build( path1, buf );
336 result = object_new( buf->value );
337 string_free( buf );
338 return result;
339 }
340
get_filename(OBJECT * path)341 static OBJECT * get_filename( OBJECT * path )
342 {
343 PATHNAME path1[ 1 ];
344 string buf[ 1 ];
345 OBJECT * result;
346 path_parse( object_str( path ), path1 );
347 path1->f_dir.ptr = NULL;
348 path1->f_dir.len = 0;
349 string_new( buf );
350 path_build( path1, buf );
351 result = object_new( buf->value );
352 string_free( buf );
353 return result;
354 }
355
is_same_file(OBJECT * file1,OBJECT * file2)356 static int is_same_file( OBJECT * file1, OBJECT * file2 )
357 {
358 OBJECT * absolute1 = make_absolute_path( file1 );
359 OBJECT * absolute2 = make_absolute_path( file2 );
360 OBJECT * norm1 = path_as_key( absolute1 );
361 OBJECT * norm2 = path_as_key( absolute2 );
362 OBJECT * base1 = get_filename( file1 );
363 OBJECT * base2 = get_filename( file2 );
364 OBJECT * normbase1 = path_as_key( base1 );
365 OBJECT * normbase2 = path_as_key( base2 );
366 int result = object_equal( norm1, norm2 ) ||
367 ( object_equal( base1, file1 ) && object_equal( normbase1, normbase2 ) );
368 object_free( absolute1 );
369 object_free( absolute2 );
370 object_free( norm1 );
371 object_free( norm2 );
372 object_free( base1 );
373 object_free( base2 );
374 object_free( normbase1 );
375 object_free( normbase2 );
376 return result;
377 }
378
debug_print_source(OBJECT * filename,int line)379 static void debug_print_source( OBJECT * filename, int line )
380 {
381 FILE * file;
382
383 if ( filename == NULL || object_equal( filename, constant_builtin ) )
384 return;
385
386 file = fopen( object_str( filename ), "r" );
387 if ( file )
388 {
389 int ch;
390 int printing = 0;
391 int current_line = 1;
392 if ( line == 1 )
393 {
394 printing = 1;
395 printf( "%d\t", current_line );
396 }
397 while ( ( ch = fgetc( file ) ) != EOF )
398 {
399 if ( printing )
400 fputc( ch, stdout );
401
402 if ( ch == '\n' )
403 {
404 if ( printing )
405 break;
406
407 ++current_line;
408 if ( current_line == line )
409 {
410 printing = 1;
411 printf( "%d\t", current_line );
412 }
413 }
414 }
415 fclose( file );
416 }
417 }
418
debug_print_frame_info(FRAME_INFO * frame)419 static void debug_print_frame_info( FRAME_INFO * frame )
420 {
421 OBJECT * file = frame->file;
422 if ( file == NULL ) file = constant_builtin;
423 printf( "%s ", frame->rulename );
424 if ( strcmp( frame->rulename, "module scope" ) != 0 )
425 {
426 printf( "( " );
427 if ( frame->args->count )
428 {
429 lol_print( frame->args );
430 printf( " " );
431 }
432 printf( ") " );
433 }
434 printf( "at %s:%d", object_str( file ), frame->line );
435 }
436
debug_mi_print_frame_info(FRAME_INFO * frame)437 static void debug_mi_print_frame_info( FRAME_INFO * frame )
438 {
439 printf( "frame={func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"}",
440 frame->rulename,
441 object_str( frame->file ),
442 object_str( frame->fullname ),
443 frame->line );
444 }
445
debug_on_breakpoint(int id)446 static void debug_on_breakpoint( int id )
447 {
448 fputc( DEBUG_MSG_BREAKPOINT, command_output );
449 debug_int_write( command_output, id );
450 fflush( command_output );
451 debug_listen();
452 }
453
debug_end_stepping(void)454 static void debug_end_stepping( void )
455 {
456 fputc( DEBUG_MSG_END_STEPPING, command_output );
457 fflush( command_output );
458 debug_listen();
459 }
460
debug_on_instruction(FRAME * frame,OBJECT * file,int line)461 void debug_on_instruction( FRAME * frame, OBJECT * file, int line )
462 {
463 int breakpoint_id;
464 assert( debug_is_debugging() );
465 if ( debug_state == DEBUG_NEXT &&
466 ( debug_depth < 0 || ( debug_depth == 0 && debug_line != line ) ) )
467 {
468 debug_file = file;
469 debug_line = line;
470 debug_frame = frame;
471 debug_end_stepping();
472 }
473 else if ( debug_state == DEBUG_STEP && debug_line != line )
474 {
475 debug_file = file;
476 debug_line = line;
477 debug_frame = frame;
478 debug_end_stepping();
479 }
480 else if ( debug_state == DEBUG_FINISH && debug_depth < 0 )
481 {
482 debug_file = file;
483 debug_line = line;
484 debug_frame = frame;
485 debug_end_stepping();
486 }
487 else if ( ( debug_file == NULL || ! object_equal( file, debug_file ) ||
488 line != debug_line || debug_depth != 0 ) &&
489 ( breakpoint_id = handle_line_breakpoint( file, line ) ) )
490 {
491 debug_file = file;
492 debug_line = line;
493 debug_frame = frame;
494 debug_on_breakpoint( breakpoint_id );
495 }
496 else if ( ( debug_state == DEBUG_RUN || debug_state == DEBUG_FINISH ) &&
497 ( debug_depth < 0 || ( debug_depth == 0 && debug_line != line ) ) )
498 {
499 debug_file = NULL;
500 debug_line = 0;
501 }
502 }
503
debug_on_enter_function(FRAME * frame,OBJECT * name,OBJECT * file,int line)504 void debug_on_enter_function( FRAME * frame, OBJECT * name, OBJECT * file, int line )
505 {
506 int breakpoint_id;
507 assert( debug_is_debugging() );
508 ++debug_depth;
509 if ( debug_state == DEBUG_STEP && file )
510 {
511 debug_file = file;
512 debug_line = line;
513 debug_frame = frame;
514 debug_end_stepping();
515 }
516 else if ( ( breakpoint_id = handle_function_breakpoint( name ) ) ||
517 ( breakpoint_id = handle_line_breakpoint( file, line ) ) )
518 {
519 debug_file = file;
520 debug_line = line;
521 debug_frame = frame;
522 debug_on_breakpoint( breakpoint_id );
523 }
524 }
525
debug_on_exit_function(OBJECT * name)526 void debug_on_exit_function( OBJECT * name )
527 {
528 assert( debug_is_debugging() );
529 --debug_depth;
530 if ( debug_depth < 0 )
531 {
532 /* The current location is no longer valid
533 after we return from the containing function. */
534 debug_file = NULL;
535 debug_line = 0;
536 }
537 }
538
539 #if NT
540 static HANDLE child_handle;
541 static DWORD child_pid;
542 #else
543 static int child_pid;
544 #endif
545
debug_child_continue(int argc,const char ** argv)546 static void debug_child_continue( int argc, const char * * argv )
547 {
548 debug_state = DEBUG_RUN;
549 debug_depth = 0;
550 }
551
debug_child_step(int argc,const char ** argv)552 static void debug_child_step( int argc, const char * * argv )
553 {
554 debug_state = DEBUG_STEP;
555 debug_depth = 0;
556 }
557
debug_child_next(int argc,const char ** argv)558 static void debug_child_next( int argc, const char * * argv )
559 {
560 debug_state = DEBUG_NEXT;
561 debug_depth = 0;
562 }
563
debug_child_finish(int argc,const char ** argv)564 static void debug_child_finish( int argc, const char * * argv )
565 {
566 debug_state = DEBUG_FINISH;
567 debug_depth = 0;
568 }
569
debug_child_kill(int argc,const char ** argv)570 static void debug_child_kill( int argc, const char * * argv )
571 {
572 exit( 0 );
573 }
574
debug_add_breakpoint(const char * name)575 static int debug_add_breakpoint( const char * name )
576 {
577 const char * file_ptr = name;
578 const char * ptr = strrchr( file_ptr, ':' );
579 if ( ptr )
580 {
581 char * end;
582 long line = strtoul( ptr + 1, &end, 10 );
583 if ( line > 0 && line <= INT_MAX && end != ptr + 1 && *end == 0 )
584 {
585 OBJECT * file = object_new_range( file_ptr, int32_t(ptr - file_ptr) );
586 return add_line_breakpoint( file, line );
587 }
588 else
589 {
590 OBJECT * name = object_new( file_ptr );
591 return add_function_breakpoint( name );
592 }
593 }
594 else
595 {
596 OBJECT * name = object_new( file_ptr );
597 return add_function_breakpoint( name );
598 }
599 }
600
debug_child_break(int argc,const char ** argv)601 static void debug_child_break( int argc, const char * * argv )
602 {
603 if ( argc == 2 )
604 {
605 debug_add_breakpoint( argv[ 1 ] );
606 }
607 }
608
get_breakpoint_by_name(const char * name)609 static int get_breakpoint_by_name( const char * name )
610 {
611 int result;
612 const char * file_ptr = name;
613 const char * ptr = strrchr( file_ptr, ':' );
614 if ( ptr )
615 {
616 char * end;
617 long line = strtoul( ptr + 1, &end, 10 );
618 if ( line > 0 && line <= INT_MAX && end != ptr + 1 && *end == 0 )
619 {
620 OBJECT * file = object_new_range( file_ptr, int32_t(ptr - file_ptr) );
621 result = handle_line_breakpoint( file, line );
622 object_free( file );
623 }
624 else
625 {
626 OBJECT * name = object_new( file_ptr );
627 result = handle_function_breakpoint( name );
628 object_free( name );
629 }
630 }
631 else
632 {
633 OBJECT * name = object_new( file_ptr );
634 result = handle_function_breakpoint( name );
635 object_free( name );
636 }
637 return result;
638 }
639
debug_child_disable(int argc,const char ** argv)640 static void debug_child_disable( int argc, const char * * argv )
641 {
642 if ( argc == 2 )
643 {
644 int id = atoi( argv[ 1 ] );
645 if ( id < 1 || id > num_breakpoints )
646 return;
647 --id;
648 if ( breakpoints[ id ].status == BREAKPOINT_DELETED )
649 return;
650 breakpoints[ id ].status = BREAKPOINT_DISABLED;
651 }
652 }
653
debug_child_enable(int argc,const char ** argv)654 static void debug_child_enable( int argc, const char * * argv )
655 {
656 if ( argc == 2 )
657 {
658 int id = atoi( argv[ 1 ] );
659 if ( id < 1 || id > num_breakpoints )
660 return;
661 --id;
662 if ( breakpoints[ id ].status == BREAKPOINT_DELETED )
663 return;
664 breakpoints[ id ].status = BREAKPOINT_ENABLED;
665 }
666 }
667
debug_child_delete(int argc,const char ** argv)668 static void debug_child_delete( int argc, const char * * argv )
669 {
670 if ( argc == 2 )
671 {
672 int id = atoi( argv[ 1 ] );
673 if ( id < 1 || id > num_breakpoints )
674 return;
675 --id;
676 breakpoints[ id ].status = BREAKPOINT_DELETED;
677 }
678 }
679
debug_child_print(int argc,const char ** argv)680 static void debug_child_print( int argc, const char * * argv )
681 {
682 FRAME * saved_frame;
683 OBJECT * saved_file;
684 int saved_line;
685 string buf[ 1 ];
686 const char * lines[ 2 ];
687 int i;
688 FRAME new_frame = *debug_frame;
689 /* Save the current file/line, since running parse_string
690 * will likely change it.
691 */
692 saved_frame = debug_frame;
693 saved_file = debug_file;
694 saved_line = debug_line;
695 string_new( buf );
696 string_append( buf, "__DEBUG_PRINT_HELPER__" );
697 for ( i = 1; i < argc; ++i )
698 {
699 string_push_back( buf, ' ' );
700 string_append( buf, argv[ i ] );
701 }
702 string_append( buf, " ;\n" );
703 lines[ 0 ] = buf->value;
704 lines[ 1 ] = NULL;
705 parse_string( constant_builtin, lines, &new_frame );
706 string_free( buf );
707 debug_list_write( command_output, debug_print_result );
708 fflush( command_output );
709 debug_frame = saved_frame;
710 debug_file = saved_file;
711 debug_line = saved_line;
712 }
713
debug_child_frame(int argc,const char ** argv)714 static void debug_child_frame( int argc, const char * * argv )
715 {
716 if ( argc == 2 )
717 {
718 debug_selected_frame_number = atoi( argv[ 1 ] );
719 }
720 else
721 {
722 assert( !"Wrong number of arguments to frame." );
723 }
724 }
725
debug_child_info(int argc,const char ** argv)726 static void debug_child_info( int argc, const char * * argv )
727 {
728 if ( strcmp( argv[ 1 ], "locals" ) == 0 )
729 {
730 LIST * locals = L0;
731 if ( debug_frame->function )
732 {
733 locals = function_get_variables( (FUNCTION*)debug_frame->function );
734 }
735 debug_list_write( command_output, locals );
736 fflush( command_output );
737 list_free( locals );
738 }
739 else if ( strcmp( argv[ 1 ], "frame" ) == 0 )
740 {
741 int frame_number = debug_selected_frame_number;
742 int i;
743 FRAME base = *debug_frame;
744 FRAME * frame = &base;
745 base.file = debug_file;
746 base.line = debug_line;
747 if ( argc == 3 ) frame_number = atoi( argv[ 2 ] );
748
749 for ( i = 0; i < frame_number; ++i ) frame = frame->prev;
750
751 debug_frame_write( command_output, frame );
752 }
753 else if ( strcmp( argv[ 1 ], "depth" ) == 0 )
754 {
755 int result = 0;
756 FRAME * frame = debug_frame;
757 while ( frame )
758 {
759 frame = frame->prev;
760 ++result;
761 }
762 fprintf( command_output, "%d", result );
763 fputc( '\0', command_output );
764 fflush( command_output );
765 }
766 }
767
768 /* Commands for the parent. */
769
770 #ifdef NT
771
get_module_filename(string * out)772 static int get_module_filename( string * out )
773 {
774 DWORD result;
775 string_reserve( out, 256 + 1 );
776 string_truncate( out, 256 );
777 while( ( result = GetModuleFileNameA( NULL, out->value, DWORD(out->size) ) ) == DWORD(out->size) )
778 {
779 string_reserve( out, out->size * 2 + 1);
780 string_truncate( out, out->size * 2 );
781 }
782 if ( result != 0 )
783 {
784 string_truncate( out, result );
785 return 1;
786 }
787 else
788 {
789 return 0;
790 }
791 }
792
793 #endif
794
795 static struct command_elem child_commands[] =
796 {
797 { "continue", &debug_child_continue },
798 { "kill", &debug_child_kill },
799 { "step", &debug_child_step },
800 { "next", &debug_child_next },
801 { "finish", &debug_child_finish },
802 { "break", &debug_child_break },
803 { "disable", &debug_child_disable },
804 { "enable", &debug_child_enable },
805 { "delete", &debug_child_delete },
806 { "print", &debug_child_print },
807 { "frame", &debug_child_frame },
808 { "info", &debug_child_info },
809 { NULL, NULL }
810 };
811
debug_mi_error(const char * message)812 static void debug_mi_error( const char * message )
813 {
814 debug_mi_format_token();
815 printf( "^error,msg=\"%s\"\n(gdb) \n", message );
816 }
817
debug_error_(const char * message)818 static void debug_error_( const char * message )
819 {
820 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
821 {
822 printf( "%s\n", message );
823 }
824 else if ( debug_interface == DEBUG_INTERFACE_MI )
825 {
826 debug_mi_error( message );
827 }
828 }
829
debug_format_message(const char * format,va_list vargs)830 static const char * debug_format_message( const char * format, va_list vargs )
831 {
832 char * buf;
833 int result;
834 int sz = 80;
835 for ( ; ; )
836 {
837 va_list args;
838 buf = (char *)malloc( sz );
839 if ( !buf )
840 return 0;
841 #ifndef va_copy
842 args = vargs;
843 #else
844 va_copy( args, vargs );
845 #endif
846 #if defined(_MSC_VER) && (_MSC_VER <= 1310)
847 result = _vsnprintf( buf, sz, format, args );
848 #else
849 result = vsnprintf( buf, sz, format, args );
850 #endif
851 va_end( args );
852 if ( 0 <= result && result < sz )
853 return buf;
854 free( buf );
855 if ( result < 0 )
856 return 0;
857 sz = result + 1;
858 }
859 }
860
debug_error(const char * format,...)861 static void debug_error( const char * format, ... )
862 {
863 va_list args;
864 const char * msg;
865 va_start( args, format );
866 msg = debug_format_message( format, args );
867 va_end( args );
868 if ( !msg )
869 {
870 debug_error_( "Failed formatting error message." );
871 return;
872 }
873 debug_error_( msg );
874 free( ( void * )msg );
875 }
876
debug_parent_child_exited(int pid,int exit_code)877 static void debug_parent_child_exited( int pid, int exit_code )
878 {
879 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
880 {
881 printf( "Child %d exited with status %d\n", (int)child_pid, (int)exit_code );
882 }
883 else if ( debug_interface == DEBUG_INTERFACE_MI )
884 {
885 if ( exit_code == 0 )
886 printf( "*stopped,reason=\"exited-normally\"\n(gdb) \n" );
887 else
888 printf( "*stopped,reason=\"exited\",exit-code=\"%d\"\n(gdb) \n", exit_code );
889 }
890 else
891 {
892 assert( !"Wrong value of debug_interface." );
893 }
894 }
895
896 #if !NT
897
debug_parent_child_signalled(int pid,int id)898 static void debug_parent_child_signalled( int pid, int id )
899 {
900
901 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
902 {
903 printf( "Child %d exited on signal %d\n", child_pid, id );
904 }
905 else if ( debug_interface == DEBUG_INTERFACE_MI )
906 {
907 const char * name = "unknown";
908 const char * meaning = "unknown";
909 switch( id )
910 {
911 case SIGINT: name = "SIGINT"; meaning = "Interrupt"; break;
912 }
913 printf("*stopped,reason=\"exited-signalled\",signal-name=\"%s\",signal-meaning=\"%s\"\n(gdb) \n", name, meaning);
914 }
915 else
916 {
917 assert( !"Wrong value of debug_interface." );
918 }
919 }
920
921 #endif
922
debug_parent_on_breakpoint(void)923 static void debug_parent_on_breakpoint( void )
924 {
925 FRAME_INFO base;
926 int id;
927 id = debug_int_read( command_child );
928 fprintf( command_output, "info frame\n" );
929 fflush( command_output );
930 debug_frame_read( command_child, &base );
931 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
932 {
933 printf( "Breakpoint %d, ", id );
934 debug_print_frame_info( &base );
935 printf( "\n" );
936 debug_print_source( base.file, base.line );
937 }
938 else if ( debug_interface == DEBUG_INTERFACE_MI )
939 {
940 printf( "*stopped,reason=\"breakpoint-hit\",bkptno=\"%d\",disp=\"keep\",", id );
941 debug_mi_print_frame_info( &base );
942 printf( ",thread-id=\"1\",stopped-threads=\"all\"" );
943 printf( "\n(gdb) \n" );
944 }
945 else
946 {
947 assert( !"Wrong value if debug_interface" );
948 }
949 fflush( stdout );
950 }
951
debug_parent_on_end_stepping(void)952 static void debug_parent_on_end_stepping( void )
953 {
954 FRAME_INFO base;
955 fprintf( command_output, "info frame\n" );
956 fflush( command_output );
957 debug_frame_read( command_child, &base );
958 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
959 {
960 debug_print_source( base.file, base.line );
961 }
962 else
963 {
964 printf( "*stopped,reason=\"end-stepping-range\"," );
965 debug_mi_print_frame_info( &base );
966 printf( ",thread-id=\"1\"" );
967 printf( "\n(gdb) \n" );
968 }
969 fflush( stdout );
970 }
971
972 /* Waits for events from the child. */
debug_parent_wait(int print_message)973 static void debug_parent_wait( int print_message )
974 {
975 int ch = fgetc( command_child );
976 if ( ch == DEBUG_MSG_BREAKPOINT )
977 {
978 debug_parent_on_breakpoint();
979 }
980 else if ( ch == DEBUG_MSG_END_STEPPING )
981 {
982 debug_parent_on_end_stepping();
983 }
984 else if ( ch == DEBUG_MSG_SETUP )
985 {
986 /* FIXME: This is handled in the caller, but it would make
987 more sense to handle it here. */
988 return;
989 }
990 else if ( ch == EOF )
991 {
992 #if NT
993 WaitForSingleObject( child_handle, INFINITE );
994 if ( print_message )
995 {
996 DWORD exit_code;
997 GetExitCodeProcess( child_handle, &exit_code );
998 debug_parent_child_exited( (int)child_pid, (int)exit_code );
999 }
1000 CloseHandle( child_handle );
1001 #else
1002 int status;
1003 int pid;
1004 while ( ( pid = waitpid( child_pid, &status, 0 ) ) == -1 )
1005 if ( errno != EINTR )
1006 break;
1007 if ( print_message )
1008 {
1009 if ( WIFEXITED( status ) )
1010 debug_parent_child_exited( child_pid, WEXITSTATUS( status ) );
1011 else if ( WIFSIGNALED( status ) )
1012 debug_parent_child_signalled( child_pid, WTERMSIG( status ) );
1013 }
1014 #endif
1015 fclose( command_child );
1016 fclose( command_output );
1017 debug_state = DEBUG_NO_CHILD;
1018 }
1019 }
1020
1021 /* Prints the message for starting the child. */
debug_parent_run_print(int argc,const char ** argv)1022 static void debug_parent_run_print( int argc, const char * * argv )
1023 {
1024 int i;
1025 extern char const * saved_argv0;
1026 char * name = executable_path( saved_argv0 );
1027 printf( "Starting program: %s", name );
1028 free( name );
1029 for ( i = 1; i < argc; ++i )
1030 {
1031 printf( " %s", argv[ i ] );
1032 }
1033 printf( "\n" );
1034 fflush( stdout );
1035 }
1036
1037 #if NT
1038
debug_init_handles(const char * in,const char * out)1039 void debug_init_handles( const char * in, const char * out )
1040 {
1041 HANDLE read_handle;
1042 int read_fd;
1043 HANDLE write_handle;
1044 int write_fd;
1045
1046 sscanf( in, "%p", &read_handle );
1047 read_fd = _open_osfhandle( (intptr_t)read_handle, _O_RDONLY );
1048 command_input = _fdopen( read_fd, "r" );
1049
1050 sscanf( out, "%p", &write_handle );
1051 write_fd = _open_osfhandle( (intptr_t)write_handle, _O_WRONLY );
1052 command_output = _fdopen( write_fd, "w" );
1053
1054 command_array = child_commands;
1055
1056 /* Handle the initial setup */
1057 /* wake up the parent */
1058 fputc( DEBUG_MSG_SETUP, command_output );
1059 debug_listen();
1060 }
1061
init_parent_handles(HANDLE out,HANDLE in)1062 static void init_parent_handles( HANDLE out, HANDLE in )
1063 {
1064 command_child = _fdopen( _open_osfhandle( (intptr_t)in, _O_RDONLY ), "r" );
1065 command_output = _fdopen( _open_osfhandle( (intptr_t)out, _O_WRONLY ), "w" );
1066 }
1067
debug_parent_copy_breakpoints(void)1068 static void debug_parent_copy_breakpoints( void )
1069 {
1070 int i;
1071 for ( i = 0; i < num_breakpoints; ++i )
1072 {
1073 fprintf( command_output, "break %s", object_str( breakpoints[ i ].file ) );
1074 if ( breakpoints[ i ].line != -1 )
1075 {
1076 fprintf( command_output, ":%d", breakpoints[ i ].line );
1077 }
1078 fprintf( command_output, "\n" );
1079
1080 switch ( breakpoints[ i ].status )
1081 {
1082 case BREAKPOINT_ENABLED:
1083 break;
1084 case BREAKPOINT_DISABLED:
1085 fprintf( command_output, "disable %d\n", i + 1 );
1086 break;
1087 case BREAKPOINT_DELETED:
1088 fprintf( command_output, "delete %d\n", i + 1 );
1089 break;
1090 default:
1091 assert( !"Wrong breakpoint status." );
1092 }
1093 }
1094 fflush( command_output );
1095 }
1096
1097 #endif
1098
debug_start_child(int argc,const char ** argv)1099 static void debug_start_child( int argc, const char * * argv )
1100 {
1101 #if NT
1102 char buf[ 80 ];
1103 HANDLE pipe1[ 2 ];
1104 HANDLE pipe2[ 2 ];
1105 string self[ 1 ];
1106 string command_line[ 1 ];
1107 SECURITY_ATTRIBUTES sa = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
1108 PROCESS_INFORMATION pi = { NULL, NULL, 0, 0 };
1109 STARTUPINFOA si = { sizeof( STARTUPINFOA ), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1110 0, 0, 0, 0, 0, 0 };
1111 assert( debug_state == DEBUG_NO_CHILD );
1112 if ( ! CreatePipe( &pipe1[ 0 ], &pipe1[ 1 ], &sa, 0 ) )
1113 {
1114 printf("internal error: CreatePipe:1: 0x%08lx\n", GetLastError());
1115 return;
1116 }
1117 if ( ! CreatePipe( &pipe2[ 0 ], &pipe2[ 1 ], &sa, 0 ) )
1118 {
1119 printf("internal error: CreatePipe:2: 0x%08lx\n", GetLastError());
1120 CloseHandle( pipe1[ 0 ] );
1121 CloseHandle( pipe1[ 1 ] );
1122 return;
1123 }
1124 string_new( self );
1125 if ( ! get_module_filename( self ) )
1126 {
1127 printf("internal error\n");
1128 CloseHandle( pipe1[ 0 ] );
1129 CloseHandle( pipe1[ 1 ] );
1130 CloseHandle( pipe2[ 0 ] );
1131 CloseHandle( pipe2[ 1 ] );
1132 return;
1133 }
1134 string_copy( command_line, "b2 " );
1135 /* Pass the handles as the first and second arguments. */
1136 string_append( command_line, debugger_opt );
1137 sprintf( buf, "%p", pipe1[ 0 ] );
1138 string_append( command_line, buf );
1139 string_push_back( command_line, ' ' );
1140 string_append( command_line, debugger_opt );
1141 sprintf( buf, "%p", pipe2[ 1 ] );
1142 string_append( command_line, buf );
1143 /* Pass the rest of the command line. */
1144 {
1145 int i;
1146 for ( i = 1; i < argc; ++i )
1147 {
1148 string_push_back( command_line, ' ' );
1149 string_append( command_line, argv[ i ] );
1150 }
1151 }
1152 SetHandleInformation( pipe1[ 1 ], HANDLE_FLAG_INHERIT, 0 );
1153 SetHandleInformation( pipe2[ 0 ], HANDLE_FLAG_INHERIT, 0 );
1154 if ( ! CreateProcessA(
1155 self->value,
1156 command_line->value,
1157 NULL,
1158 NULL,
1159 TRUE,
1160 0,
1161 NULL,
1162 NULL,
1163 &si,
1164 &pi
1165 ) )
1166 {
1167 printf("internal error\n");
1168 CloseHandle( pipe1[ 0 ] );
1169 CloseHandle( pipe1[ 1 ] );
1170 CloseHandle( pipe2[ 0 ] );
1171 CloseHandle( pipe2[ 1 ] );
1172 string_free( self );
1173 string_free( command_line );
1174 return;
1175 }
1176 child_pid = pi.dwProcessId;
1177 child_handle = pi.hProcess;
1178 CloseHandle( pi.hThread );
1179 CloseHandle( pipe1[ 0 ] );
1180 CloseHandle( pipe2[ 1 ] );
1181 string_free( self );
1182 string_free( command_line );
1183
1184 debug_state = DEBUG_RUN;
1185
1186 init_parent_handles( pipe1[ 1 ], pipe2[ 0 ] );
1187 debug_parent_wait( 1 );
1188 debug_parent_copy_breakpoints();
1189 fprintf( command_output, "continue\n" );
1190 fflush( command_output );
1191 #else
1192 int pipe1[2];
1193 int pipe2[2];
1194 int write_fd;
1195 int read_fd;
1196 int pid;
1197 assert( debug_state == DEBUG_NO_CHILD );
1198 if (pipe(pipe1) == -1)
1199 {
1200 printf("internal error: pipe:1: %s\n", strerror(errno));
1201 return;
1202 }
1203 if (pipe(pipe2) == -1)
1204 {
1205 close( pipe1[ 0 ] );
1206 close( pipe1[ 1 ] );
1207 printf("internal error: pipe:2: %s\n", strerror(errno));
1208 return;
1209 }
1210
1211 pid = fork();
1212 if ( pid == -1 )
1213 {
1214 /* error */
1215 close( pipe1[ 0 ] );
1216 close( pipe1[ 1 ] );
1217 close( pipe2[ 0 ] );
1218 close( pipe2[ 1 ] );
1219 printf("internal error: fork: %s\n", strerror(errno));
1220 return;
1221 }
1222 else if ( pid == 0 )
1223 {
1224 /* child */
1225 extern const char * saved_argv0;
1226 read_fd = pipe1[ 0 ];
1227 write_fd = pipe2[ 1 ];
1228 close( pipe2[ 0 ] );
1229 close( pipe1[ 1 ] );
1230 command_array = child_commands;
1231 argv[ 0 ] = executable_path( saved_argv0 );
1232 debug_child_data.argc = argc;
1233 debug_child_data.argv = argv;
1234 command_input = fdopen( read_fd, "r" );
1235 command_output = fdopen( write_fd, "w" );
1236 longjmp( debug_child_data.jmp, 1 );
1237 }
1238 else
1239 {
1240 /* parent */
1241 read_fd = pipe2[ 0 ];
1242 write_fd = pipe1[ 1 ];
1243 close( pipe1[ 0 ] );
1244 close( pipe2[ 1 ] );
1245 command_output = fdopen( write_fd, "w" );
1246 command_child = fdopen( read_fd, "r" );
1247 child_pid = pid;
1248 }
1249 debug_state = DEBUG_RUN;
1250 #endif
1251 }
1252
debug_parent_run(int argc,const char ** argv)1253 static void debug_parent_run( int argc, const char * * argv )
1254 {
1255 if ( debug_state == DEBUG_RUN )
1256 {
1257 fprintf( command_output, "kill\n" );
1258 fflush( command_output );
1259 debug_parent_wait( 1 );
1260 }
1261 debug_parent_run_print( argc, argv );
1262 if ( debug_interface == DEBUG_INTERFACE_MI )
1263 {
1264 printf( "=thread-created,id=\"1\",group-id=\"i1\"\n" );
1265 debug_mi_format_token();
1266 printf( "^running\n(gdb) \n" );
1267 }
1268 debug_start_child( argc, argv );
1269 debug_parent_wait( 1 );
1270 }
1271
debug_parent_forward_nowait(int argc,const char ** argv,int print_message,int require_child)1272 static int debug_parent_forward_nowait( int argc, const char * * argv, int print_message, int require_child )
1273 {
1274 int i;
1275 if ( debug_state == DEBUG_NO_CHILD )
1276 {
1277 if ( require_child )
1278 printf( "The program is not being run.\n" );
1279 return 1;
1280 }
1281 fputs( argv[ 0 ], command_output );
1282 for( i = 1; i < argc; ++i )
1283 {
1284 fputc( ' ', command_output );
1285 fputs( argv[ i ], command_output );
1286 }
1287 fputc( '\n', command_output );
1288 fflush( command_output );
1289 return 0;
1290 }
1291
1292 /* FIXME: This function should be eliminated when I finish all stdout to the parent. */
debug_parent_forward(int argc,const char ** argv,int print_message,int require_child)1293 static void debug_parent_forward( int argc, const char * * argv, int print_message, int require_child )
1294 {
1295 if ( debug_parent_forward_nowait( argc, argv, print_message, require_child ) != 0 )
1296 {
1297 return;
1298 }
1299 debug_parent_wait( print_message );
1300 }
1301
debug_parent_continue(int argc,const char ** argv)1302 static void debug_parent_continue( int argc, const char * * argv )
1303 {
1304 if ( argc > 1 )
1305 {
1306 debug_error( "Too many arguments to continue." );
1307 return;
1308 }
1309 if ( debug_interface == DEBUG_INTERFACE_MI )
1310 {
1311 debug_mi_format_token();
1312 printf( "^running\n(gdb) \n" );
1313 fflush( stdout );
1314 }
1315 debug_parent_forward( 1, argv, 1, 1 );
1316 }
1317
debug_parent_kill(int argc,const char ** argv)1318 static void debug_parent_kill( int argc, const char * * argv )
1319 {
1320 if ( argc > 1 )
1321 {
1322 debug_error( "Too many arguments to kill." );
1323 return;
1324 }
1325 if ( debug_interface == DEBUG_INTERFACE_MI )
1326 {
1327 debug_mi_format_token();
1328 printf( "^done\n(gdb) \n" );
1329 fflush( stdout );
1330 }
1331 debug_parent_forward( 1, argv, 0, 1 );
1332 }
1333
debug_parent_step(int argc,const char ** argv)1334 static void debug_parent_step( int argc, const char * * argv )
1335 {
1336 if ( argc > 1 )
1337 {
1338 debug_error( "Too many arguments to step." );
1339 return;
1340 }
1341 if ( debug_interface == DEBUG_INTERFACE_MI )
1342 {
1343 debug_mi_format_token();
1344 printf( "^running\n(gdb) \n" );
1345 fflush( stdout );
1346 }
1347 debug_parent_forward( 1, argv, 1, 1 );
1348 }
1349
debug_parent_next(int argc,const char ** argv)1350 static void debug_parent_next( int argc, const char * * argv )
1351 {
1352 if ( argc > 1 )
1353 {
1354 debug_error( "Too many arguments to next." );
1355 return;
1356 }
1357 if ( debug_interface == DEBUG_INTERFACE_MI )
1358 {
1359 debug_mi_format_token();
1360 printf( "^running\n(gdb) \n" );
1361 fflush( stdout );
1362 }
1363 debug_parent_forward( 1, argv, 1, 1 );
1364 }
1365
debug_parent_finish(int argc,const char ** argv)1366 static void debug_parent_finish( int argc, const char * * argv )
1367 {
1368 if ( argc > 1 )
1369 {
1370 debug_error( "Too many arguments to finish." );
1371 return;
1372 }
1373 if ( debug_interface == DEBUG_INTERFACE_MI )
1374 {
1375 debug_mi_format_token();
1376 printf( "^running\n(gdb) \n" );
1377 fflush( stdout );
1378 }
1379 debug_parent_forward( 1, argv, 1, 1 );
1380 }
1381
debug_parent_break(int argc,const char ** argv)1382 static void debug_parent_break( int argc, const char * * argv )
1383 {
1384 int id;
1385 if ( argc < 2 )
1386 {
1387 debug_error( "Missing argument to break." );
1388 return;
1389 }
1390 else if ( argc > 2 )
1391 {
1392 debug_error( "Too many arguments to break." );
1393 return;
1394 }
1395 id = debug_add_breakpoint( argv[ 1 ] );
1396 debug_parent_forward_nowait( argc, argv, 1, 0 );
1397 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
1398 {
1399 printf( "Breakpoint %d set at %s\n", id, argv[ 1 ] );
1400 }
1401 else if ( debug_interface == DEBUG_INTERFACE_MI )
1402 {
1403 debug_mi_format_token();
1404 printf( "^done\n(gdb) \n" );
1405 }
1406 else
1407 {
1408 assert( !"wrong value of debug_interface." );
1409 }
1410 }
1411
check_breakpoint_fn_args(int argc,const char ** argv)1412 int check_breakpoint_fn_args( int argc, const char * * argv )
1413 {
1414 if ( argc < 2 )
1415 {
1416 debug_error( "Missing argument to %s.", argv[ 0 ] );
1417 return 0;
1418 }
1419 else if ( argc > 2 )
1420 {
1421 debug_error( "Too many arguments to %s.", argv[ 0 ] );
1422 return 0;
1423 }
1424 else
1425 {
1426 char * end;
1427 long x = strtol( argv[ 1 ], &end, 10 );
1428 if ( *end )
1429 {
1430 debug_error( "Invalid breakpoint number %s.", argv[ 1 ] );
1431 return 0;
1432 }
1433 if ( x < 1 || x > num_breakpoints || breakpoints[ x - 1 ].status == BREAKPOINT_DELETED )
1434 {
1435 debug_error( "Unknown breakpoint %s.", argv[ 1 ] );
1436 return 0;
1437 }
1438 }
1439 return 1;
1440 }
1441
debug_parent_disable(int argc,const char ** argv)1442 static void debug_parent_disable( int argc, const char * * argv )
1443 {
1444 if ( ! check_breakpoint_fn_args( argc, argv ) )
1445 {
1446 return;
1447 }
1448 debug_child_disable( argc, argv );
1449 debug_parent_forward_nowait( 2, argv, 1, 0 );
1450 if ( debug_interface == DEBUG_INTERFACE_MI )
1451 {
1452 debug_mi_format_token();
1453 printf( "^done\n(gdb) \n" );
1454 }
1455 }
1456
debug_parent_enable(int argc,const char ** argv)1457 static void debug_parent_enable( int argc, const char * * argv )
1458 {
1459 if ( ! check_breakpoint_fn_args( argc, argv ) )
1460 {
1461 return;
1462 }
1463 debug_child_enable( argc, argv );
1464 debug_parent_forward_nowait( 2, argv, 1, 0 );
1465 if ( debug_interface == DEBUG_INTERFACE_MI )
1466 {
1467 debug_mi_format_token();
1468 printf( "^done\n(gdb) \n" );
1469 }
1470 }
1471
debug_parent_delete(int argc,const char ** argv)1472 static void debug_parent_delete( int argc, const char * * argv )
1473 {
1474 if ( ! check_breakpoint_fn_args( argc, argv ) )
1475 {
1476 return;
1477 }
1478 debug_child_delete( argc, argv );
1479 debug_parent_forward_nowait( 2, argv, 1, 0 );
1480 if ( debug_interface == DEBUG_INTERFACE_MI )
1481 {
1482 debug_mi_format_token();
1483 printf( "^done\n(gdb) \n" );
1484 }
1485 }
1486
debug_parent_clear(int argc,const char ** argv)1487 static void debug_parent_clear( int argc, const char * * argv )
1488 {
1489 char buf[ 16 ];
1490 const char * new_args[ 2 ];
1491 int id;
1492 if ( argc < 2 )
1493 {
1494 debug_error( "Missing argument to clear." );
1495 return;
1496 }
1497 else if ( argc > 2 )
1498 {
1499 debug_error( "Too many arguments to clear." );
1500 return;
1501 }
1502 id = get_breakpoint_by_name( argv[ 1 ] );
1503 if ( id == 0 )
1504 {
1505 debug_error( "No breakpoint at %s.", argv[ 1 ] );
1506 return;
1507 }
1508
1509 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
1510 {
1511 printf( "Deleted breakpoint %d\n", id );
1512 }
1513
1514 sprintf( buf, "%d", id );
1515 new_args[ 0 ] = "delete";
1516 new_args[ 1 ] = buf;
1517 debug_parent_delete( 2, new_args );
1518 }
1519
debug_parent_print(int argc,const char ** argv)1520 static void debug_parent_print( int argc, const char * * argv )
1521 {
1522 LIST * result;
1523 if ( debug_parent_forward_nowait( argc, argv, 1, 1 ) != 0 )
1524 {
1525 return;
1526 }
1527 result = debug_list_read( command_child );
1528
1529 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
1530 {
1531 list_print( result );
1532 printf( "\n" );
1533 }
1534 else if ( debug_interface == DEBUG_INTERFACE_MI )
1535 {
1536 printf( "~\"$1 = " );
1537 list_print( result );
1538 printf( "\"\n~\"\\n\"\n" );
1539 debug_mi_format_token();
1540 printf( "^done\n(gdb) \n" );
1541 }
1542
1543 list_free( result );
1544 }
1545
debug_parent_backtrace(int argc,const char ** argv)1546 static void debug_parent_backtrace( int argc, const char * * argv )
1547 {
1548 const char * new_args[ 3 ];
1549 OBJECT * depth_str;
1550 int depth;
1551 int i;
1552 FRAME_INFO frame;
1553
1554 if ( debug_state == DEBUG_NO_CHILD )
1555 {
1556 debug_error( "The program is not being run." );
1557 return;
1558 }
1559
1560 new_args[ 0 ] = "info";
1561 new_args[ 1 ] = "frame";
1562
1563 fprintf( command_output, "info depth\n" );
1564 fflush( command_output );
1565 depth_str = debug_object_read( command_child );
1566 depth = atoi( object_str( depth_str ) );
1567 object_free( depth_str );
1568
1569 for ( i = 0; i < depth; ++i )
1570 {
1571 char buf[ 16 ];
1572 sprintf( buf, "%d", i );
1573 new_args[ 2 ] = buf;
1574 debug_parent_forward_nowait( 3, new_args, 0, 0 );
1575 debug_frame_read( command_child, &frame );
1576 printf( "#%d in ", i );
1577 debug_print_frame_info( &frame );
1578 printf( "\n" );
1579 }
1580 fflush( stdout );
1581 }
1582
debug_parent_quit(int argc,const char ** argv)1583 static void debug_parent_quit( int argc, const char * * argv )
1584 {
1585 if ( debug_state == DEBUG_RUN )
1586 {
1587 fprintf( command_output, "kill\n" );
1588 fflush( command_output );
1589 debug_parent_wait( 0 );
1590 }
1591 exit( 0 );
1592 }
1593
1594 static const char * const help_text[][2] =
1595 {
1596 {
1597 "run",
1598 "run <args>\n"
1599 "Creates a new b2 child process passing <args> on the command line."
1600 " Terminates\nthe current child (if any).\n"
1601 },
1602 {
1603 "continue",
1604 "continue\nContinue debugging\n"
1605 },
1606 {
1607 "step",
1608 "step\nContinue to the next statement\n"
1609 },
1610 {
1611 "next",
1612 "next\nContinue to the next line in the current frame\n"
1613 },
1614 {
1615 "finish",
1616 "finish\nContinue to the end of the current frame\n"
1617 },
1618 {
1619 "break",
1620 "break <location>\n"
1621 "Sets a breakpoint at <location>. <location> can be either a the name of a\nfunction or <filename>:<lineno>\n"
1622 },
1623 {
1624 "disable",
1625 "disable <breakpoint>\nDisable a breakpoint\n"
1626 },
1627 {
1628 "enable",
1629 "enable <breakpoint>\nEnable a breakpoint\n"
1630 },
1631 {
1632 "delete",
1633 "delete <breakpoint>\nDelete a breakpoint\n"
1634 },
1635 {
1636 "clear",
1637 "clear <location>\nDelete the breakpoint at <location>\n"
1638 },
1639 {
1640 "print",
1641 "print <expression>\nDisplay the value of <expression>\n"
1642 },
1643 {
1644 "backtrace",
1645 "backtrace\nDisplay the call stack\n"
1646 },
1647 {
1648 "kill",
1649 "kill\nTerminate the child\n"
1650 },
1651 {
1652 "quit",
1653 "quit\nExit the debugger\n"
1654 },
1655 {
1656 "help",
1657 "help\nhelp <command>\nShow help for debugger commands.\n"
1658 },
1659 { 0, 0 }
1660 };
1661
debug_parent_help(int argc,const char ** argv)1662 static void debug_parent_help( int argc, const char * * argv )
1663 {
1664 if ( argc == 1 )
1665 {
1666 printf(
1667 "run - Start debugging\n"
1668 "continue - Continue debugging\n"
1669 "step - Continue to the next statement\n"
1670 "next - Continue to the next line in the current frame\n"
1671 "finish - Continue to the end of the current frame\n"
1672 "break - Set a breakpoint\n"
1673 "disable - Disable a breakpoint\n"
1674 "enable - Enable a breakpoint\n"
1675 "delete - Delete a breakpoint\n"
1676 "clear - Delete a breakpoint by location\n"
1677 );
1678 printf(
1679 "print - Display an expression\n"
1680 "backtrace - Display the call stack\n"
1681 "kill - Terminate the child\n"
1682 "quit - Exit the debugger\n"
1683 "help - Debugger help\n"
1684 );
1685 }
1686 else if ( argc == 2 )
1687 {
1688 int i;
1689 for ( i = 0; help_text[ i ][ 0 ]; ++i )
1690 {
1691 if ( strcmp( argv[ 1 ], help_text[ i ][ 0 ] ) == 0 )
1692 {
1693 printf( "%s", help_text[ i ][ 1 ] );
1694 return;
1695 }
1696 }
1697 printf( "No command named %s\n", argv[ 1 ] );
1698 }
1699 }
1700
1701 static void debug_mi_break_insert( int argc, const char * * argv );
1702 static void debug_mi_break_delete( int argc, const char * * argv );
1703 static void debug_mi_break_disable( int argc, const char * * argv );
1704 static void debug_mi_break_enable( int argc, const char * * argv );
1705 static void debug_mi_break_info( int argc, const char * * argv );
1706 static void debug_mi_break_list( int argc, const char * * argv );
1707 static void debug_mi_inferior_tty_set( int argc, const char * * argv );
1708 static void debug_mi_gdb_exit( int argc, const char * * argv );
1709 static void debug_mi_gdb_set( int argc, const char * * argv );
1710 static void debug_mi_gdb_show( int argc, const char * * argv );
1711 static void debug_mi_not_implemented( int argc, const char * * argv );
1712 static void debug_mi_file_list_exec_source_files( int argc, const char * * argv );
1713 static void debug_mi_file_list_exec_source_file( int argc, const char * * argv );
1714 static void debug_mi_thread_info( int argc, const char * * argv );
1715 static void debug_mi_thread_select( int argc, const char * * argv );
1716 static void debug_mi_stack_info_frame( int argc, const char * * argv );
1717 static void debug_mi_stack_select_frame( int argc, const char * * argv );
1718 static void debug_mi_stack_list_variables( int argc, const char * * argv );
1719 static void debug_mi_stack_list_locals( int argc, const char * * argv );
1720 static void debug_mi_stack_list_frames( int argc, const char * * argv );
1721 static void debug_mi_list_target_features( int argc, const char * * argv );
1722 static void debug_mi_exec_run( int argc, const char * * argv );
1723 static void debug_mi_exec_continue( int argc, const char * * argv );
1724 static void debug_mi_exec_step( int argc, const char * * argv );
1725 static void debug_mi_exec_next( int argc, const char * * argv );
1726 static void debug_mi_exec_finish( int argc, const char * * argv );
1727 static void debug_mi_data_list_register_names( int argc, const char * * argv );
1728 static void debug_mi_data_evaluate_expression( int argc, const char * * argv );
1729 static void debug_mi_interpreter_exec( int argc, const char * * argv );
1730
1731 static struct command_elem parent_commands[] =
1732 {
1733 { "run", &debug_parent_run },
1734 { "continue", &debug_parent_continue },
1735 { "kill", &debug_parent_kill },
1736 { "step", &debug_parent_step },
1737 { "next", &debug_parent_next },
1738 { "finish", &debug_parent_finish },
1739 { "break", &debug_parent_break },
1740 { "disable", &debug_parent_disable },
1741 { "enable", &debug_parent_enable },
1742 { "delete", &debug_parent_delete },
1743 { "clear", &debug_parent_clear },
1744 { "print", &debug_parent_print },
1745 { "backtrace", &debug_parent_backtrace },
1746 { "quit", &debug_parent_quit },
1747 { "help", &debug_parent_help },
1748 { "-break-insert", &debug_mi_break_insert },
1749 { "-break-delete", &debug_mi_break_delete },
1750 { "-break-disable", &debug_mi_break_disable },
1751 { "-break-enable", &debug_mi_break_enable },
1752 { "-break-info", &debug_mi_break_info },
1753 { "-break-list", &debug_mi_break_list },
1754 { "-inferior-tty-set", &debug_mi_inferior_tty_set },
1755 { "-gdb-exit", &debug_mi_gdb_exit },
1756 { "-gdb-set", &debug_mi_gdb_set },
1757 { "-gdb-show", &debug_mi_gdb_show },
1758 { "-enable-pretty-printing", &debug_mi_not_implemented },
1759 { "-file-list-exec-source-files", &debug_mi_file_list_exec_source_files },
1760 { "-file-list-exec-source-file", &debug_mi_file_list_exec_source_file },
1761 { "-thread-info", &debug_mi_thread_info },
1762 { "-thread-select", &debug_mi_thread_select },
1763 { "-stack-info-frame", &debug_mi_stack_info_frame },
1764 { "-stack-select-frame", &debug_mi_stack_select_frame },
1765 { "-stack-list-variables", &debug_mi_stack_list_variables },
1766 { "-stack-list-locals", &debug_mi_stack_list_locals },
1767 { "-stack-list-frames", &debug_mi_stack_list_frames },
1768 { "-list-target-features", &debug_mi_list_target_features },
1769 { "-exec-run", &debug_mi_exec_run },
1770 { "-exec-continue", &debug_mi_exec_continue },
1771 { "-exec-step", &debug_mi_exec_step },
1772 { "-exec-next", &debug_mi_exec_next },
1773 { "-exec-finish", &debug_mi_exec_finish },
1774 { "-data-list-register-names", &debug_mi_data_list_register_names },
1775 { "-data-evaluate-expression", &debug_mi_data_evaluate_expression },
1776 { "-interpreter-exec", &debug_mi_interpreter_exec },
1777 { NULL, NULL }
1778 };
1779
debug_mi_format_token(void)1780 static void debug_mi_format_token( void )
1781 {
1782 if ( current_token != 0 )
1783 {
1784 printf( "%d", current_token );
1785 }
1786 }
1787
debug_mi_format_breakpoint(int id)1788 static void debug_mi_format_breakpoint( int id )
1789 {
1790 struct breakpoint * ptr = &breakpoints[ id - 1 ];
1791 printf( "bkpt={" );
1792 printf( "number=\"%d\"", id );
1793 printf( ",type=\"breakpoint\"" );
1794 printf( ",disp=\"keep\"" ); /* FIXME: support temporary breakpoints. */
1795 printf( ",enabled=\"%s\"", ptr->status == BREAKPOINT_ENABLED ? "y" : "n" );
1796 /* addr */
1797 if ( ptr->line == -1 )
1798 {
1799 printf( ",func=\"%s\"", object_str( ptr->file ) );
1800 }
1801 else
1802 {
1803 printf( ",file=\"%s\"", object_str( ptr->file ) );
1804 printf( ",line=\"%d\"", ptr->line );
1805 printf( ",fullname=\"%s\"", object_str( ptr->file ) );
1806 }
1807 /* fullname */
1808 /* times */
1809 // printf( "" );
1810 printf( "}" );
1811 }
1812
breakpoint_id_parse(const char * name)1813 static int breakpoint_id_parse( const char * name )
1814 {
1815 int id = atoi( name );
1816 if ( id > num_breakpoints || id < 1 || breakpoints[ id ].status == BREAKPOINT_DELETED )
1817 return -1;
1818 return id;
1819 }
1820
debug_mi_break_insert(int argc,const char ** argv)1821 static void debug_mi_break_insert( int argc, const char * * argv )
1822 {
1823 const char * inner_argv[ 2 ];
1824 // int temporary = 0; /* FIXME: not supported yet */
1825 // int hardware = 0; /* unsupported */
1826 // int force = 1; /* We don't have global debug information... */
1827 int disabled = 0;
1828 // int tracepoint = 0; /* unsupported */
1829 // int thread_id = 0;
1830 // int ignore_count = 0;
1831 // const char * condition; /* FIXME: not supported yet */
1832 const char * location;
1833 int id;
1834 for ( --argc, ++argv; argc; --argc, ++argv )
1835 {
1836 if ( strcmp( *argv, "-t" ) == 0 )
1837 {
1838 // temporary = 1;
1839 }
1840 else if ( strcmp( *argv, "-h" ) == 0 )
1841 {
1842 // hardware = 1;
1843 }
1844 else if ( strcmp( *argv, "-f" ) == 0 )
1845 {
1846 // force = 1;
1847 }
1848 else if ( strcmp( *argv, "-d" ) == 0 )
1849 {
1850 disabled = 1;
1851 }
1852 else if ( strcmp( *argv, "-a" ) == 0 )
1853 {
1854 // tracepoint = 1;
1855 }
1856 else if ( strcmp( *argv, "-c" ) == 0 )
1857 {
1858 if ( argc < 2 )
1859 {
1860 debug_mi_error( "Missing argument for -c." );
1861 return;
1862 }
1863
1864 // condition = argv[ 1 ];
1865 --argc;
1866 ++argv;
1867 }
1868 else if ( strcmp( *argv, "-i" ) == 0 )
1869 {
1870 if ( argc < 2 )
1871 {
1872 debug_mi_error( "Missing argument for -i." );
1873 return;
1874 }
1875
1876 // ignore_count = atoi( argv[ 1 ] );
1877 --argc;
1878 ++argv;
1879 }
1880 else if ( strcmp( *argv, "-p" ) == 0 )
1881 {
1882 if ( argc < 2 )
1883 {
1884 debug_mi_error( "Missing argument for -p." );
1885 return;
1886 }
1887
1888 // thread_id = atoi( argv[ 1 ] );
1889 --argc;
1890 ++argv;
1891 }
1892 else if ( strcmp( *argv, "--" ) == 0 )
1893 {
1894 --argc;
1895 ++argv;
1896 break;
1897 }
1898 else if ( **argv != '-' )
1899 {
1900 break;
1901 }
1902 else
1903 {
1904 debug_mi_error( "Unknown argument." );
1905 return;
1906 }
1907 }
1908 if ( argc > 1 )
1909 {
1910 debug_mi_error( "Too many arguments for -break-insert." );
1911 return;
1912 }
1913
1914 if ( argc == 1 )
1915 {
1916 location = *argv;
1917 }
1918 else
1919 {
1920 debug_mi_error( "Not implemented: -break-insert with no location." );
1921 return;
1922 }
1923 inner_argv[ 0 ] = "break";
1924 inner_argv[ 1 ] = location;
1925
1926 id = debug_add_breakpoint( location );
1927 debug_parent_forward_nowait( 2, inner_argv, 1, 0 );
1928
1929 if ( disabled )
1930 {
1931 char buf[ 80 ];
1932 sprintf( buf, "%d", num_breakpoints );
1933 inner_argv[ 0 ] = "disable";
1934 inner_argv[ 1 ] = buf;
1935 debug_child_disable( 2, inner_argv );
1936 debug_parent_forward_nowait( 2, inner_argv, 1, 0 );
1937 }
1938
1939 debug_mi_format_token();
1940 printf( "^done," );
1941 debug_mi_format_breakpoint( id );
1942 printf( "\n(gdb) \n" );
1943 }
1944
debug_mi_break_delete(int argc,const char ** argv)1945 static void debug_mi_break_delete( int argc, const char * * argv )
1946 {
1947 if ( argc < 2 )
1948 {
1949 debug_mi_error( "Not enough arguments for -break-delete" );
1950 return;
1951 }
1952 for ( --argc, ++argv; argc; --argc, ++argv )
1953 {
1954 const char * inner_argv[ 2 ];
1955 int id = breakpoint_id_parse( *argv );
1956 if ( id == -1 )
1957 {
1958 debug_mi_error( "Not a valid breakpoint" );
1959 return;
1960 }
1961 inner_argv[ 0 ] = "delete";
1962 inner_argv[ 1 ] = *argv;
1963 debug_parent_delete( 2, inner_argv );
1964 }
1965 }
1966
debug_mi_break_enable(int argc,const char ** argv)1967 static void debug_mi_break_enable( int argc, const char * * argv )
1968 {
1969 if ( argc < 2 )
1970 {
1971 debug_mi_error( "Not enough arguments for -break-enable" );
1972 return;
1973 }
1974 for ( --argc, ++argv; argc; --argc, ++argv )
1975 {
1976 const char * inner_argv[ 2 ];
1977 int id = breakpoint_id_parse( *argv );
1978 if ( id == -1 )
1979 {
1980 debug_mi_error( "Not a valid breakpoint" );
1981 return;
1982 }
1983 inner_argv[ 0 ] = "enable";
1984 inner_argv[ 1 ] = *argv;
1985 debug_parent_enable( 2, inner_argv );
1986 }
1987 }
1988
debug_mi_break_disable(int argc,const char ** argv)1989 static void debug_mi_break_disable( int argc, const char * * argv )
1990 {
1991 if ( argc < 2 )
1992 {
1993 debug_mi_error( "Not enough arguments for -break-disable" );
1994 return;
1995 }
1996 for ( --argc, ++argv; argc; --argc, ++argv )
1997 {
1998 const char * inner_argv[ 2 ];
1999 int id = breakpoint_id_parse( *argv );
2000 if ( id == -1 )
2001 {
2002 debug_mi_error( "Not a valid breakpoint" );
2003 return;
2004 }
2005 inner_argv[ 0 ] = "disable";
2006 inner_argv[ 1 ] = *argv;
2007 debug_parent_disable( 2, inner_argv );
2008 }
2009 }
2010
debug_mi_format_breakpoint_header_col(int width,int alignment,const char * col_name,const char * colhdr)2011 static void debug_mi_format_breakpoint_header_col( int width, int alignment, const char * col_name, const char * colhdr )
2012 {
2013 printf( "{width=\"%d\",alignment=\"%d\",col_name=\"%s\",colhdr=\"%s\"}", width, alignment, col_name, colhdr );
2014 }
2015
debug_mi_format_breakpoint_hdr(void)2016 static void debug_mi_format_breakpoint_hdr( void )
2017 {
2018 printf( "hdr=[" );
2019 debug_mi_format_breakpoint_header_col( 7, -1, "number", "Num" );
2020 printf( "," );
2021 debug_mi_format_breakpoint_header_col( 14, -1, "type", "Type" );
2022 printf( "," );
2023 debug_mi_format_breakpoint_header_col( 4, -1, "disp", "Disp" );
2024 printf( "," );
2025 debug_mi_format_breakpoint_header_col( 3, -1, "enabled", "Enb" );
2026 printf( "," );
2027 debug_mi_format_breakpoint_header_col( 10, -1, "addr", "Address" );
2028 printf( "," );
2029 debug_mi_format_breakpoint_header_col( 40, 2, "what", "What" );
2030 printf( "]" );
2031 }
2032
debug_mi_break_info(int argc,const char ** argv)2033 static void debug_mi_break_info( int argc, const char * * argv )
2034 {
2035 int id;
2036 --argc;
2037 ++argv;
2038 if ( strcmp( *argv, "--" ) == 0 )
2039 {
2040 --argc;
2041 ++argv;
2042 }
2043 if ( argc < 1 )
2044 {
2045 debug_mi_error( "Not enough arguments for -break-info" );
2046 return;
2047 }
2048 if ( argc > 1 )
2049 {
2050 debug_mi_error( "Too many arguments for -break-info" );
2051 }
2052
2053 id = breakpoint_id_parse( *argv );
2054 if ( id == -1 )
2055 {
2056 debug_mi_error( "No such breakpoint." );
2057 return;
2058 }
2059
2060 printf( "^done,BreakpointTable={"
2061 "nr_rows=\"%d\",nr_cols=\"6\",", 1 );
2062 debug_mi_format_breakpoint_hdr();
2063 printf( ",body=[" );
2064 debug_mi_format_breakpoint( id );
2065 printf( "]}" );
2066 printf("\n(gdb) \n");
2067 }
2068
debug_mi_break_list(int argc,const char ** argv)2069 static void debug_mi_break_list( int argc, const char * * argv )
2070 {
2071 int number;
2072 int i;
2073 int first;
2074 if ( argc > 2 || ( argc == 2 && strcmp( argv[ 1 ], "--" ) ) )
2075 {
2076 debug_mi_error( "Too many arguments for -break-list" );
2077 return;
2078 }
2079
2080 number = 0;
2081 for ( i = 0; i < num_breakpoints; ++i )
2082 if ( breakpoints[ i ].status != BREAKPOINT_DELETED )
2083 ++number;
2084 debug_mi_format_token();
2085 printf( "^done,BreakpointTable={"
2086 "nr_rows=\"%d\",nr_cols=\"6\",", number );
2087 debug_mi_format_breakpoint_hdr();
2088 printf( ",body=[" );
2089 first = 1;
2090 for ( i = 0; i < num_breakpoints; ++i )
2091 if ( breakpoints[ i ].status != BREAKPOINT_DELETED )
2092 {
2093 if ( first ) first = 0;
2094 else printf( "," );
2095 debug_mi_format_breakpoint( i + 1 );
2096 }
2097 printf( "]}" );
2098 printf("\n(gdb) \n");
2099 }
2100
debug_mi_inferior_tty_set(int argc,const char ** argv)2101 static void debug_mi_inferior_tty_set( int argc, const char * * argv )
2102 {
2103 /* FIXME: implement this for real */
2104 debug_mi_format_token();
2105 printf( "^done\n(gdb) \n" );
2106 }
2107
debug_mi_gdb_exit(int argc,const char ** argv)2108 static void debug_mi_gdb_exit( int argc, const char * * argv )
2109 {
2110 if ( debug_state == DEBUG_RUN )
2111 {
2112 fprintf( command_output, "kill\n" );
2113 fflush( command_output );
2114 debug_parent_wait( 0 );
2115 }
2116 debug_mi_format_token();
2117 printf( "^exit\n" );
2118 exit( EXIT_SUCCESS );
2119 }
2120
debug_mi_gdb_set(int argc,const char ** argv)2121 static void debug_mi_gdb_set( int argc, const char * * argv )
2122 {
2123 /* FIXME: implement this for real */
2124 debug_mi_format_token();
2125 printf( "^done\n(gdb) \n" );
2126 }
2127
debug_mi_gdb_show(int argc,const char ** argv)2128 static void debug_mi_gdb_show( int argc, const char * * argv )
2129 {
2130 const char * value = "";
2131 /* FIXME: implement this for real */
2132 debug_mi_format_token();
2133 value = "(gdb) ";
2134 printf( "^done,value=\"%s\"\n(gdb) \n", value );
2135 }
2136
debug_mi_not_implemented(int argc,const char ** argv)2137 static void debug_mi_not_implemented( int argc, const char * * argv )
2138 {
2139 /* FIXME: implement this for real */
2140 debug_mi_format_token();
2141 printf( "^done\n(gdb) \n" );
2142 }
2143
debug_mi_file_list_exec_source_files(int argc,const char ** argv)2144 void debug_mi_file_list_exec_source_files( int argc, const char * * argv )
2145 {
2146 /* FIXME: implement this for real */
2147 debug_mi_format_token();
2148 printf( "^done,files=[]\n(gdb) \n" );
2149 }
2150
debug_mi_file_list_exec_source_file(int argc,const char ** argv)2151 static void debug_mi_file_list_exec_source_file( int argc, const char * * argv )
2152 {
2153 /* FIXME: implement this for real */
2154 debug_mi_format_token();
2155 printf( "^error,msg=\"Don't know how to handle this yet\"\n(gdb) \n" );
2156 }
2157
debug_mi_thread_info(int argc,const char ** argv)2158 static void debug_mi_thread_info( int argc, const char * * argv )
2159 {
2160 if ( debug_state == DEBUG_NO_CHILD )
2161 {
2162 debug_mi_format_token();
2163 printf( "^done,threads=[]\n(gdb) \n" );
2164 }
2165 else
2166 {
2167 const char * new_args[] = { "info", "frame" };
2168 FRAME_INFO info;
2169 debug_parent_forward_nowait( 2, new_args, 0, 0 );
2170 debug_frame_read( command_child, &info );
2171
2172 debug_mi_format_token();
2173 printf( "^done,threads=[{id=\"1\"," );
2174 debug_mi_print_frame_info( &info );
2175 debug_frame_info_free( &info );
2176 printf( "}],current-thread-id=\"1\"\n(gdb) \n" );
2177 }
2178 }
2179
debug_mi_thread_select(int argc,const char ** argv)2180 static void debug_mi_thread_select( int argc, const char * * argv )
2181 {
2182 if ( debug_state == DEBUG_NO_CHILD )
2183 {
2184 /* FIXME: better error handling*/
2185 debug_mi_format_token();
2186 printf( "^error,msg=\"Thread ID 1 not known\"\n(gdb) \n" );
2187 }
2188 else
2189 {
2190 const char * new_args[] = { "info", "frame" };
2191 FRAME_INFO info;
2192 debug_parent_forward_nowait( 2, new_args, 0, 0 );
2193 debug_frame_read( command_child, &info );
2194
2195 debug_mi_format_token();
2196 printf( "^done,new-thread-id=\"1\"," );
2197 debug_mi_print_frame_info( &info );
2198 debug_frame_info_free( &info );
2199 printf( "\n(gdb) \n" );
2200 }
2201 }
2202
debug_mi_stack_select_frame(int argc,const char ** argv)2203 static void debug_mi_stack_select_frame( int argc, const char * * argv )
2204 {
2205 if ( debug_state == DEBUG_NO_CHILD )
2206 {
2207 debug_mi_format_token();
2208 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2209 }
2210 else
2211 {
2212 const char * new_args[ 2 ];
2213 new_args[ 0 ] = "frame";
2214 new_args[ 1 ] = argv[ 1 ];
2215 debug_parent_forward_nowait( 2, new_args, 0, 0 );
2216 debug_mi_format_token();
2217 printf( "^done\n(gdb) \n" );
2218 }
2219 }
2220
debug_mi_stack_info_frame(int argc,const char ** argv)2221 static void debug_mi_stack_info_frame( int argc, const char * * argv )
2222 {
2223 if ( debug_state == DEBUG_NO_CHILD )
2224 {
2225 debug_mi_format_token();
2226 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2227 }
2228 else
2229 {
2230 FRAME_INFO info;
2231 fprintf( command_output, "info frame\n" );
2232 fflush( command_output );
2233 debug_frame_read( command_child, &info );
2234 debug_mi_format_token();
2235 printf( "^done," );
2236 debug_mi_print_frame_info( &info );
2237 debug_frame_info_free( &info );
2238 printf( "\n(gdb) \n" );
2239 }
2240 }
2241
debug_mi_stack_list_variables(int argc,const char ** argv)2242 static void debug_mi_stack_list_variables( int argc, const char * * argv )
2243 {
2244 #define DEBUG_PRINT_VARIABLES_NO_VALUES 1
2245 #define DEBUG_PRINT_VARIABLES_ALL_VALUES 2
2246 #define DEBUG_PRINT_VARIABLES_SIMPLE_VALUES 3
2247 if ( debug_state == DEBUG_NO_CHILD )
2248 {
2249 debug_mi_format_token();
2250 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2251 return;
2252 }
2253 --argc;
2254 ++argv;
2255 for ( ; argc; --argc, ++argv )
2256 {
2257 if ( strcmp( *argv, "--thread" ) == 0 )
2258 {
2259 /* Only one thread. */
2260 --argc;
2261 ++argv;
2262 }
2263 else if ( strcmp( *argv, "--no-values" ) == 0 )
2264 {
2265 // print_values = DEBUG_PRINT_VARIABLES_NO_VALUES;
2266 }
2267 else if ( strcmp( *argv, "--all-values" ) == 0 )
2268 {
2269 // print_values = DEBUG_PRINT_VARIABLES_ALL_VALUES;
2270 }
2271 else if ( strcmp( *argv, "--simple-values" ) == 0 )
2272 {
2273 // print_values = DEBUG_PRINT_VARIABLES_SIMPLE_VALUES;
2274 }
2275 else if ( strcmp( *argv, "--" ) == 0 )
2276 {
2277 --argc;
2278 ++argv;
2279 break;
2280 }
2281 else if ( argv[ 0 ][ 0 ] == '-' )
2282 {
2283 debug_mi_format_token();
2284 printf( "^error,msg=\"Unknown argument %s\"\n(gdb) \n", *argv );
2285 return;
2286 }
2287 else
2288 {
2289 break;
2290 }
2291 }
2292 if ( argc != 0 )
2293 {
2294 debug_mi_format_token();
2295 printf( "^error,msg=\"Too many arguments for -stack-list-variables\"\n(gdb) \n" );
2296 return;
2297 }
2298
2299 {
2300 LIST * vars;
2301 LISTITER iter, end;
2302 int first = 1;
2303 fprintf( command_output, "info locals\n" );
2304 fflush( command_output );
2305 vars = debug_list_read( command_child );
2306 debug_parent_wait( 0 );
2307 debug_mi_format_token();
2308 printf( "^done,variables=[" );
2309 for ( iter = list_begin( vars ), end = list_end( vars ); iter != end; iter = list_next( iter ) )
2310 {
2311 OBJECT * varname = list_item( iter );
2312 string varbuf[1];
2313 const char * new_args[2];
2314 if ( first )
2315 {
2316 first = 0;
2317 }
2318 else
2319 {
2320 printf( "," );
2321 }
2322 printf( "{name=\"%s\",value=\"", object_str( varname ) );
2323 fflush( stdout );
2324 string_new( varbuf );
2325 string_append( varbuf, "$(" );
2326 string_append( varbuf, object_str( varname ) );
2327 string_append( varbuf, ")" );
2328 new_args[ 0 ] = "print";
2329 new_args[ 1 ] = varbuf->value;
2330 debug_parent_forward( 2, new_args, 0, 0 );
2331 string_free( varbuf );
2332 printf( "\"}" );
2333 }
2334 printf( "]\n(gdb) \n" );
2335 fflush( stdout );
2336 list_free( vars );
2337 }
2338 }
2339
debug_mi_stack_list_locals(int argc,const char ** argv)2340 static void debug_mi_stack_list_locals( int argc, const char * * argv )
2341 {
2342 #define DEBUG_PRINT_VARIABLES_NO_VALUES 1
2343 #define DEBUG_PRINT_VARIABLES_ALL_VALUES 2
2344 #define DEBUG_PRINT_VARIABLES_SIMPLE_VALUES 3
2345 if ( debug_state == DEBUG_NO_CHILD )
2346 {
2347 debug_mi_format_token();
2348 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2349 return;
2350 }
2351 --argc;
2352 ++argv;
2353 for ( ; argc; --argc, ++argv )
2354 {
2355 if ( strcmp( *argv, "--thread" ) == 0 )
2356 {
2357 /* Only one thread. */
2358 --argc;
2359 ++argv;
2360 if ( argc == 0 )
2361 {
2362 debug_mi_format_token();
2363 printf( "^error,msg=\"Argument required for --thread.\"" );
2364 return;
2365 }
2366 }
2367 else if ( strcmp( *argv, "--no-values" ) == 0 )
2368 {
2369 // print_values = DEBUG_PRINT_VARIABLES_NO_VALUES;
2370 }
2371 else if ( strcmp( *argv, "--all-values" ) == 0 )
2372 {
2373 // print_values = DEBUG_PRINT_VARIABLES_ALL_VALUES;
2374 }
2375 else if ( strcmp( *argv, "--simple-values" ) == 0 )
2376 {
2377 // print_values = DEBUG_PRINT_VARIABLES_SIMPLE_VALUES;
2378 }
2379 else if ( strcmp( *argv, "--" ) == 0 )
2380 {
2381 --argc;
2382 ++argv;
2383 break;
2384 }
2385 else if ( argv[ 0 ][ 0 ] == '-' )
2386 {
2387 debug_mi_format_token();
2388 printf( "^error,msg=\"Unknown argument %s\"\n(gdb) \n", *argv );
2389 return;
2390 }
2391 else
2392 {
2393 break;
2394 }
2395 }
2396 if ( argc != 0 )
2397 {
2398 debug_mi_format_token();
2399 printf( "^error,msg=\"Too many arguments for -stack-list-variables\"\n(gdb) \n" );
2400 return;
2401 }
2402
2403 {
2404 LIST * vars;
2405 LISTITER iter, end;
2406 int first = 1;
2407 fprintf( command_output, "info locals\n" );
2408 fflush( command_output );
2409 vars = debug_list_read( command_child );
2410 debug_parent_wait( 0 );
2411 debug_mi_format_token();
2412 printf( "^done,locals=[" );
2413 for ( iter = list_begin( vars ), end = list_end( vars ); iter != end; iter = list_next( iter ) )
2414 {
2415 OBJECT * varname = list_item( iter );
2416 string varbuf[1];
2417 const char * new_args[2];
2418 if ( first )
2419 {
2420 first = 0;
2421 }
2422 else
2423 {
2424 printf( "," );
2425 }
2426 printf( "{name=\"%s\",type=\"list\",value=\"", object_str( varname ) );
2427 fflush( stdout );
2428 string_new( varbuf );
2429 string_append( varbuf, "$(" );
2430 string_append( varbuf, object_str( varname ) );
2431 string_append( varbuf, ")" );
2432 new_args[ 0 ] = "print";
2433 new_args[ 1 ] = varbuf->value;
2434 debug_parent_forward( 2, new_args, 0, 0 );
2435 string_free( varbuf );
2436 printf( "\"}" );
2437 }
2438 printf( "]\n(gdb) \n" );
2439 fflush( stdout );
2440 list_free( vars );
2441 }
2442 }
2443
debug_mi_stack_list_frames(int argc,const char ** argv)2444 static void debug_mi_stack_list_frames( int argc, const char * * argv )
2445 {
2446 int depth;
2447 int i;
2448
2449 if ( debug_state == DEBUG_NO_CHILD )
2450 {
2451 debug_mi_format_token();
2452 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2453 return;
2454 }
2455
2456 fprintf( command_output, "info depth\n" );
2457 fflush( command_output );
2458 depth = debug_int_read( command_child );
2459
2460 debug_mi_format_token();
2461 printf( "^done,stack=[" );
2462 for ( i = 0; i < depth; ++i )
2463 {
2464 FRAME_INFO frame;
2465 fprintf( command_output, "info frame %d\n", i );
2466 fflush( command_output );
2467 if ( i != 0 )
2468 {
2469 printf( "," );
2470 }
2471 debug_frame_read( command_child, &frame );
2472 debug_mi_print_frame_info( &frame );
2473 }
2474 printf( "]\n(gdb) \n" );
2475 fflush( stdout );
2476 }
2477
debug_mi_list_target_features(int argc,const char ** argv)2478 static void debug_mi_list_target_features( int argc, const char * * argv )
2479 {
2480 /* FIXME: implement this for real */
2481 debug_mi_format_token();
2482 printf( "^done,features=[\"async\"]\n(gdb) \n" );
2483 }
2484
debug_mi_exec_run(int argc,const char ** argv)2485 static void debug_mi_exec_run( int argc, const char * * argv )
2486 {
2487 printf( "=thread-created,id=\"1\",group-id=\"i1\"\n" );
2488 debug_mi_format_token();
2489 printf( "^running\n(gdb) \n" );
2490 fflush( stdout );
2491 debug_start_child( argc, argv );
2492 debug_parent_wait( 1 );
2493 }
2494
debug_mi_exec_continue(int argc,const char ** argv)2495 static void debug_mi_exec_continue( int argc, const char * * argv )
2496 {
2497 if ( debug_state == DEBUG_NO_CHILD )
2498 {
2499 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2500 }
2501 else
2502 {
2503 const char * new_args[] = { "continue" };
2504 debug_mi_format_token();
2505 printf( "^running\n(gdb) \n" );
2506 fflush( stdout );
2507 debug_parent_forward( 1, new_args, 1, 0 );
2508 }
2509 }
2510
debug_mi_exec_step(int argc,const char ** argv)2511 static void debug_mi_exec_step( int argc, const char * * argv )
2512 {
2513 if ( debug_state == DEBUG_NO_CHILD )
2514 {
2515 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2516 }
2517 else
2518 {
2519 const char * new_args[] = { "step" };
2520 debug_mi_format_token();
2521 printf( "^running\n(gdb) \n" );
2522 fflush( stdout );
2523 debug_parent_forward( 1, new_args, 1, 0 );
2524 }
2525 }
2526
debug_mi_exec_next(int argc,const char ** argv)2527 static void debug_mi_exec_next( int argc, const char * * argv )
2528 {
2529 if ( debug_state == DEBUG_NO_CHILD )
2530 {
2531 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2532 }
2533 else
2534 {
2535 const char * new_args[] = { "next" };
2536 debug_mi_format_token();
2537 printf( "^running\n(gdb) \n" );
2538 fflush( stdout );
2539 debug_parent_forward( 1, new_args, 1, 0 );
2540 }
2541 }
2542
debug_mi_exec_finish(int argc,const char ** argv)2543 static void debug_mi_exec_finish( int argc, const char * * argv )
2544 {
2545 if ( debug_state == DEBUG_NO_CHILD )
2546 {
2547 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2548 }
2549 else
2550 {
2551 const char * new_args[] = { "finish" };
2552 debug_mi_format_token();
2553 printf( "^running\n(gdb) \n" );
2554 fflush( stdout );
2555 debug_parent_forward( 1, new_args, 1, 0 );
2556 }
2557 }
2558
debug_mi_data_list_register_names(int argc,const char ** argv)2559 static void debug_mi_data_list_register_names( int argc, const char * * argv )
2560 {
2561 debug_mi_format_token();
2562 printf( "^done,register-names=[]\n(gdb) \n" );
2563 }
2564
debug_mi_data_evaluate_expression(int argc,const char ** argv)2565 static void debug_mi_data_evaluate_expression( int argc, const char * * argv )
2566 {
2567 if ( argc < 2 )
2568 {
2569 printf( "^error,msg=\"Not enough arguments for -data-evaluate-expression\"\n(gdb) \n" );
2570 }
2571 if ( debug_state == DEBUG_NO_CHILD )
2572 {
2573 printf( "^error,msg=\"No child\"\n(gdb) \n" );
2574 }
2575 else
2576 {
2577 const char * new_args[ 2 ];
2578 debug_mi_format_token();
2579 printf( "^done,value=\"" );
2580 fflush( stdout );
2581 new_args[ 0 ] = "print";
2582 new_args[ 1 ] = argv[ 1 ];
2583 debug_parent_forward( 2, new_args, 1, 0 );
2584 printf( "\"\n(gdb) \n" );
2585 }
2586 }
2587
2588 static int process_command( char * command );
2589
debug_mi_interpreter_exec(int argc,const char ** argv)2590 static void debug_mi_interpreter_exec( int argc, const char * * argv )
2591 {
2592 if ( argc < 3 )
2593 {
2594 debug_mi_error( "Not enough arguments for -interpreter-exec" );
2595 }
2596 process_command( (char *)argv[ 2 ] );
2597 }
2598
2599 /* The debugger's main loop. */
debugger(void)2600 int debugger( void )
2601 {
2602 command_array = parent_commands;
2603 command_input = stdin;
2604 if ( debug_interface == DEBUG_INTERFACE_MI )
2605 printf( "=thread-group-added,id=\"i1\"\n(gdb) \n" );
2606 while ( 1 )
2607 {
2608 if ( debug_interface == DEBUG_INTERFACE_CONSOLE )
2609 printf("(b2db) ");
2610 fflush( stdout );
2611 read_command();
2612 }
2613 return 0;
2614 }
2615
2616
2617 /* Runs the matching command in the current command_array. */
run_command(int argc,const char ** argv)2618 static int run_command( int argc, const char * * argv )
2619 {
2620 struct command_elem * command;
2621 const char * command_name;
2622 if ( argc == 0 )
2623 {
2624 return 1;
2625 }
2626 command_name = argv[ 0 ];
2627 /* Skip the GDB/MI token when choosing the command to run. */
2628 while( isdigit( *command_name ) ) ++command_name;
2629 current_token = atoi( argv[ 0 ] );
2630 for( command = command_array; command->key; ++command )
2631 {
2632 if ( strcmp( command->key, command_name ) == 0 )
2633 {
2634 ( *command->command )( argc, argv );
2635 return 1;
2636 }
2637 }
2638 debug_error( "Unknown command: %s", command_name );
2639 return 0;
2640 }
2641
2642 /* Parses a single command into whitespace separated tokens, and runs it. */
process_command(char * line)2643 static int process_command( char * line )
2644 {
2645 int result;
2646 size_t capacity = 8;
2647 char * * buffer = (char **)malloc( capacity * sizeof( char * ) );
2648 char * * current = buffer;
2649 char * iter = line;
2650 char * saved = iter;
2651 *current = iter;
2652 for ( ; ; )
2653 {
2654 /* skip spaces */
2655 while ( *iter && isspace( *iter ) )
2656 {
2657 ++iter;
2658 }
2659 if ( ! *iter )
2660 {
2661 break;
2662 }
2663 /* Find the next token */
2664 saved = iter;
2665 if ( *iter == '\"' )
2666 {
2667 saved = ++iter;
2668 /* FIXME: handle escaping */
2669 while ( *iter && *iter != '\"' )
2670 {
2671 ++iter;
2672 }
2673 }
2674 else
2675 {
2676 while ( *iter && ! isspace( *iter ) )
2677 {
2678 ++iter;
2679 }
2680 }
2681 /* resize the buffer if necessary */
2682 if ( current == buffer + capacity )
2683 {
2684 buffer = (char**)realloc( (void *)buffer, capacity * 2 * sizeof( char * ) );
2685 current = buffer + capacity;
2686 }
2687 /* append the token to the buffer */
2688 *current++ = saved;
2689 /* null terminate the token */
2690 if ( *iter )
2691 {
2692 *iter++ = '\0';
2693 }
2694 }
2695 result = run_command( int(current - buffer), (const char **)buffer );
2696 free( (void *)buffer );
2697 return result;
2698 }
2699
read_command(void)2700 static int read_command( void )
2701 {
2702 int result;
2703 int ch;
2704 string line[ 1 ];
2705 string_new( line );
2706 /* HACK: force line to be on the heap. */
2707 string_reserve( line, 64 );
2708 while( ( ch = fgetc( command_input ) ) != EOF )
2709 {
2710 if ( ch == '\n' )
2711 {
2712 break;
2713 }
2714 else
2715 {
2716 string_push_back( line, (char)ch );
2717 }
2718 }
2719 result = process_command( line->value );
2720 string_free( line );
2721 return result;
2722 }
2723
debug_listen(void)2724 static void debug_listen( void )
2725 {
2726 debug_state = DEBUG_STOPPED;
2727 while ( debug_state == DEBUG_STOPPED )
2728 {
2729 if ( feof( command_input ) )
2730 exit( 1 );
2731 fflush(stdout);
2732 fflush( command_output );
2733 read_command();
2734 }
2735 debug_selected_frame_number = 0;
2736 }
2737
2738 struct debug_child_data_t debug_child_data;
2739 const char debugger_opt[] = "--b2db-internal-debug-handle=";
2740 int debug_interface;
2741