mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 10:05:29 +00:00
Implement --merge-recursive-frames + provide VALGRIND_MONITOR_COMMAND client req.
In a big applications, some recursive algorithms have created hundreds of thousands of stacktraces, taking a lot of memory. Option --merge-recursive-frames=<number> tells Valgrind to detect and merge (collapse) recursive calls when recording stack traces. The value is changeable using the monitor command 'v.set merge-recursive-frames'. Also, this provides a new client request: VALGRIND_MONITOR_COMMAND allowing to execute a gdbsrv monitor command from the client program. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13246
This commit is contained in:
parent
ef7a42868a
commit
6fb1158a78
12
NEWS
12
NEWS
@ -30,6 +30,18 @@ Release 3.9.0 (?? ?????? 201?)
|
||||
This can be used to analyse one possible cause of Valgrind high
|
||||
memory usage for some programs.
|
||||
|
||||
- Option --merge-recursive-frames=<number> tells Valgrind to
|
||||
detect and merge (collapse) recursive calls when recording stack traces.
|
||||
When your program has recursive algorithms, this limits
|
||||
the memory used by Valgrind for recorded stack traces and avoid
|
||||
recording uninteresting repeated calls.
|
||||
The value is changeable using the monitor command
|
||||
'v.set merge-recursive-frames'.
|
||||
|
||||
- valgrind.h has a new request VALGRIND_MONITOR_COMMAND.
|
||||
This can be used to execute gdbserver monitor commands from
|
||||
the client program.
|
||||
|
||||
* ==================== FIXED BUGS ====================
|
||||
|
||||
The following bugs have been fixed or resolved. Note that "n-i-bz"
|
||||
|
||||
@ -771,19 +771,23 @@ int putpkt (char *buf)
|
||||
|
||||
void monitor_output (char *s)
|
||||
{
|
||||
const int len = strlen(s);
|
||||
char *buf = malloc(1 + 2*len + 1);
|
||||
|
||||
buf[0] = 'O';
|
||||
hexify(buf+1, s, len);
|
||||
if (putpkt (buf) < 0) {
|
||||
/* We probably have lost the connection with vgdb. */
|
||||
reset_valgrind_sink("Error writing monitor output");
|
||||
/* write again after reset */
|
||||
VG_(printf) ("%s", s);
|
||||
if (remote_connected()) {
|
||||
const int len = strlen(s);
|
||||
char *buf = malloc(1 + 2*len + 1);
|
||||
|
||||
buf[0] = 'O';
|
||||
hexify(buf+1, s, len);
|
||||
if (putpkt (buf) < 0) {
|
||||
/* We probably have lost the connection with vgdb. */
|
||||
reset_valgrind_sink("Error writing monitor output");
|
||||
/* write again after reset */
|
||||
VG_(printf) ("%s", s);
|
||||
}
|
||||
|
||||
free (buf);
|
||||
} else {
|
||||
print_to_initial_valgrind_sink (s);
|
||||
}
|
||||
|
||||
free (buf);
|
||||
}
|
||||
|
||||
/* Returns next char from remote GDB. -1 if error. */
|
||||
|
||||
@ -106,6 +106,13 @@ void reset_valgrind_sink(const char *info)
|
||||
}
|
||||
}
|
||||
|
||||
void print_to_initial_valgrind_sink (const char *msg)
|
||||
{
|
||||
vg_assert (initial_valgrind_sink_saved);
|
||||
VG_(write) (initial_valgrind_sink.fd, msg, strlen(msg));
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void kill_request (const char *msg)
|
||||
{
|
||||
@ -172,6 +179,7 @@ int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return)
|
||||
" v.set gdb_output : set valgrind output to gdb\n"
|
||||
" v.set log_output : set valgrind output to log\n"
|
||||
" v.set mixed_output : set valgrind output to log, interactive output to gdb\n"
|
||||
" v.set merge-recursive-frames <num> : merge recursive calls in max <num> frames\n"
|
||||
" v.set vgdb-error <errornr> : debug me at error >= <errornr> \n");
|
||||
if (int_value) { VG_(gdb_printf) (
|
||||
"debugging valgrind internals monitor commands:\n"
|
||||
@ -190,13 +198,15 @@ int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return)
|
||||
ret = 1;
|
||||
wcmd = strtok_r (NULL, " ", &ssaveptr);
|
||||
switch (kwdid = VG_(keyword_id)
|
||||
("vgdb-error debuglog gdb_output log_output mixed_output",
|
||||
("vgdb-error debuglog merge-recursive-frames"
|
||||
" gdb_output log_output mixed_output",
|
||||
wcmd, kwd_report_all)) {
|
||||
case -2:
|
||||
case -1:
|
||||
break;
|
||||
case 0: /* vgdb-error */
|
||||
case 1: /* debuglog */
|
||||
case 2: /* merge-recursive-frames */
|
||||
wcmd = strtok_r (NULL, " ", &ssaveptr);
|
||||
if (wcmd == NULL) {
|
||||
int_value = 0;
|
||||
@ -216,21 +226,26 @@ int handle_gdb_valgrind_command (char* mon, OutputSink* sink_wanted_at_return)
|
||||
VG_(gdb_printf) ("debuglog value changed from %d to %d\n",
|
||||
VG_(debugLog_getLevel)(), int_value);
|
||||
VG_(debugLog_startup) (int_value, "gdbsrv");
|
||||
} else if (kwdid == 2) {
|
||||
VG_(gdb_printf)
|
||||
("merge-recursive-frames value changed from %d to %d\n",
|
||||
VG_(clo_merge_recursive_frames), int_value);
|
||||
VG_(clo_merge_recursive_frames) = int_value;
|
||||
} else {
|
||||
vg_assert (0);
|
||||
}
|
||||
break;
|
||||
case 2: /* gdb_output */
|
||||
case 3: /* gdb_output */
|
||||
(*sink_wanted_at_return).fd = -2;
|
||||
command_output_to_log = False;
|
||||
VG_(gdb_printf) ("valgrind output will go to gdb\n");
|
||||
break;
|
||||
case 3: /* log_output */
|
||||
case 4: /* log_output */
|
||||
(*sink_wanted_at_return).fd = initial_valgrind_sink.fd;
|
||||
command_output_to_log = True;
|
||||
VG_(gdb_printf) ("valgrind output will go to log\n");
|
||||
break;
|
||||
case 4: /* mixed output */
|
||||
case 5: /* mixed output */
|
||||
(*sink_wanted_at_return).fd = initial_valgrind_sink.fd;
|
||||
command_output_to_log = False;
|
||||
VG_(gdb_printf)
|
||||
@ -459,6 +474,26 @@ void handle_set (char *arg_own_buf, int *new_packet_len_p)
|
||||
arg_own_buf[0] = 0;
|
||||
}
|
||||
|
||||
Bool VG_(client_monitor_command) (HChar* cmd)
|
||||
{
|
||||
const Bool connected = remote_connected();
|
||||
const int saved_command_output_to_log = command_output_to_log;
|
||||
Bool handled;
|
||||
|
||||
if (!connected)
|
||||
command_output_to_log = True;
|
||||
handled = handle_gdb_monitor_command (cmd);
|
||||
if (!connected) {
|
||||
// reset the log output unless cmd changed it.
|
||||
if (command_output_to_log)
|
||||
command_output_to_log = saved_command_output_to_log;
|
||||
}
|
||||
if (handled)
|
||||
return False; // recognised
|
||||
else
|
||||
return True; // not recognised
|
||||
}
|
||||
|
||||
/* Handle all of the extended 'q' packets. */
|
||||
static
|
||||
void handle_query (char *arg_own_buf, int *new_packet_len_p)
|
||||
|
||||
@ -63,7 +63,7 @@ extern void gdbserver_terminate (void);
|
||||
|
||||
|
||||
/* Output string s to the gdb debugging this process or to vgdb.
|
||||
Do not call this directly. Rather use VG_(monitor_print)
|
||||
Do not call this directly. Rather use VG_(gdb_printf)
|
||||
to output something to gdb, use normal valgrind messaging
|
||||
(e.g. VG_(umsg)) to send output that can either go
|
||||
to gdb or to log. */
|
||||
@ -94,6 +94,11 @@ extern void remote_finish(FinishReason reason);
|
||||
and does VG_(umsg). If info != NULL, info added in VG_(usmg). */
|
||||
extern void reset_valgrind_sink(const char* info);
|
||||
|
||||
// VG_(gdb_printf) by default writes to vgdb/gdb.
|
||||
// If there is no connection, it will rather write to the initial (log)
|
||||
// valgrind fd using the below.
|
||||
extern void print_to_initial_valgrind_sink (const char *msg);
|
||||
|
||||
/* For ARM usage.
|
||||
Guesses if pc is a thumb pc.
|
||||
In this case, returns pc with the thumb bit set (bit0)
|
||||
|
||||
@ -193,6 +193,8 @@ static void usage_NORETURN ( Bool debug_help )
|
||||
" --fair-sched=no|yes|try schedule threads fairly on multicore systems [no]\n"
|
||||
" --kernel-variant=variant1,variant2,... known variants: bproc [none]\n"
|
||||
" handle non-standard kernel variants\n"
|
||||
" --merge-recursive-frames=<number> merge frames between identical\n"
|
||||
" program counters in max <number> frames) [0]\n"
|
||||
" --show-emwarns=no|yes show warnings about emulation limits? [no]\n"
|
||||
" --require-text-symbol=:sonamepattern:symbolpattern abort run if the\n"
|
||||
" stated shared object doesn't have the stated\n"
|
||||
@ -599,6 +601,9 @@ void main_process_cmd_line_options ( /*OUT*/Bool* logging_to_fd,
|
||||
else if VG_INT_CLO (arg, "--sanity-level", VG_(clo_sanity_level)) {}
|
||||
else if VG_BINT_CLO(arg, "--num-callers", VG_(clo_backtrace_size), 1,
|
||||
VG_DEEPEST_BACKTRACE) {}
|
||||
else if VG_BINT_CLO(arg, "--merge-recursive-frames",
|
||||
VG_(clo_merge_recursive_frames), 0,
|
||||
VG_DEEPEST_BACKTRACE) {}
|
||||
|
||||
else if VG_XACT_CLO(arg, "--smc-check=none", VG_(clo_smc_check),
|
||||
Vg_SmcNone);
|
||||
|
||||
@ -105,6 +105,7 @@ Int VG_(clo_core_redzone_size) = CORE_REDZONE_DEFAULT_SZB;
|
||||
Int VG_(clo_redzone_size) = -1;
|
||||
Int VG_(clo_dump_error) = 0;
|
||||
Int VG_(clo_backtrace_size) = 12;
|
||||
Int VG_(clo_merge_recursive_frames) = 0; // default value: no merge
|
||||
const HChar* VG_(clo_sim_hints) = NULL;
|
||||
Bool VG_(clo_sym_offsets) = False;
|
||||
Bool VG_(clo_read_var_info) = False;
|
||||
|
||||
@ -1881,6 +1881,13 @@ void do_client_request ( ThreadId tid )
|
||||
break;
|
||||
}
|
||||
|
||||
case VG_USERREQ__GDB_MONITOR_COMMAND: {
|
||||
UWord ret;
|
||||
ret = (UWord) VG_(client_monitor_command) ((HChar*)arg[1]);
|
||||
SET_CLREQ_RETVAL(tid, ret);
|
||||
break;
|
||||
}
|
||||
|
||||
case VG_USERREQ__MALLOCLIKE_BLOCK:
|
||||
case VG_USERREQ__RESIZEINPLACE_BLOCK:
|
||||
case VG_USERREQ__FREELIKE_BLOCK:
|
||||
|
||||
@ -62,6 +62,21 @@
|
||||
traces on ppc64-linux and has no effect on other platforms.
|
||||
*/
|
||||
|
||||
/* Do frame merging in the _i frames in _ips array of recursive cycles
|
||||
of up to _nframes. The merge is done during stack unwinding
|
||||
(i.e. in platform specific unwinders) to collect as many
|
||||
"interesting" stack traces as possible. */
|
||||
#define RECURSIVE_MERGE(_nframes,_ips,_i){ \
|
||||
Int dist; \
|
||||
for (dist = 1; dist <= _nframes && dist < (Int)_i; dist++) { \
|
||||
if (_ips[_i-1] == _ips[_i-1-dist]) { \
|
||||
_i = _i - dist; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------ x86 ------------------------- */
|
||||
|
||||
#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
|
||||
@ -76,6 +91,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
Int i;
|
||||
Addr fp_max;
|
||||
UInt n_found = 0;
|
||||
const Int cmrf = VG_(clo_merge_recursive_frames);
|
||||
|
||||
vg_assert(sizeof(Addr) == sizeof(UWord));
|
||||
vg_assert(sizeof(Addr) == sizeof(void*));
|
||||
@ -178,6 +194,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
VG_(printf)(" ipsF[%d]=0x%08lx\n", i-1, ips[i-1]);
|
||||
uregs.xip = uregs.xip - 1;
|
||||
/* as per comment at the head of this loop */
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -192,6 +209,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
VG_(printf)(" ipsC[%d]=0x%08lx\n", i-1, ips[i-1]);
|
||||
uregs.xip = uregs.xip - 1;
|
||||
/* as per comment at the head of this loop */
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -205,6 +223,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (debug)
|
||||
VG_(printf)(" ipsC[%d]=0x%08lx\n", i-1, ips[i-1]);
|
||||
uregs.xip = uregs.xip - 1;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -232,6 +251,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
Int i;
|
||||
Addr fp_max;
|
||||
UInt n_found = 0;
|
||||
const Int cmrf = VG_(clo_merge_recursive_frames);
|
||||
|
||||
vg_assert(sizeof(Addr) == sizeof(UWord));
|
||||
vg_assert(sizeof(Addr) == sizeof(void*));
|
||||
@ -314,6 +334,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (debug)
|
||||
VG_(printf)(" ipsC[%d]=%#08lx\n", i-1, ips[i-1]);
|
||||
uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -342,6 +363,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (debug)
|
||||
VG_(printf)(" ipsF[%d]=%#08lx\n", i-1, ips[i-1]);
|
||||
uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -371,6 +393,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
VG_(printf)(" ipsH[%d]=%#08lx\n", i-1, ips[i-1]);
|
||||
uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */
|
||||
uregs.xsp += 8;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -399,6 +422,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
Word redir_stack_size = 0;
|
||||
Word redirs_used = 0;
|
||||
# endif
|
||||
const Int cmrf = VG_(clo_merge_recursive_frames);
|
||||
|
||||
Bool debug = False;
|
||||
Int i;
|
||||
@ -557,6 +581,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
ip = ip - 1; /* ip is probably dead at this point, but
|
||||
play safe, a la x86/amd64 above. See
|
||||
extensive comments above. */
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -666,6 +691,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
Int i;
|
||||
Addr fp_max;
|
||||
UInt n_found = 0;
|
||||
const Int cmrf = VG_(clo_merge_recursive_frames);
|
||||
|
||||
vg_assert(sizeof(Addr) == sizeof(UWord));
|
||||
vg_assert(sizeof(Addr) == sizeof(void*));
|
||||
@ -737,6 +763,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
VG_(printf)("USING CFI: r15: 0x%lx, r13: 0x%lx\n",
|
||||
uregs.r15, uregs.r13);
|
||||
uregs.r15 = (uregs.r15 & 0xFFFFFFFE) - 1;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
/* No luck. We have to give up. */
|
||||
@ -759,6 +786,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (sps) sps[i] = 0;
|
||||
if (fps) fps[i] = 0;
|
||||
ips[i++] = cand;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
nByStackScan++;
|
||||
}
|
||||
}
|
||||
@ -775,6 +803,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (sps) sps[i] = 0;
|
||||
if (fps) fps[i] = 0;
|
||||
ips[i++] = cand;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
if (++nByStackScan >= 5) break;
|
||||
}
|
||||
}
|
||||
@ -802,6 +831,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
Int i;
|
||||
Addr fp_max;
|
||||
UInt n_found = 0;
|
||||
const Int cmrf = VG_(clo_merge_recursive_frames);
|
||||
|
||||
vg_assert(sizeof(Addr) == sizeof(UWord));
|
||||
vg_assert(sizeof(Addr) == sizeof(void*));
|
||||
@ -841,6 +871,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (fps) fps[i] = uregs.fp;
|
||||
ips[i++] = uregs.ia - 1;
|
||||
uregs.ia = uregs.ia - 1;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
/* A problem on the first frame? Lets assume it was a bad jump.
|
||||
@ -857,6 +888,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
}
|
||||
uregs.ia = uregs.lr - 1;
|
||||
ips[i++] = uregs.lr - 1;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -884,6 +916,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
Int i;
|
||||
Addr fp_max;
|
||||
UInt n_found = 0;
|
||||
const Int cmrf = VG_(clo_merge_recursive_frames);
|
||||
|
||||
vg_assert(sizeof(Addr) == sizeof(UWord));
|
||||
vg_assert(sizeof(Addr) == sizeof(void*));
|
||||
@ -935,6 +968,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (fps) fps[i] = uregs.fp;
|
||||
ips[i++] = uregs.pc - 4;
|
||||
uregs.pc = uregs.pc - 4;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
} else
|
||||
uregs = uregs_copy;
|
||||
@ -993,6 +1027,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (0 == uregs.ra || 1 == uregs.ra) break;
|
||||
uregs.pc = uregs.ra - 8;
|
||||
ips[i++] = uregs.ra - 8;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1008,6 +1043,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
|
||||
if (0 == uregs.ra || 1 == uregs.ra) break;
|
||||
uregs.pc = uregs.ra - 8;
|
||||
ips[i++] = uregs.ra - 8;
|
||||
if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);};
|
||||
continue;
|
||||
}
|
||||
/* No luck. We have to give up. */
|
||||
|
||||
@ -88,6 +88,11 @@ extern void VG_(invoke_gdbserver) ( int check );
|
||||
// guest program.
|
||||
extern Bool VG_(gdbserver_report_signal) (Int signo, ThreadId tid);
|
||||
|
||||
/* Entry point invoked by scheduler.c to execute the request
|
||||
VALGRIND_CLIENT_MONITOR_COMMAND.
|
||||
Returns True if command was not recognised. */
|
||||
extern Bool VG_(client_monitor_command) (HChar* cmd);
|
||||
|
||||
/* software_breakpoint, single step and jump support ------------------------*/
|
||||
/* VG_(instrument_for_gdbserver_if_needed) allows to do "standard and easy"
|
||||
instrumentation for gdbserver.
|
||||
|
||||
@ -252,6 +252,14 @@ extern Word VG_(clo_max_stackframe);
|
||||
be? */
|
||||
extern Word VG_(clo_main_stacksize);
|
||||
|
||||
/* If the same IP is found twice in a backtrace in a sequence of max
|
||||
VG_(clo_merge_recursive_frames) frames, then the recursive call
|
||||
is merged in the backtrace.
|
||||
Note also that the merge is done during unwinding, to obtain
|
||||
an much as possible significant backtrace.
|
||||
Note that the value is changeable by a gdbsrv command. */
|
||||
extern Int VG_(clo_merge_recursive_frames);
|
||||
|
||||
/* Delay startup to allow GDB to be attached? Default: NO */
|
||||
extern Bool VG_(clo_wait_for_gdb);
|
||||
|
||||
|
||||
@ -1809,6 +1809,39 @@ need to use them.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.merge-recursive-frames" xreflabel="--merge-recursive-frames">
|
||||
<term>
|
||||
<option><![CDATA[--merge-recursive-frames=<number> [default: 0] ]]></option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Some recursive algorithms (such as balanced binary tree
|
||||
implementations) have the property to create many different
|
||||
stack traces, containing cycles of calls. A cycle is defined by
|
||||
two identical program counters separated by 0 or more other
|
||||
program counters. Valgrind might then use a lot of memory to
|
||||
record these stack traces, containing repeated uninteresting
|
||||
recursive calls instead of more interesting information such as
|
||||
the function that has initiated the recursive call.
|
||||
</para>
|
||||
<para>The option <option>--merge-recursive-frames=<number></option>
|
||||
instructs Valgrind to detect and merge recursive call cycles
|
||||
having a size of up to <option><number></option>
|
||||
frames. When such a cycle is detected, Valgrind records the
|
||||
cycle in the stack trace as a unique program counter.
|
||||
</para>
|
||||
<para>
|
||||
The value 0 (the default) causes no recursive call merging.
|
||||
A value of 1 will cause stack traces of simple recursive algorithms
|
||||
(for example, a factorial implementation) to be collapsed.
|
||||
A value of 2 will usually be needed to collapsed stack traces produced
|
||||
by recursive algorithms such binary trees, quick sort, ...
|
||||
Higher values might be needed for more complex recursive algorithms.
|
||||
</para>
|
||||
<para>Note: recursive calls are detected based on program counters.
|
||||
The cycles are not detected based on function names. </para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="opt.show-emwarns" xreflabel="--show-emwarns">
|
||||
<term>
|
||||
<option><![CDATA[--show-emwarns=<yes|no> [default: no] ]]></option>
|
||||
|
||||
@ -9,6 +9,7 @@ general valgrind monitor commands:
|
||||
v.set gdb_output : set valgrind output to gdb
|
||||
v.set log_output : set valgrind output to log
|
||||
v.set mixed_output : set valgrind output to log, interactive output to gdb
|
||||
v.set merge-recursive-frames <num> : merge recursive calls in max <num> frames
|
||||
v.set vgdb-error <errornr> : debug me at error >= <errornr>
|
||||
|
||||
memcheck monitor commands:
|
||||
@ -50,6 +51,7 @@ general valgrind monitor commands:
|
||||
v.set gdb_output : set valgrind output to gdb
|
||||
v.set log_output : set valgrind output to log
|
||||
v.set mixed_output : set valgrind output to log, interactive output to gdb
|
||||
v.set merge-recursive-frames <num> : merge recursive calls in max <num> frames
|
||||
v.set vgdb-error <errornr> : debug me at error >= <errornr>
|
||||
debugging valgrind internals monitor commands:
|
||||
v.info gdbserver_status : show gdbserver status
|
||||
|
||||
@ -11,6 +11,7 @@ general valgrind monitor commands:
|
||||
v.set gdb_output : set valgrind output to gdb
|
||||
v.set log_output : set valgrind output to log
|
||||
v.set mixed_output : set valgrind output to log, interactive output to gdb
|
||||
v.set merge-recursive-frames <num> : merge recursive calls in max <num> frames
|
||||
v.set vgdb-error <errornr> : debug me at error >= <errornr>
|
||||
|
||||
massif monitor commands:
|
||||
|
||||
@ -4464,8 +4464,8 @@ typedef
|
||||
errors. */
|
||||
VG_USERREQ__COUNT_ERRORS = 0x1201,
|
||||
|
||||
/* Allows a string (gdb monitor command) to be passed to the tool
|
||||
Used for interaction with vgdb/gdb */
|
||||
/* Allows the client program and/or gdbserver to execute a monitor
|
||||
command. */
|
||||
VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202,
|
||||
|
||||
/* These are useful and can be interpreted by any tool that
|
||||
@ -4893,6 +4893,16 @@ VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
|
||||
VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__CHANGE_ERR_DISABLEMENT, \
|
||||
-1, 0, 0, 0, 0)
|
||||
|
||||
/* Execute a monitor command from the client program.
|
||||
If a connection is opened with GDB, the output will be sent
|
||||
according to the output mode set for vgdb.
|
||||
If no connection is opened, output will go to the log output.
|
||||
Returns 1 if command not recognised, 0 otherwise. */
|
||||
#define VALGRIND_MONITOR_COMMAND(command) \
|
||||
VALGRIND_DO_CLIENT_REQUEST_EXPR(0, VG_USERREQ__GDB_MONITOR_COMMAND, \
|
||||
command, 0, 0, 0, 0)
|
||||
|
||||
|
||||
#undef PLAT_x86_darwin
|
||||
#undef PLAT_amd64_darwin
|
||||
#undef PLAT_x86_win32
|
||||
|
||||
@ -184,6 +184,7 @@ EXTRA_DIST = \
|
||||
realloc1.stderr.exp realloc1.vgtest \
|
||||
realloc2.stderr.exp realloc2.vgtest \
|
||||
realloc3.stderr.exp realloc3.vgtest \
|
||||
recursive-merge.stderr.exp recursive-merge.vgtest \
|
||||
sbfragment.stdout.exp sbfragment.stderr.exp sbfragment.vgtest \
|
||||
sem.stderr.exp sem.vgtest \
|
||||
sh-mem.stderr.exp sh-mem.vgtest \
|
||||
@ -289,6 +290,7 @@ check_PROGRAMS = \
|
||||
pipe pointer-trace \
|
||||
post-syscall \
|
||||
realloc1 realloc2 realloc3 \
|
||||
recursive-merge \
|
||||
sbfragment \
|
||||
sh-mem sh-mem-random \
|
||||
sigaltstack signal2 sigprocmask static_malloc sigkill \
|
||||
|
||||
71
memcheck/tests/recursive-merge.c
Normal file
71
memcheck/tests/recursive-merge.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <valgrind.h>
|
||||
|
||||
void (*fnptr[256])(char*, char*);
|
||||
|
||||
#define BODY(f) \
|
||||
{ \
|
||||
fprintf(stderr, f); \
|
||||
calls++; \
|
||||
(*fnptr[(int)*calls])(calls,seq); \
|
||||
}
|
||||
|
||||
void stacktrace(char*last, char* callsequence)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
VALGRIND_PRINTF_BACKTRACE (callsequence);
|
||||
}
|
||||
__attribute__((noinline)) void f_a(char *calls, char*seq);
|
||||
__attribute__((noinline)) void f_b(char *calls, char*seq);
|
||||
__attribute__((noinline)) void f_c(char *calls, char*seq);
|
||||
__attribute__((noinline)) void f_d(char *calls, char*seq);
|
||||
|
||||
__attribute__((noinline)) void f_a(char *calls, char*seq)
|
||||
BODY("a")
|
||||
|
||||
__attribute__((noinline)) void f_b(char *calls, char*seq)
|
||||
BODY("b")
|
||||
|
||||
__attribute__((noinline)) void f_c(char *calls, char*seq)
|
||||
BODY("c");
|
||||
|
||||
__attribute__((noinline)) void f_d(char *calls, char*seq)
|
||||
BODY("d");
|
||||
|
||||
void doit (int argc, char**argv)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i < argc; i++) {
|
||||
char* calls = argv[i];
|
||||
char* seq = argv[i];
|
||||
calls--;
|
||||
BODY("test ")
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
|
||||
fnptr[0] = stacktrace;
|
||||
fnptr['a'] = f_a;
|
||||
fnptr['b'] = f_b;
|
||||
fnptr['c'] = f_c;
|
||||
fnptr['d'] = f_d;
|
||||
|
||||
doit(argc, argv); // with default value of our argument.
|
||||
|
||||
VALGRIND_MONITOR_COMMAND("v.set merge-recursive-frames 3");
|
||||
doit(argc, argv);
|
||||
|
||||
VALGRIND_MONITOR_COMMAND("v.set merge-recursive-frames 2");
|
||||
doit(argc, argv);
|
||||
|
||||
VALGRIND_MONITOR_COMMAND("v.set merge-recursive-frames 1");
|
||||
doit(argc, argv);
|
||||
|
||||
VALGRIND_MONITOR_COMMAND("v.set merge-recursive-frames 0");
|
||||
doit(argc, argv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
263
memcheck/tests/recursive-merge.stderr.exp
Normal file
263
memcheck/tests/recursive-merge.stderr.exp
Normal file
@ -0,0 +1,263 @@
|
||||
test a
|
||||
a at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
test aa
|
||||
aa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
test aaa
|
||||
aaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
test aaaa
|
||||
aaaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
test abab
|
||||
abab at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
test abca
|
||||
abca at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
test abcda
|
||||
abcda at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_d (recursive-merge.c:34)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:56)
|
||||
merge-recursive-frames value changed from 1 to 3
|
||||
test a
|
||||
a at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
test aa
|
||||
aa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
test aaa
|
||||
aaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
test aaaa
|
||||
aaaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
test abab
|
||||
abab at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
test abca
|
||||
abca at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
test abcda
|
||||
abcda at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_d (recursive-merge.c:34)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:59)
|
||||
merge-recursive-frames value changed from 3 to 2
|
||||
test a
|
||||
a at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
test aa
|
||||
aa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
test aaa
|
||||
aaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
test aaaa
|
||||
aaaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
test abab
|
||||
abab at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
test abca
|
||||
abca at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
test abcda
|
||||
abcda at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_d (recursive-merge.c:34)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:62)
|
||||
merge-recursive-frames value changed from 2 to 1
|
||||
test a
|
||||
a at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
test aa
|
||||
aa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
test aaa
|
||||
aaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
test aaaa
|
||||
aaaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
test abab
|
||||
abab at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
test abca
|
||||
abca at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
test abcda
|
||||
abcda at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_d (recursive-merge.c:34)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:65)
|
||||
merge-recursive-frames value changed from 1 to 0
|
||||
test a
|
||||
a at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
test aa
|
||||
aa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
test aaa
|
||||
aaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
test aaaa
|
||||
aaaa at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
test abab
|
||||
abab at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
test abca
|
||||
abca at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
test abcda
|
||||
abcda at 0x........: VALGRIND_PRINTF_BACKTRACE (valgrind.h:...)
|
||||
by 0x........: stacktrace (recursive-merge.c:17)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: f_d (recursive-merge.c:34)
|
||||
by 0x........: f_c (recursive-merge.c:31)
|
||||
by 0x........: f_b (recursive-merge.c:28)
|
||||
by 0x........: f_a (recursive-merge.c:25)
|
||||
by 0x........: doit (recursive-merge.c:43)
|
||||
by 0x........: main (recursive-merge.c:68)
|
||||
3
memcheck/tests/recursive-merge.vgtest
Normal file
3
memcheck/tests/recursive-merge.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: recursive-merge
|
||||
args: a aa aaa aaaa abab abca abcda
|
||||
vgopts: -q --leak-check=full --merge-recursive-frames=1
|
||||
@ -81,6 +81,8 @@ usage: valgrind [options] prog-and-args
|
||||
--fair-sched=no|yes|try schedule threads fairly on multicore systems [no]
|
||||
--kernel-variant=variant1,variant2,... known variants: bproc [none]
|
||||
handle non-standard kernel variants
|
||||
--merge-recursive-frames=<number> merge frames between identical
|
||||
program counters in max <number> frames) [0]
|
||||
--show-emwarns=no|yes show warnings about emulation limits? [no]
|
||||
--require-text-symbol=:sonamepattern:symbolpattern abort run if the
|
||||
stated shared object doesn't have the stated
|
||||
|
||||
@ -81,6 +81,8 @@ usage: valgrind [options] prog-and-args
|
||||
--fair-sched=no|yes|try schedule threads fairly on multicore systems [no]
|
||||
--kernel-variant=variant1,variant2,... known variants: bproc [none]
|
||||
handle non-standard kernel variants
|
||||
--merge-recursive-frames=<number> merge frames between identical
|
||||
program counters in max <number> frames) [0]
|
||||
--show-emwarns=no|yes show warnings about emulation limits? [no]
|
||||
--require-text-symbol=:sonamepattern:symbolpattern abort run if the
|
||||
stated shared object doesn't have the stated
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user