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;