#include "pub_core_clientstate.h"
#include "pub_core_aspacemgr.h"
#include "pub_core_aspacehl.h"
+#include "pub_core_clreq.h"
#include "pub_core_commandline.h"
#include "pub_core_debuglog.h"
#include "pub_core_errormgr.h"
" --vgdb-shadow-registers=no|yes let gdb see the shadow registers [no]\n"
" --vgdb-prefix=<prefix> prefix for vgdb FIFOs [%s]\n"
" --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]\n"
+" --run-cxx-freeres=no|yes free up libstdc++ memory at exit on Linux\n"
+" and Solaris? [yes]\n"
" --sim-hints=hint1,hint2,... activate unusual sim behaviours [none] \n"
" where hint is one of:\n"
" lax-ioctls lax-doors fuse-compatible enable-outer\n"
else if VG_BOOL_CLO(arg, "--show-emwarns", VG_(clo_show_emwarns)) {}
else if VG_BOOL_CLO(arg, "--run-libc-freeres", VG_(clo_run_libc_freeres)) {}
+ else if VG_BOOL_CLO(arg, "--run-cxx-freeres", VG_(clo_run_cxx_freeres)) {}
else if VG_BOOL_CLO(arg, "--show-below-main", VG_(clo_show_below_main)) {}
else if VG_BOOL_CLO(arg, "--time-stamp", VG_(clo_time_stamp)) {}
else if VG_BOOL_CLO(arg, "--track-fds", VG_(clo_track_fds)) {}
So don't.
The final_tidyup call makes a bit of a nonsense of the ExitProcess
- case, since it will run the libc_freeres function, thus allowing
- other lurking threads to run again. Hmm. */
+ case, since it will run __gnu_cxx::__freeres and libc_freeres functions,
+ thus allowing other lurking threads to run again. Hmm. */
static
void shutdown_actions_NORETURN( ThreadId tid,
// jrs: Huh? but they surely are already gone
VG_(reap_threads)(tid);
- // Clean the client up before the final report
- // this causes the libc_freeres function to run
+ // Clean the client up before the final report.
+ // This causes __gnu_cxx::__freeres and libc_freeres functions to run.
final_tidyup(tid);
/* be paranoid */
// that none of the other threads ever run again.
vg_assert( VG_(count_living_threads)() >= 1 );
- // Clean the client up before the final report
- // this causes the libc_freeres function to run
- // perhaps this is unsafe, as per comment above
+ // Clean the client up before the final report.
+ // This causes __gnu_cxx::__freeres and libc_freeres functions to run.
+ // Perhaps this is unsafe, as per comment above.
final_tidyup(tid);
/* be paranoid */
/* -------------------- */
/* Final clean-up before terminating the process.
- Clean up the client by calling __libc_freeres() (if requested)
- This is Linux-specific?
- GrP fixme glibc-specific, anyway
+ Clean up the client by calling __gnu_cxx::__freeres() (if requested)
+ and __libc_freeres() (if requested).
*/
static void final_tidyup(ThreadId tid)
{
-#if !defined(VGO_darwin)
- Addr __libc_freeres_wrapper = VG_(client___libc_freeres_wrapper);
+#if defined(VGO_linux) || defined(VGO_solaris)
+ Addr freeres_wrapper = VG_(client_freeres_wrapper);
vg_assert(VG_(is_running_thread)(tid));
-
- if ( !VG_(needs).libc_freeres ||
- !VG_(clo_run_libc_freeres) ||
- 0 == __libc_freeres_wrapper )
- return; /* can't/won't do it */
+
+ if (freeres_wrapper == 0) {
+ return; /* can't do it */
+ }
+
+ Vg_FreeresToRun to_run = 0;
+ if (VG_(needs).cxx_freeres && VG_(clo_run_cxx_freeres)) {
+ to_run |= VG_RUN__GNU_CXX__FREERES;
+ }
+
+ if (VG_(needs).libc_freeres && VG_(clo_run_libc_freeres)) {
+ to_run |= VG_RUN__LIBC_FREERES;
+ }
+
+ if (to_run == 0) {
+ return; /* won't do it */
+ }
# if defined(VGP_ppc64be_linux)
- Addr r2 = VG_(get_tocptr)( __libc_freeres_wrapper );
+ Addr r2 = VG_(get_tocptr)(freeres_wrapper);
if (r2 == 0) {
VG_(message)(Vg_UserMsg,
- "Caught __NR_exit, but can't run __libc_freeres()\n");
+ "Caught __NR_exit, but can't run __gnu_cxx::__freeres()\n");
VG_(message)(Vg_UserMsg,
- " since cannot establish TOC pointer for it.\n");
+ " or __libc_freeres() since cannot establish TOC pointer "
+ "for it.\n");
return;
}
# endif
if (VG_(clo_verbosity) > 2 ||
VG_(clo_trace_syscalls) ||
- VG_(clo_trace_sched))
- VG_(message)(Vg_DebugMsg,
- "Caught __NR_exit; running __libc_freeres()\n");
+ VG_(clo_trace_sched)) {
+
+ vg_assert(to_run > 0);
+ vg_assert(to_run <= (VG_RUN__GNU_CXX__FREERES | VG_RUN__LIBC_FREERES));
+
+ const HChar *msgs[] = {"__gnu_cxx::__freeres()", "__libc_freeres()",
+ "__gnu_cxx::__freeres and __libc_freeres()"};
+ VG_(message)(Vg_DebugMsg,
+ "Caught __NR_exit; running %s wrapper\n", msgs[to_run - 1]);
+ }
- /* set thread context to point to libc_freeres_wrapper */
- /* ppc64be-linux note: __libc_freeres_wrapper gives us the real
+ /* set thread context to point to freeres_wrapper */
+ /* ppc64be-linux note: freeres_wrapper gives us the real
function entry point, not a fn descriptor, so can use it
directly. However, we need to set R2 (the toc pointer)
appropriately. */
- VG_(set_IP)(tid, __libc_freeres_wrapper);
+ VG_(set_IP)(tid, freeres_wrapper);
# if defined(VGP_ppc64be_linux)
VG_(threads)[tid].arch.vex.guest_GPR2 = r2;
# elif defined(VGP_ppc64le_linux)
/* setting GPR2 but not really needed, GPR12 is needed */
- VG_(threads)[tid].arch.vex.guest_GPR2 = __libc_freeres_wrapper;
- VG_(threads)[tid].arch.vex.guest_GPR12 = __libc_freeres_wrapper;
+ VG_(threads)[tid].arch.vex.guest_GPR2 = freeres_wrapper;
+ VG_(threads)[tid].arch.vex.guest_GPR12 = freeres_wrapper;
# endif
/* mips-linux note: we need to set t9 */
# if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
- VG_(threads)[tid].arch.vex.guest_r25 = __libc_freeres_wrapper;
+ VG_(threads)[tid].arch.vex.guest_r25 = freeres_wrapper;
# endif
+ /* Pass a parameter to freeres_wrapper(). */
+# if defined(VGA_x86)
+ Addr sp = VG_(threads)[tid].arch.vex.guest_ESP;
+ sp = sp - sizeof(UWord);
+ *((UWord *) sp) = to_run;
+ VG_TRACK(post_mem_write, Vg_CoreClientReq, tid, sp, sizeof(UWord));
+ VG_(threads)[tid].arch.vex.guest_ESP = sp;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestX86State, guest_ESP),
+ sizeof(VG_(threads)[tid].arch.vex.guest_ESP));
+# elif defined(VGA_amd64)
+ VG_(threads)[tid].arch.vex.guest_RDI = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestAMD64State, guest_RDI),
+ sizeof(VG_(threads)[tid].arch.vex.guest_RDI));
+# elif defined(VGA_arm)
+ VG_(threads)[tid].arch.vex.guest_R0 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestARMState, guest_R0),
+ sizeof(VG_(threads)[tid].arch.vex.guest_R0));
+# elif defined(VGA_arm64)
+ VG_(threads)[tid].arch.vex.guest_X0 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestARM64State, guest_X0),
+ sizeof(VG_(threads)[tid].arch.vex.guest_X0));
+# elif defined(VGA_mips32)
+ VG_(threads)[tid].arch.vex.guest_r4 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestMIPS32State, guest_r4),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r4));
+# elif defined(VGA_mips64)
+ VG_(threads)[tid].arch.vex.guest_r4 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestMIPS64State, guest_r4),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r4));
+# elif defined(VGA_ppc32)
+ VG_(threads)[tid].arch.vex.guest_GPR3 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestPPC32State, guest_GPR3),
+ sizeof(VG_(threads)[tid].arch.vex.guest_GPR3));
+# elif defined(VGA_ppc64be) || defined(VGA_ppc64le)
+ VG_(threads)[tid].arch.vex.guest_GPR3 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestPPC64State, guest_GPR3),
+ sizeof(VG_(threads)[tid].arch.vex.guest_GPR3));
+# elif defined(VGA_s390x)
+ VG_(threads)[tid].arch.vex.guest_r2 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestS390XState, guest_r2),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r2));
+# elif defined(VGA_tilegx)
+ VG_(threads)[tid].arch.vex.guest_r0 = to_run;
+ VG_TRACK(post_reg_write, Vg_CoreClientReq, tid,
+ offsetof(VexGuestTILEGXState, guest_r0),
+ sizeof(VG_(threads)[tid].arch.vex.guest_r0));
+#else
+ I_die_here : architecture missing in m_main.c
+#endif
+
/* Block all blockable signals by copying the real block state into
- the thread's block state*/
+ the thread's block state */
VG_(sigprocmask)(VKI_SIG_BLOCK, NULL, &VG_(threads)[tid].sig_mask);
VG_(threads)[tid].tmp_sig_mask = VG_(threads)[tid].sig_mask;
- /* and restore handlers to default */
+ /* and restore handlers to default. */
VG_(set_default_handler)(VKI_SIGSEGV);
VG_(set_default_handler)(VKI_SIGBUS);
VG_(set_default_handler)(VKI_SIGILL);
// We were exiting, so assert that...
vg_assert(VG_(is_exiting)(tid));
- // ...but now we're not again
+ // ...but now we're not again.
VG_(threads)[tid].exitreason = VgSrc_None;
- // run until client thread exits - ideally with LIBC_FREERES_DONE,
- // but exit/exitgroup/signal will do
+ // Run until client thread exits - ideally with FREERES_DONE,
+ // but exit/exitgroup/signal will do.
VG_(scheduler)(tid);
vg_assert(VG_(is_exiting)(tid));