aboutsummaryrefslogtreecommitdiff
path: root/src/monkey/cpp_int.cc
diff options
context:
space:
mode:
authorSafey A.Halim <safey.allah@gmail.com>2010-06-29 19:14:37 +0000
committerSafey A.Halim <safey.allah@gmail.com>2010-06-29 19:14:37 +0000
commit1e2ec555753751d032dbe1f19d5206a2da4de65a (patch)
treeba5f6d9487ab2f7aea7fa98d1de3d6abef268b33 /src/monkey/cpp_int.cc
parentc75af8bb6df74bfcba1e7b1a3123babf066a1939 (diff)
downloadgnunet-1e2ec555753751d032dbe1f19d5206a2da4de65a.tar.gz
gnunet-1e2ec555753751d032dbe1f19d5206a2da4de65a.zip
Adding "Monkey", GNUnet module for automatic debugging. Experimental code so far.
Diffstat (limited to 'src/monkey/cpp_int.cc')
-rw-r--r--src/monkey/cpp_int.cc1123
1 files changed, 1123 insertions, 0 deletions
diff --git a/src/monkey/cpp_int.cc b/src/monkey/cpp_int.cc
new file mode 100644
index 000000000..815d6f7b7
--- /dev/null
+++ b/src/monkey/cpp_int.cc
@@ -0,0 +1,1123 @@
1/**[txh]********************************************************************
2
3 Copyright (c) 2004-2007 by Salvador E. Tropea.
4 Covered by the GPL license.
5
6 Module: C++ Interface.
7 Comments:
8 Implements a very simple (naive ;-) C++ wrapper.@p
9
10***************************************************************************/
11
12#include <string.h>
13#include <limits.h>
14#include "mi_gdb.h"
15
16/**[txh]********************************************************************
17
18 Description:
19 Initializes a debugger object. It starts in the "disconnected" state.
20Use @x{::Connect} after it.
21
22***************************************************************************/
23
24MIDebugger::MIDebugger()
25{
26 state=disconnected;
27 h=NULL;
28 aux_tty=NULL;
29 waitingTempBkpt=0;
30 targetEndian=enUnknown;
31 targetArch=arUnknown;
32}
33
34/**[txh]********************************************************************
35
36 Description:
37 This is the destructor for the class. It tries to change the state to
38"disconnected" doing the needed actions.
39
40***************************************************************************/
41
42MIDebugger::~MIDebugger()
43{
44 if (state==running)
45 {
46 Stop();
47 mi_stop *rs;
48 // TODO: Some kind of time-out
49 while (!Poll(rs));
50 mi_free_stop(rs);
51 state=stopped;
52 }
53 if (state==stopped)
54 {
55 Kill();
56 state=target_specified;
57 }
58 if (state==target_specified)
59 {
60 TargetUnselect();
61 state=connected;
62 }
63 if (state==connected)
64 Disconnect();
65 // Here state==disconnected
66}
67
68/**[txh]********************************************************************
69
70 Description:
71 Connects to gdb. Currently only local connections are supported, that's
72a gdb limitation. Call it when in "unconnected" state, on success it will
73change to the "connected" state. After it you should call one of the
74SelectTarget members. @x{::SelectTargetX11}, @x{::SelectTargetLinux} or
75@x{::SelectTargetRemote}. To finish the connection use @x{::Disconnect}.
76
77 Return: !=0 OK.
78
79***************************************************************************/
80
81int MIDebugger::Connect(bool )
82{
83 if (state==disconnected)
84 {
85 h=mi_connect_local();
86 if (h!=NULL)
87 {
88 state=connected;
89 return 1;
90 }
91 }
92 return 0;
93}
94
95/**[txh]********************************************************************
96
97 Description:
98 Finishes the connection to gdb. Call when in "connected" state, on success
99it will change to "disconnected" state. This function first tries to exit
100from gdb and then close the connection. But if gdb fails to exit it will be
101killed.
102
103 Return: !=0 OK
104
105***************************************************************************/
106
107int MIDebugger::Disconnect()
108{
109 if (state==connected)
110 {
111 gmi_gdb_exit(h);
112 mi_disconnect(h);
113 state=disconnected;
114 return 1;
115 }
116 return 0;
117}
118
119/**[txh]********************************************************************
120
121 Description:
122 Protected member that implements @x{::SelectTargetX11} and
123@x{::SelectTargetLinux}.
124
125 Return: !=0 OK.
126
127***************************************************************************/
128
129int MIDebugger::SelectTargetTTY(const char *exec, const char *args,
130 const char *auxtty, dMode m)
131{
132 if (state!=connected)
133 return 0;
134
135 targetEndian=enUnknown;
136 targetArch=arUnknown;
137 mode=m;
138 if (!gmi_set_exec(h,exec,args))
139 return 0;
140
141 const char *tty_name;
142 #ifndef __CYGWIN__
143 if (!auxtty)
144 {
145 aux_tty=m==dmLinux ? gmi_look_for_free_vt() : gmi_start_xterm();
146 if (!aux_tty)
147 return 0;
148 tty_name=aux_tty->tty;
149 }
150 else
151 {
152 tty_name=auxtty;
153 }
154 if (!gmi_target_terminal(h,tty_name))
155 return 0;
156 #else
157 tty_name=NULL;
158 if (!gmi_gdb_set(h,"new-console","on"))
159 return 0;
160 #endif
161
162 state=target_specified;
163 preRun=false;
164 return 1;
165}
166
167/**[txh]********************************************************************
168
169 Description:
170 Starts a debug session for X11. It opens an xterm console for the program
171to debug and tells gdb which executable to debug and the command line
172options to pass. You can specify an already existing tty console to be used.
173Can be called when the state is "connected". On success will change to the
174"target_specified" state. After it you can use @x{::Run} or use the members
175to define breakpoints and similar stuff. To finish it use
176@x{::TargetUnselect}.
177
178 Return: !=0 OK.
179
180***************************************************************************/
181
182int MIDebugger::SelectTargetX11(const char *exec, const char *args,
183 const char *auxtty)
184{
185 return SelectTargetTTY(exec,args,auxtty,dmX11);
186}
187
188
189/**[txh]********************************************************************
190
191 Description:
192 Starts a debug session for Linux console. It selects an empty VT for the
193program to debug and tells gdb which executable to debug and the command line
194options to pass. You can specify an already existing tty console to be used.
195Can be called when the state is "connected". On success will change to the
196"target_specified" state. After it you can use @x{::Run} or use the members
197to define breakpoints and similar stuff. To finish it use
198@x{::TargetUnselect}.
199
200 Return: !=0 OK.
201
202***************************************************************************/
203
204int MIDebugger::SelectTargetLinux(const char *exec, const char *args,
205 const char *auxtty)
206{
207 return SelectTargetTTY(exec,args,auxtty,dmLinux);
208}
209
210/**[txh]********************************************************************
211
212 Description:
213 Starts a remote session. The other end should be running gdbserver. You
214must specify a local copy of the program to debug with debug info. The remote
215copy can be stripped. The @var{rtype} and @var{rparams} selects the protocol
216and the remote machine. Read gdb docs to know more about the available
217options. If @var{rtype} is omitted "extended-remote" protocol is used.
218Can be called when the state is "connected". On success will change to the
219"target_specified" state. After it you can use @x{::Run} or use the members
220to define breakpoints and similar stuff. To finish it use
221@x{::TargetUnselect}. Note that when gdb uses remote debugging the remote
222program starts running. The @x{::Run} member knows about it.
223
224 Return: !=0 OK.
225 Example:
226 o->SelectTargetRemote("./exec_file","192.168.1.65:5000");
227
228***************************************************************************/
229
230int MIDebugger::SelectTargetRemote(const char *exec, const char *rparams,
231 const char *rtype, bool download)
232{
233 if (state!=connected)
234 return 0;
235
236 mode=dmRemote;
237 preRun=true;
238 targetEndian=enUnknown;
239 targetArch=arUnknown;
240 if (rtype==NULL)
241 rtype="extended-remote";
242
243 /* Tell gdb to load symbols from the local copy. */
244 int res=download ? gmi_set_exec(h,exec,NULL) : gmi_file_symbol_file(h,exec);
245 if (!res)
246 return 0;
247 /* Select the target */
248 if (!gmi_target_select(h,rtype,rparams))
249 return 0;
250 /* Download the binary */
251 if (download)
252 {
253 if (!gmi_target_download(h))
254 return 0;
255 }
256
257 state=target_specified;
258 return 1;
259}
260
261/**[txh]********************************************************************
262
263 Description:
264 Starts a local session using an already running process.
265
266 Return: !=0 OK.
267
268***************************************************************************/
269
270mi_frames *MIDebugger::SelectTargetPID(const char *exec, int pid)
271{
272 if (state!=connected)
273 return NULL;
274
275 mode=dmPID;
276 preRun=false;
277 targetEndian=enUnknown;
278 targetArch=arUnknown;
279
280 mi_frames *res=gmi_target_attach(h,pid);
281 if (res)
282 {
283 state=stopped;
284
285 /* Tell gdb to load symbols from the local copy. */
286 if (!gmi_file_symbol_file(h,exec))
287 {
288 mi_free_frames(res);
289 return NULL;
290 }
291 }
292
293 return res;
294}
295
296/**[txh]********************************************************************
297
298 Description:
299 Used to unselect the current target. When X11 mode it closes the auxiliar
300terminal. For remote debugging it uses "detach". Can be called when in
301"target_specified" state. On success it changes to "connected" state.
302
303 Return: !=0 OK
304
305***************************************************************************/
306
307int MIDebugger::TargetUnselect()
308{
309 switch (mode)
310 {
311 case dmX11:
312 case dmLinux:
313 if (state!=target_specified)
314 return 0;
315 if (aux_tty)
316 {
317 gmi_end_aux_term(aux_tty);
318 aux_tty=NULL;
319 }
320 break;
321 case dmPID:
322 case dmRemote:
323 if (state!=target_specified)
324 {
325 if (state!=stopped || !gmi_target_detach(h))
326 return 0;
327 }
328 break;
329 }
330 state=connected;
331 return 1;
332}
333
334/**[txh]********************************************************************
335
336 Description:
337 Starts running the program. You should set breakpoint before it. Can be
338called when state is "target_specified". On success will change to "running"
339state. After it you should poll for async responses using @x{::Poll}. The
340program can stop for many reasons asynchronously and also exit. This
341information is known using Poll. You can stop the program using @x{::Stop}.
342
343 Return: !=0 OK.
344
345***************************************************************************/
346
347int MIDebugger::Run()
348{
349 if (state!=target_specified)
350 return 0;
351
352 int res;
353 if (preRun)
354 res=gmi_exec_continue(h);
355 else
356 res=gmi_exec_run(h);
357 if (res)
358 state=running;
359
360 return res;
361}
362
363/**[txh]********************************************************************
364
365 Description:
366 Stops the program execution. GDB sends an interrupt signal to the program.
367Can be called when the state is "running". It won't switch to "stopped"
368state automatically. Instead you must poll for async events and wait for a
369stopped notification. After it you can call @x{::Continue} to resume
370execution.
371
372 Return:
373 Example: !=0 OK
374
375***************************************************************************/
376
377int MIDebugger::Stop()
378{
379 if (state!=running)
380 return 0;
381 return gmi_exec_interrupt(h);
382}
383
384/**[txh]********************************************************************
385
386 Description:
387 Polls gdb looking for async responses. Currently it just looks for
388"stopped" messages. You must call it when the state is "running". But the
389function will poll gdb even if the state isn't "running". When a stopped
390message is received the state changes to stopped or target_specified (the
391last is when we get some exit).
392
393 Return: !=0 if we got a response. The @var{rs} pointer will point to an
394mi_stop structure if we got it or will be NULL if we didn't.
395
396***************************************************************************/
397
398int MIDebugger::Poll(mi_stop *&rs)
399{
400 if (state==disconnected || !mi_get_response(h))
401 return 0;
402
403 mi_stop *res=mi_res_stop(h);
404 if (res)
405 {
406 if (res->reason==sr_exited_signalled ||
407 res->reason==sr_exited ||
408 res->reason==sr_exited_normally)
409 // When we use a PID the exit makes it invalid, so we don't have a
410 // valid target to re-run.
411 state=mode==dmPID ? connected : target_specified;
412 else
413 state=stopped;
414 if (res->reason==sr_unknown && waitingTempBkpt)
415 {
416 waitingTempBkpt=0;
417 res->reason=sr_bkpt_hit;
418 }
419 }
420 else
421 {// We got an error. It looks like most async commands returns running even
422 // before they are sure the process is running. Latter we get the real
423 // error. So I'm assuming the program is stopped.
424 // Lamentably -target-exec-status isn't implemented and even in this case
425 // if the program is really running as real async isn't implemented it
426 // will fail anyways.
427 if (state==running)
428 state=stopped;
429 }
430 rs=res;
431 return 1;
432}
433
434/**[txh]********************************************************************
435
436 Description:
437 Resumes execution after the program "stopped". Can be called when the state
438is stopped. On success will change to "running" state.
439
440 Return: !=0 OK
441
442***************************************************************************/
443
444int MIDebugger::Continue()
445{
446 if (state!=stopped)
447 return 0;
448 int res=gmi_exec_continue(h);
449 if (res)
450 state=running;
451 return res;
452}
453
454/**[txh]********************************************************************
455
456 Description:
457 Starts program execution or resumes it. When the state is target_specified
458it calls @x{::Run} otherwise it uses @x{::Continue}. Can be called when the
459state is "target_specified" or "stopped". On success will change to
460"running" state.
461
462 Return: !=0 OK
463
464***************************************************************************/
465
466int MIDebugger::RunOrContinue()
467{
468 if (state==target_specified)
469 return Run();
470 return Continue();
471}
472
473/**[txh]********************************************************************
474
475 Description:
476 Kills the program you are debugging. Can be called when the state is
477"stopped" or "running". On success changes the state to "target_specified".
478Note that if you want to restart the program you can just call @x{::Run} and
479if you want to just stop the program call @x{::Stop}.
480
481 Return: !=0 OK
482
483***************************************************************************/
484
485int MIDebugger::Kill()
486{
487 if (state!=stopped && state!=running)
488 return 0;
489 /* GDB/MI doesn't implement it (yet), so we use the regular kill. */
490 /* Ensure confirm is off. */
491 char *prev=gmi_gdb_show(h,"confirm");
492 if (!prev)
493 return 0;
494 if (strcmp(prev,"off"))
495 {
496 if (!gmi_gdb_set(h,"confirm","off"))
497 {
498 free(prev);
499 return 0;
500 }
501 }
502 else
503 {
504 free(prev);
505 prev=NULL;
506 }
507 /* Do the kill. */
508 int res=gmi_exec_kill(h);
509 /* Revert confirm option if needed. */
510 if (prev)
511 {
512 gmi_gdb_set(h,"confirm",prev);
513 free(prev);
514 }
515
516 if (res)
517 state=target_specified;
518
519 return res;
520}
521
522/**[txh]********************************************************************
523
524 Description:
525 Inserts a breakpoint at @var{file} and @var{line}. Can be called when the
526state is "stopped" or "target_specified".
527
528 Return: An mi_bkpt structure or NULL if error.
529
530***************************************************************************/
531
532mi_bkpt *MIDebugger::Breakpoint(const char *file, int line)
533{
534 if (state!=stopped && state!=target_specified)
535 return NULL;
536 return gmi_break_insert(h,file,line);
537}
538
539/**[txh]********************************************************************
540
541 Description:
542 Inserts a breakpoint at @var{where}, all options available. Can be called
543when the state is "stopped" or "target_specified".
544
545 Return: An mi_bkpt structure or NULL if error.
546
547***************************************************************************/
548
549mi_bkpt *MIDebugger::Breakpoint(const char *where, bool temporary,
550 const char *cond, int count, int thread,
551 bool hard_assist)
552{
553 if (state!=stopped && state!=target_specified)
554 return NULL;
555 return gmi_break_insert_full(h,temporary,hard_assist,cond,count,thread,where);
556}
557
558
559const int maxWhere=PATH_MAX+256;
560
561mi_bkpt *MIDebugger::Breakpoint(mi_bkpt *b)
562{
563 if (state!=stopped && state!=target_specified)
564 return NULL;
565
566 char buf[maxWhere];
567 buf[0]=0;
568 switch (b->mode)
569 {
570 case m_file_line:
571 snprintf(buf,maxWhere,"%s:%d",b->file,b->line);
572 break;
573 case m_function:
574 snprintf(buf,maxWhere,"%s",b->func);
575 break;
576 case m_file_function:
577 snprintf(buf,maxWhere,"%s:%s",b->file,b->func);
578 break;
579 case m_address:
580 snprintf(buf,maxWhere,"*%p",b->addr);
581 break;
582 }
583 return Breakpoint(buf,b->disp==d_del,b->cond,b->ignore,b->thread,
584 b->type==t_hw);
585}
586
587/**[txh]********************************************************************
588
589 Description:
590 Inserts a breakpoint at @var{file} and @var{line} all options available.
591Can be called when the state is "stopped" or "target_specified".
592
593 Return: An mi_bkpt structure or NULL if error.
594
595***************************************************************************/
596
597mi_bkpt *MIDebugger::BreakpointFull(const char *file, int line,
598 bool temporary, const char *cond,
599 int count, int thread, bool hard_assist)
600{
601 if (state!=stopped && state!=target_specified)
602 return NULL;
603 return gmi_break_insert_full_fl(h,file,line,temporary,hard_assist,cond,
604 count,thread);
605}
606
607/**[txh]********************************************************************
608
609 Description:
610 Removes the specified breakpoint. It doesn't free the structure. Can be
611called when the state is "stopped" or "target_specified".
612
613 Return: !=0 OK
614
615***************************************************************************/
616
617int MIDebugger::BreakDelete(mi_bkpt *b)
618{
619 if ((state!=stopped && state!=target_specified) || !b)
620 return 0;
621 return gmi_break_delete(h,b->number);
622}
623
624/**[txh]********************************************************************
625
626 Description:
627 Inserts a watchpoint for the specified expression. Can be called when the
628state is "stopped" or "target_specified".
629
630 Return: An mi_wp structure or NULL if error.
631
632***************************************************************************/
633
634mi_wp *MIDebugger::Watchpoint(enum mi_wp_mode mode, const char *exp)
635{
636 if (state!=stopped && state!=target_specified)
637 return NULL;
638 return gmi_break_watch(h,mode,exp);
639}
640
641/**[txh]********************************************************************
642
643 Description:
644 Removes the specified watchpoint. It doesn't free the structure. Can be
645called when the state is "stopped" or "target_specified".
646
647 Return: !=0 OK
648
649***************************************************************************/
650
651int MIDebugger::WatchDelete(mi_wp *w)
652{
653 if ((state!=stopped && state!=target_specified) || !w)
654 return 0;
655 return gmi_break_delete(h,w->number);
656}
657
658/**[txh]********************************************************************
659
660 Description:
661 Puts a temporal breakpoint in main function and starts running. Can be
662called when the state is "target_specified". If successful the state will
663change to "running".
664
665 Return: !=0 OK
666
667***************************************************************************/
668
669int MIDebugger::RunToMain()
670{
671 if (state!=target_specified)
672 return 0;
673 mi_bkpt *b=Breakpoint(mi_get_main_func(),true);
674 if (!b)
675 return 0;
676 mi_free_bkpt(b);
677 waitingTempBkpt=1;
678 return Run();
679}
680
681/**[txh]********************************************************************
682
683 Description:
684 Executes upto the next line, doesn't follow function calls. The @var{inst}
685argument is for assembler. If the state is "target_specified" it will go to
686the first line in the main function. If the state is "stopped" will use the
687next command. If successfully the state will change to "running".
688
689 Return: !=0 OK
690
691***************************************************************************/
692
693int MIDebugger::StepOver(bool inst)
694{
695 int res=0;
696
697 if (state==target_specified)
698 {// We aren't running
699 // Walk to main
700 return RunToMain();
701 }
702 if (state==stopped)
703 {
704 if (inst)
705 res=gmi_exec_next_instruction(h);
706 else
707 res=gmi_exec_next(h);
708 if (res)
709 state=running;
710 }
711 return res;
712}
713
714/**[txh]********************************************************************
715
716 Description:
717 Executes until the specified point. If the state is "target_specified" it
718uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
719Fails for any other state.
720
721 Return: !=0 OK
722
723***************************************************************************/
724
725int MIDebugger::GoTo(const char *file, int line)
726{
727 int res=0;
728
729 if (state==target_specified)
730 {// We aren't running
731 // Use a temporal breakpoint
732 int l=strlen(file)+32;
733 char buf[l];
734 snprintf(buf,l,"%s:%d",file,line);
735 mi_bkpt *b=Breakpoint(buf,true);
736 if (b)
737 {
738 mi_free_bkpt(b);
739 waitingTempBkpt=1;
740 res=Run();
741 }
742 }
743 else if (state==stopped)
744 {
745 res=gmi_exec_until(h,file,line);
746 if (res)
747 state=running;
748 }
749 return res;
750}
751
752/**[txh]********************************************************************
753
754 Description:
755 Executes until the specified point. If the state is "target_specified" it
756uses a temporal breakpoint. If the state is "stopped" it uses -exec-until.
757Fails for any other state.
758
759 Return: !=0 OK
760
761***************************************************************************/
762
763int MIDebugger::GoTo(void *addr)
764{
765 int res=0;
766
767 if (state==target_specified)
768 {// We aren't running
769 // Use a temporal breakpoint
770 char buf[32];
771 snprintf(buf,32,"*%p",addr);
772 mi_bkpt *b=Breakpoint(buf,true);
773 if (b)
774 {
775 mi_free_bkpt(b);
776 waitingTempBkpt=1;
777 res=Run();
778 }
779 }
780 else if (state==stopped)
781 {
782 res=gmi_exec_until_addr(h,addr);
783 if (res)
784 state=running;
785 }
786 return res;
787}
788
789
790/**[txh]********************************************************************
791
792 Description:
793 Resumes execution until the end of the current funtion is reached. Only
794usable when we are in the "stopped" state.
795
796 Return: !=0 OK
797
798***************************************************************************/
799
800int MIDebugger::FinishFun()
801{
802 if (state!=stopped)
803 return 0;
804 int res=gmi_exec_finish(h);
805 if (res)
806 state=running;
807 return res;
808}
809
810/**[txh]********************************************************************
811
812 Description:
813 Returns immediately. Only usable when we are in the "stopped" state.
814
815 Return: !=NULL OK, the returned frame is the current location. That's a
816synchronous function.
817
818***************************************************************************/
819
820mi_frames *MIDebugger::ReturnNow()
821{
822 if (state!=stopped)
823 return 0;
824 return gmi_exec_return(h);
825}
826
827/**[txh]********************************************************************
828
829 Description:
830 Returns the current list of frames.
831
832 Return: !=NULL OK, the list of frames is returned.
833
834***************************************************************************/
835
836mi_frames *MIDebugger::CallStack(bool args)
837{
838 if (state!=stopped)
839 return 0;
840 mi_frames *fr1=gmi_stack_list_frames(h);
841 if (fr1 && args)
842 {// Get the function arguments
843 mi_frames *fr2=gmi_stack_list_arguments(h,1);
844 if (fr2)
845 {// Transfer them to the other list
846 mi_frames *p=fr1, *p2=fr2;
847 while (p2 && p)
848 {
849 p->args=p2->args;
850 p2->args=NULL;
851 p2=p2->next;
852 p=p->next;
853 }
854 mi_free_frames(fr2);
855 }
856 }
857 return fr1;
858}
859
860/**[txh]********************************************************************
861
862 Description:
863 Executes upto the next line, it follows function calls. The @var{inst}
864argument is for assembler. If the state is "target_specified" it will go to
865the first line in the main function. If the state is "stopped" will use the
866next command. If successfully the state will change to "running".
867
868 Return: !=0 OK
869
870***************************************************************************/
871
872int MIDebugger::TraceInto(bool inst)
873{
874 int res=0;
875
876 if (state==target_specified)
877 {// We aren't running
878 // Walk to main
879 return RunToMain();
880 }
881 if (state==stopped)
882 {
883 if (inst)
884 res=gmi_exec_step_instruction(h);
885 else
886 res=gmi_exec_step(h);
887 if (res)
888 state=running;
889 }
890 return res;
891}
892
893/**[txh]********************************************************************
894
895 Description:
896 Evaluates the provided expression. If we get an error the error
897description is returned instead. Can't be called if "disconnected" or
898"running".
899
900 Return: The result of the expression (use free) or NULL.
901
902***************************************************************************/
903
904char *MIDebugger::EvalExpression(const char *exp)
905{
906 if (state==disconnected ||
907 state==running) // No async :-(
908 return NULL;
909 // Evaluate it
910 mi_error=MI_OK;
911 char *res=gmi_data_evaluate_expression(h,exp);
912 if (!res && mi_error_from_gdb)
913 {// Not valid, return the error
914 res=strdup(mi_error_from_gdb);
915 }
916 return res;
917}
918
919/**[txh]********************************************************************
920
921 Description:
922 Modifies the provided expression. If we get an error the error
923description is returned instead. Can't be called if "disconnected" or
924"running".
925
926 Return: The result of the expression (use free) or NULL.
927
928***************************************************************************/
929
930char *MIDebugger::ModifyExpression(char *exp, char *newVal)
931{
932 if (state==disconnected ||
933 state==running) // No async :-(
934 return NULL;
935 // Create an assignment
936 int l1=strlen(exp);
937 int l2=strlen(newVal);
938 char b[l1+l2+2], *s=b;
939 memcpy(s,exp,l1);
940 s+=l1;
941 *s='=';
942 memcpy(++s,newVal,l2);
943 s[l2]=0;
944 // Evaluate it
945 char *res=gmi_data_evaluate_expression(h,b);
946 if (!res && mi_error_from_gdb)
947 {// Not valid, return the error
948 res=strdup(mi_error_from_gdb);
949 }
950 return res;
951}
952
953/**[txh]********************************************************************
954
955 Description:
956 Sends a command to gdb.
957
958 Return: !=0 OK
959
960***************************************************************************/
961
962int MIDebugger::Send(const char *command)
963{
964 if (state==disconnected ||
965 state==running) // No async :-(
966 return 0;
967 // TODO: detect and use -interpreter-exec?
968 mi_send(h,"%s\n",command);
969 return mi_res_simple_done(h);
970}
971
972
973/**[txh]********************************************************************
974
975 Description:
976 Fills the type and value fields of the mi_gvar provided list.
977
978 Return: !=0 OK
979
980***************************************************************************/
981
982int MIDebugger::FillTypeVal(mi_gvar *var)
983{
984 while (var)
985 {
986 if (!var->type && !gmi_var_info_type(h,var))
987 return 0;
988 if (!var->value && !gmi_var_evaluate_expression(h,var))
989 return 0;
990 var=var->next;
991 }
992 return 1;
993}
994
995int MIDebugger::FillOneTypeVal(mi_gvar *var)
996{
997 if (!var)
998 return 0;
999
1000 int ok=1;
1001 if (!var->type && !gmi_var_info_type(h,var))
1002 {
1003 var->type=strdup("");
1004 ok=0;
1005 }
1006 if (!var->value && !gmi_var_evaluate_expression(h,var))
1007 {
1008 var->value=strdup("");
1009 ok=0;
1010 }
1011 return ok;
1012}
1013
1014int MIDebugger::AssigngVar(mi_gvar *var, const char *exp)
1015{
1016 if (state!=stopped)
1017 return 0;
1018 return gmi_var_assign(h,var,exp);
1019}
1020
1021char *MIDebugger::Show(const char *var)
1022{
1023 if (state==running || state==disconnected)
1024 return 0;
1025 // GDB 5.x doesn't reply all in the response record, just to the console :-(
1026 h->catch_console=1;
1027 if (h->catched_console)
1028 {
1029 free(h->catched_console);
1030 h->catched_console=NULL;
1031 }
1032 char *res=gmi_gdb_show(h,var);
1033 h->catch_console=0;
1034 if (!res && h->catched_console)
1035 {
1036 res=h->catched_console;
1037 h->catched_console=NULL;
1038 }
1039 return res;
1040}
1041
1042MIDebugger::endianType MIDebugger::GetTargetEndian()
1043{
1044 if (targetEndian!=enUnknown)
1045 return targetEndian;
1046 if (state!=stopped && state!=target_specified)
1047 return enUnknown;
1048
1049 char *end=Show("endian");
1050 if (end)
1051 {
1052 if (strstr(end,"big"))
1053 targetEndian=enBig;
1054 else if (strstr(end,"little"))
1055 targetEndian=enLittle;
1056 free(end);
1057 }
1058 return targetEndian;
1059}
1060
1061MIDebugger::archType MIDebugger::GetTargetArchitecture()
1062{
1063 if (targetArch!=arUnknown)
1064 return targetArch;
1065 if (state!=stopped && state!=target_specified)
1066 return arUnknown;
1067
1068 char *end=Show("architecture");
1069 if (end)
1070 {
1071 if (strstr(end,"i386"))
1072 targetArch=arIA32;
1073 else if (strstr(end,"sparc"))
1074 targetArch=arSPARC;
1075 else if (strstr(end,"pic14"))
1076 targetArch=arPIC14;
1077 else if (strstr(end,"avr"))
1078 targetArch=arAVR;
1079 free(end);
1080 }
1081 return targetArch;
1082}
1083
1084int MIDebugger::GetErrorNumberSt()
1085{
1086 if (mi_error==MI_GDB_DIED)
1087 {
1088 state=target_specified;
1089 TargetUnselect();
1090 state=connected;
1091 Disconnect();
1092 }
1093 return mi_error;
1094}
1095
1096int MIDebugger::UpdateRegisters(mi_chg_reg *regs)
1097{
1098 int updated=0;
1099 mi_chg_reg *chg=GetChangedRegisters();
1100 if (chg)
1101 {
1102 mi_chg_reg *r=regs, *c;
1103 while (r)
1104 {
1105 c=chg;
1106 while (c && c->reg!=r->reg)
1107 c=c->next;
1108 if (c)
1109 {
1110 r->updated=1;
1111 free(r->val);
1112 r->val=c->val;
1113 c->val=NULL;
1114 updated++;
1115 }
1116 else
1117 r->updated=0;
1118 r=r->next;
1119 }
1120 }
1121 return updated;
1122}
1123