1 /* Target operations for the remote server for GDB.
2 Copyright (C) 2002, 2004, 2005, 2011
3 Free Software Foundation, Inc.
4
5 Contributed by MontaVista Software.
6
7 This file is part of GDB.
8 It has been modified to integrate it in valgrind
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 Boston, MA 02110-1301, USA. */
24
25 #include "server.h"
26 #include "target.h"
27 #include "regdef.h"
28 #include "regcache.h"
29 #include "valgrind_low.h"
30 #include "gdb/signals.h"
31 #include "pub_core_aspacemgr.h"
32 #include "pub_core_machine.h"
33 #include "pub_core_threadstate.h"
34 #include "pub_core_transtab.h"
35 #include "pub_core_gdbserver.h"
36 #include "pub_core_debuginfo.h"
37
38
39 /* the_low_target defines the architecture specific aspects depending
40 on the cpu */
41 static struct valgrind_target_ops the_low_target;
42
43 static
image_ptid(unsigned long ptid)44 char *image_ptid(unsigned long ptid)
45 {
46 static char result[100];
47 VG_(sprintf) (result, "id %ld", ptid);
48 return result;
49 }
50 #define get_thread(inf) ((struct thread_info *)(inf))
51 static
remove_thread_if_not_in_vg_threads(struct inferior_list_entry * inf)52 void remove_thread_if_not_in_vg_threads (struct inferior_list_entry *inf)
53 {
54 struct thread_info *thread = get_thread (inf);
55 if (!VG_(lwpid_to_vgtid)(thread_to_gdb_id(thread))) {
56 dlog(1, "removing gdb ptid %s\n",
57 image_ptid(thread_to_gdb_id(thread)));
58 remove_thread (thread);
59 }
60 }
61
62 /* synchronize threads known by valgrind and threads known by gdbserver */
63 static
valgrind_update_threads(int pid)64 void valgrind_update_threads (int pid)
65 {
66 ThreadId tid;
67 ThreadState *ts;
68 unsigned long ptid;
69 struct thread_info *ti;
70
71 /* call remove_thread for all gdb threads not in valgrind threads */
72 for_each_inferior (&all_threads, remove_thread_if_not_in_vg_threads);
73
74 /* call add_thread for all valgrind threads not known in gdb all_threads */
75 for (tid = 1; tid < VG_N_THREADS; tid++) {
76
77 #define LOCAL_THREAD_TRACE " ti* %p vgtid %d status %s as gdb ptid %s lwpid %d\n", \
78 ti, tid, VG_(name_of_ThreadStatus) (ts->status), \
79 image_ptid (ptid), ts->os_state.lwpid
80
81 if (VG_(is_valid_tid) (tid)) {
82 ts = VG_(get_ThreadState) (tid);
83 ptid = ts->os_state.lwpid;
84 ti = gdb_id_to_thread (ptid);
85 if (!ti) {
86 /* we do not report the threads which are not yet fully
87 initialized otherwise this creates duplicated threads
88 in gdb: once with pid xxx lwpid 0, then after that
89 with pid xxx lwpid yyy. */
90 if (ts->status != VgTs_Init) {
91 dlog(1, "adding_thread" LOCAL_THREAD_TRACE);
92 add_thread (ptid, ts, ptid);
93 }
94 } else {
95 dlog(2, "(known thread)" LOCAL_THREAD_TRACE);
96 }
97 }
98 #undef LOCAL_THREAD_TRACE
99 }
100 }
101
102 static
build_shadow_arch(struct reg * reg_defs,int n)103 struct reg* build_shadow_arch (struct reg *reg_defs, int n) {
104 int i, r;
105 static const char *postfix[3] = { "", "s1", "s2" };
106 struct reg *new_regs = malloc(3 * n * sizeof(reg_defs[0]));
107 int reg_set_len = reg_defs[n-1].offset + reg_defs[n-1].size;
108
109 for (i = 0; i < 3; i++) {
110 for (r = 0; r < n; r++) {
111 char *regname = malloc(strlen(reg_defs[r].name)
112 + strlen (postfix[i]) + 1);
113 strcpy (regname, reg_defs[r].name);
114 strcat (regname, postfix[i]);
115 new_regs[i*n + r].name = regname;
116 new_regs[i*n + r].offset = i*reg_set_len + reg_defs[r].offset;
117 new_regs[i*n + r].size = reg_defs[r].size;
118 dlog(1,
119 "%10s Nr %d offset(bit) %d offset(byte) %d size(bit) %d\n",
120 new_regs[i*n + r].name, i*n + r, new_regs[i*n + r].offset,
121 (new_regs[i*n + r].offset) / 8, new_regs[i*n + r].size);
122 }
123 }
124
125 return new_regs;
126 }
127
128
129 static CORE_ADDR stopped_data_address = 0;
VG_(set_watchpoint_stop_address)130 void VG_(set_watchpoint_stop_address) (Addr addr)
131 {
132 stopped_data_address = addr;
133 }
134
valgrind_stopped_by_watchpoint(void)135 int valgrind_stopped_by_watchpoint (void)
136 {
137 return stopped_data_address != 0;
138 }
139
valgrind_stopped_data_address(void)140 CORE_ADDR valgrind_stopped_data_address (void)
141 {
142 return stopped_data_address;
143 }
144
145 /* pc at which we last stopped */
146 static CORE_ADDR stop_pc;
147
148 /* pc at which we resume.
149 If stop_pc != resume_pc, it means
150 gdb/gdbserver has changed the pc so as to have either
151 a "continue by jumping at that address"
152 or a "continue at that address to call some code from gdb".
153 */
154 static CORE_ADDR resume_pc;
155
156 static int vki_signal_to_report;
157
gdbserver_signal_encountered(Int vki_sigNo)158 void gdbserver_signal_encountered (Int vki_sigNo)
159 {
160 vki_signal_to_report = vki_sigNo;
161 }
162
163 static int vki_signal_to_deliver;
gdbserver_deliver_signal(Int vki_sigNo)164 Bool gdbserver_deliver_signal (Int vki_sigNo)
165 {
166 return vki_sigNo == vki_signal_to_deliver;
167 }
168
169 static unsigned char exit_status_to_report;
170 static int exit_code_to_report;
gdbserver_process_exit_encountered(unsigned char status,Int code)171 void gdbserver_process_exit_encountered (unsigned char status, Int code)
172 {
173 vg_assert (status == 'W' || status == 'X');
174 exit_status_to_report = status;
175 exit_code_to_report = code;
176 }
177
178 static
sym(Addr addr)179 char* sym (Addr addr)
180 {
181 static char buf[200];
182 VG_(describe_IP) (addr, buf, 200);
183 return buf;
184 }
185
186 ThreadId vgdb_interrupted_tid = 0;
187
188 /* 0 => not single stepping.
189 1 => single stepping asked by gdb
190 2 => single stepping asked by valgrind (watchpoint) */
191 static int stepping = 0;
192
valgrind_get_ignore_break_once(void)193 Addr valgrind_get_ignore_break_once(void)
194 {
195 if (valgrind_single_stepping())
196 return resume_pc;
197 else
198 return 0;
199 }
200
valgrind_set_single_stepping(Bool set)201 void valgrind_set_single_stepping(Bool set)
202 {
203 if (set)
204 stepping = 2;
205 else
206 stepping = 0;
207 }
208
valgrind_single_stepping(void)209 Bool valgrind_single_stepping(void)
210 {
211 if (stepping)
212 return True;
213 else
214 return False;
215 }
216
valgrind_thread_alive(unsigned long tid)217 int valgrind_thread_alive (unsigned long tid)
218 {
219 struct thread_info *ti = gdb_id_to_thread(tid);
220 ThreadState *tst;
221
222 if (ti != NULL) {
223 tst = (ThreadState *) inferior_target_data (ti);
224 return tst->status != VgTs_Zombie;
225 }
226 else {
227 return 0;
228 }
229 }
230
valgrind_resume(struct thread_resume * resume_info)231 void valgrind_resume (struct thread_resume *resume_info)
232 {
233 dlog(1,
234 "resume_info step %d sig %d stepping %d\n",
235 resume_info->step,
236 resume_info->sig,
237 stepping);
238 if (valgrind_stopped_by_watchpoint()) {
239 dlog(1, "clearing watchpoint stopped_data_address %p\n",
240 C2v(stopped_data_address));
241 VG_(set_watchpoint_stop_address) ((Addr) 0);
242 }
243 vki_signal_to_deliver = resume_info->sig;
244
245 stepping = resume_info->step;
246 resume_pc = (*the_low_target.get_pc) ();
247 if (resume_pc != stop_pc) {
248 dlog(1,
249 "stop_pc %p changed to be resume_pc %s\n",
250 C2v(stop_pc), sym(resume_pc));
251 }
252 regcache_invalidate();
253 }
254
valgrind_wait(char * ourstatus)255 unsigned char valgrind_wait (char *ourstatus)
256 {
257 int pid;
258 unsigned long wptid;
259 ThreadState *tst;
260 enum target_signal sig;
261 int code;
262
263 pid = VG_(getpid) ();
264 dlog(1, "enter valgrind_wait pid %d\n", pid);
265
266 regcache_invalidate();
267 valgrind_update_threads(pid);
268
269 /* First see if we are done with this process. */
270 if (exit_status_to_report != 0) {
271 *ourstatus = exit_status_to_report;
272 exit_status_to_report = 0;
273
274 if (*ourstatus == 'W') {
275 code = exit_code_to_report;
276 exit_code_to_report = 0;
277 dlog(1, "exit valgrind_wait status W exit code %d\n", code);
278 return code;
279 }
280
281 if (*ourstatus == 'X') {
282 sig = target_signal_from_host(exit_code_to_report);
283 exit_code_to_report = 0;
284 dlog(1, "exit valgrind_wait status X signal %d\n", sig);
285 return sig;
286 }
287 }
288
289 /* in valgrind, we consider that a wait always succeeds with STOPPED 'T'
290 and with a signal TRAP (i.e. a breakpoint), unless there is
291 a signal to report. */
292 *ourstatus = 'T';
293 if (vki_signal_to_report == 0)
294 sig = TARGET_SIGNAL_TRAP;
295 else {
296 sig = target_signal_from_host(vki_signal_to_report);
297 vki_signal_to_report = 0;
298 }
299
300 if (vgdb_interrupted_tid != 0)
301 tst = VG_(get_ThreadState) (vgdb_interrupted_tid);
302 else
303 tst = VG_(get_ThreadState) (VG_(running_tid));
304 wptid = tst->os_state.lwpid;
305 /* we can only change the current_inferior when the wptid references
306 an existing thread. Otherwise, we are still in the init phase.
307 (hack similar to main thread hack in valgrind_update_threads) */
308 if (tst->os_state.lwpid)
309 current_inferior = gdb_id_to_thread (wptid);
310 stop_pc = (*the_low_target.get_pc) ();
311
312 dlog(1,
313 "exit valgrind_wait status T ptid %s stop_pc %s signal %d\n",
314 image_ptid (wptid), sym (stop_pc), sig);
315 return sig;
316 }
317
318 /* Fetch one register from valgrind VEX guest state. */
319 static
fetch_register(int regno)320 void fetch_register (int regno)
321 {
322 int size;
323 ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
324 ThreadId tid = tst->tid;
325
326 if (regno >= the_low_target.num_regs) {
327 dlog(0, "error fetch_register regno %d max %d\n",
328 regno, the_low_target.num_regs);
329 return;
330 }
331 size = register_size (regno);
332 if (size > 0) {
333 Bool mod;
334 char buf [size];
335 VG_(memset) (buf, 0, size); // registers not fetched will be seen as 0.
336 (*the_low_target.transfer_register) (tid, regno, buf,
337 valgrind_to_gdbserver, size, &mod);
338 // Note: the *mod received from transfer_register is not interesting.
339 // We are interested to see if the register data in the register cache is modified.
340 supply_register (regno, buf, &mod);
341 if (mod && VG_(debugLog_getLevel)() > 1) {
342 char bufimage [2*size + 1];
343 heximage (bufimage, buf, size);
344 dlog(2, "fetched register %d size %d name %s value %s tid %d status %s\n",
345 regno, size, the_low_target.reg_defs[regno].name, bufimage,
346 tid, VG_(name_of_ThreadStatus) (tst->status));
347 }
348 }
349 }
350
351 /* Fetch all registers, or just one, from the child process. */
352 static
usr_fetch_inferior_registers(int regno)353 void usr_fetch_inferior_registers (int regno)
354 {
355 if (regno == -1 || regno == 0)
356 for (regno = 0; regno < the_low_target.num_regs; regno++)
357 fetch_register (regno);
358 else
359 fetch_register (regno);
360 }
361
362 /* Store our register values back into the inferior.
363 If REGNO is -1, do this for all registers.
364 Otherwise, REGNO specifies which register (so we can save time). */
365 static
usr_store_inferior_registers(int regno)366 void usr_store_inferior_registers (int regno)
367 {
368 int size;
369 ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
370 ThreadId tid = tst->tid;
371
372 if (regno >= 0) {
373
374 if (regno >= the_low_target.num_regs) {
375 dlog(0, "error store_register regno %d max %d\n",
376 regno, the_low_target.num_regs);
377 return;
378 }
379
380 size = register_size (regno);
381 if (size > 0) {
382 Bool mod;
383 Addr old_SP, new_SP;
384 char buf[size];
385
386 if (regno == the_low_target.stack_pointer_regno) {
387 /* When the stack pointer register is changed such that
388 the stack is extended, we better inform the tool of the
389 stack increase. This is needed in particular to avoid
390 spurious Memcheck errors during Inferior calls. So, we
391 save in old_SP the SP before the change. A change of
392 stack pointer is also assumed to have initialised this
393 new stack space. For the typical example of an inferior
394 call, gdb writes arguments on the stack, and then
395 changes the stack pointer. As the stack increase tool
396 function might mark it as undefined, we have to call it
397 at the good moment. */
398 VG_(memset) ((void *) &old_SP, 0, size);
399 (*the_low_target.transfer_register) (tid, regno, (void *) &old_SP,
400 valgrind_to_gdbserver, size, &mod);
401 }
402
403 VG_(memset) (buf, 0, size);
404 collect_register (regno, buf);
405 (*the_low_target.transfer_register) (tid, regno, buf,
406 gdbserver_to_valgrind, size, &mod);
407 if (mod && VG_(debugLog_getLevel)() > 1) {
408 char bufimage [2*size + 1];
409 heximage (bufimage, buf, size);
410 dlog(2,
411 "stored register %d size %d name %s value %s "
412 "tid %d status %s\n",
413 regno, size, the_low_target.reg_defs[regno].name, bufimage,
414 tid, VG_(name_of_ThreadStatus) (tst->status));
415 }
416 if (regno == the_low_target.stack_pointer_regno) {
417 VG_(memcpy) (&new_SP, buf, size);
418 if (old_SP > new_SP) {
419 Word delta = (Word)new_SP - (Word)old_SP;
420 dlog(1,
421 " stack increase by stack pointer changed from %p to %p "
422 "delta %ld\n",
423 (void*) old_SP, (void *) new_SP,
424 delta);
425 VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, 0 );
426 VG_TRACK( new_mem_stack, new_SP, -delta );
427 VG_TRACK( post_mem_write, Vg_CoreClientReq, tid,
428 new_SP, -delta);
429 }
430 }
431 }
432 }
433 else {
434 for (regno = 0; regno < the_low_target.num_regs; regno++)
435 usr_store_inferior_registers (regno);
436 }
437 }
438
valgrind_fetch_registers(int regno)439 void valgrind_fetch_registers (int regno)
440 {
441 usr_fetch_inferior_registers (regno);
442 }
443
valgrind_store_registers(int regno)444 void valgrind_store_registers (int regno)
445 {
446 usr_store_inferior_registers (regno);
447 }
448
449 Bool hostvisibility = False;
450
valgrind_read_memory(CORE_ADDR memaddr,unsigned char * myaddr,int len)451 int valgrind_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
452 {
453 const void *sourceaddr = C2v (memaddr);
454 dlog(2, "reading memory %p size %d\n", sourceaddr, len);
455 if (VG_(am_is_valid_for_client) ((Addr) sourceaddr,
456 len, VKI_PROT_READ)
457 || (hostvisibility
458 && VG_(am_is_valid_for_valgrind) ((Addr) sourceaddr,
459 len, VKI_PROT_READ))) {
460 VG_(memcpy) (myaddr, sourceaddr, len);
461 return 0;
462 } else {
463 dlog(1, "error reading memory %p size %d\n", sourceaddr, len);
464 return -1;
465 }
466 }
467
valgrind_write_memory(CORE_ADDR memaddr,const unsigned char * myaddr,int len)468 int valgrind_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
469 {
470 Bool is_valid_client_memory;
471 void *targetaddr = C2v (memaddr);
472 dlog(2, "writing memory %p size %d\n", targetaddr, len);
473 is_valid_client_memory
474 = VG_(am_is_valid_for_client) ((Addr)targetaddr, len, VKI_PROT_WRITE);
475 if (is_valid_client_memory
476 || (hostvisibility
477 && VG_(am_is_valid_for_valgrind) ((Addr) targetaddr,
478 len, VKI_PROT_READ))) {
479 if (len > 0) {
480 VG_(memcpy) (targetaddr, myaddr, len);
481 if (is_valid_client_memory && VG_(tdict).track_post_mem_write) {
482 /* Inform the tool of the post memwrite. Note that we do the
483 minimum necessary to avoid complains from e.g.
484 memcheck. The idea is that the debugger is as least
485 intrusive as possible. So, we do not inform of the pre
486 mem write (and in any case, this would cause problems with
487 memcheck that does not like our CorePart in
488 pre_mem_write. */
489 ThreadState *tst =
490 (ThreadState *) inferior_target_data (current_inferior);
491 ThreadId tid = tst->tid;
492 VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid,
493 (Addr) targetaddr, len );
494 }
495 }
496 return 0;
497 } else {
498 dlog(1, "error writing memory %p size %d\n", targetaddr, len);
499 return -1;
500 }
501 }
502
503 /* insert or remove a breakpoint */
504 static
valgrind_point(Bool insert,char type,CORE_ADDR addr,int len)505 int valgrind_point (Bool insert, char type, CORE_ADDR addr, int len)
506 {
507 PointKind kind;
508 switch (type) {
509 case '0': /* implemented by inserting checks at each instruction in sb */
510 kind = software_breakpoint;
511 break;
512 case '1': /* hw breakpoint, same implementation as sw breakpoint */
513 kind = hardware_breakpoint;
514 break;
515 case '2':
516 kind = write_watchpoint;
517 break;
518 case '3':
519 kind = read_watchpoint;
520 break;
521 case '4':
522 kind = access_watchpoint;
523 break;
524 default:
525 vg_assert (0);
526 }
527
528 /* Attention: gdbserver convention differs: 0 means ok; 1 means not ok */
529 if (VG_(gdbserver_point) (kind, insert, addr, len))
530 return 0;
531 else
532 return 1; /* error or unsupported */
533 }
534
valgrind_target_xml(Bool shadow_mode)535 const char* valgrind_target_xml (Bool shadow_mode)
536 {
537 return (*the_low_target.target_xml) (shadow_mode);
538 }
539
valgrind_insert_watchpoint(char type,CORE_ADDR addr,int len)540 int valgrind_insert_watchpoint (char type, CORE_ADDR addr, int len)
541 {
542 return valgrind_point (/* insert */ True, type, addr, len);
543 }
544
valgrind_remove_watchpoint(char type,CORE_ADDR addr,int len)545 int valgrind_remove_watchpoint (char type, CORE_ADDR addr, int len)
546 {
547 return valgrind_point (/* insert*/ False, type, addr, len);
548 }
549
550 /* returns a pointer to the architecture state corresponding to
551 the provided register set: 0 => normal guest registers,
552 1 => shadow1
553 2 => shadow2
554 */
get_arch(int set,ThreadState * tst)555 VexGuestArchState* get_arch (int set, ThreadState* tst)
556 {
557 switch (set) {
558 case 0: return &tst->arch.vex;
559 case 1: return &tst->arch.vex_shadow1;
560 case 2: return &tst->arch.vex_shadow2;
561 default: vg_assert(0);
562 }
563 }
564
565 static int non_shadow_num_regs = 0;
566 static struct reg *non_shadow_reg_defs = NULL;
initialize_shadow_low(Bool shadow_mode)567 void initialize_shadow_low(Bool shadow_mode)
568 {
569 if (non_shadow_reg_defs == NULL) {
570 non_shadow_reg_defs = the_low_target.reg_defs;
571 non_shadow_num_regs = the_low_target.num_regs;
572 }
573
574 regcache_invalidate();
575 if (the_low_target.reg_defs != non_shadow_reg_defs) {
576 free (the_low_target.reg_defs);
577 }
578 if (shadow_mode) {
579 the_low_target.num_regs = 3 * non_shadow_num_regs;
580 the_low_target.reg_defs = build_shadow_arch (non_shadow_reg_defs, non_shadow_num_regs);
581 } else {
582 the_low_target.num_regs = non_shadow_num_regs;
583 the_low_target.reg_defs = non_shadow_reg_defs;
584 }
585 set_register_cache (the_low_target.reg_defs, the_low_target.num_regs);
586 }
587
set_desired_inferior(int use_general)588 void set_desired_inferior (int use_general)
589 {
590 struct thread_info *found;
591
592 if (use_general == 1) {
593 found = (struct thread_info *) find_inferior_id (&all_threads,
594 general_thread);
595 } else {
596 found = NULL;
597
598 /* If we are continuing any (all) thread(s), use step_thread
599 to decide which thread to step and/or send the specified
600 signal to. */
601 if ((step_thread != 0 && step_thread != -1)
602 && (cont_thread == 0 || cont_thread == -1))
603 found = (struct thread_info *) find_inferior_id (&all_threads,
604 step_thread);
605
606 if (found == NULL)
607 found = (struct thread_info *) find_inferior_id (&all_threads,
608 cont_thread);
609 }
610
611 if (found == NULL)
612 current_inferior = (struct thread_info *) all_threads.head;
613 else
614 current_inferior = found;
615 {
616 ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
617 ThreadId tid = tst->tid;
618 dlog(1, "set_desired_inferior use_general %d found %p tid %d lwpid %d\n",
619 use_general, found, tid, tst->os_state.lwpid);
620 }
621 }
622
VG_(dmemcpy)623 void* VG_(dmemcpy) ( void *d, const void *s, SizeT sz, Bool *mod )
624 {
625 if (VG_(memcmp) (d, s, sz)) {
626 *mod = True;
627 return VG_(memcpy) (d, s, sz);
628 } else {
629 *mod = False;
630 return d;
631 }
632 }
633
VG_(transfer)634 void VG_(transfer) (void *valgrind,
635 void *gdbserver,
636 transfer_direction dir,
637 SizeT sz,
638 Bool *mod)
639 {
640 if (dir == valgrind_to_gdbserver)
641 VG_(dmemcpy) (gdbserver, valgrind, sz, mod);
642 else if (dir == gdbserver_to_valgrind)
643 VG_(dmemcpy) (valgrind, gdbserver, sz, mod);
644 else
645 vg_assert (0);
646 }
647
valgrind_initialize_target(void)648 void valgrind_initialize_target(void)
649 {
650 #if defined(VGA_x86)
651 x86_init_architecture(&the_low_target);
652 #elif defined(VGA_amd64)
653 amd64_init_architecture(&the_low_target);
654 #elif defined(VGA_arm)
655 arm_init_architecture(&the_low_target);
656 #elif defined(VGA_arm64)
657 arm64_init_architecture(&the_low_target);
658 #elif defined(VGA_ppc32)
659 ppc32_init_architecture(&the_low_target);
660 #elif defined(VGA_ppc64)
661 ppc64_init_architecture(&the_low_target);
662 #elif defined(VGA_s390x)
663 s390x_init_architecture(&the_low_target);
664 #elif defined(VGA_mips32)
665 mips32_init_architecture(&the_low_target);
666 #elif defined(VGA_mips64)
667 mips64_init_architecture(&the_low_target);
668 #else
669 #error "architecture missing in target.c valgrind_initialize_target"
670 #endif
671 }
672