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