|
From: <sv...@va...> - 2012-05-23 21:50:46
|
philippe 2012-05-23 22:50:36 +0100 (Wed, 23 May 2012)
New Revision: 12579
Log:
Prepare for AVX support : restructure gdbsrv/target/valgrind-low/arch low
AVX support implies to have target xml files which are selected
according to the machine hwcaps.
This change improves the structure of the gdbserver software layering
to prepare for this.
Basically, the protocol files (e.g. server.c) are now calling directly
the valgrind target operations which are now defined in target.h/target.c
(before, there was a level of indirection inheritated from the GDB
structure which was useless for valgrind gdbserver).
+ clarified some comments
Removed files:
trunk/coregrind/m_gdbserver/valgrind-low.c
Modified files:
trunk/coregrind/Makefile.am
trunk/coregrind/m_gdbserver/m_gdbserver.c
trunk/coregrind/m_gdbserver/regcache.c
trunk/coregrind/m_gdbserver/remote-utils.c
trunk/coregrind/m_gdbserver/server.c
trunk/coregrind/m_gdbserver/server.h
trunk/coregrind/m_gdbserver/target.c
trunk/coregrind/m_gdbserver/target.h
trunk/coregrind/m_gdbserver/valgrind-low-amd64.c
trunk/coregrind/m_gdbserver/valgrind-low-x86.c
trunk/coregrind/m_gdbserver/valgrind_low.h
Deleted: trunk/coregrind/m_gdbserver/valgrind-low.c (+0 -641)
===================================================================
--- trunk/coregrind/m_gdbserver/valgrind-low.c 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/valgrind-low.c 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -1,641 +0,0 @@
-/* Low level interface to valgrind, for the remote server for GDB integrated
- in valgrind.
- Copyright (C) 2011
- Free Software Foundation, Inc.
-
- This file is part of VALGRIND.
- It has been inspired from a file from gdbserver in gdb 6.6.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-#include "server.h"
-#include "target.h"
-#include "regdef.h"
-#include "regcache.h"
-#include "valgrind_low.h"
-#include "gdb/signals.h"
-#include "pub_core_aspacemgr.h"
-#include "pub_tool_machine.h"
-#include "pub_core_threadstate.h"
-#include "pub_core_transtab.h"
-#include "pub_core_gdbserver.h"
-#include "pub_tool_debuginfo.h"
-
-/* the_low_target defines the architecture specific aspects depending
- on the cpu */
-static struct valgrind_target_ops the_low_target;
-
-/* builds an image of bin according to byte order of the architecture
- Useful for register and int image */
-char* heximage (char *buf, char *bin, int count)
-{
-#if defined(VGA_x86) || defined(VGA_amd64)
- char rev[count];
- /* note: no need for trailing \0, length is known with count */
- int i;
- for (i = 0; i < count; i++)
- rev[i] = bin[count - i - 1];
- hexify (buf, rev, count);
-#else
- hexify (buf, bin, count);
-#endif
- return buf;
-}
-
-void* C2v(CORE_ADDR addr)
-{
- return (void*) addr;
-}
-
-static
-char *image_ptid(unsigned long ptid)
-{
- static char result[100];
- VG_(sprintf) (result, "id %ld", ptid);
- return result;
-}
-#define get_thread(inf) ((struct thread_info *)(inf))
-static
-void remove_thread_if_not_in_vg_threads (struct inferior_list_entry *inf)
-{
- struct thread_info *thread = get_thread (inf);
- if (!VG_(lwpid_to_vgtid)(thread_to_gdb_id(thread))) {
- dlog(1, "removing gdb ptid %s\n",
- image_ptid(thread_to_gdb_id(thread)));
- remove_thread (thread);
- }
-}
-
-/* synchronize threads known by valgrind and threads known by gdbserver */
-static
-void valgrind_update_threads (int pid)
-{
- ThreadId tid;
- ThreadState *ts;
- unsigned long ptid;
- struct thread_info *ti;
-
- /* call remove_thread for all gdb threads not in valgrind threads */
- for_each_inferior (&all_threads, remove_thread_if_not_in_vg_threads);
-
- /* call add_thread for all valgrind threads not known in gdb all_threads */
- for (tid = 1; tid < VG_N_THREADS; tid++) {
-
-#define LOCAL_THREAD_TRACE " ti* %p vgtid %d status %s as gdb ptid %s lwpid %d\n", \
- ti, tid, VG_(name_of_ThreadStatus) (ts->status), \
- image_ptid (ptid), ts->os_state.lwpid
-
- if (VG_(is_valid_tid) (tid)) {
- ts = VG_(get_ThreadState) (tid);
- ptid = ts->os_state.lwpid;
- ti = gdb_id_to_thread (ptid);
- if (!ti) {
- /* we do not report the threads which are not yet fully
- initialized otherwise this creates duplicated threads
- in gdb: once with pid xxx lwpid 0, then after that
- with pid xxx lwpid yyy. */
- if (ts->status != VgTs_Init) {
- dlog(1, "adding_thread" LOCAL_THREAD_TRACE);
- add_thread (ptid, ts, ptid);
- }
- } else {
- dlog(2, "(known thread)" LOCAL_THREAD_TRACE);
- }
- }
-#undef LOCAL_THREAD_TRACE
- }
-}
-
-/* Return nonzero if the given thread is still alive. */
-static
-int valgrind_thread_alive (unsigned long tid)
-{
- struct thread_info *ti = gdb_id_to_thread(tid);
- ThreadState *tst;
-
- if (ti != NULL) {
- tst = (ThreadState *) inferior_target_data (ti);
- return tst->status != VgTs_Zombie;
- }
- else {
- return 0;
- }
-}
-
-/* allocate and build a register structure containing the shadow registers.
- reg_defs is the normal registers, n is their numbers */
-static
-struct reg* build_shadow_arch (struct reg *reg_defs, int n) {
- int i, r;
- static char *postfix[3] = { "", "s1", "s2" };
- struct reg *new_regs = malloc(3 * n * sizeof(reg_defs[0]));
- int reg_set_len = reg_defs[n-1].offset + reg_defs[n-1].size;
-
- for (i = 0; i < 3; i++) {
- for (r = 0; r < n; r++) {
- new_regs[i*n + r].name = malloc(strlen(reg_defs[r].name)
- + strlen (postfix[i]) + 1);
- strcpy (new_regs[i*n + r].name, reg_defs[r].name);
- strcat (new_regs[i*n + r].name, postfix[i]);
- new_regs[i*n + r].offset = i*reg_set_len + reg_defs[r].offset;
- new_regs[i*n + r].size = reg_defs[r].size;
- dlog(1,
- "%10s Nr %d offset(bit) %d offset(byte) %d size(bit) %d\n",
- new_regs[i*n + r].name, i*n + r, new_regs[i*n + r].offset,
- (new_regs[i*n + r].offset) / 8, new_regs[i*n + r].size);
- }
- }
-
- return new_regs;
-}
-
-/* Fetch one register from valgrind VEX guest state. */
-static
-void fetch_register (int regno)
-{
- int size;
- ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
- ThreadId tid = tst->tid;
-
- if (regno >= the_low_target.num_regs) {
- dlog(0, "error fetch_register regno %d max %d\n",
- regno, the_low_target.num_regs);
- return;
- }
- size = register_size (regno);
- if (size > 0) {
- Bool mod;
- char buf [size];
- VG_(memset) (buf, 0, size); // registers not fetched will be seen as 0.
- (*the_low_target.transfer_register) (tid, regno, buf,
- valgrind_to_gdbserver, size, &mod);
- // Note: the *mod received from transfer_register is not interesting.
- // We are interested to see if the register data in the register cache is modified.
- supply_register (regno, buf, &mod);
- if (mod && VG_(debugLog_getLevel)() > 1) {
- char bufimage [2*size + 1];
- heximage (bufimage, buf, size);
- dlog(2, "fetched register %d size %d name %s value %s tid %d status %s\n",
- regno, size, the_low_target.reg_defs[regno].name, bufimage,
- tid, VG_(name_of_ThreadStatus) (tst->status));
- }
- }
-}
-
-/* Fetch all registers, or just one, from the child process. */
-static
-void usr_fetch_inferior_registers (int regno)
-{
- if (regno == -1 || regno == 0)
- for (regno = 0; regno < the_low_target.num_regs; regno++)
- fetch_register (regno);
- else
- fetch_register (regno);
-}
-
-/* Store our register values back into the inferior.
- If REGNO is -1, do this for all registers.
- Otherwise, REGNO specifies which register (so we can save time). */
-static
-void usr_store_inferior_registers (int regno)
-{
- int size;
- ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
- ThreadId tid = tst->tid;
-
- if (regno >= 0) {
-
- if (regno >= the_low_target.num_regs) {
- dlog(0, "error store_register regno %d max %d\n",
- regno, the_low_target.num_regs);
- return;
- }
-
- size = register_size (regno);
- if (size > 0) {
- Bool mod;
- Addr old_SP, new_SP;
- char buf[size];
-
- if (regno == the_low_target.stack_pointer_regno) {
- /* When the stack pointer register is changed such that
- the stack is extended, we better inform the tool of the
- stack increase. This is needed in particular to avoid
- spurious Memcheck errors during Inferior calls. So, we
- save in old_SP the SP before the change. A change of
- stack pointer is also assumed to have initialised this
- new stack space. For the typical example of an inferior
- call, gdb writes arguments on the stack, and then
- changes the stack pointer. As the stack increase tool
- function might mark it as undefined, we have to call it
- at the good moment. */
- VG_(memset) ((void *) &old_SP, 0, size);
- (*the_low_target.transfer_register) (tid, regno, (void *) &old_SP,
- valgrind_to_gdbserver, size, &mod);
- }
-
- VG_(memset) (buf, 0, size);
- collect_register (regno, buf);
- (*the_low_target.transfer_register) (tid, regno, buf,
- gdbserver_to_valgrind, size, &mod);
- if (mod && VG_(debugLog_getLevel)() > 1) {
- char bufimage [2*size + 1];
- heximage (bufimage, buf, size);
- dlog(2,
- "stored register %d size %d name %s value %s "
- "tid %d status %s\n",
- regno, size, the_low_target.reg_defs[regno].name, bufimage,
- tid, VG_(name_of_ThreadStatus) (tst->status));
- }
- if (regno == the_low_target.stack_pointer_regno) {
- VG_(memcpy) (&new_SP, buf, size);
- if (old_SP > new_SP) {
- Word delta = (Word)new_SP - (Word)old_SP;
- dlog(1,
- " stack increase by stack pointer changed from %p to %p "
- "delta %ld\n",
- (void*) old_SP, (void *) new_SP,
- delta);
- VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, 0 );
- VG_TRACK( new_mem_stack, new_SP, -delta );
- if (VG_(tdict).track_post_mem_write) {
- VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid,
- new_SP, -delta);
- }
- }
- }
- }
- }
- else {
- for (regno = 0; regno < the_low_target.num_regs; regno++)
- usr_store_inferior_registers (regno);
- }
-}
-
-static
-void valgrind_fetch_registers (int regno)
-{
- usr_fetch_inferior_registers (regno);
-}
-
-static
-void valgrind_store_registers (int regno)
-{
- usr_store_inferior_registers (regno);
-}
-
-/* Copy LEN bytes from inferior's memory starting at MEMADDR
- to debugger memory starting at MYADDR. */
-
-static
-int valgrind_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
-{
- const void *sourceaddr = C2v (memaddr);
- dlog(2, "reading memory %p size %d\n", sourceaddr, len);
- if (!VG_(am_is_valid_for_client_or_free_or_resvn) ((Addr) sourceaddr,
- len, VKI_PROT_READ)) {
- dlog(1, "error reading memory %p size %d\n", sourceaddr, len);
- return -1;
- }
- VG_(memcpy) (myaddr, sourceaddr, len);
- return 0;
-}
-
-/* Copy LEN bytes of data from debugger memory at MYADDR
- to inferior's memory at MEMADDR.
- On failure (cannot write the inferior)
- returns the value of errno. */
-
-static
-int valgrind_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
-{
- void *targetaddr = C2v (memaddr);
- dlog(2, "writing memory %p size %d\n", targetaddr, len);
- if (!VG_(am_is_valid_for_client_or_free_or_resvn) ((Addr)targetaddr,
- len, VKI_PROT_WRITE)) {
- dlog(1, "error writing memory %p size %d\n", targetaddr, len);
- return -1;
- }
- if (len > 0) {
- VG_(memcpy) (targetaddr, myaddr, len);
- if (VG_(tdict).track_post_mem_write) {
- /* Inform the tool of the post memwrite. Note that we do the
- minimum necessary to avoid complains from e.g.
- memcheck. The idea is that the debugger is as least
- intrusive as possible. So, we do not inform of the pre
- mem write (and in any case, this would cause problems with
- memcheck that does not like our CorePart in
- pre_mem_write. */
- ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
- ThreadId tid = tst->tid;
- VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid, (Addr) targetaddr, len );
- }
- }
- return 0;
-}
-
-/* insert or remove a breakpoint */
-static
-int valgrind_point (Bool insert, char type, CORE_ADDR addr, int len)
-{
- PointKind kind;
- switch (type) {
- case '0': /* implemented by inserting checks at each instruction in sb */
- kind = software_breakpoint;
- break;
- case '1': /* hw breakpoint, same implementation as sw breakpoint */
- kind = hardware_breakpoint;
- break;
- case '2':
- kind = write_watchpoint;
- break;
- case '3':
- kind = read_watchpoint;
- break;
- case '4':
- kind = access_watchpoint;
- break;
- default:
- vg_assert (0);
- }
-
- /* Attention: gdbserver convention differs: 0 means ok; 1 means not ok */
- if (VG_(gdbserver_point) (kind, insert, addr, len))
- return 0;
- else
- return 1; /* error or unsupported */
-}
-
-static
-void valgrind_send_signal (int sig)
-{
- dlog(1, "valgrind_send_signal %d called ????\n", sig);
-}
-
-static
-char* valgrind_target_xml (void)
-{
- return (char *) the_low_target.target_xml;
-}
-
-static
-char* valgrind_shadow_target_xml (void)
-{
- return (char *) the_low_target.shadow_target_xml;
-}
-
-static
-int valgrind_insert_point (char type, CORE_ADDR addr, int len)
-{
- return valgrind_point (/* insert */ True, type, addr, len);
-}
-
-static
-int valgrind_remove_point (char type, CORE_ADDR addr, int len)
-{
- return valgrind_point (/* insert*/ False, type, addr, len);
-}
-
-static CORE_ADDR stopped_data_address = 0;
-void VG_(set_watchpoint_stop_address) (Addr addr)
-{
- stopped_data_address = addr;
-}
-
-static
-int valgrind_stopped_by_watchpoint (void)
-{
- return stopped_data_address != 0;
-}
-
-static
-CORE_ADDR valgrind_stopped_data_address (void)
-{
- return stopped_data_address;
-}
-
-/* pc at which we last stopped */
-static CORE_ADDR stop_pc;
-
-/* pc at which we resume.
- If stop_pc != resume_pc, it means
- gdb/gdbserver has changed the pc so as to have either
- a "continue by jumping at that address"
- or a "continue at that address to call some code from gdb".
-*/
-static CORE_ADDR resume_pc;
-
-static int vki_signal_to_report;
-
-void gdbserver_signal_encountered (Int vki_sigNo)
-{
- vki_signal_to_report = vki_sigNo;
-}
-
-static int vki_signal_to_deliver;
-Bool gdbserver_deliver_signal (Int vki_sigNo)
-{
- return vki_sigNo == vki_signal_to_deliver;
-}
-
-static
-char* sym (Addr addr)
-{
- static char buf[200];
- VG_(describe_IP) (addr, buf, 200);
- return buf;
-}
-
-ThreadId vgdb_interrupted_tid = 0;
-/* called to wait for the process to stop */
-static
-unsigned char valgrind_wait (char *ourstatus)
-{
- int pid;
- unsigned long wptid;
- ThreadState *tst;
- enum target_signal sig;
-
- pid = VG_(getpid) ();
- dlog(1, "enter valgrind_wait pid %d\n", pid);
-
- regcache_invalidate();
- valgrind_update_threads(pid);
-
- /* in valgrind, we consider that a wait always succeeds with STOPPED 'T'
- and with a signal TRAP (i.e. a breakpoint), unless there is
- a signal to report. */
- *ourstatus = 'T';
- if (vki_signal_to_report == 0)
- sig = TARGET_SIGNAL_TRAP;
- else {
- sig = target_signal_from_host(vki_signal_to_report);
- vki_signal_to_report = 0;
- }
-
- if (vgdb_interrupted_tid != 0)
- tst = VG_(get_ThreadState) (vgdb_interrupted_tid);
- else
- tst = VG_(get_ThreadState) (VG_(running_tid));
- wptid = tst->os_state.lwpid;
- /* we can only change the current_inferior when the wptid references
- an existing thread. Otherwise, we are still in the init phase.
- (hack similar to main thread hack in valgrind_update_threads) */
- if (tst->os_state.lwpid)
- current_inferior = gdb_id_to_thread (wptid);
- stop_pc = (*the_low_target.get_pc) ();
-
- dlog(1,
- "exit valgrind_wait returns ptid %s stop_pc %s signal %d\n",
- image_ptid (wptid), sym (stop_pc), sig);
- return sig;
-}
-
-/* 0 => not single stepping.
- 1 => single stepping asked by gdb
- 2 => single stepping asked by valgrind (watchpoint) */
-static int stepping = 0;
-
-/* called when the process is to be resumed */
-static
-void valgrind_resume (struct thread_resume *resume_info)
-{
- dlog(1,
- "resume_info thread %ld leave_stopped %d step %d sig %d stepping %d\n",
- resume_info->thread,
- resume_info->leave_stopped,
- resume_info->step,
- resume_info->sig,
- stepping);
- if (valgrind_stopped_by_watchpoint()) {
- dlog(1, "clearing watchpoint stopped_data_address %p\n",
- C2v(stopped_data_address));
- VG_(set_watchpoint_stop_address) ((Addr) 0);
- }
- vki_signal_to_deliver = resume_info->sig;
-
- stepping = resume_info->step;
- resume_pc = (*the_low_target.get_pc) ();
- if (resume_pc != stop_pc) {
- dlog(1,
- "stop_pc %p changed to be resume_pc %s\n",
- C2v(stop_pc), sym(resume_pc));
- }
- regcache_invalidate();
-}
-
-Addr valgrind_get_ignore_break_once(void)
-{
- if (valgrind_single_stepping())
- return resume_pc;
- else
- return 0;
-}
-
-
-void valgrind_set_single_stepping(Bool set)
-{
- if (set)
- stepping = 2;
- else
- stepping = 0;
-}
-
-Bool valgrind_single_stepping(void)
-{
- if (stepping)
- return True;
- else
- return False;
-}
-
-static struct target_ops valgrind_target_ops = {
- valgrind_thread_alive,
- valgrind_resume,
- valgrind_wait,
- valgrind_fetch_registers,
- valgrind_store_registers,
- valgrind_read_memory,
- valgrind_write_memory,
- valgrind_send_signal,
- valgrind_target_xml,
- valgrind_shadow_target_xml,
- valgrind_insert_point,
- valgrind_remove_point,
- valgrind_stopped_by_watchpoint,
- valgrind_stopped_data_address,
-};
-
-
-/* returns a pointer to the architecture state corresponding to
- the provided register set: 0 => normal guest registers,
- 1 => shadow1
- 2 => shadow2
-*/
-VexGuestArchState* get_arch (int set, ThreadState* tst)
-{
- switch (set) {
- case 0: return &tst->arch.vex;
- case 1: return &tst->arch.vex_shadow1;
- case 2: return &tst->arch.vex_shadow2;
- default: vg_assert(0);
- }
-}
-
-static int non_shadow_num_regs = 0;
-static struct reg *non_shadow_reg_defs = NULL;
-void initialize_shadow_low(Bool shadow_mode)
-{
- if (non_shadow_reg_defs == NULL) {
- non_shadow_reg_defs = the_low_target.reg_defs;
- non_shadow_num_regs = the_low_target.num_regs;
- }
-
- regcache_invalidate();
- if (the_low_target.reg_defs != non_shadow_reg_defs) {
- free (the_low_target.reg_defs);
- }
- if (shadow_mode) {
- the_low_target.num_regs = 3 * non_shadow_num_regs;
- the_low_target.reg_defs = build_shadow_arch (non_shadow_reg_defs, non_shadow_num_regs);
- } else {
- the_low_target.num_regs = non_shadow_num_regs;
- the_low_target.reg_defs = non_shadow_reg_defs;
- }
- set_register_cache (the_low_target.reg_defs, the_low_target.num_regs);
-}
-
-void initialize_low(void)
-{
- set_target_ops (&valgrind_target_ops);
-
-#if defined(VGA_x86)
- x86_init_architecture(&the_low_target);
-#elif defined(VGA_amd64)
- amd64_init_architecture(&the_low_target);
-#elif defined(VGA_arm)
- arm_init_architecture(&the_low_target);
-#elif defined(VGA_ppc32)
- ppc32_init_architecture(&the_low_target);
-#elif defined(VGA_ppc64)
- ppc64_init_architecture(&the_low_target);
-#elif defined(VGA_s390x)
- s390x_init_architecture(&the_low_target);
-#else
- architecture missing in valgrind-low.c
-#endif
-
-}
Modified: trunk/coregrind/m_gdbserver/remote-utils.c (+26 -4)
===================================================================
--- trunk/coregrind/m_gdbserver/remote-utils.c 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/remote-utils.c 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -542,6 +542,29 @@
return i;
}
+/* builds an image of bin according to byte order of the architecture
+ Useful for register and int image */
+char* heximage (char *buf, char *bin, int count)
+{
+#if defined(VGA_x86) || defined(VGA_amd64)
+ char rev[count];
+ /* note: no need for trailing \0, length is known with count */
+ int i;
+ for (i = 0; i < count; i++)
+ rev[i] = bin[count - i - 1];
+ hexify (buf, rev, count);
+#else
+ hexify (buf, bin, count);
+#endif
+ return buf;
+}
+
+void* C2v(CORE_ADDR addr)
+{
+ return (void*) addr;
+}
+
+
/* Convert BUFFER, binary data at least LEN bytes long, into escaped
binary data in OUT_BUF. Set *OUT_LEN to the length of the data
encoded in OUT_BUF, and return the number of bytes in OUT_BUF
@@ -729,7 +752,7 @@
/* Check for an input interrupt while we're here. */
if (cc == '\003')
- (*the_target->send_signal) (VKI_SIGINT);
+ dlog(1, "Received 0x03 character (SIGINT)\n");
}
while (cc != '+');
@@ -962,15 +985,14 @@
if (status == 'T') {
const char **regp = gdbserver_expedite_regs;
- if (the_target->stopped_by_watchpoint != NULL
- && (*the_target->stopped_by_watchpoint) ()) {
+ if (valgrind_stopped_by_watchpoint()) {
CORE_ADDR addr;
int i;
strncpy (buf, "watch:", 6);
buf += 6;
- addr = (*the_target->stopped_data_address) ();
+ addr = valgrind_stopped_data_address ();
/* Convert each byte of the address into two hexadecimal chars.
Note that we take sizeof (void *) instead of sizeof (addr);
Modified: trunk/coregrind/Makefile.am (+0 -1)
===================================================================
--- trunk/coregrind/Makefile.am 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/Makefile.am 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -312,7 +312,6 @@
m_gdbserver/signals.c \
m_gdbserver/target.c \
m_gdbserver/utils.c \
- m_gdbserver/valgrind-low.c \
m_gdbserver/valgrind-low-x86.c \
m_gdbserver/valgrind-low-amd64.c \
m_gdbserver/valgrind-low-arm.c \
Modified: trunk/coregrind/m_gdbserver/valgrind-low-amd64.c (+1 -10)
===================================================================
--- trunk/coregrind/m_gdbserver/valgrind-low-amd64.c 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/valgrind-low-amd64.c 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -160,16 +160,7 @@
case 13: VG_(transfer) (&amd64->guest_R13, buf, dir, size, mod); break;
case 14: VG_(transfer) (&amd64->guest_R14, buf, dir, size, mod); break;
case 15: VG_(transfer) (&amd64->guest_R15, buf, dir, size, mod); break;
- case 16:
- VG_(transfer) (&amd64->guest_RIP, buf, dir, size, mod);
- if (*mod && VG_(debugLog_getLevel)() > 2) {
- char bufimage [2*sizeof(amd64->guest_IP_AT_SYSCALL) + 1];
- heximage (bufimage,
- (char *) &amd64->guest_IP_AT_SYSCALL,
- sizeof(amd64->guest_IP_AT_SYSCALL));
- dlog(3, "guest_IP_AT_SYSCALL %s\n", bufimage);
- }
- break;
+ case 16: VG_(transfer) (&amd64->guest_RIP, buf, dir, size, mod); break;
case 17:
if (dir == valgrind_to_gdbserver) {
ULong rflags;
Modified: trunk/coregrind/m_gdbserver/m_gdbserver.c (+0 -7)
===================================================================
--- trunk/coregrind/m_gdbserver/m_gdbserver.c 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/m_gdbserver.c 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -130,13 +130,6 @@
static void call_gdbserver ( ThreadId tid , CallReason reason);
-/* convert from CORE_ADDR to void* */
-static
-void* C2v(CORE_ADDR addr)
-{
- return (void*) addr;
-}
-
/* Describes the address addr (for debugging/printing purposes).
Last two results are kept. A third call will replace the
oldest result. */
Modified: trunk/coregrind/m_gdbserver/target.h (+151 -93)
===================================================================
--- trunk/coregrind/m_gdbserver/target.h 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/target.h 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -1,6 +1,7 @@
-/* Target operations for the remote server for GDB.
- Copyright (C) 2002, 2003, 2004, 2005
+/* Target operations for the Valgrind remote server for GDB.
+ Copyright (C) 2002, 2003, 2004, 2005, 2012
Free Software Foundation, Inc.
+ Philippe Waroquiers.
Contributed by MontaVista Software.
@@ -25,134 +26,189 @@
#ifndef TARGET_H
#define TARGET_H
-/* This structure describes how to resume a particular thread (or
- all threads) based on the client's request. If thread is -1, then
- this entry applies to all threads. These are generally passed around
- as an array, and terminated by a thread == -1 entry. */
+/* This file defines the architecture independent Valgrind gdbserver
+ high level operations such as read memory, get/set registers, ...
-struct thread_resume
-{
- unsigned long thread;
+ These high level operations are called by the gdbserver
+ protocol implementation (e.g. typically server.c).
+
+ For some of these high level operations, target.c will call
+ low level operations dependent on the architecture.
+
+ For example, getting or setting the registers will work on a
+ register cache. The exact details of the registers (how much,
+ their size, etc) is not defined by target.c or the register cache.
- /* If non-zero, leave this thread stopped. */
- int leave_stopped;
+ Such architecture dependent information is defined by
+ valgrind_low.h/valgrind-low-xxxxx.c providing 'low level operations'
+ specific to the xxxxx architecture (for example,
+ valgrind-low-x86.c, valgrind-low-armc.c). */
+
+/* -------------------------------------------------------------------------- */
+/* ------------------------ Initialisation ---------------------------------- */
+/* -------------------------------------------------------------------------- */
- /* If non-zero, we want to single-step. */
- int step;
+/* Initialize the Valgrind high target. This will in turn
+ initialise the low (architecture specific) target. */
+extern void valgrind_initialize_target(void);
- /* If non-zero, send this signal when we resume. */
- int sig;
-};
+/* initialize or re-initialize the register set of the low target.
+ if shadow_mode, then (re-)define the normal and valgrind shadow registers
+ else (re-)define only the normal registers. */
+extern void initialize_shadow_low (Bool shadow_mode);
-struct target_ops
-{
- /* Return 1 iff the thread with process ID PID is alive. */
+/* Returns the name of the xml target description file.
+ returns NULL if no xml target description available. */
+extern char* valgrind_target_xml (void);
- int (*thread_alive) (unsigned long pid);
+/* Same but describes also the shadow registers. */
+extern char* valgrind_shadow_target_xml (void);
- /* Resume the inferior process. */
- void (*resume) (struct thread_resume *resume_info);
- /* Wait for the inferior process to change state.
+/* -------------------------------------------------------------------------- */
+/* --------------------------- Execution control ---------------------------- */
+/* -------------------------------------------------------------------------- */
- STATUS will be filled in with a response code to send to GDB.
+/* This structure describes how to resume the execution.
+ Currently, there is no way to resume only a specific thread. */
+struct thread_resume
+{
+ /* If non-zero, we want to single-step. */
+ int step;
- Returns the signal which caused the process to stop, in the
- remote protocol numbering (e.g. TARGET_SIGNAL_STOP), or the
- exit code as an integer if *STATUS is 'W'. */
+ /* If non-zero, send this signal when we resume. */
+ int sig;
+};
- unsigned char (*wait) (char *status);
+/* Prepare to Resume (i.e. restart) the guest.
+ The resume info indicates how the resume will be done.
+ In case GDB has changed the program counter, valgrind_resume
+ will also ensure that the execution will be resumed at this
+ new program counter.
+ The Resume is really only executed once the gdbserver
+ returns (giving back the control to Valgrind). */
+extern void valgrind_resume (struct thread_resume *resume_info);
- /* Fetch registers from the inferior process.
+/* When Valgrind gets the control, it will execute the guest
+ process till there is a reason to call the gdbserver
+ again (e.g. because a breakpoint is encountered or the
+ tool reports an error).
+ In such case, the executionof guest code stops, and the
+ control is given to gdbserver. Gdbserver will send a resume
+ reply packet to GDB.
- If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
+ valgrind_wait gets from Valgrind data structures the
+ information needed produce the resume reply for GDB:
+ a.o. OURSTATUS will be filled in with a response code to send to GDB.
- void (*fetch_registers) (int regno);
+ Returns the signal which caused the process to stop, in the
+ remote protocol numbering (e.g. TARGET_SIGNAL_STOP), or the
+ exit code as an integer if *OURSTATUS is 'W'. */
+extern unsigned char valgrind_wait (char *outstatus);
- /* Store registers to the inferior process.
+/* When execution is stopped and gdbserver has control, more
+ info about the stop reason can be retrieved using the following
+ functions. */
- If REGNO is -1, store all registers; otherwise, store at least REGNO. */
+/* gets the addr at which a (possible) break must be ignored once.
+ If there is no such break to be ignored once, 0 is returned.
+ This is needed for the following case:
+ The user sets a break at address AAA.
+ The break is encountered. Then the user does stepi
+ (i.e. step one instruction).
+ In such a case, the already encountered break must be ignored
+ to ensure the stepi will advance by one instruction: a "break"
+ is implemented in valgrind by some helper code just after the
+ instruction mark at which the break is set. This helper code
+ verifies if either there is a break at the current PC
+ or if we are in stepping mode. If we are in stepping mode,
+ the already encountered break must be ignored once to advance
+ to the next instruction.
+ ??? need to check if this is *really* needed. */
+extern Addr valgrind_get_ignore_break_once(void);
- void (*store_registers) (int regno);
+/* When addr > 0, ensures the next resume reply packet informs
+ gdb about the encountered watchpoint.
+ valgrind_stopped_by_watchpoint() will return 1 till reset.
+ Use addr 0x0 to reset. */
+extern void VG_(set_watchpoint_stop_address) (Addr addr);
- /* Read memory from the inferior process. This should generally be
- called through read_inferior_memory, which handles breakpoint shadowing.
+/* Returns 1 if target was stopped due to a watchpoint hit, 0 otherwise. */
+extern int valgrind_stopped_by_watchpoint (void);
- Read LEN bytes at MEMADDR into a buffer at MYADDR.
-
- Returns 0 on success and errno on failure. */
+/* Returns the address associated with the watchpoint that hit, if any;
+ returns 0 otherwise. */
+extern CORE_ADDR valgrind_stopped_data_address (void);
- int (*read_memory) (CORE_ADDR memaddr, unsigned char *myaddr, int len);
+/* True if gdbserver is single stepping the valgrind process */
+extern Bool valgrind_single_stepping(void);
- /* Write memory to the inferior process. This should generally be
- called through write_inferior_memory, which handles breakpoint shadowing.
+/* Set Valgrind in single stepping mode or not according to Bool. */
+extern void valgrind_set_single_stepping(Bool);
- Write LEN bytes from the buffer at MYADDR to MEMADDR.
+/* -------------------------------------------------------------------------- */
+/* ----------------- Examining/modifying data while stopped ----------------- */
+/* -------------------------------------------------------------------------- */
- Returns 0 on success and errno on failure. */
+/* Return 1 iff the thread with ID tid is alive. */
+extern int valgrind_thread_alive (unsigned long tid);
- int (*write_memory) (CORE_ADDR memaddr, const unsigned char *myaddr,
- int len);
+/* Allows to controls the thread (current_inferior) used for following
+ valgrind_(fetch|store)_registers calls.
+ If USE_GENERAL,
+ current_inferior is set to general_thread
+ else
+ current_inferior is set to step_thread or else cont_thread.
+ If the above gives no valid thread, then current_inferior is
+ set to the first valid thread. */
+extern void set_desired_inferior (int use_general);
- /* Send a signal to the inferior process, however is appropriate. */
- void (*send_signal) (int);
+/* Fetch registers from the current_inferior thread.
+ If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
+extern void valgrind_fetch_registers (int regno);
- /* Returns the name of the xml target description file.
- returns NULL if no xml target description available. */
- char* (*target_xml)(void);
+/* Store registers to the current_inferior thread.
+ If REGNO is -1, store all registers; otherwise, store at least REGNO. */
+extern void valgrind_store_registers (int regno);
- /* Same but describes also the shadow registers. */
- char* (*shadow_target_xml)(void);
- /* Insert and remove a hardware watchpoint.
- Returns 0 on success, -1 on failure and 1 on unsupported.
- The type is coded as follows:
- 2 = write watchpoint
- 3 = read watchpoint
- 4 = access watchpoint
- */
- int (*insert_watchpoint) (char type, CORE_ADDR addr, int len);
- int (*remove_watchpoint) (char type, CORE_ADDR addr, int len);
+/* Read memory from the inferior process.
+ Read LEN bytes at MEMADDR into a buffer at MYADDR.
+ Returns 0 on success and errno on failure. */
+extern int valgrind_read_memory (CORE_ADDR memaddr,
+ unsigned char *myaddr, int len);
- /* Returns 1 if target was stopped due to a watchpoint hit, 0 otherwise. */
+/* Write memory to the inferior process.
+ Write LEN bytes from the buffer at MYADDR to MEMADDR.
+ Returns 0 on success and errno on failure. */
+extern int valgrind_write_memory (CORE_ADDR memaddr,
+ const unsigned char *myaddr, int len);
- int (*stopped_by_watchpoint) (void);
- /* Returns the address associated with the watchpoint that hit, if any;
- returns 0 otherwise. */
+/* Insert and remove a hardware watchpoint.
+ Returns 0 on success, -1 on failure and 1 on unsupported.
+ The type is coded as follows:
+ 2 = write watchpoint
+ 3 = read watchpoint
+ 4 = access watchpoint
+*/
+extern int valgrind_insert_watchpoint (char type, CORE_ADDR addr, int len);
+extern int valgrind_remove_watchpoint (char type, CORE_ADDR addr, int len);
- CORE_ADDR (*stopped_data_address) (void);
-};
+/* -------------------------------------------------------------------------- */
+/* ----------- Utils functions for low level arch specific files ------------ */
+/* -------------------------------------------------------------------------- */
-extern struct target_ops *the_target;
+/* returns a pointer to the architecture state corresponding to
+ the provided register set: 0 => normal guest registers,
+ 1 => shadow1
+ 2 => shadow2
+*/
+extern VexGuestArchState* get_arch (int set, ThreadState* tst);
-void set_target_ops (struct target_ops *);
-
-#define detach_inferior() \
- (*the_target->detach) ()
-
-#define mythread_alive(pid) \
- (*the_target->thread_alive) (pid)
-
-#define fetch_inferior_registers(regno) \
- (*the_target->fetch_registers) (regno)
-
-#define store_inferior_registers(regno) \
- (*the_target->store_registers) (regno)
-
-#define mywait(statusp) \
- (*the_target->wait) (statusp)
-
-int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
-
-int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
- int len);
-
-void set_desired_inferior (int id);
-
/* like memcpy but first check if content of destination and source
differs. If no difference, no copy is done, *mod set to False.
If different; copy is done, *mod set to True. */
@@ -173,4 +229,6 @@
SizeT sz,
Bool *mod);
+
+
#endif /* TARGET_H */
Modified: trunk/coregrind/m_gdbserver/target.c (+543 -37)
===================================================================
--- trunk/coregrind/m_gdbserver/target.c 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/target.c 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -23,9 +23,532 @@
Boston, MA 02110-1301, USA. */
#include "server.h"
+#include "target.h"
+#include "regdef.h"
+#include "regcache.h"
+#include "valgrind_low.h"
+#include "gdb/signals.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_tool_machine.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_transtab.h"
+#include "pub_core_gdbserver.h"
+#include "pub_tool_debuginfo.h"
-struct target_ops *the_target;
+/* the_low_target defines the architecture specific aspects depending
+ on the cpu */
+static struct valgrind_target_ops the_low_target;
+
+static
+char *image_ptid(unsigned long ptid)
+{
+ static char result[100];
+ VG_(sprintf) (result, "id %ld", ptid);
+ return result;
+}
+#define get_thread(inf) ((struct thread_info *)(inf))
+static
+void remove_thread_if_not_in_vg_threads (struct inferior_list_entry *inf)
+{
+ struct thread_info *thread = get_thread (inf);
+ if (!VG_(lwpid_to_vgtid)(thread_to_gdb_id(thread))) {
+ dlog(1, "removing gdb ptid %s\n",
+ image_ptid(thread_to_gdb_id(thread)));
+ remove_thread (thread);
+ }
+}
+
+/* synchronize threads known by valgrind and threads known by gdbserver */
+static
+void valgrind_update_threads (int pid)
+{
+ ThreadId tid;
+ ThreadState *ts;
+ unsigned long ptid;
+ struct thread_info *ti;
+
+ /* call remove_thread for all gdb threads not in valgrind threads */
+ for_each_inferior (&all_threads, remove_thread_if_not_in_vg_threads);
+
+ /* call add_thread for all valgrind threads not known in gdb all_threads */
+ for (tid = 1; tid < VG_N_THREADS; tid++) {
+
+#define LOCAL_THREAD_TRACE " ti* %p vgtid %d status %s as gdb ptid %s lwpid %d\n", \
+ ti, tid, VG_(name_of_ThreadStatus) (ts->status), \
+ image_ptid (ptid), ts->os_state.lwpid
+
+ if (VG_(is_valid_tid) (tid)) {
+ ts = VG_(get_ThreadState) (tid);
+ ptid = ts->os_state.lwpid;
+ ti = gdb_id_to_thread (ptid);
+ if (!ti) {
+ /* we do not report the threads which are not yet fully
+ initialized otherwise this creates duplicated threads
+ in gdb: once with pid xxx lwpid 0, then after that
+ with pid xxx lwpid yyy. */
+ if (ts->status != VgTs_Init) {
+ dlog(1, "adding_thread" LOCAL_THREAD_TRACE);
+ add_thread (ptid, ts, ptid);
+ }
+ } else {
+ dlog(2, "(known thread)" LOCAL_THREAD_TRACE);
+ }
+ }
+#undef LOCAL_THREAD_TRACE
+ }
+}
+
+static
+struct reg* build_shadow_arch (struct reg *reg_defs, int n) {
+ int i, r;
+ static char *postfix[3] = { "", "s1", "s2" };
+ struct reg *new_regs = malloc(3 * n * sizeof(reg_defs[0]));
+ int reg_set_len = reg_defs[n-1].offset + reg_defs[n-1].size;
+
+ for (i = 0; i < 3; i++) {
+ for (r = 0; r < n; r++) {
+ new_regs[i*n + r].name = malloc(strlen(reg_defs[r].name)
+ + strlen (postfix[i]) + 1);
+ strcpy (new_regs[i*n + r].name, reg_defs[r].name);
+ strcat (new_regs[i*n + r].name, postfix[i]);
+ new_regs[i*n + r].offset = i*reg_set_len + reg_defs[r].offset;
+ new_regs[i*n + r].size = reg_defs[r].size;
+ dlog(1,
+ "%10s Nr %d offset(bit) %d offset(byte) %d size(bit) %d\n",
+ new_regs[i*n + r].name, i*n + r, new_regs[i*n + r].offset,
+ (new_regs[i*n + r].offset) / 8, new_regs[i*n + r].size);
+ }
+ }
+
+ return new_regs;
+}
+
+
+static CORE_ADDR stopped_data_address = 0;
+void VG_(set_watchpoint_stop_address) (Addr addr)
+{
+ stopped_data_address = addr;
+}
+
+int valgrind_stopped_by_watchpoint (void)
+{
+ return stopped_data_address != 0;
+}
+
+CORE_ADDR valgrind_stopped_data_address (void)
+{
+ return stopped_data_address;
+}
+
+/* pc at which we last stopped */
+static CORE_ADDR stop_pc;
+
+/* pc at which we resume.
+ If stop_pc != resume_pc, it means
+ gdb/gdbserver has changed the pc so as to have either
+ a "continue by jumping at that address"
+ or a "continue at that address to call some code from gdb".
+*/
+static CORE_ADDR resume_pc;
+
+static int vki_signal_to_report;
+
+void gdbserver_signal_encountered (Int vki_sigNo)
+{
+ vki_signal_to_report = vki_sigNo;
+}
+
+static int vki_signal_to_deliver;
+Bool gdbserver_deliver_signal (Int vki_sigNo)
+{
+ return vki_sigNo == vki_signal_to_deliver;
+}
+
+static
+char* sym (Addr addr)
+{
+ static char buf[200];
+ VG_(describe_IP) (addr, buf, 200);
+ return buf;
+}
+
+ThreadId vgdb_interrupted_tid = 0;
+
+/* 0 => not single stepping.
+ 1 => single stepping asked by gdb
+ 2 => single stepping asked by valgrind (watchpoint) */
+static int stepping = 0;
+
+Addr valgrind_get_ignore_break_once(void)
+{
+ if (valgrind_single_stepping())
+ return resume_pc;
+ else
+ return 0;
+}
+
+void valgrind_set_single_stepping(Bool set)
+{
+ if (set)
+ stepping = 2;
+ else
+ stepping = 0;
+}
+
+Bool valgrind_single_stepping(void)
+{
+ if (stepping)
+ return True;
+ else
+ return False;
+}
+
+int valgrind_thread_alive (unsigned long tid)
+{
+ struct thread_info *ti = gdb_id_to_thread(tid);
+ ThreadState *tst;
+
+ if (ti != NULL) {
+ tst = (ThreadState *) inferior_target_data (ti);
+ return tst->status != VgTs_Zombie;
+ }
+ else {
+ return 0;
+ }
+}
+
+void valgrind_resume (struct thread_resume *resume_info)
+{
+ dlog(1,
+ "resume_info step %d sig %d stepping %d\n",
+ resume_info->step,
+ resume_info->sig,
+ stepping);
+ if (valgrind_stopped_by_watchpoint()) {
+ dlog(1, "clearing watchpoint stopped_data_address %p\n",
+ C2v(stopped_data_address));
+ VG_(set_watchpoint_stop_address) ((Addr) 0);
+ }
+ vki_signal_to_deliver = resume_info->sig;
+
+ stepping = resume_info->step;
+ resume_pc = (*the_low_target.get_pc) ();
+ if (resume_pc != stop_pc) {
+ dlog(1,
+ "stop_pc %p changed to be resume_pc %s\n",
+ C2v(stop_pc), sym(resume_pc));
+ }
+ regcache_invalidate();
+}
+
+unsigned char valgrind_wait (char *ourstatus)
+{
+ int pid;
+ unsigned long wptid;
+ ThreadState *tst;
+ enum target_signal sig;
+
+ pid = VG_(getpid) ();
+ dlog(1, "enter valgrind_wait pid %d\n", pid);
+
+ regcache_invalidate();
+ valgrind_update_threads(pid);
+
+ /* in valgrind, we consider that a wait always succeeds with STOPPED 'T'
+ and with a signal TRAP (i.e. a breakpoint), unless there is
+ a signal to report. */
+ *ourstatus = 'T';
+ if (vki_signal_to_report == 0)
+ sig = TARGET_SIGNAL_TRAP;
+ else {
+ sig = target_signal_from_host(vki_signal_to_report);
+ vki_signal_to_report = 0;
+ }
+
+ if (vgdb_interrupted_tid != 0)
+ tst = VG_(get_ThreadState) (vgdb_interrupted_tid);
+ else
+ tst = VG_(get_ThreadState) (VG_(running_tid));
+ wptid = tst->os_state.lwpid;
+ /* we can only change the current_inferior when the wptid references
+ an existing thread. Otherwise, we are still in the init phase.
+ (hack similar to main thread hack in valgrind_update_threads) */
+ if (tst->os_state.lwpid)
+ current_inferior = gdb_id_to_thread (wptid);
+ stop_pc = (*the_low_target.get_pc) ();
+
+ dlog(1,
+ "exit valgrind_wait returns ptid %s stop_pc %s signal %d\n",
+ image_ptid (wptid), sym (stop_pc), sig);
+ return sig;
+}
+
+/* Fetch one register from valgrind VEX guest state. */
+static
+void fetch_register (int regno)
+{
+ int size;
+ ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
+ ThreadId tid = tst->tid;
+
+ if (regno >= the_low_target.num_regs) {
+ dlog(0, "error fetch_register regno %d max %d\n",
+ regno, the_low_target.num_regs);
+ return;
+ }
+ size = register_size (regno);
+ if (size > 0) {
+ Bool mod;
+ char buf [size];
+ VG_(memset) (buf, 0, size); // registers not fetched will be seen as 0.
+ (*the_low_target.transfer_register) (tid, regno, buf,
+ valgrind_to_gdbserver, size, &mod);
+ // Note: the *mod received from transfer_register is not interesting.
+ // We are interested to see if the register data in the register cache is modified.
+ supply_register (regno, buf, &mod);
+ if (mod && VG_(debugLog_getLevel)() > 1) {
+ char bufimage [2*size + 1];
+ heximage (bufimage, buf, size);
+ dlog(2, "fetched register %d size %d name %s value %s tid %d status %s\n",
+ regno, size, the_low_target.reg_defs[regno].name, bufimage,
+ tid, VG_(name_of_ThreadStatus) (tst->status));
+ }
+ }
+}
+
+/* Fetch all registers, or just one, from the child process. */
+static
+void usr_fetch_inferior_registers (int regno)
+{
+ if (regno == -1 || regno == 0)
+ for (regno = 0; regno < the_low_target.num_regs; regno++)
+ fetch_register (regno);
+ else
+ fetch_register (regno);
+}
+
+/* Store our register values back into the inferior.
+ If REGNO is -1, do this for all registers.
+ Otherwise, REGNO specifies which register (so we can save time). */
+static
+void usr_store_inferior_registers (int regno)
+{
+ int size;
+ ThreadState *tst = (ThreadState *) inferior_target_data (current_inferior);
+ ThreadId tid = tst->tid;
+
+ if (regno >= 0) {
+
+ if (regno >= the_low_target.num_regs) {
+ dlog(0, "error store_register regno %d max %d\n",
+ regno, the_low_target.num_regs);
+ return;
+ }
+
+ size = register_size (regno);
+ if (size > 0) {
+ Bool mod;
+ Addr old_SP, new_SP;
+ char buf[size];
+
+ if (regno == the_low_target.stack_pointer_regno) {
+ /* When the stack pointer register is changed such that
+ the stack is extended, we better inform the tool of the
+ stack increase. This is needed in particular to avoid
+ spurious Memcheck errors during Inferior calls. So, we
+ save in old_SP the SP before the change. A change of
+ stack pointer is also assumed to have initialised this
+ new stack space. For the typical example of an inferior
+ call, gdb writes arguments on the stack, and then
+ changes the stack pointer. As the stack increase tool
+ function might mark it as undefined, we have to call it
+ at the good moment. */
+ VG_(memset) ((void *) &old_SP, 0, size);
+ (*the_low_target.transfer_register) (tid, regno, (void *) &old_SP,
+ valgrind_to_gdbserver, size, &mod);
+ }
+
+ VG_(memset) (buf, 0, size);
+ collect_register (regno, buf);
+ (*the_low_target.transfer_register) (tid, regno, buf,
+ gdbserver_to_valgrind, size, &mod);
+ if (mod && VG_(debugLog_getLevel)() > 1) {
+ char bufimage [2*size + 1];
+ heximage (bufimage, buf, size);
+ dlog(2,
+ "stored register %d size %d name %s value %s "
+ "tid %d status %s\n",
+ regno, size, the_low_target.reg_defs[regno].name, bufimage,
+ tid, VG_(name_of_ThreadStatus) (tst->status));
+ }
+ if (regno == the_low_target.stack_pointer_regno) {
+ VG_(memcpy) (&new_SP, buf, size);
+ if (old_SP > new_SP) {
+ Word delta = (Word)new_SP - (Word)old_SP;
+ dlog(1,
+ " stack increase by stack pointer changed from %p to %p "
+ "delta %ld\n",
+ (void*) old_SP, (void *) new_SP,
+ delta);
+ VG_TRACK( new_mem_stack_w_ECU, new_SP, -delta, 0 );
+ VG_TRACK( new_mem_stack, new_SP, -delta );
+ if (VG_(tdict).track_post_mem_write) {
+ VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid,
+ new_SP, -delta);
+ }
+ }
+ }
+ }
+ }
+ else {
+ for (regno = 0; regno < the_low_target.num_regs; regno++)
+ usr_store_inferior_registers (regno);
+ }
+}
+
+void valgrind_fetch_registers (int regno)
+{
+ usr_fetch_inferior_registers (regno);
+}
+
+void valgrind_store_registers (int regno)
+{
+ usr_store_inferior_registers (regno);
+}
+
+int valgrind_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+ const void *sourceaddr = C2v (memaddr);
+ dlog(2, "reading memory %p size %d\n", sourceaddr, len);
+ if (!VG_(am_is_valid_for_client_or_free_or_resvn) ((Addr) sourceaddr,
+ len, VKI_PROT_READ)) {
+ dlog(1, "error reading memory %p size %d\n", sourceaddr, len);
+ return -1;
+ }
+ VG_(memcpy) (myaddr, sourceaddr, len);
+ return 0;
+}
+
+int valgrind_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+ void *targetaddr = C2v (memaddr);
+ dlog(2, "writing memory %p size %d\n", targetaddr, len);
+ if (!VG_(am_is_valid_for_client_or_free_or_resvn) ((Addr)targetaddr,
+ len, VKI_PROT_WRITE)) {
+ dlog(1, "error writing memory %p size %d\n", targetaddr, len);
+ return -1;
+ }
+ if (len > 0) {
+ VG_(memcpy) (targetaddr, myaddr, len);
+ if (VG_(tdict).track_post_mem_write) {
+ /* Inform the tool of the post memwrite. Note that we do the
+ minimum necessary to avoid complains from e.g.
+ memcheck. The idea is that the debugger is as least
+ intrusive as possible. So, we do not inform of the pre
+ mem write (and in any case, this would cause problems with
+ memcheck that does not like our CorePart in
+ pre_mem_write. */
+ ThreadState *tst =
+ (ThreadState *) inferior_target_data (current_inferior);
+ ThreadId tid = tst->tid;
+ VG_(tdict).track_post_mem_write( Vg_CoreClientReq, tid,
+ (Addr) targetaddr, len );
+ }
+ }
+ return 0;
+}
+
+/* insert or remove a breakpoint */
+static
+int valgrind_point (Bool insert, char type, CORE_ADDR addr, int len)
+{
+ PointKind kind;
+ switch (type) {
+ case '0': /* implemented by inserting checks at each instruction in sb */
+ kind = software_breakpoint;
+ break;
+ case '1': /* hw breakpoint, same implementation as sw breakpoint */
+ kind = hardware_breakpoint;
+ break;
+ case '2':
+ kind = write_watchpoint;
+ break;
+ case '3':
+ kind = read_watchpoint;
+ break;
+ case '4':
+ kind = access_watchpoint;
+ break;
+ default:
+ vg_assert (0);
+ }
+
+ /* Attention: gdbserver convention differs: 0 means ok; 1 means not ok */
+ if (VG_(gdbserver_point) (kind, insert, addr, len))
+ return 0;
+ else
+ return 1; /* error or unsupported */
+}
+
+char* valgrind_target_xml (void)
+{
+ return (char *) the_low_target.target_xml;
+}
+
+char* valgrind_shadow_target_xml (void)
+{
+ return (char *) the_low_target.shadow_target_xml;
+}
+
+int valgrind_insert_watchpoint (char type, CORE_ADDR addr, int len)
+{
+ return valgrind_point (/* insert */ True, type, addr, len);
+}
+
+int valgrind_remove_watchpoint (char type, CORE_ADDR addr, int len)
+{
+ return valgrind_point (/* insert*/ False, type, addr, len);
+}
+
+/* returns a pointer to the architecture state corresponding to
+ the provided register set: 0 => normal guest registers,
+ 1 => shadow1
+ 2 => shadow2
+*/
+VexGuestArchState* get_arch (int set, ThreadState* tst)
+{
+ switch (set) {
+ case 0: return &tst->arch.vex;
+ case 1: return &tst->arch.vex_shadow1;
+ case 2: return &tst->arch.vex_shadow2;
+ default: vg_assert(0);
+ }
+}
+
+static int non_shadow_num_regs = 0;
+static struct reg *non_shadow_reg_defs = NULL;
+void initialize_shadow_low(Bool shadow_mode)
+{
+ if (non_shadow_reg_defs == NULL) {
+ non_shadow_reg_defs = the_low_target.reg_defs;
+ non_shadow_num_regs = the_low_target.num_regs;
+ }
+
+ regcache_invalidate();
+ if (the_low_target.reg_defs != non_shadow_reg_defs) {
+ free (the_low_target.reg_defs);
+ }
+ if (shadow_mode) {
+ the_low_target.num_regs = 3 * non_shadow_num_regs;
+ the_low_target.reg_defs = build_shadow_arch (non_shadow_reg_defs, non_shadow_num_regs);
+ } else {
+ the_low_target.num_regs = non_shadow_num_regs;
+ the_low_target.reg_defs = non_shadow_reg_defs;
+ }
+ set_register_cache (the_low_target.reg_defs, the_low_target.num_regs);
+}
+
void set_desired_inferior (int use_general)
{
struct thread_info *found;
@@ -61,42 +584,6 @@
}
}
-int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
-{
- int res;
- res = (*the_target->read_memory) (memaddr, myaddr, len);
- return res;
-}
-
-int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
- int len)
-{
- /* Lacking cleanups, there is some potential for a memory leak if the
- write fails and we go through error(). Make sure that no more than
- one buffer is ever pending by making BUFFER static. */
- static unsigned char *buffer = 0;
- int res;
-
- if (buffer != NULL)
- free (buffer);
-
- buffer = malloc (len);
- VG_(memcpy) (buffer, myaddr, len);
- res = (*the_target->write_memory) (memaddr, buffer, len);
- free (buffer);
- buffer = NULL;
-
- return res;
-}
-
-void set_target_ops (struct target_ops *target)
-{
- // Can be called again after a fork => do not re-malloc the_target.
- if (the_target == NULL)
- the_target = (struct target_ops *) malloc (sizeof (*the_target));
- VG_(memcpy) (the_target, target, sizeof (*the_target));
-}
-
void* VG_(dmemcpy) ( void *d, const void *s, SizeT sz, Bool *mod )
{
if (VG_(memcmp) (d, s, sz)) {
@@ -121,3 +608,22 @@
else
vg_assert (0);
}
+
+void valgrind_initialize_target(void)
+{
+#if defined(VGA_x86)
+ x86_init_architecture(&the_low_target);
+#elif defined(VGA_amd64)
+ amd64_init_architecture(&the_low_target);
+#elif defined(VGA_arm)
+ arm_init_architecture(&the_low_target);
+#elif defined(VGA_ppc32)
+ ppc32_init_architecture(&the_low_target);
+#elif defined(VGA_ppc64)
+ ppc64_init_architecture(&the_low_target);
+#elif defined(VGA_s390x)
+ s390x_init_architecture(&the_low_target);
+#else
+ architecture missing in target.c valgrind_initialize_target
+#endif
+}
Modified: trunk/coregrind/m_gdbserver/server.h (+8 -35)
===================================================================
--- trunk/coregrind/m_gdbserver/server.h 2012-05-23 16:59:40 +01:00 (rev 12578)
+++ trunk/coregrind/m_gdbserver/server.h 2012-05-23 22:50:36 +01:00 (rev 12579)
@@ -107,34 +107,6 @@
If debug info not found for this pc, assumes arm */
extern Addr thumb_pc (Addr pc);
-/* True if gdbserver is single stepping the valgrind process */
-extern Bool valgrind_single_stepping(void);
-
-/* Set Valgrind in single stepping mode or not according to Bool. */
-extern void valgrind_set_single_stepping(Bool);
-
-/* gets the addr at which a (possible) break must be ignored once.
- If there is no such break to be ignored once, 0 is returned.
- This is needed for the following case:
- The user sets a break at address AAA.
- The break is encountered. Then the user does stepi
- (i.e. step one instruction).
- In such a case, the already encountered break must be ignored
- to ensure the stepi will advance by one instruction: a "break"
- is implemented in valgrind by some helper code just after the
- instruction mark at which the break is set. This helper code
- verifies if either there is a break at the current PC
- or if we are in stepping mode. If we are in stepping mode,
- the already encountered break must be ignored once to advance
- to the next instruction.
- ??? need to check if this is *really* needed. */
-extern Addr valgrind_get_ignore_break_once(void);
-
-/* When addr > 0, ensures the next stop reply packet informs
- gdb about the encountered watchpoint.
- Use addr 0x0 to reset. */
-extern void VG_(set_watchpoint_stop_address) (Addr addr);
-
/* when invoked by vgdb using ptrace, contains the tid chosen
by vgdb (if vgdb gives a tid different of 0: a 0 tid by
vgdb means use the running_tid if there is one running
@@ -249,13 +221,6 @@
/* Target-specific functions */
-void initialize_low (void);
-
-/* initialize or re-initialize the register set of the low target.
- if shadow_mode, then (re-)define the normal and valgrind shadow registers
- else (re-)define only the normal registers. */
-void initialize_shadow_low (Bool shadow_mode);
-
/* From inferiors.c. */
extern struct inferior_list all_threads;
@@ -323,6 +288,14 @@
int unhexify (char *bin, const char *hex, int count);
int hexify (char *hex, const char *bin, int count);
+/* heximage builds an image of bin according to byte order of the architecture
+ Useful for register and int image */
+char* heximage (char *buf, char *bin, int count);
+
+/* convert from CORE_ADDR to void* */
+void* C2v(CORE_ADDR addr);
+
+
int remote_escape_output (const gdb_byte *buffer, int len,
gdb_byte *out_buf, int *out_len,
int out_maxlen);
Modified: trunk/coregrind/m_gdbserver/server.c (+32 -37)
=======================================...
[truncated message content] |