mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
Enhance block_list memcheck gdbserver monitor command
Due to the (still to be done) default activation of --leak-check-heuristics=all, improve the block_list monitor command for easier display of blocks found reachable via heuristics. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15617
This commit is contained in:
parent
d0cf6ac4fa
commit
0307c6dcaa
12
NEWS
12
NEWS
@ -48,10 +48,14 @@ X86/MacOSX 10.10 and 10.11 and AMD64/MacOSX 10.10 and 10.11.
|
||||
than get_vbits when you need to associate byte data value with
|
||||
their corresponding validity bits.
|
||||
|
||||
- The 'block_list' monitor command now accepts an optional argument
|
||||
'limited <max_blocks>' to control the nr of block addresses
|
||||
printed. Also, if a block has been found using an heuristic, then
|
||||
'block_list' will now show the heuristic after the block size.
|
||||
- The 'block_list' monitor command has been enhanced:
|
||||
o it can print a range of loss records
|
||||
o it now accepts an optional argument 'limited <max_blocks>'
|
||||
to control the nr of block printed.
|
||||
o if a block has been found using an heuristic, then
|
||||
'block_list' now shows the heuristic after the block size.
|
||||
o the loss records/blocks to print can be limited to the blocks
|
||||
found via specified heuristics.
|
||||
|
||||
- The C helper functions used to instrument loads on x86-linux and
|
||||
arm-linux (both 32-bit only) have been replaced by handwritten
|
||||
|
||||
@ -41,8 +41,12 @@ memcheck monitor commands:
|
||||
leak_check summary any
|
||||
leak_check full kinds indirect,possible
|
||||
leak_check full reachable any limited 100
|
||||
block_list <loss_record_nr> [unlimited*|limited <max_blocks>]
|
||||
block_list <loss_record_nr>|<loss_record_nr_from>..<loss_record_nr_to>
|
||||
[unlimited*|limited <max_blocks>]
|
||||
[heuristics heur1,heur2,...]
|
||||
after a leak search, shows the list of blocks of <loss_record_nr>
|
||||
(or of the range <loss_record_nr_from>..<loss_record_nr_to>).
|
||||
With heuristics, only shows the blocks found via heur1,heur2,...
|
||||
* = defaults
|
||||
who_points_at <addr> [<len>]
|
||||
shows places pointing inside <len> (default 1) bytes at <addr>
|
||||
@ -106,8 +110,12 @@ memcheck monitor commands:
|
||||
leak_check summary any
|
||||
leak_check full kinds indirect,possible
|
||||
leak_check full reachable any limited 100
|
||||
block_list <loss_record_nr> [unlimited*|limited <max_blocks>]
|
||||
block_list <loss_record_nr>|<loss_record_nr_from>..<loss_record_nr_to>
|
||||
[unlimited*|limited <max_blocks>]
|
||||
[heuristics heur1,heur2,...]
|
||||
after a leak search, shows the list of blocks of <loss_record_nr>
|
||||
(or of the range <loss_record_nr_from>..<loss_record_nr_to>).
|
||||
With heuristics, only shows the blocks found via heur1,heur2,...
|
||||
* = defaults
|
||||
who_points_at <addr> [<len>]
|
||||
shows places pointing inside <len> (default 1) bytes at <addr>
|
||||
|
||||
@ -1903,12 +1903,19 @@ Address 0x8049E28 len 1 defined
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><varname>block_list <loss_record_nr>
|
||||
[unlimited*|limited <max_blocks>]</varname>
|
||||
shows the list of blocks belonging to <loss_record_nr>.
|
||||
<para><varname>block_list <loss_record_nr>|<loss_record_nr_from>..<loss_record_nr_to>
|
||||
[unlimited*|limited <max_blocks>]
|
||||
[heuristics heur1,heur2,...]
|
||||
</varname>
|
||||
shows the list of blocks belonging to
|
||||
<varname><loss_record_nr></varname> (or to the loss records range
|
||||
<varname><loss_record_nr_from>..<loss_record_nr_to></varname>).
|
||||
The nr of blocks to print can be controlled using the
|
||||
<varname>limited</varname> argument followed by the maximum nr
|
||||
of blocks to output.
|
||||
If one or more heuristics are given, only prints the loss records
|
||||
and blocks found via one of the given <varname>heur1,heur2,...</varname>
|
||||
heuristics.
|
||||
</para>
|
||||
|
||||
<para> A leak search merges the allocated blocks in loss records :
|
||||
|
||||
@ -460,11 +460,16 @@ extern UInt MC_(leak_search_gen);
|
||||
// maintains the lcp.deltamode given in the last call to detect_memory_leaks
|
||||
extern LeakCheckDeltaMode MC_(detect_memory_leaks_last_delta_mode);
|
||||
|
||||
// prints the list of blocks corresponding to the given loss_record_nr.
|
||||
// (up to maximum max_blocks)
|
||||
// Returns True if loss_record_nr identifies a correct loss record from last
|
||||
// leak search, returns False otherwise.
|
||||
Bool MC_(print_block_list) ( UInt loss_record_nr, UInt max_blocks);
|
||||
// prints the list of blocks corresponding to the given loss_record_nr slice
|
||||
// (from/to) (up to maximum max_blocks)
|
||||
// Returns True if loss_record_nr_from identifies a correct loss record
|
||||
// from last leak search, returns False otherwise.
|
||||
// Note that loss_record_nr_to can be bigger than the nr of loss records. All
|
||||
// loss records after from will then be examined and maybe printed.
|
||||
// If heuristics != 0, print only the loss records/blocks found via
|
||||
// one of the heuristics in the set.
|
||||
Bool MC_(print_block_list) ( UInt loss_record_nr_from, UInt loss_record_nr_to,
|
||||
UInt max_blocks, UInt heuristics);
|
||||
|
||||
// Prints the addresses/registers/... at which a pointer to
|
||||
// the given range [address, address+szB[ is found.
|
||||
|
||||
@ -1544,10 +1544,15 @@ static void print_clique (Int clique, UInt level, UInt *remaining)
|
||||
}
|
||||
}
|
||||
|
||||
Bool MC_(print_block_list) ( UInt loss_record_nr, UInt max_blocks)
|
||||
Bool MC_(print_block_list) ( UInt loss_record_nr_from,
|
||||
UInt loss_record_nr_to,
|
||||
UInt max_blocks,
|
||||
UInt heuristics)
|
||||
{
|
||||
UInt loss_record_nr;
|
||||
UInt i, n_lossrecords;
|
||||
LossRecord* lr;
|
||||
Bool lr_printed;
|
||||
UInt remaining = max_blocks;
|
||||
|
||||
if (lr_table == NULL || lc_chunks == NULL || lc_extras == NULL) {
|
||||
@ -1561,52 +1566,75 @@ Bool MC_(print_block_list) ( UInt loss_record_nr, UInt max_blocks)
|
||||
}
|
||||
|
||||
n_lossrecords = VG_(OSetGen_Size)(lr_table);
|
||||
if (loss_record_nr >= n_lossrecords)
|
||||
return False; // Invalid loss record nr.
|
||||
if (loss_record_nr_from >= n_lossrecords)
|
||||
return False; // Invalid starting loss record nr.
|
||||
|
||||
if (loss_record_nr_to >= n_lossrecords)
|
||||
loss_record_nr_to = n_lossrecords - 1;
|
||||
|
||||
tl_assert (lr_array);
|
||||
lr = lr_array[loss_record_nr];
|
||||
|
||||
for (loss_record_nr = loss_record_nr_from;
|
||||
loss_record_nr <= loss_record_nr_to && remaining > 0;
|
||||
loss_record_nr++) {
|
||||
lr = lr_array[loss_record_nr];
|
||||
lr_printed = False;
|
||||
|
||||
/* If user asks to print a specific loss record, we print
|
||||
the block details, even if no block will be shown for this lr.
|
||||
If user asks to print a range of lr, we only print lr details
|
||||
when at least one block is shown. */
|
||||
if (loss_record_nr_from == loss_record_nr_to) {
|
||||
/* (+1 on loss_record_nr as user numbering for loss records
|
||||
starts at 1). */
|
||||
MC_(pp_LossRecord)(loss_record_nr+1, n_lossrecords, lr);
|
||||
lr_printed = True;
|
||||
}
|
||||
|
||||
// (re-)print the loss record details.
|
||||
// (+1 on loss_record_nr as user numbering for loss records starts at 1).
|
||||
MC_(pp_LossRecord)(loss_record_nr+1, n_lossrecords, lr);
|
||||
// Match the chunks with loss records.
|
||||
for (i = 0; i < lc_n_chunks && remaining > 0; i++) {
|
||||
MC_Chunk* ch = lc_chunks[i];
|
||||
LC_Extra* ex = &(lc_extras)[i];
|
||||
LossRecord* old_lr;
|
||||
LossRecordKey lrkey;
|
||||
lrkey.state = ex->state;
|
||||
lrkey.allocated_at = MC_(allocated_at)(ch);
|
||||
|
||||
// Match the chunks with loss records.
|
||||
for (i = 0; i < lc_n_chunks && remaining > 0; i++) {
|
||||
MC_Chunk* ch = lc_chunks[i];
|
||||
LC_Extra* ex = &(lc_extras)[i];
|
||||
LossRecord* old_lr;
|
||||
LossRecordKey lrkey;
|
||||
lrkey.state = ex->state;
|
||||
lrkey.allocated_at = MC_(allocated_at)(ch);
|
||||
old_lr = VG_(OSetGen_Lookup)(lr_table, &lrkey);
|
||||
if (old_lr) {
|
||||
// We found an existing loss record matching this chunk.
|
||||
// If this is the loss record we are looking for, output the
|
||||
// pointer.
|
||||
if (old_lr == lr_array[loss_record_nr]
|
||||
&& (heuristics == 0 || HiS(ex->heuristic, heuristics))) {
|
||||
if (!lr_printed) {
|
||||
MC_(pp_LossRecord)(loss_record_nr+1, n_lossrecords, lr);
|
||||
lr_printed = True;
|
||||
}
|
||||
|
||||
old_lr = VG_(OSetGen_Lookup)(lr_table, &lrkey);
|
||||
if (old_lr) {
|
||||
// We found an existing loss record matching this chunk.
|
||||
// If this is the loss record we are looking for, output the pointer.
|
||||
if (old_lr == lr_array[loss_record_nr]) {
|
||||
if (ex->heuristic)
|
||||
VG_(umsg)("%p[%lu] (found via heuristic %s)\n",
|
||||
(void *)ch->data, (SizeT)ch->szB,
|
||||
pp_heuristic (ex->heuristic));
|
||||
else
|
||||
VG_(umsg)("%p[%lu]\n",
|
||||
(void *)ch->data, (SizeT)ch->szB);
|
||||
remaining--;
|
||||
if (ex->state != Reachable) {
|
||||
// We can print the clique in all states, except Reachable.
|
||||
// In Unreached state, lc_chunk[i] is the clique leader.
|
||||
// In IndirectLeak, lc_chunk[i] might have been a clique leader
|
||||
// which was later collected in another clique.
|
||||
// For Possible, lc_chunk[i] might be the top of a clique
|
||||
// or an intermediate clique.
|
||||
print_clique(i, 1, &remaining);
|
||||
if (ex->heuristic)
|
||||
VG_(umsg)("%p[%lu] (found via heuristic %s)\n",
|
||||
(void *)ch->data, (SizeT)ch->szB,
|
||||
pp_heuristic (ex->heuristic));
|
||||
else
|
||||
VG_(umsg)("%p[%lu]\n",
|
||||
(void *)ch->data, (SizeT)ch->szB);
|
||||
remaining--;
|
||||
if (ex->state != Reachable) {
|
||||
// We can print the clique in all states, except Reachable.
|
||||
// In Unreached state, lc_chunk[i] is the clique leader.
|
||||
// In IndirectLeak, lc_chunk[i] might have been a clique
|
||||
// leader which was later collected in another clique.
|
||||
// For Possible, lc_chunk[i] might be the top of a clique
|
||||
// or an intermediate clique.
|
||||
print_clique(i, 1, &remaining);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No existing loss record matches this chunk ???
|
||||
VG_(umsg)("error: no loss record found for %p[%lu]?????\n",
|
||||
(void *)ch->data, (SizeT)ch->szB);
|
||||
}
|
||||
} else {
|
||||
// No existing loss record matches this chunk ???
|
||||
VG_(umsg)("error: no loss record found for %p[%lu]?????\n",
|
||||
(void *)ch->data, (SizeT)ch->szB);
|
||||
}
|
||||
}
|
||||
return True;
|
||||
|
||||
@ -6032,8 +6032,12 @@ static void print_monitor_help ( void )
|
||||
" leak_check summary any\n"
|
||||
" leak_check full kinds indirect,possible\n"
|
||||
" leak_check full reachable any limited 100\n"
|
||||
" block_list <loss_record_nr> [unlimited*|limited <max_blocks>]\n"
|
||||
" block_list <loss_record_nr>|<loss_record_nr_from>..<loss_record_nr_to>\n"
|
||||
" [unlimited*|limited <max_blocks>]\n"
|
||||
" [heuristics heur1,heur2,...]\n"
|
||||
" after a leak search, shows the list of blocks of <loss_record_nr>\n"
|
||||
" (or of the range <loss_record_nr_from>..<loss_record_nr_to>).\n"
|
||||
" With heuristics, only shows the blocks found via heur1,heur2,...\n"
|
||||
" * = defaults\n"
|
||||
" who_points_at <addr> [<len>]\n"
|
||||
" shows places pointing inside <len> (default 1) bytes at <addr>\n"
|
||||
@ -6064,6 +6068,81 @@ static void gdb_xb (Addr address, SizeT szB, Int res[])
|
||||
VG_(printf) ("\n"); // Terminate previous line
|
||||
}
|
||||
|
||||
|
||||
/* Returns the address of the next non space character,
|
||||
or address of the string terminator. */
|
||||
static HChar* next_non_space (HChar *s)
|
||||
{
|
||||
while (*s && *s == ' ')
|
||||
s++;
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Parse an integer slice, i.e. a single integer or a range of integer.
|
||||
Syntax is:
|
||||
<integer>[..<integer> ]
|
||||
(spaces are allowed before and/or after ..).
|
||||
Return True if range correctly parsed, False otherwise. */
|
||||
static Bool VG_(parse_slice) (HChar* s, HChar** saveptr,
|
||||
UInt *from, UInt *to)
|
||||
{
|
||||
HChar* wl;
|
||||
HChar *endptr;
|
||||
endptr = NULL;////
|
||||
wl = VG_(strtok_r) (s, " ", saveptr);
|
||||
|
||||
/* slice must start with an integer. */
|
||||
if (wl == NULL) {
|
||||
VG_(gdb_printf) ("expecting integer or slice <from>..<to>\n");
|
||||
return False;
|
||||
}
|
||||
*from = VG_(strtoull10) (wl, &endptr);
|
||||
if (endptr == wl) {
|
||||
VG_(gdb_printf) ("invalid integer or slice <from>..<to>\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (*endptr == '\0' && *next_non_space(*saveptr) != '.') {
|
||||
/* wl token is an integer terminating the string
|
||||
or else next token does not start with .
|
||||
In both cases, the slice is a single integer. */
|
||||
*to = *from;
|
||||
return True;
|
||||
}
|
||||
|
||||
if (*endptr == '\0') {
|
||||
// iii .. => get the next token
|
||||
wl = VG_(strtok_r) (NULL, " .", saveptr);
|
||||
} else {
|
||||
// It must be iii..
|
||||
if (*endptr != '.' && *(endptr+1) != '.') {
|
||||
VG_(gdb_printf) ("expecting slice <from>..<to>\n");
|
||||
return False;
|
||||
}
|
||||
if ( *(endptr+2) == ' ') {
|
||||
// It must be iii.. jjj => get the next token
|
||||
wl = VG_(strtok_r) (NULL, " .", saveptr);
|
||||
} else {
|
||||
// It must be iii..jjj
|
||||
wl = endptr+2;
|
||||
}
|
||||
}
|
||||
|
||||
*to = VG_(strtoull10) (wl, &endptr);
|
||||
if (*endptr != '\0') {
|
||||
VG_(gdb_printf) ("missing/wrong 'to' of slice <from>..<to>\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (*from > *to) {
|
||||
VG_(gdb_printf) ("<from> cannot be bigger than <to> "
|
||||
"in slice <from>..<to>\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* return True if request recognised, False otherwise */
|
||||
static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
{
|
||||
@ -6316,22 +6395,19 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
|
||||
case 5: { /* block_list */
|
||||
HChar* wl;
|
||||
HChar *endptr;
|
||||
HChar *the_end;
|
||||
UInt lr_nr = 0;
|
||||
UInt lr_nr_from = 0;
|
||||
UInt lr_nr_to = 0;
|
||||
|
||||
wl = VG_(strtok_r) (NULL, " ", &ssaveptr);
|
||||
if (wl != NULL)
|
||||
lr_nr = VG_(strtoull10) (wl, &endptr);
|
||||
if (wl == NULL || *endptr != '\0') {
|
||||
VG_(gdb_printf) ("malformed or missing integer\n");
|
||||
} else {
|
||||
UInt limit_blocks;
|
||||
if (VG_(parse_slice) (NULL, &ssaveptr, &lr_nr_from, &lr_nr_to)) {
|
||||
UInt limit_blocks = 999999999;
|
||||
Int int_value;
|
||||
|
||||
wl = VG_(strtok_r) (NULL, " ", &ssaveptr);
|
||||
if (wl != NULL) {
|
||||
switch (VG_(keyword_id) ("unlimited limited ",
|
||||
UInt heuristics = 0;
|
||||
|
||||
for (wl = VG_(strtok_r) (NULL, " ", &ssaveptr);
|
||||
wl != NULL;
|
||||
wl = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
|
||||
switch (VG_(keyword_id) ("unlimited limited heuristics ",
|
||||
wl, kwd_report_all)) {
|
||||
case -2: return True;
|
||||
case -1: return True;
|
||||
@ -6355,15 +6431,27 @@ static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
|
||||
}
|
||||
limit_blocks = (UInt) int_value;
|
||||
break;
|
||||
case 2: /* heuristics */
|
||||
wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
|
||||
if (wcmd == NULL
|
||||
|| !VG_(parse_enum_set)(MC_(parse_leak_heuristics_tokens),
|
||||
True,/*allow_all*/
|
||||
wcmd,
|
||||
&heuristics)) {
|
||||
VG_(gdb_printf) ("missing or malformed heuristics set\n");
|
||||
return True;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
tl_assert (0);
|
||||
}
|
||||
} else {
|
||||
limit_blocks = 999999999;
|
||||
}
|
||||
/* lr_nr-1 as what is shown to the user is 1 more than the index
|
||||
in lr_array. */
|
||||
if (lr_nr == 0 || ! MC_(print_block_list) (lr_nr-1, limit_blocks))
|
||||
/* substract 1 from lr_nr_from/lr_nr_to as what is shown to the user
|
||||
is 1 more than the index in lr_array. */
|
||||
if (lr_nr_from == 0 || ! MC_(print_block_list) (lr_nr_from-1,
|
||||
lr_nr_to-1,
|
||||
limit_blocks,
|
||||
heuristics))
|
||||
VG_(gdb_printf) ("invalid loss record nr\n");
|
||||
}
|
||||
return True;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user