diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/docs/coregrind_core.html ../working/valgrind/coregrind/docs/coregrind_core.html
--- ../originals/valgrind-2.0.0/coregrind/docs/coregrind_core.html 2003-11-06 01:43:37.000000000 +0000
+++ ../working/valgrind/coregrind/docs/coregrind_core.html 2004-02-12 18:43:25.000000000 +0000
@@ -1354,10 +1354,15 @@ the simulated CPU, not the real one. Th
gruesome fakery; see vg_signals.c for details.
+
+
2.14 External debuggers
+Valgrind can be used in conjunction with external debuggers for enhanced debugging. For this to work, Valgrind must be explicitly supported by your debugger. For example, a patch for GDB allows you to debug a process running under Valgrind using that debugger.
+For developers of external debuggers:
+The state of the process running on the emulated CPU is exported in a shared memory region with IPC key VG_DEBUG_STATE_SHM_KEY + pid. The shared memory region contains a DebugState structure followed by an array of VG_N_THREAD ThreadState structures. These structures and constants are defined in coregrind/vg_include.h
-
2.14 An example run
+2.15 An example run
This is the log for a run of a small program using the memcheck
skin. The program is in fact correct, and the reported error is as the
result of a potentially serious code generation bug in GNU g++
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_constants.h ../working/valgrind/coregrind/vg_constants.h
--- ../originals/valgrind-2.0.0/coregrind/vg_constants.h 2003-04-15 15:57:39.000000000 +0100
+++ ../working/valgrind/coregrind/vg_constants.h 2004-02-12 14:53:57.000000000 +0000
@@ -48,6 +48,7 @@
scheduler. */
#define VG_TRC_EBP_JMP_SYSCALL 19 /* EBP and TRC */
#define VG_TRC_EBP_JMP_CLIENTREQ 23 /* EBP and TRC */
+#define VG_TRC_EBP_JMP_BREAKPOINT 27 /* EBP and TRC */
#define VG_TRC_INNER_FASTMISS 31 /* TRC only; means fast-cache miss. */
#define VG_TRC_INNER_COUNTERZERO 29 /* TRC only; means bb ctr == 0 */
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_dispatch.S ../working/valgrind/coregrind/vg_dispatch.S
--- ../originals/valgrind-2.0.0/coregrind/vg_dispatch.S 2003-04-15 15:57:40.000000000 +0100
+++ ../working/valgrind/coregrind/vg_dispatch.S 2004-02-12 14:54:15.000000000 +0000
@@ -111,7 +112,7 @@ dispatch_boring:
/* Are we out of timeslice? If yes, defer to scheduler. */
cmpl $0, VG_(dispatch_ctr)
- jz counter_is_zero
+ jle counter_is_zero
/* try a fast lookup in the translation cache */
TT_LOOKUP(%ebx, fast_lookup_failed)
@@ -151,11 +152,14 @@ run_innerloop_exit:
make it look cleaner.
*/
dispatch_exceptional:
+ incl VG_(dispatch_ctr)
/* this is jumped to only, not fallen-through from above */
cmpl $VG_TRC_EBP_JMP_SYSCALL, %ebp
jz dispatch_syscall
cmpl $VG_TRC_EBP_JMP_CLIENTREQ, %ebp
jz dispatch_clientreq
+ cmpl $VG_TRC_EBP_JMP_BREAKPOINT, %ebp
+ jz dispatch_breakpoint
cmpl $VG_TRC_INNER_COUNTERZERO, %ebp
jz counter_is_zero
@@ -180,6 +184,13 @@ dispatch_clientreq:
movl $VG_TRC_EBP_JMP_CLIENTREQ, %eax
jmp run_innerloop_exit
+dispatch_breakpoint:
+ /* save %eax in %EIP and defer to sched */
+ movl $VG_(baseBlock), %ebp
+ movl VGOFF_(m_eip), %esi
+ movl %eax, (%ebp, %esi, 4)
+ movl $VG_TRC_EBP_JMP_BREAKPOINT, %eax
+ jmp run_innerloop_exit
/*
This is the translation chainer, our run-time linker, if you like.
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_from_ucode.c ../working/valgrind/coregrind/vg_from_ucode.c
--- ../originals/valgrind-2.0.0/coregrind/vg_from_ucode.c 2003-10-19 15:12:36.000000000 +0100
+++ ../working/valgrind/coregrind/vg_from_ucode.c 2004-02-12 14:54:38.000000000 +0000
@@ -2449,6 +2449,9 @@ static void load_ebp_from_JmpKind ( JmpK
case JmpClientReq:
VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_CLIENTREQ, R_EBP );
break;
+ case JmpBreakpoint:
+ VG_(emit_movv_lit_reg) ( 4, VG_TRC_EBP_JMP_BREAKPOINT, R_EBP );
+ break;
default:
VG_(core_panic)("load_ebp_from_JmpKind");
}
@@ -4119,7 +4122,7 @@ UChar* VG_(emit_code) ( UCodeBlock* cb,
emit_amode_litmem_reg((Addr)&VG_(dispatch_ctr), 1);
if (dis)
VG_(printf)("\n\t\tdecl (%p)\n", &VG_(dispatch_ctr));
- VG_(emit_jcondshort_target)(False, CondNZ, &tgt);
+ VG_(emit_jcondshort_target)(False, CondNL, &tgt);
VG_(emit_movv_lit_reg) ( 4, VG_TRC_INNER_COUNTERZERO, R_EBP );
emit_ret();
VG_(target_forward)(&tgt);
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_include.h ../working/valgrind/coregrind/vg_include.h
--- ../originals/valgrind-2.0.0/coregrind/vg_include.h 2003-10-02 21:24:37.000000000 +0100
+++ ../working/valgrind/coregrind/vg_include.h 2004-02-12 14:56:46.000000000 +0000
@@ -697,6 +697,13 @@ typedef
}
ForkHandlerEntry;
+typedef
+ struct _DebugState {
+ ThreadId tid_currently_in_baseBlock;
+ ThreadId tid_last_in_baseBlock;
+ Bool need_to_invalidate_all_translations;
+ }
+ DebugState;
typedef
struct _ThreadState {
@@ -744,6 +751,12 @@ typedef
void** joiner_thread_return;
ThreadId joiner_jee_tid;
+ /* Whether or not to single step */
+ Bool single_step;
+
+ /* Whether or not the thread is stopped */
+ Bool stopped;
+
/* Whether or not detached. */
Bool detached;
@@ -863,9 +876,11 @@ typedef
}
ThreadState;
+#define VG_DEBUG_STATE_SHM_KEY 0x29BD0000
/* The thread table. */
-extern ThreadState VG_(threads)[VG_N_THREADS];
+extern ThreadState *VG_(threads);
+extern DebugState *VG_(debug_state);
/* Check that tid is in range and denotes a non-Empty thread. */
extern Bool VG_(is_valid_tid) ( ThreadId tid );
@@ -885,6 +900,18 @@ extern void VG_(load_thread_state)( Thre
VG_(baseBlock) with junk, for sanity-check reasons. */
extern void VG_(save_thread_state)( ThreadId );
+/* Initialise shared memory for the threads table. */
+extern void VG_(init_threads) ();
+
+/* Free the shared memory for the threads table. */
+extern void VG_(cleanup_threads) ();
+
+/* Before a fork, save the old thread state. */
+extern void VG_(pre_fork) (ThreadId tid);
+
+/* After a fork switch shared memory regions for the child. */
+extern void VG_(post_fork) (ThreadId tid, Bool child);
+
/* And for the currently running one, if valid. */
extern ThreadState* VG_(get_current_thread_state) ( void );
@@ -1099,7 +1126,7 @@ extern Bool VG_(is_chained_jumpsite)
Exports of vg_to_ucode.c
------------------------------------------------------------------ */
-extern Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 );
+extern Int VG_(disBB) ( UCodeBlock* cb, Addr eip0, Bool single_step );
/* ---------------------------------------------------------------------
Exports of vg_translate.c
@@ -1495,6 +1522,8 @@ extern void VG_(add_to_trans_tab) ( Addr
extern void VG_(invalidate_translations) ( Addr start, UInt range, Bool unchain_blocks );
+extern void VG_(invalidate_all_translations) (void);
+
extern void VG_(init_tt_tc) ( void );
extern void VG_(sanity_check_tc_tt) ( void );
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_main.c ../working/valgrind/coregrind/vg_main.c
--- ../originals/valgrind-2.0.0/coregrind/vg_main.c 2003-10-05 01:02:43.000000000 +0100
+++ ../working/valgrind/coregrind/vg_main.c 2004-02-12 15:24:08.000000000 +0000
@@ -1496,6 +1495,8 @@ void VG_(main) ( void )
/* Set up baseBlock offsets and copy the saved machine's state into it. */
vg_init_baseBlock();
+ VG_(init_threads) ();
+
/* Initialise the scheduler, and copy the client's state from
baseBlock into VG_(threads)[1]. Must be before:
- VG_(sigstartup_actions)()
@@ -1553,6 +1554,8 @@ void VG_(main) ( void )
VGP_POPCC(VgpSched);
VG_(running_on_simd_CPU) = False;
+ VG_(cleanup_threads);
+
if (VG_(clo_verbosity) > 0)
VG_(message)(Vg_UserMsg, "");
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_mylibc.c ../working/valgrind/coregrind/vg_mylibc.c
--- ../originals/valgrind-2.0.0/coregrind/vg_mylibc.c 2003-07-06 02:14:42.000000000 +0100
+++ ../working/valgrind/coregrind/vg_mylibc.c 2004-02-12 14:57:30.000000000 +0000
@@ -127,6 +126,20 @@ UInt vg_do_syscall5 ( UInt syscallno,
}
#endif
+static
+UInt vg_do_syscall6 ( UInt syscallno,
+ UInt arg1, UInt arg2, UInt arg3, UInt arg4,
+ UInt arg5, UInt arg6 )
+{
+ UInt __res;
+ __asm__ volatile ("push %%ebp ; movl %1,%%ebp ; int $0x80 ; pop %%ebp"
+ : "=a" (__res)
+ : "a" (syscallno),"b" (arg1),"c" (arg2),
+ "d" (arg3),"S" (arg4),"D" (arg5),
+ "g" (arg6));
+ return __res;
+}
+
/* ---------------------------------------------------------------------
Wrappers around system calls, and other stuff, to do with signals.
------------------------------------------------------------------ */
@@ -1674,6 +1686,42 @@ Int VG_(write_socket)( Int sd, void *msg
return res;
}
+Int VG_(shmget) (Int key, ULong size, Int shmflg)
+{
+ Int res;
+ res = vg_do_syscall6(__NR_ipc, VKI_SHMGET, key, size, shmflg, 0, 0);
+ if (VG_(is_kerror)(res))
+ res = -1;
+ return res;
+}
+
+void *VG_(shmat) (Int shmid, const void *shmaddr, Int shmflg)
+{
+ ULong raddr;
+ Int res;
+ res = vg_do_syscall6(__NR_ipc, VKI_SHMAT, shmid, shmflg, (UInt) &raddr, (UInt) shmaddr, 0);
+ if (VG_(is_kerror)(res))
+ raddr = -1;
+ return (void *)(UInt)raddr;
+}
+
+Int VG_(shmdt) (const void *shmaddr)
+{
+ Int res;
+ res = vg_do_syscall6(__NR_ipc, VKI_SHMGET, 0, 0, 0, (UInt) shmaddr, 0);
+ if (VG_(is_kerror)(res))
+ res = -1;
+ return res;
+}
+
+Int VG_(shmctl) (Int shmid, Int cmd, struct vki_shmid_ds *buf)
+{
+ Int res;
+ res = vg_do_syscall6(__NR_ipc, VKI_SHMCTL, shmid, cmd, 0, (UInt) buf, 0);
+ if (VG_(is_kerror)(res))
+ res = -1;
+ return res;
+}
/*--------------------------------------------------------------------*/
/*--- end vg_mylibc.c ---*/
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_scheduler.c ../working/valgrind/coregrind/vg_scheduler.c
--- ../originals/valgrind-2.0.0/coregrind/vg_scheduler.c 2003-07-24 09:45:31.000000000 +0100
+++ ../working/valgrind/coregrind/vg_scheduler.c 2004-02-12 17:21:56.000000000 +0000
@@ -89,7 +89,13 @@
/* Globals. A statically allocated array of threads. NOTE: [0] is
never used, to simplify the simulation of initialisers for
LinuxThreads. */
-ThreadState VG_(threads)[VG_N_THREADS];
+ThreadState *VG_(threads);
+
+/* The debug state of the process (for use by an external debugger.) */
+DebugState *VG_(debug_state);
+
+/* Shared memory region id. */
+static Int vg_shmid;
/* The process' fork-handler stack. */
static Int vg_fhstack_used = 0;
@@ -97,12 +103,12 @@ static ForkHandlerEntry vg_fhstack[VG_N_
/* The tid of the thread currently in VG_(baseBlock). */
-static ThreadId vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
+#define vg_tid_currently_in_baseBlock VG_(debug_state)->tid_currently_in_baseBlock
/* The tid either currently in baseBlock, or was in baseBlock before
was saved it out; this is only updated when a new thread is loaded
into the baseBlock */
-static ThreadId vg_tid_last_in_baseBlock = VG_INVALID_THREADID;
+#define vg_tid_last_in_baseBlock VG_(debug_state)->tid_last_in_baseBlock
/* vg_oursignalhandler() might longjmp(). Here's the jmp_buf. */
jmp_buf VG_(scheduler_jmpbuf);
@@ -232,6 +238,10 @@ ThreadId VG_(first_matching_thread_stack
/* Print the scheduler status. */
void VG_(pp_sched_status) ( void )
{
+ if (!VG_(threads)) {
+ VG_(printf) ("\nscheduler not initialised\n");
+ return;
+ }
Int i;
VG_(printf)("\nsched status:\n");
for (i = 1; i < VG_N_THREADS; i++) {
@@ -308,6 +318,7 @@ Char* name_of_sched_event ( UInt event )
switch (event) {
case VG_TRC_EBP_JMP_SYSCALL: return "SYSCALL";
case VG_TRC_EBP_JMP_CLIENTREQ: return "CLIENTREQ";
+ case VG_TRC_EBP_JMP_BREAKPOINT: return "BREAKPOINT";
case VG_TRC_INNER_COUNTERZERO: return "COUNTERZERO";
case VG_TRC_INNER_FASTMISS: return "FASTMISS";
case VG_TRC_UNRESUMABLE_SIGNAL: return "FATALSIGNAL";
@@ -547,6 +558,59 @@ void VG_(save_thread_state) ( ThreadId t
vg_tid_currently_in_baseBlock = VG_INVALID_THREADID;
}
+void VG_(init_threads) () {
+ if (VG_(debug_state) != NULL)
+ VG_(shmdt) (VG_(debug_state));
+
+ Int key = VG_(getpid) () + VG_DEBUG_STATE_SHM_KEY;
+
+ vg_shmid = VG_(shmget) (key,
+ sizeof (DebugState) +
+ VG_N_THREADS * sizeof (ThreadState),
+ VKI_IPC_CREAT | VKI_S_IRUSR | VKI_S_IWUSR);
+ vg_assert (vg_shmid != -1);
+
+ VG_(debug_state) = VG_(shmat) (vg_shmid, NULL, 0);
+ vg_assert (VG_(debug_state) != (DebugState *) 0xffffffff);
+
+ VG_(memset) (VG_(debug_state), 0, sizeof (DebugState) +
+ VG_N_THREADS * sizeof (ThreadState));
+
+ VG_(threads) = (ThreadState *) (VG_(debug_state) + 1);
+}
+
+void VG_(cleanup_threads) () {
+ struct vki_shmid_ds buf;
+ VG_(shmctl) (vg_shmid, VKI_IPC_RMID, &buf);
+}
+
+static void *threads_save = NULL;
+
+void VG_(pre_fork) (ThreadId tid) {
+ /* Save the old threads array for use by post_fork.
+ * This means the parent may go on while the child is switching
+ * shared memory regions. */
+ threads_save = VG_(arena_malloc) (VG_AR_TRANSIENT,
+ sizeof (DebugState) +
+ VG_N_THREADS * sizeof (ThreadState));
+ VG_(memcpy) (threads_save,
+ VG_(debug_state), sizeof (DebugState) +
+ VG_N_THREADS * sizeof (ThreadState));
+}
+
+void VG_(post_fork) (ThreadId tid, Bool child) {
+ if (child) {
+ /* The child can't share the same thread array as the parent
+ * so we need to setup another shared memory region. */
+ VG_(init_threads) ();
+ VG_(memcpy) (VG_(debug_state),
+ threads_save,
+ sizeof (DebugState) +
+ VG_N_THREADS * sizeof (ThreadState));
+ VG_(nuke_all_threads_except)( tid );
+ }
+ VG_(arena_free) (VG_AR_TRANSIENT, threads_save);
+}
/* Run the thread tid for a while, and return a VG_TRC_* value to the
scheduler indicating what happened. */
@@ -1301,14 +1365,16 @@ VgSchedReturnCode VG_(scheduler) ( void
|| (VG_(threads)[tid_next].status == VgTs_WaitCV
&& VG_(threads)[tid_next].awaken_at != 0xFFFFFFFF))
n_in_bounded_wait ++;
- if (VG_(threads)[tid_next].status == VgTs_Runnable)
+ if (VG_(threads)[tid_next].status == VgTs_Runnable
+ && !VG_(threads)[tid_next].stopped)
break; /* We can run this one. */
if (tid_next == tid)
break; /* been all the way round */
}
tid = tid_next;
- if (VG_(threads)[tid].status == VgTs_Runnable) {
+ if (VG_(threads)[tid].status == VgTs_Runnable
+ && !VG_(threads)[tid_next].stopped) {
/* Found a suitable candidate. Fall out of this loop, so
we can advance to stage 2 of the scheduler: actually
running the thread. */
@@ -1353,9 +1419,9 @@ VgSchedReturnCode VG_(scheduler) ( void
always get at least one decrement even if nothing happens.
*/
if (VG_(bbs_to_go) >= VG_SCHEDULING_QUANTUM)
- VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM + 1;
+ VG_(dispatch_ctr) = VG_SCHEDULING_QUANTUM;
else
- VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go) + 1;
+ VG_(dispatch_ctr) = (UInt)VG_(bbs_to_go);
/* ... and remember what we asked for. */
dispatch_ctr_SAVED = VG_(dispatch_ctr);
@@ -1383,6 +1449,17 @@ VgSchedReturnCode VG_(scheduler) ( void
vg_assert(VG_(threads)[tid].m_eip != 0);
# endif
+ /* Debugger support. Used after breakpoint is set, etc. */
+ if (VG_(debug_state)->need_to_invalidate_all_translations) {
+ VG_(invalidate_all_translations) ();
+ VG_(debug_state)->need_to_invalidate_all_translations = False;
+ }
+
+ /* If we are single stepping just execute one instruction. */
+ if (VG_(threads)[tid].single_step) {
+ dispatch_ctr_SAVED = VG_(dispatch_ctr) = 1;
+ }
+
trc = run_thread_for_a_while ( tid );
# if 0
@@ -1541,6 +1618,27 @@ VgSchedReturnCode VG_(scheduler) ( void
}
}
+ if (trc == VG_TRC_EBP_JMP_BREAKPOINT) {
+ /* A software breakpoint. */
+ VG_(debug_state)->tid_currently_in_baseBlock =
+ VG_(debug_state)->tid_last_in_baseBlock;
+ VG_(kkill) (0, VKI_SIGTRAP);
+ VG_(debug_state)->tid_currently_in_baseBlock = 0;
+ break;
+ }
+
+ if (trc == VG_TRC_INNER_COUNTERZERO &&
+ VG_(threads)[tid].single_step) {
+ /* Signal to the debugger */
+ VG_(debug_state)->tid_currently_in_baseBlock =
+ VG_(debug_state)->tid_last_in_baseBlock;
+ VG_(kkill) (0, VKI_SIGTRAP);
+ VG_(debug_state)->tid_currently_in_baseBlock = 0;
+ /* Do NOT continue here otherwise other threads will never have
+ * chance to run. */
+ break;
+ }
+
/* It's an event we can't quickly deal with. Give up running
this thread and handle things the expensive way. */
break;
@@ -1553,7 +1651,7 @@ VgSchedReturnCode VG_(scheduler) ( void
non-completely-trivial reason. First, update basic-block
counters. */
- done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr) - 1;
+ done_this_time = (Int)dispatch_ctr_SAVED - (Int)VG_(dispatch_ctr);
vg_assert(done_this_time >= 0);
VG_(bbs_to_go) -= (ULong)done_this_time;
VG_(bbs_done) += (ULong)done_this_time;
@@ -1588,6 +1686,9 @@ VgSchedReturnCode VG_(scheduler) ( void
1, whereupon the signal will be "delivered". */
break;
+ case VG_TRC_EBP_JMP_BREAKPOINT:
+ break;
+
default:
VG_(printf)("\ntrc = %d\n", trc);
VG_(core_panic)("VG_(scheduler), phase 3: "
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_syscalls.c ../working/valgrind/coregrind/vg_syscalls.c
--- ../originals/valgrind-2.0.0/coregrind/vg_syscalls.c 2003-11-03 19:15:04.000000000 +0000
+++ ../working/valgrind/coregrind/vg_syscalls.c 2004-02-12 15:06:25.000000000 +0000
@@ -1516,12 +1516,9 @@ void VG_(perform_assumed_nonblocking_sys
case __NR_fork: /* syscall 2 */
/* pid_t fork(void); */
MAYBE_PRINTF("fork ()\n");
+ VG_(pre_fork) (tid);
KERNEL_DO_SYSCALL(tid,res);
- if (res == 0) {
- /* I am the child. Nuke all other threads which I might
- have inherited from my parent. POSIX mandates this. */
- VG_(nuke_all_threads_except)( tid );
- }
+ VG_(post_fork) (tid, res==0);
break;
case __NR_fsync: /* syscall 118 */
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_to_ucode.c ../working/valgrind/coregrind/vg_to_ucode.c
--- ../originals/valgrind-2.0.0/coregrind/vg_to_ucode.c 2003-11-03 13:55:17.000000000 +0000
+++ ../working/valgrind/coregrind/vg_to_ucode.c 2004-02-04 11:55:04.000000000 +0000
@@ -4993,6 +4993,15 @@ static Addr disInstr ( UCodeBlock* cb, A
/* ------------------------ INT ------------------------ */
+ case 0xCC: /* INT 3 */
+ uInstr1(cb, JMP, 0, Literal, 0);
+ uLiteral(cb, eip);
+ uCond(cb, CondAlways);
+ LAST_UINSTR(cb).jmpkind = JmpBreakpoint;
+ *isEnd = True;
+ if (dis) VG_(printf)("int $0x03\n");
+ break;
+
case 0xCD: /* INT imm8 */
d32 = getUChar(eip); eip++;
if (d32 != 0x80) VG_(core_panic)("disInstr: INT but not 0x80 !");
@@ -6711,7 +6720,7 @@ static Addr disInstr ( UCodeBlock* cb, A
the ucode into cb. Returns the size, in bytes, of the basic
block. */
-Int VG_(disBB) ( UCodeBlock* cb, Addr eip0 )
+Int VG_(disBB) ( UCodeBlock* cb, Addr eip0, Bool single_step )
{
Addr eip = eip0;
Bool isEnd = False;
@@ -6727,7 +6736,8 @@ Int VG_(disBB) ( UCodeBlock* cb, Addr ei
* The INCEIPs and JMP.extra4b fields allows a skin to track x86
* instruction sizes, important for some skins (eg. cache simulation).
*/
- if (VG_(clo_single_step)) {
+ if (VG_(clo_single_step)
+ || single_step) {
eip = disInstr ( cb, eip, &isEnd );
/* Add a JMP to the next (single x86 instruction) BB if it doesn't
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_translate.c ../working/valgrind/coregrind/vg_translate.c
--- ../originals/valgrind-2.0.0/coregrind/vg_translate.c 2003-10-19 15:12:36.000000000 +0100
+++ ../working/valgrind/coregrind/vg_translate.c 2004-02-12 15:06:34.000000000 +0000
@@ -1129,6 +1129,7 @@ void pp_UInstrWorker ( Int instrNo, UIns
case JmpRet: VG_(printf)("-r"); break;
case JmpSyscall: VG_(printf)("-sys"); break;
case JmpClientReq: VG_(printf)("-cli"); break;
+ case JmpBreakpoint:VG_(printf)("-brk"); break;
default: break;
}
VG_(pp_UOperand)(u, 1, u->size, False);
@@ -2407,7 +2408,7 @@ void VG_(translate) ( /*IN*/ ThreadId t
/* Disassemble this basic block into cb. */
VG_(print_codegen) = DECIDE_IF_PRINTING_CODEGEN_FOR_PHASE(1);
VGP_PUSHCC(VgpToUCode);
- n_disassembled_bytes = VG_(disBB) ( cb, orig_addr );
+ n_disassembled_bytes = VG_(disBB) ( cb, orig_addr, VG_(threads) [tid].single_step );
VGP_POPCC(VgpToUCode);
/* Try and improve the code a bit. */
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/coregrind/vg_transtab.c ../working/valgrind/coregrind/vg_transtab.c
--- ../originals/valgrind-2.0.0/coregrind/vg_transtab.c 2003-05-18 11:05:38.000000000 +0100
+++ ../working/valgrind/coregrind/vg_transtab.c 2004-01-30 21:11:19.000000000 +0000
@@ -628,6 +628,47 @@ void VG_(invalidate_translations) ( Addr
out_count, out_osize, out_tsize, i_start, i_end );
}
+/* For debugging support */
+void VG_(invalidate_all_translations) (void)
+{
+ Int i, j;
+ TCEntry* tce;
+# ifdef DEBUG_TRANSTAB
+ VG_(sanity_check_tc_tt)();
+# endif
+
+ for (i = 0; i < VG_TT_SIZE; i++) {
+ if (vg_tt[i].orig_addr == VG_TTE_EMPTY
+ || vg_tt[i].orig_addr == VG_TTE_DELETED) continue;
+ tce = vg_tt[i].tcentry;
+
+ if (VG_(needs).basic_block_discards)
+ SK_(discard_basic_block_info)( tce->orig_addr,
+ tce->orig_size );
+
+ vg_tt[i].orig_addr = VG_TTE_DELETED;
+ tce->orig_addr = VG_TTE_DELETED;
+
+ /* make sure no other blocks chain to the one we just discarded */
+ for(j = 0; j < VG_TC_N_SECTORS; j++) {
+ if (vg_tc[j] != NULL)
+ unchain_sector(j, (Addr)tce->payload, tce->trans_size);
+ }
+
+ VG_(overall_out_count) ++;
+ VG_(overall_out_osize) += tce->orig_size;
+ VG_(overall_out_tsize) += tce->trans_size;
+ }
+
+ vg_invalidate_tt_fast();
+ VG_(sanity_check_tc_tt)();
+# ifdef DEBUG_TRANSTAB
+ { Addr aa;
+ for (aa = i_start; aa <= i_end; aa++)
+ vg_assert(search_tt ( aa ) == NULL);
+ }
+# endif
+}
/*------------------------------------------------------------*/
/*--- Initialisation. ---*/
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/include/vg_kerneliface.h ../working/valgrind/include/vg_kerneliface.h
--- ../originals/valgrind-2.0.0/include/vg_kerneliface.h 2003-07-24 20:35:00.000000000 +0100
+++ ../working/valgrind/include/vg_kerneliface.h 2004-02-13 13:55:53.000000000 +0000
@@ -124,6 +124,7 @@ typedef
#define VKI_SIGSEGV 11
#define VKI_SIGBUS 7
#define VKI_SIGILL 4
+#define VKI_SIGTRAP 5
#define VKI_SIGFPE 8
#define VKI_SIGKILL 9
#define VKI_SIGSTOP 19
@@ -138,6 +139,8 @@ typedef
#define VKI_MAP_ANONYMOUS 0x20 /* Don't use a file. */
#define VKI_MAP_PRIVATE 0x02 /* Changes are private. */
#define VKI_MAP_FIXED 0x10 /* Interpret addr exactly */
+#define VKI_MAP_SHARED 0x01 /* Share changes */
+#define VKI_MAP_FAILED ((void *) -1)
/* Copied from linux-2.4.19/include/asm-i386/fcntl.h */
@@ -410,7 +413,75 @@ typedef struct vki_modify_ldt_ldt_s {
#define VKI_MODIFY_LDT_CONTENTS_STACK 1
#define VKI_MODIFY_LDT_CONTENTS_CODE 2
+/* Copied from bits/ipc.h */
+/* Mode bits for `msgget', `semget', and `shmget'. */
+#define VKI_IPC_CREAT 01000 /* Create key if key does not exist. */
+#define VKI_IPC_EXCL 02000 /* Fail if key exists. */
+#define VKI_IPC_NOWAIT 04000 /* Return error on wait. */
+
+/* Control commands for `msgctl', `semctl', and `shmctl'. */
+#define VKI_IPC_RMID 0 /* Remove identifier. */
+#define VKI_IPC_SET 1 /* Set `ipc_perm' options. */
+#define VKI_IPC_STAT 2 /* Get `ipc_perm' options. */
+# define VKI_IPC_INFO 3 /* See ipcs. */
+
+/* Special key values. */
+#define IPC_PRIVATE ((int) 0) /* Private key. */
+
+/* Data structure used to pass permission information to IPC operations. */
+struct vki_ipc_perm
+ {
+ int __key; /* Key. */
+ unsigned short uid; /* Owner's user ID. */
+ unsigned short gid; /* Owner's group ID. */
+ unsigned short cuid; /* Creator's user ID. */
+ unsigned short cgid; /* Creator's group ID. */
+ unsigned short int mode; /* Read/write permission. */
+ unsigned short int __pad1;
+ unsigned short int __seq; /* Sequence number. */
+ unsigned short int __pad2;
+ unsigned long int __unused1;
+ unsigned long int __unused2;
+ };
+
+/* Copied from bits/shm.h */
+
+/* Permission flag for shmget. */
+#define VKI_SHM_R 0400 /* or S_IRUGO from */
+#define VKI_SHM_W 0200 /* or S_IWUGO from */
+
+/* Flags for `shmat'. */
+#define VKI_SHM_RDONLY 010000 /* attach read-only else read-write */
+#define VKI_SHM_RND 020000 /* round attach address to SHMLBA */
+#define VKI_SHM_REMAP 040000 /* take-over region on attach */
+
+/* Commands for `shmctl'. */
+#define VKI_SHM_LOCK 11 /* lock segment (root only) */
+#define VKI_SHM_UNLOCK 12 /* unlock segment (root only) */
+
+#define VKI_SHMAT 21
+#define VKI_SHMDT 22
+#define VKI_SHMGET 23
+#define VKI_SHMCTL 24
+
+/* Data structure describing a set of semaphores. */
+struct vki_shmid_ds
+ {
+ struct vki_ipc_perm shm_perm; /* operation permission struct */
+ unsigned int shm_segsz; /* size of segment in bytes */
+ unsigned int shm_atime; /* time of last shmat() */
+ unsigned long int __unused1;
+ unsigned int shm_dtime; /* time of last shmdt() */
+ unsigned long int __unused2;
+ unsigned int shm_ctime; /* time of last change by shmctl() */
+ unsigned long int __unused3;
+ int shm_cpid; /* pid of creator */
+ int shm_lpid; /* pid of last shmop */
+ unsigned long int shm_nattch; /* number of current attaches */
+ unsigned long int __unused4;
+ unsigned long int __unused5;
+ };
#endif /* ndef __VG_KERNELIFACE_H */
diff -I '$Id' -I '$Revision' -I '$Date' -X valgrind-exclusions -rpubBN ../originals/valgrind-2.0.0/include/vg_skin.h ../working/valgrind/include/vg_skin.h
--- ../originals/valgrind-2.0.0/include/vg_skin.h 2003-11-06 01:02:46.000000000 +0000
+++ ../working/valgrind/include/vg_skin.h 2004-02-13 13:59:35.000000000 +0000
@@ -490,6 +489,13 @@ extern Int VG_(ksigaltstack) ( const vki
extern Int VG_(kkill) ( Int pid, Int signo );
extern Int VG_(ksigpending) ( vki_ksigset_t* set );
+/* ------------------------------------------------------------------ */
+/* sys/ipc.h */
+
+extern Int VG_(shmget) (Int key, ULong size, Int shmflg);
+extern void *VG_(shmat) (Int shmid, const void *shmaddr, Int shmflg);
+extern Int VG_(shmdt) (const void *shmaddr);
+extern Int VG_(shmctl) (Int shmid, Int cmd, struct vki_shmid_ds *buf);
/*====================================================================*/
/*=== UCode definition ===*/
@@ -782,7 +788,8 @@ typedef
JmpCall=1, /* jump due to an x86 call insn */
JmpRet=2, /* jump due to an x86 ret insn */
JmpSyscall=3, /* do a system call, then jump */
- JmpClientReq=4 /* do a client request, then jump */
+ JmpClientReq=4, /* do a client request, then jump */
+ JmpBreakpoint=5 /* breakpoint, then jump */
}
JmpKind;