source: vendor/emx/current/src/pmgdb/gdbio.cc

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 20.3 KB
Line 
1/* gdbio.cc
2 Copyright (c) 1996 Eberhard Mattes
3
4This file is part of pmgdb.
5
6pmgdb is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11pmgdb is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with pmgdb; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21
22#define INCL_DOS
23#define INCL_DOSERRORS
24#include <os2.h>
25#include <stdio.h> // vsnprintf()
26#include <stdlib.h>
27#include <stdarg.h>
28#include <string.h>
29#include <signal.h>
30#include <io.h>
31#include <sys/ptrace.h>
32#include "string.h"
33#include "pmapp.h"
34#include "pmframe.h"
35#include "pmtxt.h"
36#include "pmtty.h"
37#include "breakpoi.h"
38#include "display.h"
39#include "threads.h"
40#include "annotati.h"
41#include "capture.h"
42#include "gdbio.h"
43#include "pmdebug.h"
44#include "command.h"
45
46
47gdbio::gdbio (command_window *in_cmd)
48{
49 cmd = in_cmd;
50 ignore_prompt = false; ignore_output = false;
51 show_annotations = false;
52 breakpoints_invalid = false; breakpoints_invalid_pending = false;
53 exec_file_pending = false; stopped_pending = false;
54 call_flag = false;
55 capture_head = capture_cur = NULL;
56 display_head = display_cur = NULL;
57 frame_head = frame_cur = NULL;
58 gdb_prompt = GSP_NOTREADY;
59 gdb_running = GSR_NONE;
60 cmd_head = NULL; cmd_add = &cmd_head;
61 to_gdb = -1;
62 _fmutex_checked_create (&mutex_cmd_queue, 0);
63 if (DosCreateEventSem (NULL, &hev_done, 0, FALSE) != 0)
64 abort ();
65}
66
67
68gdbio::~gdbio ()
69{
70}
71
72
73void gdbio::lock_cmd_queue ()
74{
75 _fmutex_checked_request (&mutex_cmd_queue, _FMR_IGNINT);
76}
77
78
79void gdbio::unlock_cmd_queue ()
80{
81 _fmutex_checked_release (&mutex_cmd_queue);
82}
83
84
85void gdbio::reset_hev_done ()
86{
87 ULONG post_count;
88 ULONG rc = DosResetEventSem (hev_done, &post_count);
89 if (rc != 0 && rc != ERROR_ALREADY_RESET) abort ();
90}
91
92
93void gdbio::post_hev_done ()
94{
95 ULONG rc = DosPostEventSem (hev_done);
96 if (rc != 0) abort ();
97}
98
99
100void gdbio::wait_hev_done ()
101{
102 ULONG rc;
103
104 do
105 {
106 rc = DosWaitEventSem (hev_done, SEM_INDEFINITE_WAIT);
107 } while (rc == ERROR_INTERRUPT);
108 if (rc != 0) abort ();
109}
110
111
112void gdbio::fetch ()
113{
114 if (get_next () == READ_ERROR)
115 {
116 // TODO: Message box?
117 DosExit (EXIT_THREAD, 0);
118 }
119 if (show_annotations && get_code () != TEXT)
120 cmd->show_annotation (this);
121}
122
123
124void gdbio::handle_output (const char *text, int len)
125{
126 if (!ignore_output)
127 {
128 cmd->handle_output (text, len);
129 ignore_prompt = false;
130 }
131}
132
133
134void gdbio::copy_text (bool to_screen, bool to_field)
135{
136 if (to_field)
137 field_init ();
138 for (;;)
139 {
140 fetch ();
141 if (get_code () != TEXT)
142 break;
143 if (to_field)
144 field.append (get_text (), get_text_len ());
145 if (to_screen)
146 handle_output (get_text (), get_text_len ());
147 }
148}
149
150
151void gdbio::parse_gdb ()
152{
153 char *end;
154 long n;
155 int pid;
156
157 fetch ();
158 for (;;)
159 {
160 switch (get_code ())
161 {
162 case TEXT:
163 handle_output (get_text (), get_text_len ());
164 // TODO: not always needed, add arg to capture_cmd()
165 if (capture_head != NULL)
166 output.append (get_text (), get_text_len ());
167 fetch ();
168 break;
169
170 case breakpoint_new:
171 // Note: add to head!
172 // TODO: strtol()
173 if (capture_head != NULL)
174 capture_head->bpt_number.set (atoi (get_args ()));
175 fetch ();
176 break;
177
178 case breakpoints_table:
179 parse_breakpoints_table ();
180 break;
181
182 case annotation::breakpoints_invalid:
183 breakpoints_invalid = true;
184 breakpoints_invalid_pending = true;
185 fetch ();
186 break;
187
188 case display_begin:
189 parse_display_begin ();
190 break;
191
192 case display_delete:
193 if (cmd->dsp != NULL)
194 cmd->dsp->remove (atoi (get_args ()));
195 fetch ();
196 break;
197
198 case display_disable:
199 if (cmd->dsp != NULL)
200 cmd->dsp->disable (atoi (get_args ()));
201 fetch ();
202 break;
203
204 case display_enable:
205 if (cmd->dsp != NULL)
206 cmd->dsp->enable (atoi (get_args ()));
207 fetch ();
208 break;
209
210 case error_begin:
211 parse_error_begin ();
212 break;
213
214 case error:
215 cmd->set_fg_color ();
216 fetch ();
217 break;
218
219 case exec_file:
220 exec_file_pending = true;
221 cmd->exec_file (get_args (), get_args_len ());
222 fetch ();
223 break;
224
225 case exec_file_invalid:
226 cmd->exec_file (NULL, 0);
227 fetch ();
228 break;
229
230 case exited:
231 gdb_running = GSR_NONE;
232 cmd->pmdbg_term ();
233 cmd->notify (command_window::GSC_RUNNING);
234 fetch ();
235 break;
236
237 case frame_begin:
238 parse_frame_begin ();
239 break;
240
241 case pre_commands:
242 case pre_overload_choice:
243 case pre_prompt:
244 case pre_prompt_for_continue:
245 case pre_query:
246 parse_pre_prompt ();
247 break;
248
249 case show_value:
250 copy_text (true, capture_head != NULL);
251 if (get_code () == show_value_end)
252 {
253 if (capture_head != NULL)
254 capture_head->show_value.set (field, field.length ());
255 fetch ();
256 }
257 break;
258
259 case starting:
260 gdb_running = GSR_RUNNING;
261 // TODO: This may be too late
262 cmd->pmdbg_start ();
263 cmd->notify (command_window::GSC_RUNNING);
264 fetch ();
265 break;
266
267 case stopped:
268 if (gdb_running == GSR_RUNNING)
269 {
270 gdb_running = GSR_STOPPED;
271 cmd->pmdbg_stop ();
272 }
273 stopped_pending = true;
274 cmd->notify (command_window::GSC_RUNNING);
275 fetch ();
276 break;
277
278 case signalled:
279 gdb_running = GSR_NONE;
280 cmd->pmdbg_term ();
281 cmd->notify (command_window::GSC_RUNNING);
282 fetch ();
283 break;
284
285 case source:
286 parse_source ();
287 fetch ();
288 break;
289
290 case source_file:
291 if (capture_cur != NULL)
292 {
293 if (capture_cur->srcs_file.is_set ())
294 {
295 capture_cur->next = new capture;
296 capture_cur = capture_cur->next;
297 }
298 capture_cur->srcs_file.set (get_args ());
299 }
300 fetch ();
301 break;
302
303 case source_location:
304 parse_source_location ();
305 break;
306
307 case thread_add:
308 n = strtol (get_args (), &end, 10);
309 if (*end == ' ')
310 {
311 pid = atoi (end);
312 if (PTRACE_GETTID (pid) == 1)
313 pmdbg.set_pid (PTRACE_GETPID (pid));
314 cmd->thr->add ((int)n, pid);
315 }
316 fetch ();
317 break;
318
319 case thread_disable:
320 cmd->thr->disable (atoi (get_args ()));
321 fetch ();
322 break;
323
324 case thread_enable:
325 cmd->thr->enable (atoi (get_args ()));
326 fetch ();
327 break;
328
329 case thread_end:
330 cmd->thr->remove (atoi (get_args ()));
331 fetch ();
332 break;
333
334 case thread_switch:
335 cmd->thr->select (atoi (get_args ()));
336 fetch ();
337 break;
338
339 default:
340 fetch ();
341 break;
342 }
343 }
344}
345
346
347// Handle `source FILENAME;LINE;CHARACTER;MIDDLE;ADDR' annotation
348
349#define SOURCE_SEP ';'
350
351// TODO: `info line' typed by user must not update source window!
352void gdbio::parse_source ()
353{
354 const char *args = get_args ();
355 const char *p;
356 char *filename, *end;
357 long lineno, addr;
358 int len;
359
360 // FILENAME
361 p = strchr (args, SOURCE_SEP);
362 if (p == NULL) return;
363 len = p - args;
364 filename = (char *)alloca (len + 1);
365 memcpy (filename, args, len);
366 filename[len] = 0;
367
368 // LINE
369 lineno = strtol (p + 1, &end, 10);
370 if (lineno <= 0 || *end != SOURCE_SEP) return;
371
372 // CHARACTER
373 p = strchr (end + 1, SOURCE_SEP);
374 if (p == NULL) return;
375
376 // MIDDLE
377 p = strchr (p + 1, SOURCE_SEP);
378 if (p == NULL) return;
379
380 // ADDR
381 addr = strtol (p + 1, &end, 16);
382 if (end == p + 1 || *end != 0) return;
383
384 capture *capt;
385 if (capture_head != NULL)
386 capt = capture_head;
387 else
388 {
389 if (frame_head == NULL)
390 frame_head = frame_cur = new capture;
391 capt = frame_head;
392 }
393 capt->source_file.set (filename, len);
394 capt->source_lineno.set (lineno);
395 capt->source_addr.set (addr);
396}
397
398
399void gdbio::parse_breakpoints_table ()
400{
401 long n = -1; // Keep the compiler happy
402 char *end;
403
404 fetch ();
405 if (capture_head == NULL)
406 return;
407 while (get_code () == record)
408 {
409 capture_cur->next = new capture;
410 capture_cur = capture_cur->next;
411 fetch ();
412 while (get_code () == annotation::field)
413 {
414 int number = atoi (get_args ());
415 copy_text (true, true);
416 switch (number)
417 {
418 case 0:
419 // NUMBER: "1 "
420 capture_cur->bpt_number.set (atoi (field));
421 break;
422 case 1:
423 // TYPE: "breakpoint "
424 break;
425 case 2:
426 // DISPOSITION: "keep "
427 field.remove_trailing (' ');
428 capture_cur->bpt_disposition.set (field, field.length ());
429 break;
430 case 3:
431 // ENABLE: "y "
432 capture_cur->bpt_enable.set (field[0] == 'y');
433 break;
434 case 4:
435 // ADDRESS: "0x100b2 "
436 // TODO: This field is language-dependent
437 n = strtol (field, &end, 16);
438 if (end != (const char *)field && (*end == ' ' || *end == 0))
439 capture_cur->bpt_address.set (n);
440 break;
441 case 5:
442 // WHAT: "in main at source.c:217"
443 capture_cur->bpt_what.set (field, field.length ());
444 break;
445 case 6:
446 // FRAME: TODO
447 break;
448 case 7:
449 // CONDITION: "\tstop only if i >= 2\n"
450 field.remove_trailing ('\n');
451 if (strncmp (field, "\tstop only if ", 14) == 0)
452 capture_cur->bpt_condition.set ((const char *)field + 14,
453 field.length () - 14);
454 break;
455 case 8:
456 // IGNORE-COUNT: "\tignore next X hits\n"
457 if (strncmp (field, "\tignore next ", 13) == 0
458 && (n = strtol ((const char *)field + 13, &end, 10)) >= 1)
459 capture_cur->bpt_ignore.set (n);
460 break;
461 case 9:
462 // COMMANDS: TODO
463 break;
464 }
465 }
466 }
467 if (get_code () == breakpoints_table_end)
468 fetch ();
469}
470
471
472void gdbio::parse_display_begin ()
473{
474 bool to_screen = frame_head == NULL;
475 capture *capt = new capture;
476 if (display_cur == NULL)
477 display_head = capt;
478 else
479 display_cur->next = capt;
480 display_cur = capt;
481
482 // display-begin NUMBER display-number-end
483 copy_text (to_screen, true);
484 if (get_code () != display_number_end)
485 return;
486 char *end;
487 long n = strtol (field, &end, 10);
488 if (end == (const char *)field || *end != 0)
489 return;
490 display_cur->disp_number.set (n);
491 // For adding displays, see IDM_ADD of display_window
492 if (capture_head != NULL)
493 capture_head->disp_number.set (n);
494
495 // NUMBER-SEPARATOR display-format FORMAT display-expression
496 copy_text (to_screen, false);
497 if (get_code () != display_format)
498 return;
499 copy_text (to_screen, true);
500 if (get_code () != display_expression)
501 return;
502 field.remove_trailing (' ');
503 display_cur->disp_format.set (field, field.length ());
504
505 // EXPRESSION display-expression-end
506 copy_text (to_screen, true);
507 if (get_code () == error_begin)
508 {
509 display_cur->disp_expr.set ("*ERROR*");
510 display_cur->disp_value.set ("");
511 parse_error_begin ();
512 display_cur->disp_enable.set (false);
513 return;
514 }
515 if (get_code () != display_expression_end)
516 return;
517 display_cur->disp_expr.set (field, field.length ());
518
519 // EXPRESSION-SEPARATOR display-value VALUE display-end
520 copy_text (to_screen, false);
521 if (get_code () != display_value)
522 return;
523 parse_value (to_screen, true);
524 if (get_code () != display_end)
525 return;
526 field.remove_trailing ('\n');
527 display_cur->disp_value.set (field, field.length ());
528 display_cur->disp_enable.set (true);
529 fetch ();
530}
531
532
533void gdbio::parse_value (bool to_screen, bool to_field)
534{
535 if (to_field)
536 field_init ();
537 bool more = true;
538 while (more)
539 {
540 fetch ();
541 switch (get_code ())
542 {
543 case TEXT:
544 if (to_field)
545 field.append (get_text (), get_text_len ());
546 if (to_screen)
547 handle_output (get_text (), get_text_len ());
548 break;
549 case array_section_begin:
550 case array_section_end:
551 case elt:
552 case elt_rep:
553 case elt_rep_end:
554 case field_begin:
555 case field_name_end:
556 case field_value:
557 case field_end:
558 break;
559 default:
560 more = false;
561 break;
562 }
563 }
564}
565
566
567void gdbio::parse_error_begin ()
568{
569 cmd->set_fg_color (CLR_RED);
570 copy_text (true, capture_head != NULL);
571 if (get_code () == quit || get_code () == error)
572 {
573 if (capture_head != NULL)
574 {
575 field.remove_trailing ('\n');
576 capture_head->error.set (field, field.length ());
577 }
578 fetch ();
579 }
580 cmd->set_fg_color ();
581}
582
583
584void gdbio::parse_source_location ()
585{
586 copy_text (true, capture_head != NULL);
587 if (get_code () == source_location_end)
588 {
589 if (capture_head != NULL)
590 capture_head->source_location.set (field, field.length ());
591 fetch ();
592 }
593}
594
595
596void gdbio::parse_frame_begin ()
597{
598 capture *capt = new capture;
599 if (frame_cur == NULL)
600 frame_head = capt;
601 else
602 frame_cur->next = capt;
603 frame_cur = capt;
604 // TODO: parse
605 fetch ();
606}
607
608
609void gdbio::parse_pre_prompt ()
610{
611 cmd->set_fg_color (CLR_BLUE);
612 copy_text (!ignore_prompt, false);
613 switch (get_code ())
614 {
615 case commands:
616 case overload_choice:
617 case prompt_for_continue:
618 case query:
619 if (gdb_prompt != GSP_OTHER)
620 {
621 gdb_prompt = GSP_OTHER;
622 cmd->set_fg_color (CLR_DARKBLUE);
623 cmd->notify (command_window::GSC_PROMPT);
624 }
625 break;
626
627 case prompt:
628 if (cmd_head != NULL)
629 {
630 lock_cmd_queue ();
631 cmd_queue *q = cmd_head;
632 cmd_head = cmd_head->next;
633 if (cmd_head == NULL)
634 cmd_add = &cmd_head;
635 unlock_cmd_queue ();
636 ignore_prompt = true;
637 send_str (q->cmd, strlen (q->cmd));
638 delete q;
639 }
640 else
641 {
642 gdb_prompt = GSP_CMD;
643 ignore_prompt = false;
644 unsigned change = command_window::GSC_PROMPT;
645 cmd->set_fg_color (CLR_DARKBLUE);
646 if (call_flag)
647 {
648 // Note that this is done before posting UWM_STATE, so
649 // that, say, a new display number can be picked up
650 // before updating the displays
651 post_hev_done ();
652 }
653 if (breakpoints_invalid_pending)
654 {
655 breakpoints_invalid_pending = false;
656 change |= command_window::GSC_BREAKPOINTS;
657 }
658 if (exec_file_pending)
659 {
660 exec_file_pending = false;
661 change |= command_window::GSC_EXEC_FILE;
662 }
663 cmd->notify (change);
664 }
665 break;
666
667 default:
668 cmd->set_fg_color ();
669 ignore_prompt = false;
670 return;
671 }
672
673 // input
674 copy_text (true, false);
675 switch (get_code ())
676 {
677 case post_commands:
678 case post_overload_choice:
679 case post_prompt:
680 case post_prompt_for_continue:
681 case post_query:
682 gdb_prompt = GSP_NONE;
683 cmd->set_fg_color ();
684 cmd->notify (command_window::GSC_PROMPT);
685 fetch ();
686 break;
687
688 default:
689 cmd->set_fg_color ();
690 break;
691 }
692}
693
694
695void gdbio::prepare_run ()
696{
697 if (frame_head != NULL)
698 {
699 delete_capture (frame_head);
700 frame_head = NULL; frame_cur = NULL;
701 }
702}
703
704
705static void sigpipe_handler (int)
706{
707}
708
709
710void gdbio::send_init (int fd)
711{
712 to_gdb = fd;
713}
714
715
716void gdbio::send_init ()
717{
718 struct sigaction sa;
719
720 sa.sa_handler = sigpipe_handler;
721 sa.sa_flags = 0;
722 sigemptyset (&sa.sa_mask);
723 sigaction (SIGPIPE, &sa, NULL);
724}
725
726
727void gdbio::send_str (const char *str, int len)
728{
729 write (to_gdb, str, len);
730}
731
732
733void gdbio::send_vfmt (const char *fmt, va_list args)
734{
735 char buf[512];
736
737 int len = vsnprintf (buf, sizeof (buf) - 1, fmt, args);
738 if (len >= (int)sizeof (buf) - 1)
739 abort ();
740 buf[len] = '\n';
741 buf[len+1] = 0;
742 send_str (buf, len + 1);
743}
744
745
746bool gdbio::send_cmd (const char *fmt, ...)
747{
748 va_list arg_ptr;
749
750 if (!is_ready () || cmd_head != NULL)
751 {
752 DosBeep (400, 200);
753 return false;
754 }
755 gdb_prompt = GSP_NOTREADY;
756 ignore_prompt = true;
757 va_start (arg_ptr, fmt);
758 send_vfmt (fmt, arg_ptr);
759 va_end (arg_ptr);
760 return true;
761}
762
763
764void gdbio::queue_cmd (const char *fmt, ...)
765{
766 va_list arg_ptr;
767
768 char buf[512];
769 va_start (arg_ptr, fmt);
770 int len = vsnprintf (buf, sizeof (buf) - 1, fmt, arg_ptr);
771 va_end (arg_ptr);
772 if (len >= (int)sizeof (buf) - 1)
773 abort ();
774 buf[len] = '\n';
775 buf[len+1] = 0;
776
777 lock_cmd_queue ();
778 if (is_ready () && cmd_head == NULL)
779 {
780 gdb_prompt = GSP_NOTREADY;
781 unlock_cmd_queue ();
782 ignore_prompt = true;
783 send_str (buf, len + 1);
784 }
785 else
786 {
787 cmd_queue *q = new cmd_queue;
788 q->cmd.set (buf, len + 1);
789 q->next = NULL;
790 *cmd_add = q; cmd_add = &q->next;
791 unlock_cmd_queue ();
792 }
793}
794
795
796bool gdbio::call_cmd (const char *fmt, ...)
797{
798 va_list arg_ptr;
799
800 // TODO: mutex
801 if (!is_ready () || cmd_head != NULL)
802 return false;
803
804 gdb_prompt = GSP_NOTREADY;
805 ignore_prompt = true; ignore_output = true; call_flag = true;
806 output.set (0);
807 reset_hev_done ();
808 va_start (arg_ptr, fmt);
809 send_vfmt (fmt, arg_ptr);
810 va_end (arg_ptr);
811 wait_hev_done ();
812 ignore_output = false; call_flag = false;
813 return true;
814}
815
816
817capture * gdbio::capture_cmd (const char *fmt, ...)
818{
819 va_list arg_ptr;
820
821 // TODO: mutex
822 if (!is_ready () || capture_head != NULL || cmd_head != NULL)
823 return NULL;
824
825 gdb_prompt = GSP_NOTREADY;
826 ignore_prompt = true; ignore_output = true; call_flag = true;
827 capture_head = capture_cur = new capture;
828 output.set (0);
829 reset_hev_done ();
830 va_start (arg_ptr, fmt);
831 send_vfmt (fmt, arg_ptr);
832 va_end (arg_ptr);
833 wait_hev_done ();
834 capture *tmp = capture_head;
835 capture_head = capture_cur = NULL;
836 ignore_output = false; call_flag = false;
837 return tmp;
838}
839
840
841ULONG gdbio::address_of_line (const char *fname, int lineno)
842{
843 capture *capt = capture_cmd ("server info line %s:%d", fname, lineno);
844 if (capt == NULL)
845 return 0;
846 ULONG addr = 0;
847 if (capt->source_addr.is_set ())
848 addr = (ULONG)capt->source_addr.get ();
849 delete_capture (capt);
850 return addr;
851}
852
853
854bool gdbio::get_setshow_boolean (const char *name)
855{
856 capture *capt = capture_cmd ("server show %s", name);
857 if (capt == NULL)
858 return false;
859 bool result = (capt->show_value.is_set ()
860 && strcmp (capt->show_value.get (), "on") == 0);
861 delete_capture (capt);
862 return result;
863}
864
865
866void gdbio::set_setshow_boolean (const char *name, bool value)
867{
868 queue_cmd ("server set %s %s", name, value ? "on" : "off");
869}
870
871
872char *gdbio::get_setshow_string (const char *name)
873{
874 capture *capt = capture_cmd ("server show %s", name);
875 if (capt == NULL)
876 return NULL;
877 char *result = NULL;
878 if (capt->show_value.is_set ())
879 {
880 const char *s = capt->show_value.get ();
881 size_t len = strlen (s);
882 if (len >= 2 && s[0] == '"' && s[len-1] == '"')
883 {
884 ++s; len -= 2;
885 }
886 result = new char[len + 1];
887 memcpy (result, s, len);
888 result[len] = 0;
889 }
890 delete_capture (capt);
891 return result;
892}
893
894
895void gdbio::set_setshow_string (const char *name, const char *value)
896{
897 queue_cmd ("server set %s %s", name, value);
898}
Note: See TracBrowser for help on using the repository browser.