Author: philippe
Date: Sat May 3 11:12:50 2014
New Revision: 13930
Log:
Helgrind : two new gdbserver commands 'describe address' and 'info locks'
- Helgrind GDB server monitor command 'describe <address>'
allowing to describe an address (e.g. where it was allocated).
- Helgrind GDB server monitor command 'info locks' giving
the list of locks, their location, and their status.
In a further patch, it is intended to
1. factorise the describe address code between memcheck and helgrind
2. generalise the describe address gdbsrv command so as to make
it usable for all tools.
Added:
trunk/helgrind/hg_addrdescr.c
trunk/helgrind/hg_addrdescr.h
Modified:
trunk/NEWS
trunk/docs/xml/manual-core-adv.xml
trunk/helgrind/Makefile.am
trunk/helgrind/docs/hg-manual.xml
trunk/helgrind/hg_errors.c
trunk/helgrind/hg_errors.h
trunk/helgrind/hg_main.c
Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS (original)
+++ trunk/NEWS Sat May 3 11:12:50 2014
@@ -15,6 +15,10 @@
VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE
* Helgrind:
+ - Helgrind GDB server monitor command 'describe <address>'
+ allowing to describe an address (e.g. where it was allocated).
+ - Helgrind GDB server monitor command 'info locks' giving
+ the list of locks, their location, and their status.
* Callgrind:
- callgrind_control now supports the --vgdb-prefix argument,
Modified: trunk/docs/xml/manual-core-adv.xml
==============================================================================
--- trunk/docs/xml/manual-core-adv.xml (original)
+++ trunk/docs/xml/manual-core-adv.xml Sat May 3 11:12:50 2014
@@ -603,6 +603,9 @@
<listitem>
<para><xref linkend="ms-manual.monitor-commands"/></para>
</listitem>
+ <listitem>
+ <para><xref linkend="hg-manual.monitor-commands"/></para>
+ </listitem>
</itemizedlist>
</para>
Modified: trunk/helgrind/Makefile.am
==============================================================================
--- trunk/helgrind/Makefile.am (original)
+++ trunk/helgrind/Makefile.am Sat May 3 11:12:50 2014
@@ -12,6 +12,7 @@
pkginclude_HEADERS = helgrind.h
noinst_HEADERS = \
+ hg_addrdescr.h \
hg_basics.h \
hg_errors.h \
hg_lock_n_thread.h \
@@ -28,6 +29,7 @@
endif
HELGRIND_SOURCES_COMMON = \
+ hg_addrdescr.c \
hg_basics.c \
hg_errors.c \
hg_lock_n_thread.c \
Modified: trunk/helgrind/docs/hg-manual.xml
==============================================================================
--- trunk/helgrind/docs/hg-manual.xml (original)
+++ trunk/helgrind/docs/hg-manual.xml Sat May 3 11:12:50 2014
@@ -1254,6 +1254,76 @@
</sect1>
+<sect1 id="hg-manual.monitor-commands" xreflabel="Helgrind Monitor Commands">
+<title>Helgrind Monitor Commands</title>
+<para>The Helgrind tool provides monitor commands handled by Valgrind's
+built-in gdbserver (see <xref linkend="manual-core-adv.gdbserver-commandhandling"/>).
+</para>
+<itemizedlist>
+ <listitem>
+ <para><varname>info locks</varname> shows the list of locks and their
+ status. </para>
+ <para>
+ In the following example, helgrind knows about one lock.
+ This lock is located at the guest address <varname>ga 0x8049a20</varname>.
+ The lock kind is <varname>rdwr</varname> indicating a reader-writer lock.
+ Other possible lock kinds are <varname>nonRec</varname> (simple mutex, non recursive)
+ and <varname>mbRec</varname> (simple mutex, possibly recursive).
+ The lock kind is then followed by the list of threads helding the lock.
+ In the below example, <varname>R1:thread #6 tid 3</varname> indicates that the
+ helgrind thread #6 has acquired (once, as the counter following the letter R is one)
+ the lock in read mode. The helgrind thread nr is incremented for each started thread.
+ The presence of 'tid 3' indicates that the thread #6 is has not exited yet and is the
+ valgrind tid 3. If a thread has terminated, then this is indicated with 'tid (exited)'.
+ </para>
+<programlisting><![CDATA[
+(gdb) monitor info locks
+Lock ga 0x8049a20 {
+ kind rdwr
+ { R1:thread #6 tid 3 }
+}
+(gdb)
+]]></programlisting>
+
+ <para> If you give the option <varname>--read-var-info=yes</varname>, then more
+ information will be provided about the lock location, such as the global variable
+ or the heap block that contains the lock:
+ </para>
+<programlisting><![CDATA[
+Lock ga 0x8049a20 {
+Location 0x8049a20 is 0 bytes inside global var "s_rwlock"
+declared at rwlock_race.c:17
+ kind rdwr
+ { R1:thread #3 tid 3 }
+}
+]]></programlisting>
+
+ </listitem>
+
+ <listitem>
+ <para><varname>describe <addr></varname> describes the address
+ <addr>. For example, an heap address will be described by the
+ length of the heap block and the stacktrace where this block was allocated.
+ The option <varname>--read-var-info=yes</varname> allows to give information
+ about global or local variables.
+ </para>
+<programlisting><![CDATA[
+(gdb) monitor describe 0x404e028
+
+address 0x404E028 is 0 bytes inside a block of size 100 alloc'd
+==16448== at 0x4028AA5: malloc (vg_replace_malloc.c:292)
+==16448== by 0x8048BD7: main (tc19_shadowmem.c:144)
+(gdb) mo d 0xbec6f040
+
+Location 0xbec6f040 is 0 bytes inside info.child,
+declared at tc19_shadowmem.c:139, in frame #0 of thread 1
+(gdb)
+]]></programlisting>
+ </listitem>
+
+</itemizedlist>
+
+</sect1>
<sect1 id="hg-manual.client-requests" xreflabel="Helgrind Client Requests">
<title>Helgrind Client Requests</title>
Added: trunk/helgrind/hg_addrdescr.c
==============================================================================
--- trunk/helgrind/hg_addrdescr.c (added)
+++ trunk/helgrind/hg_addrdescr.c Sat May 3 11:12:50 2014
@@ -0,0 +1,192 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Address Description. ---*/
+/*--- hg_addrdescr.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Helgrind, a Valgrind tool for detecting errors
+ in threaded programs.
+
+ Copyright (C) 2007-2012 OpenWorks Ltd
+ in...@op...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+#include "pub_tool_basics.h"
+#include "pub_tool_libcbase.h"
+#include "pub_tool_libcprint.h"
+#include "pub_tool_libcassert.h"
+#include "pub_tool_xarray.h"
+#include "pub_tool_execontext.h"
+#include "pub_tool_debuginfo.h"
+#include "pub_tool_threadstate.h"
+
+#include "hg_basics.h"
+#include "hg_addrdescr.h" /* self */
+
+void HG_(init_AddrDescr) ( AddrDescr* ad ) {
+ VG_(memset)(ad, 0, sizeof(*ad) );
+}
+
+void HG_(describe_addr) ( Addr a, /*OUT*/AddrDescr* ad )
+{
+ tl_assert(!ad->hctxt);
+ tl_assert(!ad->descr1);
+ tl_assert(!ad->descr2);
+
+ /* First, see if it's in any heap block. Unfortunately this
+ means a linear search through all allocated heap blocks. The
+ assertion says that if it's detected as a heap block, then we
+ must have an allocation context for it, since all heap blocks
+ should have an allocation context. */
+ Bool is_heapblock
+ = HG_(mm_find_containing_block)(
+ &ad->hctxt,
+ &ad->haddr,
+ &ad->hszB,
+ a
+ );
+ tl_assert(is_heapblock == (ad->hctxt != NULL));
+
+ if (!ad->hctxt) {
+ /* It's not in any heap block. See if we can map it to a
+ stack or global symbol. */
+
+ ad->descr1
+ = VG_(newXA)( HG_(zalloc), "hg.addrdescr.descr1",
+ HG_(free), sizeof(HChar) );
+ ad->descr2
+ = VG_(newXA)( HG_(zalloc), "hg.addrdescr.descr2",
+ HG_(free), sizeof(HChar) );
+
+ (void) VG_(get_data_description)( ad->descr1,
+ ad->descr2,
+ a );
+
+ /* If there's nothing in descr1/2, free it. Why is it safe to
+ to VG_(indexXA) at zero here? Because
+ VG_(get_data_description) guarantees to zero terminate
+ descr1/2 regardless of the outcome of the call. So there's
+ always at least one element in each XA after the call.
+ */
+ if (0 == VG_(strlen)( VG_(indexXA)(ad->descr1, 0 ))) {
+ VG_(deleteXA)( ad->descr1 );
+ ad->descr1 = NULL;
+ }
+ if (0 == VG_(strlen)( VG_(indexXA)( ad->descr2, 0 ))) {
+ VG_(deleteXA)( ad->descr2 );
+ ad->descr2 = NULL;
+ }
+ }
+}
+
+void HG_(pp_addrdescr) (Bool xml, const HChar* what, Addr addr,
+ AddrDescr* ad,
+ void(*print)(const HChar *format, ...))
+{
+ /* If we have a description of the address in terms of a heap
+ block, show it. */
+ if (ad->hctxt) {
+ SizeT delta = addr - ad->haddr;
+ if (xml) {
+ (*print)(" <auxwhat>%s %p is %ld bytes inside a block "
+ "of size %ld alloc'd</auxwhat>\n", what,
+ (void*)addr, delta,
+ ad->hszB);
+ VG_(pp_ExeContext)( ad->hctxt );
+ } else {
+ (*print)("\n");
+ (*print)("%s %p is %ld bytes inside a block "
+ "of size %ld alloc'd\n", what,
+ (void*)addr, delta,
+ ad->hszB);
+ VG_(pp_ExeContext)( ad->hctxt );
+ }
+ }
+
+ /* If we have a better description of the address, show it.
+ Note that in XML mode, it will already by nicely wrapped up
+ in tags, either <auxwhat> or <xauxwhat>, so we can just emit
+ it verbatim. */
+ if (xml) {
+ if (ad->descr1)
+ (*print)( " %s\n",
+ (HChar*)VG_(indexXA)( ad->descr1, 0 ) );
+ if (ad->descr2)
+ (*print)( " %s\n",
+ (HChar*)VG_(indexXA)( ad->descr2, 0 ) );
+ } else {
+ if (ad->descr1 || ad->descr2)
+ (*print)("\n");
+ if (ad->descr1)
+ (*print)( "%s\n",
+ (HChar*)VG_(indexXA)( ad->descr1, 0 ) );
+ if (ad->descr2)
+ (*print)( "%s\n",
+ (HChar*)VG_(indexXA)( ad->descr2, 0 ) );
+ }
+}
+
+static void void_printf(const HChar *format, ...)
+{
+ UInt ret;
+ va_list vargs;
+ va_start(vargs, format);
+ ret = VG_(vprintf)(format, vargs);
+ va_end(vargs);
+}
+
+Bool HG_(get_and_pp_addrdescr) (const HChar* what, Addr addr)
+{
+
+ Bool ret;
+ AddrDescr glad;
+
+ HG_(init_AddrDescr) (&glad);
+
+ HG_(describe_addr) (addr, &glad);
+
+ HG_(pp_addrdescr) (False /* xml */, what, addr,
+ &glad,
+ void_printf);
+ ret = glad.hctxt || glad.descr1 || glad.descr2;
+
+ HG_(clear_addrdesc) (&glad);
+
+ return ret;
+}
+
+void HG_(clear_addrdesc) ( AddrDescr* ad)
+{
+ ad->hctxt = NULL;
+ ad->haddr = 0;
+ ad->hszB = 0;
+ if (ad->descr1 != NULL) {
+ VG_(deleteXA)( ad->descr1 );
+ ad->descr1 = NULL;
+ }
+ if (ad->descr2 != NULL) {
+ VG_(deleteXA)( ad->descr2 );
+ ad->descr2 = NULL;
+ }
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end hg_addrdescr.c ---*/
+/*--------------------------------------------------------------------*/
Added: trunk/helgrind/hg_addrdescr.h
==============================================================================
--- trunk/helgrind/hg_addrdescr.h (added)
+++ trunk/helgrind/hg_addrdescr.h Sat May 3 11:12:50 2014
@@ -0,0 +1,94 @@
+
+/*---------------------------------------------------------------------*/
+/*--- Address Description, used e.g. to describe addresses involved ---*/
+/*--- in race conditions, locks. ---*/
+/*--- hg_addrdescr.h ---*/
+/*---------------------------------------------------------------------*/
+
+/*
+ This file is part of Helgrind, a Valgrind tool for detecting errors
+ in threaded programs.
+
+ Copyright (C) 2007-2012 OpenWorks Ltd
+ in...@op...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __HG_ADDRDESCR_H
+#define __HG_ADDRDESCR_H
+
+/*----------------------------------------------------------------*/
+/*--- Address Description ---*/
+/*--- Used e.g. to describe an address in a Race cond. error ---*/
+/*--- or a lock. ---*/
+/*----------------------------------------------------------------*/
+typedef
+ struct {
+ /* descr1/2 provide a description of stack/global locs */
+ XArray* descr1; /* XArray* of HChar */
+ XArray* descr2; /* XArray* of HChar */
+ /* hctxt/haddr/hszB describe the addr if it is a heap block. */
+ ExeContext* hctxt;
+ Addr haddr;
+ SizeT hszB;
+ }
+ AddrDescr;
+
+/* Initialises an empty AddrDescr. */
+void HG_(init_AddrDescr) ( AddrDescr* ad );
+
+/* Describe an address as best you can, for error messages or
+ lock description, putting the result in ad.
+ This allocates some memory in ad, to be cleared with VG_(clear_addrdesc). */
+extern void HG_(describe_addr) ( Addr a, /*OUT*/AddrDescr* ad );
+
+/* Prints (using *print) the readable description of addr given in ad.
+ "what" identifies the type pointed to by addr (e.g. a lock). */
+extern void HG_(pp_addrdescr) (Bool xml, const HChar* what, Addr addr,
+ AddrDescr* ad,
+ void(*print)(const HChar *format, ...));
+
+/* Get a readable description of addr, then print it using HG_(pp_addrdescr)
+ using xml False and VG_(printf) to emit the characters.
+ Returns True if a description was found/printed, False otherwise. */
+extern Bool HG_(get_and_pp_addrdescr) (const HChar* what, Addr a);
+
+/* Free all memory allocated by HG_(describe_addr)
+ Sets all elements of ad to 0/NULL. */
+extern void HG_(clear_addrdesc) ( AddrDescr* ad);
+
+/* For error creation/address description:
+ map 'data_addr' to a malloc'd chunk, if any.
+ Slow linear search accelerated in some special cases normal hash
+ search of the mallocmeta table. This is an abuse of the normal file
+ structure since this is exported by hg_main.c, not hg_addrdesc.c. Oh
+ Well. Returns True if found, False if not. Zero-sized blocks are
+ considered to contain the searched-for address if they equal that
+ address. */
+Bool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
+ /*OUT*/Addr* payload,
+ /*OUT*/SizeT* szB,
+ Addr data_addr );
+
+
+#endif /* ! __HG_ADDRDESCR_H */
+
+/*--------------------------------------------------------------------*/
+/*--- end hg_addrdescr.h ---*/
+/*--------------------------------------------------------------------*/
Modified: trunk/helgrind/hg_errors.c
==============================================================================
--- trunk/helgrind/hg_errors.c (original)
+++ trunk/helgrind/hg_errors.c Sat May 3 11:12:50 2014
@@ -42,6 +42,7 @@
#include "pub_tool_options.h" // VG_(clo_xml)
#include "hg_basics.h"
+#include "hg_addrdescr.h"
#include "hg_wordset.h"
#include "hg_lock_n_thread.h"
#include "libhb.h"
@@ -291,16 +292,10 @@
struct {
Addr data_addr;
Int szB;
+ AddrDescr data_addrdescr;
Bool isWrite;
Thread* thr;
Lock** locksHeldW;
- /* descr1/2 provide a description of stack/global locs */
- XArray* descr1; /* XArray* of HChar */
- XArray* descr2; /* XArray* of HChar */
- /* halloc/haddr/hszB describe the addr if it is a heap block. */
- ExeContext* hctxt;
- Addr haddr;
- SizeT hszB;
/* h1_* and h2_* provide some description of a previously
observed access with which we are conflicting. */
Thread* h1_ct; /* non-NULL means h1 info present */
@@ -411,52 +406,7 @@
VG_(printf)("HG_(update_extra): "
"%d conflicting-event queries\n", xxx);
- tl_assert(!xe->XE.Race.hctxt);
- tl_assert(!xe->XE.Race.descr1);
- tl_assert(!xe->XE.Race.descr2);
-
- /* First, see if it's in any heap block. Unfortunately this
- means a linear search through all allocated heap blocks. The
- assertion says that if it's detected as a heap block, then we
- must have an allocation context for it, since all heap blocks
- should have an allocation context. */
- Bool is_heapblock
- = HG_(mm_find_containing_block)(
- &xe->XE.Race.hctxt, &xe->XE.Race.haddr, &xe->XE.Race.hszB,
- xe->XE.Race.data_addr
- );
- tl_assert(is_heapblock == (xe->XE.Race.hctxt != NULL));
-
- if (!xe->XE.Race.hctxt) {
- /* It's not in any heap block. See if we can map it to a
- stack or global symbol. */
-
- xe->XE.Race.descr1
- = VG_(newXA)( HG_(zalloc), "hg.update_extra.Race.descr1",
- HG_(free), sizeof(HChar) );
- xe->XE.Race.descr2
- = VG_(newXA)( HG_(zalloc), "hg.update_extra.Race.descr2",
- HG_(free), sizeof(HChar) );
-
- (void) VG_(get_data_description)( xe->XE.Race.descr1,
- xe->XE.Race.descr2,
- xe->XE.Race.data_addr );
-
- /* If there's nothing in descr1/2, free it. Why is it safe to
- to VG_(indexXA) at zero here? Because
- VG_(get_data_description) guarantees to zero terminate
- descr1/2 regardless of the outcome of the call. So there's
- always at least one element in each XA after the call.
- */
- if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Race.descr1, 0 ))) {
- VG_(deleteXA)( xe->XE.Race.descr1 );
- xe->XE.Race.descr1 = NULL;
- }
- if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Race.descr2, 0 ))) {
- VG_(deleteXA)( xe->XE.Race.descr2 );
- xe->XE.Race.descr2 = NULL;
- }
- }
+ HG_(describe_addr) (xe->XE.Race.data_addr, &xe->XE.Race.data_addrdescr);
/* And poke around in the conflicting-event map, to see if we
can rustle up a plausible-looking conflicting memory access
@@ -538,8 +488,7 @@
/* Skip on the detailed description of the raced-on address at this
point; it's expensive. Leave it for the update_extra function
if we ever make it that far. */
- tl_assert(xe.XE.Race.descr1 == NULL);
- tl_assert(xe.XE.Race.descr2 == NULL);
+ HG_(init_AddrDescr) (&xe.XE.Race.data_addrdescr);
// FIXME: tid vs thr
// Skip on any of the conflicting-access info at this point.
// It's expensive to obtain, and this error is more likely than
@@ -807,7 +756,6 @@
return True;
}
-
/* Announce 'lk'. */
static void announce_LockP ( Lock* lk )
{
@@ -1285,46 +1233,9 @@
}
- /* If we have a description of the address in terms of a heap
- block, show it. */
- if (xe->XE.Race.hctxt) {
- SizeT delta = err_ga - xe->XE.Race.haddr;
- if (xml) {
- emit(" <auxwhat>Address %p is %ld bytes inside a block "
- "of size %ld alloc'd</auxwhat>\n", (void*)err_ga, delta,
- xe->XE.Race.hszB);
- VG_(pp_ExeContext)( xe->XE.Race.hctxt );
- } else {
- emit("\n");
- emit("Address %p is %ld bytes inside a block "
- "of size %ld alloc'd\n", (void*)err_ga, delta,
- xe->XE.Race.hszB);
- VG_(pp_ExeContext)( xe->XE.Race.hctxt );
- }
- }
-
- /* If we have a better description of the address, show it.
- Note that in XML mode, it will already by nicely wrapped up
- in tags, either <auxwhat> or <xauxwhat>, so we can just emit
- it verbatim. */
- if (xml) {
- if (xe->XE.Race.descr1)
- emit( " %s\n",
- (HChar*)VG_(indexXA)( xe->XE.Race.descr1, 0 ) );
- if (xe->XE.Race.descr2)
- emit( " %s\n",
- (HChar*)VG_(indexXA)( xe->XE.Race.descr2, 0 ) );
- } else {
- if (xe->XE.Race.descr1 || xe->XE.Race.descr2)
- emit("\n");
- if (xe->XE.Race.descr1)
- emit( "%s\n",
- (HChar*)VG_(indexXA)( xe->XE.Race.descr1, 0 ) );
- if (xe->XE.Race.descr2)
- emit( "%s\n",
- (HChar*)VG_(indexXA)( xe->XE.Race.descr2, 0 ) );
- }
-
+ HG_(pp_addrdescr) (xml, "Address", err_ga,
+ &xe->XE.Race.data_addrdescr,
+ emit);
break; /* case XE_Race */
} /* case XE_Race */
Modified: trunk/helgrind/hg_errors.h
==============================================================================
--- trunk/helgrind/hg_errors.h (original)
+++ trunk/helgrind/hg_errors.h Sat May 3 11:12:50 2014
@@ -79,18 +79,6 @@
extern ULong HG_(stats__string_table_queries);
extern ULong HG_(stats__string_table_get_map_size) ( void );
-/* For error creation: map 'data_addr' to a malloc'd chunk, if any.
- Slow linear search accelerated in some special cases normal hash
- search of the mallocmeta table. This is an abuse of the normal file
- structure since this is exported by hg_main.c, not hg_errors.c. Oh
- Well. Returns True if found, False if not. Zero-sized blocks are
- considered to contain the searched-for address if they equal that
- address. */
-Bool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
- /*OUT*/Addr* payload,
- /*OUT*/SizeT* szB,
- Addr data_addr );
-
#endif /* ! __HG_ERRORS_H */
/*--------------------------------------------------------------------*/
Modified: trunk/helgrind/hg_main.c
==============================================================================
--- trunk/helgrind/hg_main.c (original)
+++ trunk/helgrind/hg_main.c Sat May 3 11:12:50 2014
@@ -37,6 +37,7 @@
*/
#include "pub_tool_basics.h"
+#include "pub_tool_gdbserver.h"
#include "pub_tool_libcassert.h"
#include "pub_tool_libcbase.h"
#include "pub_tool_libcprint.h"
@@ -58,6 +59,7 @@
#include "hg_basics.h"
#include "hg_wordset.h"
+#include "hg_addrdescr.h"
#include "hg_lock_n_thread.h"
#include "hg_errors.h"
@@ -457,29 +459,61 @@
}
}
-static void pp_Lock ( Int d, Lock* lk )
-{
- space(d+0); VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
+/* Pretty Print lock lk.
+ if show_lock_addrdescr, describes the (guest) lock address.
+ (this description will be more complete with --read-var-info=yes).
+ if show_internal_data, shows also helgrind internal information.
+ d is the level at which output is indented. */
+static void pp_Lock ( Int d, Lock* lk,
+ Bool show_lock_addrdescr,
+ Bool show_internal_data)
+{
+ space(d+0);
+ if (show_internal_data)
+ VG_(printf)("Lock %p (ga %#lx) {", lk, lk->guestaddr);
+ else
+ VG_(printf)("Lock ga %#lx {", lk->guestaddr);
+ if (!show_lock_addrdescr
+ || !HG_(get_and_pp_addrdescr) ("lock", (Addr) lk->guestaddr))
+ VG_(printf)("\n");
+
if (sHOW_ADMIN) {
space(d+3); VG_(printf)("admin_n %p\n", lk->admin_next);
space(d+3); VG_(printf)("admin_p %p\n", lk->admin_prev);
space(d+3); VG_(printf)("magic 0x%x\n", (UInt)lk->magic);
}
- space(d+3); VG_(printf)("unique %llu\n", lk->unique);
+ if (show_internal_data) {
+ space(d+3); VG_(printf)("unique %llu\n", lk->unique);
+ }
space(d+3); VG_(printf)("kind %s\n", show_LockKind(lk->kind));
- space(d+3); VG_(printf)("heldW %s\n", lk->heldW ? "yes" : "no");
- space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
+ if (show_internal_data) {
+ space(d+3); VG_(printf)("heldW %s\n", lk->heldW ? "yes" : "no");
+ }
+ if (show_internal_data) {
+ space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
+ }
if (lk->heldBy) {
Thread* thr;
UWord count;
VG_(printf)(" { ");
VG_(initIterBag)( lk->heldBy );
- while (VG_(nextIterBag)( lk->heldBy, (UWord*)&thr, &count ))
- VG_(printf)("%lu:%p ", count, thr);
+ while (VG_(nextIterBag)( lk->heldBy, (UWord*)&thr, &count )) {
+ if (show_internal_data)
+ VG_(printf)("%lu:%p ", count, thr);
+ else {
+ VG_(printf)("%c%lu:thread #%d ",
+ lk->heldW ? 'W' : 'R',
+ count, thr->errmsg_index);
+ if (thr->coretid == VG_INVALID_THREADID)
+ VG_(printf)("tid (exited) ");
+ else
+ VG_(printf)("tid %d ", thr->coretid);
+
+ }
+ }
VG_(doneIterBag)( lk->heldBy );
- VG_(printf)("}");
+ VG_(printf)("}\n");
}
- VG_(printf)("\n");
space(d+0); VG_(printf)("}\n");
}
@@ -496,12 +530,14 @@
space(n);
VG_(printf)("admin_locks record %d of %d:\n", i, n);
}
- pp_Lock(d+3, lk);
+ pp_Lock(d+3, lk,
+ False /* show_lock_addrdescr */,
+ True /* show_internal_data */);
}
space(d); VG_(printf)("}\n");
}
-static void pp_map_locks ( Int d )
+static void pp_map_locks ( Int d)
{
void* gla;
Lock* lk;
@@ -4703,11 +4739,89 @@
}
}
+static void print_monitor_help ( void )
+{
+ VG_(gdb_printf)
+ (
+"\n"
+"helgrind monitor commands:\n"
+" describe <addr> : outputs a description of <addr>\n"
+" info locks : show list of locks and their status\n"
+"\n");
+}
+
+/* return True if request recognised, False otherwise */
+static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
+{
+ UWord ret = 0;
+ HChar* wcmd;
+ HChar s[VG_(strlen(req))]; /* copy for strtok_r */
+ HChar *ssaveptr;
+ Int kwdid;
+
+ VG_(strcpy) (s, req);
+
+ wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
+ /* NB: if possible, avoid introducing a new command below which
+ starts with the same first letter(s) as an already existing
+ command. This ensures a shorter abbreviation for the user. */
+ switch (VG_(keyword_id)
+ ("help info describe",
+ wcmd, kwd_report_duplicated_matches)) {
+ case -2: /* multiple matches */
+ return True;
+ case -1: /* not found */
+ return False;
+ case 0: /* help */
+ print_monitor_help();
+ return True;
+ case 1: /* info */
+ ret = 1;
+ wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
+ switch (kwdid = VG_(keyword_id)
+ ("locks",
+ wcmd, kwd_report_all)) {
+ case -2:
+ case -1:
+ break;
+ case 0: // locks
+ {
+ Int i;
+ Lock* lk;
+ for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next) {
+ pp_Lock(0, lk,
+ True /* show_lock_addrdescr */,
+ False /* show_internal_data */);
+ }
+ if (i == 0)
+ VG_(gdb_printf) ("no locks\n");
+ }
+ break;
+ default:
+ tl_assert(0);
+ }
+ return True;
+ case 2: { /* describe */
+ Addr address;
+ SizeT szB = 1;
+ VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+ if (address == (Addr) 0 && szB == 0) return True;
+ if (!HG_(get_and_pp_addrdescr) ("address", address))
+ VG_(gdb_printf) ("No description found for address %p\n",
+ (void*)address);
+ return True;
+ }
+ default:
+ tl_assert(0);
+ return False;
+ }
+}
static
Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret)
{
- if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
+ if (!VG_IS_TOOL_USERREQ('H','G',args[0])
+ && VG_USERREQ__GDB_MONITOR_COMMAND != args[0])
return False;
/* Anything that gets past the above check is one of ours, so we
@@ -5021,6 +5135,15 @@
evh__HG_USERSO_FORGET_ALL( tid, args[1] );
break;
+ case VG_USERREQ__GDB_MONITOR_COMMAND: {
+ Bool handled = handle_gdb_monitor_command (tid, (HChar*)args[1]);
+ if (handled)
+ *ret = 1;
+ else
+ *ret = 0;
+ return handled;
+ }
+
default:
/* Unhandled Helgrind client request! */
tl_assert2(0, "unhandled Helgrind client request 0x%lx",
|