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