Fix 284540 and 307465
284540 Memcheck shouldn't count suppressions matching still-reachable allocations
307465 --show-possibly-lost=no should bring down the error count / exit code

Using the options --show-leak-kinds=kind1,kind2,.. and
--errors-for-leak-kinds=kind1,kind2,.., each leak kind (definite, indirect,
possible, reachable) can now be individually reported and/or counted as
an error.
In a leak suppression entry, an optional line 'match-leak-kinds:'
controls which leak kinds are suppressed by this entry.
This is a.o. useful to avoid definite leaks being "catched"
by a suppression entry aimed at suppressing possibly lost blocks.
Default behaviour is the same as 3.8.1

Old args (--show-reachable and --show-possibly-lost) are still accepted.

Addition of a new test (memcheck/tests/lks) testing the new args
and the new suppression line.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13170 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index f48a546..4734c3e 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,16 @@
 * ================== PLATFORM CHANGES =================
 
 * ==================== TOOL CHANGES ====================
+* Memcheck:
+
+  - Using the options --show-leak-kinds=kind1,kind2,.. and
+    --errors-for-leak-kinds=kind1,kind2,.., each leak kind (definite, indirect,
+    possible, reachable) can now be individually reported and/or counted as
+    an error.
+    In a leak suppression entry, an optional line 'match-leak-kinds:'
+    controls which leak kinds are suppressed by this entry.
+    This is a.o. useful to avoid definite leaks being "catched"
+    by a suppression entry aimed at suppressing possibly lost blocks.
 
 * ==================== OTHER CHANGES ====================
 
@@ -34,10 +44,12 @@
 274695    [390] s390x: Support "compare to/from logical" instructions (z196)
 275800    [390] s390x: Add support for the ecag instruction (part 1)
 275800    [390] s390x: Autodetect cache info (part 2)
+284540    [390] Memcheck shouldn't count suppressions matching still-reachable allocations
 305948    [390] ppc64: code generation for ShlD64 / ShrD64 asserts
 306035    [390] s390x: Fix IR generation for LAAG and friends
 306054    [390] s390x: Condition code computation for convert-to-int/logical
 307155    [390] filter_gdb should filter out syscall-template.S T_PSEUDO
+307465    [390] --show-possibly-lost=no should bring down the error count / exit code
 308321    [390] testsuite memcheck filter interferes with gdb_filter 
 308341    [390] vgdb should report process exit (or fatal signal)
 308644    [390] vgdb command for having the info for the track-fds option
diff --git a/coregrind/m_errormgr.c b/coregrind/m_errormgr.c
index c325148..0e99234 100644
--- a/coregrind/m_errormgr.c
+++ b/coregrind/m_errormgr.c
@@ -1058,13 +1058,16 @@
    return 1;
 }
 
-Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
+// Get a non blank non comment line.
+// Returns True if eof.
+static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
 {
    HChar* buf  = *bufpp;
    SizeT nBuf = *nBufp;
    HChar  ch;
    Int   n, i;
    while (True) {
+      buf[0] = 0;
       /* First, read until a non-blank char appears. */
       while (True) {
          n = get_char(fd, &ch);
@@ -1104,6 +1107,26 @@
    }
 }
 
+// True if buf starts with fun: or obj: or is ...
+static Bool is_location_line (HChar* buf)
+{
+   return VG_(strncmp)(buf, "fun:", 4) == 0
+      || VG_(strncmp)(buf, "obj:", 4) == 0
+      || VG_(strcmp)(buf, "...") == 0;
+}
+
+Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
+{
+   Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
+
+   if (eof)
+      return True;
+
+   if (is_location_line(*bufpp))
+      return True; // Not a extra suppr line
+   else
+      return False; // An suppression extra line
+}
 
 /* True if s contains no wildcard (?, *) characters. */
 static Bool is_simple_str (const HChar *s)
@@ -1176,6 +1199,7 @@
 {
    SysRes sres;
    Int    fd, i, j, lineno = 0;
+   Bool   got_a_location_line_read_by_tool;
    Bool   eof;
    SizeT  nBuf = 200;
    HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
@@ -1220,7 +1244,7 @@
 
       supp->string = supp->extra = NULL;
 
-      eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
+      eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
       if (eof) {
          VG_(arena_free)(VG_AR_CORE, supp);
          break;
@@ -1228,15 +1252,15 @@
 
       if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
       
-      eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
+      eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
 
       if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
 
       supp->sname = VG_(arena_strdup)(VG_AR_CORE, "errormgr.losf.2", buf);
 
-      eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
+      eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
 
-      if (eof) BOMB("unexpected end-of-file");
+      if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
 
       /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
       i = 0;
@@ -1272,8 +1296,8 @@
       else {
          // Ignore rest of suppression
          while (True) {
-            eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
-            if (eof) BOMB("unexpected end-of-file");
+            eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
+            if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
             if (VG_STREQ(buf, "}"))
                break;
          }
@@ -1282,6 +1306,9 @@
          continue;
       }
 
+      buf[0] = 0;
+      // tool_read_extra_suppression_info might read lines
+      // from fd till a location line. 
       if (VG_(needs).tool_errors && 
           !VG_TDICT_CALL(tool_read_extra_suppression_info,
                          fd, &buf, &nBuf, supp))
@@ -1289,12 +1316,19 @@
          BOMB("bad or missing extra suppression info");
       }
 
+      got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
+
       /* the main frame-descriptor reading loop */
       i = 0;
       while (True) {
-         eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
+         if (got_a_location_line_read_by_tool) {
+            got_a_location_line_read_by_tool = False;
+            eof = False;
+         } else {
+            eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
+         }
          if (eof)
-            BOMB("unexpected end-of-file");
+            BOMB("unexpected end-of-file (when reading stack trace)");
          if (VG_STREQ(buf, "}")) {
             if (i > 0) {
                break;
@@ -1316,7 +1350,7 @@
       // lines and grab the '}'.
       if (!VG_STREQ(buf, "}")) {
          do {
-            eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
+            eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
          } while (!eof && !VG_STREQ(buf, "}"));
       }
 
diff --git a/gdbserver_tests/mchelp.stdoutB.exp b/gdbserver_tests/mchelp.stdoutB.exp
index 24b27c8..32f9ff7 100644
--- a/gdbserver_tests/mchelp.stdoutB.exp
+++ b/gdbserver_tests/mchelp.stdoutB.exp
@@ -22,12 +22,15 @@
   check_memory [addressable|defined] <addr> [<len>]
         check that <len> (or 1) bytes at <addr> have the given accessibility
             and outputs a description of <addr>
-  leak_check [full*|summary] [reachable|possibleleak*|definiteleak]
+  leak_check [full*|summary]
+                [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]
                 [increased*|changed|any]
                 [unlimited*|limited <max_loss_records_output>]
             * = defaults
+        where kind is one of definite indirect possible reachable all none
         Examples: leak_check
                   leak_check summary any
+                  leak_check full kinds indirect,possible
                   leak_check full reachable any limited 100
   block_list <loss_record_nr>
         after a leak search, shows the list of blocks of <loss_record_nr>
@@ -69,12 +72,15 @@
   check_memory [addressable|defined] <addr> [<len>]
         check that <len> (or 1) bytes at <addr> have the given accessibility
             and outputs a description of <addr>
-  leak_check [full*|summary] [reachable|possibleleak*|definiteleak]
+  leak_check [full*|summary]
+                [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]
                 [increased*|changed|any]
                 [unlimited*|limited <max_loss_records_output>]
             * = defaults
+        where kind is one of definite indirect possible reachable all none
         Examples: leak_check
                   leak_check summary any
+                  leak_check full kinds indirect,possible
                   leak_check full reachable any limited 100
   block_list <loss_record_nr>
         after a leak search, shows the list of blocks of <loss_record_nr>
diff --git a/include/pub_tool_errormgr.h b/include/pub_tool_errormgr.h
index 039115d..fcb5e09 100644
--- a/include/pub_tool_errormgr.h
+++ b/include/pub_tool_errormgr.h
@@ -87,13 +87,16 @@
                                 ExeContext* where, Bool print_error,
                                 Bool allow_GDB_attach, Bool count_error );
 
-/* Gets a non-blank, non-comment line from fd.  bufpp is a pointer to a
-   pointer to a buffer that must be allocated with VG_(malloc);  nBufp is a
-   pointer to size_t holding its size;  if the buffer is too small for the
-   line, it will be realloc'd until big enough (updating *bufpp and *nBufp in
-   the process).  (It will bomb out if the size gets ridiculous).  Skips
-   leading spaces on the line.  Increments lineno with the number of lines
-   read if lineno is non-NULL. Returns True if EOF was hit.  */
+/* Gets from fd (an opened suppression file) a non-blank, non-comment
+   line containing suppression extra information (e.g. the syscall
+   line for the Param memcheck suppression kind.  bufpp is a pointer
+   to a pointer to a buffer that must be allocated with VG_(malloc);
+   nBufp is a pointer to size_t holding its size; if the buffer is too
+   small for the line, it will be realloc'd until big enough (updating
+   *bufpp and *nBufp in the process).  (It will bomb out if the size
+   gets ridiculous).  Skips leading spaces on the line.  Increments
+   lineno with the number of lines read if lineno is non-NULL. Returns
+   True if no extra information line could be read. */
 extern Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno );
 
 
diff --git a/memcheck/docs/mc-manual.xml b/memcheck/docs/mc-manual.xml
index 53568d9..98f5139 100644
--- a/memcheck/docs/mc-manual.xml
+++ b/memcheck/docs/mc-manual.xml
@@ -428,8 +428,8 @@
 following figure.</para>
 
 <programlisting><![CDATA[
-     Pointer chain            AAA Category    BBB Category
-     -------------            ------------    ------------
+     Pointer chain            AAA Leak Case   BBB Leak Case
+     -------------            -------------   -------------
 (1)  RRR ------------> BBB                    DR
 (2)  RRR ---> AAA ---> BBB    DR              IR
 (3)  RRR               BBB                    DL
@@ -446,7 +446,7 @@
 - --->: a start-pointer
 - -?->: an interior-pointer
 
-Category legend:
+Leak Case legend:
 - DR: Directly reachable
 - IR: Indirectly reachable
 - DL: Directly lost
@@ -458,7 +458,7 @@
 
 <para>Every possible case can be reduced to one of the above nine.  Memcheck
 merges some of these cases in its output, resulting in the following four
-categories.</para>
+leak kinds.</para>
 
 
 <itemizedlist>
@@ -467,10 +467,9 @@
     <para>"Still reachable". This covers cases 1 and 2 (for the BBB blocks)
     above.  A start-pointer or chain of start-pointers to the block is
     found.  Since the block is still pointed at, the programmer could, at
-    least in principle, have freed it before program exit.  Because these
-    are very common and arguably not a problem, Memcheck won't report such
-    blocks individually unless <option>--show-reachable=yes</option> is
-    specified.</para>
+    least in principle, have freed it before program exit.  "Still reachable"
+    blocks are very common and arguably not a problem. So, by default,
+    Memcheck won't report such blocks individually.</para>
   </listitem>
 
   <listitem>
@@ -490,7 +489,7 @@
     node is lost, all its children nodes will be indirectly lost.  Because
     the problem will disappear if the definitely lost block that caused the
     indirect leak is fixed, Memcheck won't report such blocks individually
-    unless <option>--show-reachable=yes</option> is specified.</para>
+    by default.</para>
   </listitem>
 
   <listitem>
@@ -504,13 +503,13 @@
 
 </itemizedlist>
 
-<para>(Note: This mapping of the nine possible cases onto four categories is
+<para>(Note: This mapping of the nine possible cases onto four leak kinds is
 not necessarily the best way that leaks could be reported;  in particular,
 interior-pointers are treated inconsistently.  It is possible the
 categorisation may be improved in the future.)</para>
 
 <para>Furthermore, if suppressions exists for a block, it will be reported
-as "suppressed" no matter what which of the above four categories it belongs
+as "suppressed" no matter what which of the above four kinds it belongs
 to.</para>
 
 
@@ -528,7 +527,7 @@
 <para>If <option>--leak-check=full</option> is specified,
 Memcheck will give details for each definitely lost or possibly lost block,
 including where it was allocated.  (Actually, it merges results for all
-blocks that have the same category and sufficiently similar stack traces
+blocks that have the same leak kind and sufficiently similar stack traces
 into a single "loss record".  The
 <option>--leak-resolution</option> lets you control the
 meaning of "sufficiently similar".)  It cannot tell you when or how or why
@@ -554,10 +553,40 @@
 block that has been definitely lost;  the difference is that a further 80
 bytes in other blocks are indirectly lost because of this lost block.
 The loss records are not presented in any notable order, so the loss record
-numbers aren't particularly meaningful.</para>
+numbers aren't particularly meaningful. The loss record numbers can be used
+in the Valgrind gdbserver to list the addresses of the leaked blocks and/or give
+more details about how a block is still reachable.</para>
 
-<para>If you specify <option>--show-reachable=yes</option>,
-reachable and indirectly lost blocks will also be shown, as the following
+<para>The option <option>--show-leak-kinds=&lt;set&gt;</option>
+controls the set of leak kinds to show
+if <option>--leak-check=full</option> is specified. </para>
+
+<para>The <option>&lt;set&gt;</option> of leak kinds is specified by
+using one of the following forms:
+
+<itemizedlist>
+  <listitem>a comma separated list of one or more of
+    <option>definite indirect possible reachable</option>.
+  </listitem>
+
+  <listitem><option>all</option> to specify the complete set (all leak kinds).
+  </listitem>
+
+  <listitem><option>none</option> is the empty set.
+  </listitem>
+</itemizedlist>
+
+</para>
+
+<para> The default value for the leak kinds to show is
+  <option>--show-leak-kinds=definite,possible</option>.
+</para>
+
+<para>To also show the reachable and indirectly lost blocks in addition to the definitely
+and possibly lost blocks, you can use <option>--show-leak-kinds=all</option>.
+To only show the reachable and indirectly lost blocks, use
+<option>--show-leak-kinds=indirect,reachable</option>.
+The reachable and indirectly lost blocks will then be presented as the following
 two examples show.</para>
 
 <programlisting><![CDATA[
@@ -572,31 +601,20 @@
    by 0x........: main (leak-cases.c:80)
 ]]></programlisting>
 
-<para>Because there are different kinds of leaks with different severities, an
-interesting question is this: which leaks should be counted as true "errors"
-and which should not?  The answer to this question affects the numbers printed
-in the <computeroutput>ERROR SUMMARY</computeroutput> line, and also the effect
-of the <option>--error-exitcode</option> option.  Memcheck uses the following
-criteria:</para>
+<para>Because there are different kinds of leaks with different
+severities, an interesting question is this: which leaks should be
+counted as true "errors" and which should not?
+</para>
 
-<itemizedlist>
-  <listitem>
-    <para>First, a leak is only counted as a true "error" if
-    <option>--leak-check=full</option> is specified.  In other words, an
-    unprinted leak is not considered a true "error".  If this were not the
-    case, it would be possible to get a high error count but not have any
-    errors printed, which would be confusing.</para>
-  </listitem>
-
-  <listitem>
-    <para>After that, definitely lost and possibly lost blocks are counted as
-    true "errors".  Indirectly lost and still reachable blocks are not counted
-    as true "errors", even if <option>--show-reachable=yes</option> is
-    specified and they are printed;  this is because such blocks don't need
-    direct fixing by the programmer.
-    </para>
-  </listitem>
-</itemizedlist>
+<para> The answer to this question affects the numbers printed in
+the <computeroutput>ERROR SUMMARY</computeroutput> line, and also the
+effect of the <option>--error-exitcode</option> option.  First, a leak
+is only counted as a true "error"
+if <option>--leak-check=full</option> is specified.  Then, the
+option <option>--errors-for-leak-kinds=&lt;set&gt;</option> controls
+the set of leak kinds to consider as errors.  The default value
+is <option>--errors-for-leak-kinds=definite,possible</option>
+</para>
 
 </sect2>
 
@@ -624,16 +642,6 @@
     </listitem>
   </varlistentry>
 
-  <varlistentry id="opt.show-possibly-lost" xreflabel="--show-possibly-lost">
-    <term>
-      <option><![CDATA[--show-possibly-lost=<yes|no> [default: yes] ]]></option>
-    </term>
-    <listitem>
-      <para>When disabled, the memory leak detector will not show "possibly lost" blocks.  
-      </para>
-    </listitem>
-  </varlistentry>
-
   <varlistentry id="opt.leak-resolution" xreflabel="--leak-resolution">
     <term>
       <option><![CDATA[--leak-resolution=<low|med|high> [default: high] ]]></option>
@@ -658,20 +666,74 @@
     </listitem>
   </varlistentry>
 
-  <varlistentry id="opt.show-reachable" xreflabel="--show-reachable">
+  <varlistentry id="opt.show-leak-kinds" xreflabel="--show-leak-kinds">
     <term>
-      <option><![CDATA[--show-reachable=<yes|no> [default: no] ]]></option>
+      <option><![CDATA[--show-leak-kinds=<set> [default: definite,possible] ]]></option>
     </term>
     <listitem>
-      <para>When disabled, the memory leak detector only shows "definitely
-      lost" and "possibly lost" blocks.  When enabled, the leak detector also
-      shows "reachable" and "indirectly lost" blocks.  (In other words, it
-      shows all blocks, except suppressed ones, so
-      <option>--show-all</option> would be a better name for
-      it.)</para>
+      <para>Specifies the leak kinds to show in a full leak search by
+        using one of the following forms:
+
+        <itemizedlist>
+          <listitem>a comma separated list of one or more of
+            <option>definite indirect possible reachable</option>.
+          </listitem>
+          
+          <listitem><option>all</option> to specify the complete set (all leak kinds).
+            It is equivalent to
+            <option>--show-leak-kinds=definite,indirect,possible,reachable</option>.
+          </listitem>
+          
+          <listitem><option>none</option> is the empty set.
+          </listitem>
+        </itemizedlist>
+      </para>
     </listitem>
   </varlistentry>
 
+
+  <varlistentry id="opt.errors-for-leak-kinds" xreflabel="--errors-for-leak-kinds">
+    <term>
+      <option><![CDATA[--errors-for-leak-kinds=<set> [default: definite,possible] ]]></option>
+    </term>
+    <listitem>
+      <para>Specifies the leak kinds to count as errors in a full leak search. The
+        <option><![CDATA[<set>]]></option> is specified similarly to
+        <option>--show-leak-kinds</option>
+      </para>
+    </listitem>
+  </varlistentry>
+
+
+  <varlistentry id="opt.show-reachable" xreflabel="--show-reachable">
+    <term>
+      <option><![CDATA[--show-reachable=<yes|no> ]]></option>
+    </term>
+    <term>
+      <option><![CDATA[--show-possibly-lost=<yes|no> ]]></option>
+    </term>
+    <listitem>
+      <para>These options provide an alternative way to specify the leak kinds to show:
+        <itemizedlist>
+          <listitem>
+            <option>--show-reachable=no --show-possibly-lost=yes</option> is equivalent to
+            <option>--show-leak-kinds=definite,possible</option>.
+          </listitem>
+          <listitem>
+            <option>--show-reachable=no --show-possibly-lost=no</option> is equivalent to
+            <option>--show-leak-kinds=definite</option>.
+          </listitem>
+          <listitem>
+            <option>--show-reachable=yes</option> is equivalent to
+            <option>--show-leak-kinds=all</option>.
+            Note that  <option>--show-possibly-lost=no</option> has no effect
+            if <option>--show-reachable=yes</option> is specified.
+          </listitem>
+        </itemizedlist>
+      </para>
+    </listitem>
+  </varlistentry>
+  
   <varlistentry id="opt.undef-value-errors" xreflabel="--undef-value-errors">
     <term>
       <option><![CDATA[--undef-value-errors=<yes|no> [default: yes] ]]></option>
@@ -955,10 +1017,25 @@
 
 </itemizedlist>
 
-<para><computeroutput>Param</computeroutput> errors have an extra
+<para><computeroutput>Param</computeroutput> errors have a mandatory extra
 information line at this point, which is the name of the offending
-system call parameter.  No other error kinds have this extra
-line.</para>
+system call parameter. </para>
+
+<para>
+<computeroutput>Leak</computeroutput> errors have an optional extra
+information line. This optional extra information line has the
+following format:</para>
+<programlisting><![CDATA[
+match-leak-kinds:<set>]]></programlisting>
+<para>where <computeroutput>&lt;set&gt;</computeroutput> specifies which
+leak kinds are matched by this suppression entry. 
+<computeroutput>&lt;set&gt;</computeroutput> is specified similarly
+to the option <option>--show-leak-kinds</option>.
+If this optional extra line is not present, the suppression entry will match
+all leak kinds.
+</para>
+
+<para>The other memcheck error kinds do not have extra lines.</para>
 
 <para>The first line of the calling context: for <varname>ValueN</varname>
 and <varname>AddrN</varname> errors, it is either the name of the function
@@ -1391,7 +1468,7 @@
 
   <listitem>
     <para><varname>leak_check [full*|summary]
-                              [reachable|possibleleak*|definiteleak]
+                              [kinds &lt;set&gt;|reachable|possibleleak*|definiteleak]
                               [increased*|changed|any]
                               [unlimited*|limited &lt;max_loss_records_output&gt;]
           </varname>
@@ -1414,14 +1491,17 @@
     </para>
 
     <para>The second argument controls what kind of blocks are shown for
-    a <varname>full</varname> leak search.  The
-    value <varname>definiteleak</varname> specifies that only
-    definitely leaked blocks should be shown.  The
-    value <varname>possibleleak</varname> will also show possibly
-    leaked blocks (those for which only an interior pointer was
-    found).  The value
-    <varname>reachable</varname> will show all block categories
-    (reachable, possibly leaked, definitely leaked).
+    a <varname>full</varname> leak search.  The set of leak kinds to show
+    can be specified using a <varname>&lt;set&gt;</varname> similarly
+    to the command line option <option>--show-leak-kinds</option>.
+    Alternatively, the  value <varname>definiteleak</varname> 
+    is equivalent to <varname>kinds definite</varname>, the
+    value <varname>possibleleak</varname> is equivalent to
+    <varname>kinds definite,possible</varname> : it will also show
+    possibly leaked blocks, .i.e those for which only an interior
+    pointer was found.  The value <varname>reachable</varname> will
+    show all block categories (i.e. is equivalent to <varname>kinds
+    all</varname>).
     </para>
 
     <para>The third argument controls what kinds of changes are shown
diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c
index d3aed41..91a6045 100644
--- a/memcheck/mc_errors.c
+++ b/memcheck/mc_errors.c
@@ -410,6 +410,65 @@
    return loss;
 }
 
+Bool MC_(parse_leak_kinds) ( const HChar* str0, UInt* lks )
+{
+   HChar  tok_str0[VG_(strlen)(str0)+1];
+   HChar* saveptr;
+   HChar* token;
+
+   Bool seen_all_kw = False;
+   Bool seen_none_kw = False;
+
+   VG_(strcpy) (tok_str0, str0);
+   *lks = 0;
+
+   for (token = VG_(strtok_r)(tok_str0, ",", &saveptr);
+        token;
+        token = VG_(strtok_r)(NULL, ",", &saveptr)) {
+      if      (0 == VG_(strcmp)(token, "reachable"))
+         *lks |= R2S(Reachable);
+      else if (0 == VG_(strcmp)(token, "possible"))
+         *lks |= R2S(Possible);
+      else if (0 == VG_(strcmp)(token, "indirect"))
+         *lks |= R2S(IndirectLeak);
+      else if (0 == VG_(strcmp)(token, "definite"))
+         *lks |= R2S(Unreached);
+      else if (0 == VG_(strcmp)(token, "all"))
+         seen_all_kw = True;
+      else if (0 == VG_(strcmp)(token, "none"))
+         seen_none_kw = True;
+      else
+         return False;
+   }
+
+   if (seen_all_kw) {
+      if (seen_none_kw || *lks)
+         return False; // mixing all with either none or a specific value.
+      *lks = RallS;
+   } else if (seen_none_kw) {
+      if (seen_all_kw || *lks)
+         return False; // mixing none with either all or a specific value.
+      *lks = 0;
+   } else {
+      // seen neither all or none, we must see at least one value
+      if (*lks == 0)
+         return False;
+   }
+
+   return True;
+}
+
+static const HChar* pp_Reachedness_for_leak_kinds(Reachedness r)
+{
+   switch(r) {
+   case Reachable:    return "reachable";
+   case Possible:     return "possible";
+   case IndirectLeak: return "indirect";
+   case Unreached:    return "definite";
+   default:           tl_assert(0);
+   }
+}
+
 static void mc_pp_origin ( ExeContext* ec, UInt okind )
 {
    const HChar* src = NULL;
@@ -1442,15 +1501,40 @@
    return True;
 }
 
+typedef struct _MC_LeakSuppExtra MC_LeakSuppExtra;
+
+struct _MC_LeakSuppExtra {
+   UInt match_leak_kinds;
+};
+
 Bool MC_(read_extra_suppression_info) ( Int fd, HChar** bufpp,
                                         SizeT* nBufp, Supp *su )
 {
    Bool eof;
+   Int i;
 
    if (VG_(get_supp_kind)(su) == ParamSupp) {
       eof = VG_(get_line) ( fd, bufpp, nBufp, NULL );
       if (eof) return False;
       VG_(set_supp_string)(su, VG_(strdup)("mc.resi.1", *bufpp));
+   } else if (VG_(get_supp_kind)(su) == LeakSupp) {
+      // We might have the optional match-leak-kinds line
+      MC_LeakSuppExtra* lse;
+      lse = VG_(malloc)("mc.resi.2", sizeof(MC_LeakSuppExtra));
+      lse->match_leak_kinds = RallS;
+      VG_(set_supp_extra)(su, lse); // By default, all kinds will match.
+      eof = VG_(get_line) ( fd, bufpp, nBufp, NULL );
+      if (eof) return True; // old LeakSupp style, no match-leak-kinds line.
+      if (0 == VG_(strncmp)(*bufpp, "match-leak-kinds:", 17)) {
+         i = 17;
+         while ((*bufpp)[i] && VG_(isspace((*bufpp)[i])))
+            i++;
+         if (!MC_(parse_leak_kinds)((*bufpp)+i, &lse->match_leak_kinds)) {
+            return False;
+         }
+      } else {
+         return False; // unknown extra line.
+      }
    }
    return True;
 }
@@ -1504,7 +1588,11 @@
          return (ekind == Err_Overlap);
 
       case LeakSupp:
-         return (ekind == Err_Leak);
+         if (ekind == Err_Leak) {
+            MC_LeakSuppExtra* lse = (MC_LeakSuppExtra*) VG_(get_supp_extra)(su);
+            return RiS(extra->Err.Leak.lr->key.state, lse->match_leak_kinds);
+         } else
+            return False;
 
       case MempoolSupp:
          return (ekind == Err_IllegalMempool);
@@ -1569,6 +1657,12 @@
       tl_assert(errstr);
       VG_(snprintf)(buf, nBuf-1, "%s", errstr);
       return True;
+   } else if (Err_Leak == ekind) {
+      MC_Error* extra = VG_(get_error_extra)(err);
+      VG_(snprintf)
+         (buf, nBuf-1, "match-leak-kinds: %s",
+          pp_Reachedness_for_leak_kinds(extra->Err.Leak.lr->key.state));
+      return True;
    } else {
       return False;
    }
diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h
index 797dce2..f9f07bf 100644
--- a/memcheck/mc_include.h
+++ b/memcheck/mc_include.h
@@ -260,6 +260,13 @@
   }
   Reachedness;
 
+// Build mask to check or set Reachedness r membership
+#define R2S(r) (1 << (r))
+// Reachedness r is member of the Set s ?
+#define RiS(r,s) ((s) & R2S(r))
+// A set with all Reachedness:
+#define RallS \
+   (R2S(Reachable) | R2S(Possible) | R2S(IndirectLeak) | R2S(Unreached))
 
 /* For VALGRIND_COUNT_LEAKS client request */
 extern SizeT MC_(bytes_leaked);
@@ -318,8 +325,8 @@
 typedef
    struct _LeakCheckParams {
       LeakCheckMode mode;
-      Bool show_reachable;
-      Bool show_possibly_lost;
+      UInt show_leak_kinds;
+      UInt errors_for_leak_kinds;
       LeakCheckDeltaMode deltamode;
       UInt max_loss_records_output;       // limit on the nr of loss records output.
       Bool requested_by_monitor_command; // True when requested by gdb/vgdb.
@@ -411,6 +418,12 @@
                                   Bool print_record,
                                   Bool count_error );
 
+/* Parses a set of leak kinds (separated by ,).
+   and give the resulting set in *lks.
+   If parsing is succesful, returns True and *lks contains the resulting set.
+   else return False. */
+extern Bool MC_(parse_leak_kinds) ( const HChar* str0, UInt* lks );
+
 /* prints a description of address a */
 void MC_(pp_describe_addr) (Addr a);
 
@@ -458,11 +471,13 @@
 /* How closely should we compare ExeContexts in leak records? default: 2 */
 extern VgRes MC_(clo_leak_resolution);
 
-/* In leak check, show reachable-but-not-freed blocks?  default: NO */
-extern Bool MC_(clo_show_reachable);
+/* In leak check, show loss records if their R2S(reachedness) is set.
+   Default : R2S(Possible) | R2S(Unreached). */
+extern UInt MC_(clo_show_leak_kinds);
 
-/* In leak check, show possibly-lost blocks?  default: YES */
-extern Bool MC_(clo_show_possibly_lost);
+/* In leak check, a loss record is an error if its R2S(reachedness) is set.
+   Default : R2S(Possible) | R2S(Unreached). */
+extern UInt MC_(clo_errors_for_leak_kinds);
 
 /* Assume accesses immediately below %esp are due to gcc-2.96 bugs.
  * default: NO */
diff --git a/memcheck/mc_leakcheck.c b/memcheck/mc_leakcheck.c
index 9632391..1ebd682 100644
--- a/memcheck/mc_leakcheck.c
+++ b/memcheck/mc_leakcheck.c
@@ -120,6 +120,7 @@
 // Also, --show-reachable is a bad name because it also turns on the showing
 // of indirectly leaked blocks(!)  It would be better named --show-all or
 // --show-all-heap-blocks, because that's the end result.
+// We now have the option --show-leak-kinds=... which allows to specify =all.
 //
 // ----
 //
@@ -167,7 +168,8 @@
 // 
 // ==20397== 16 bytes in 1 blocks are definitely lost in loss record 14
 // of 15 (and 16 bytes in 1 block are indirectly lost as a result;  they
-// are mentioned elsewhere (if --show-reachable=yes is given!))
+// are mentioned elsewhere (if --show-reachable=yes or indirect is given
+// in --show-leak-kinds=... !))
 // ==20397==    at 0x4C2694E: malloc (vg_replace_malloc.c:177)
 // ==20397==    by 0x400521: mk (leak-cases.c:49)
 // ==20397==    by 0x400580: main (leak-cases.c:72)
@@ -906,14 +908,8 @@
    // Rules for printing:
    // - We don't show suppressed loss records ever (and that's controlled
    //   within the error manager).
-   // - We show non-suppressed loss records that are not "reachable" if 
-   //   --leak-check=yes.
-   // - We show all non-suppressed loss records if --leak-check=yes and
-   //   --show-reachable=yes.
-   //
-   // Nb: here "reachable" means Reachable *or* IndirectLeak;  note that
-   // this is different to "still reachable" used elsewhere because it
-   // includes indirectly lost blocks!
+   // - We show non-suppressed loss records that are specified in
+   //   --show-leak-kinds=... if --leak-check=yes.
 
    Bool delta_considered;
 
@@ -936,20 +932,14 @@
       tl_assert(0);
    }
 
-   *print_record = lcp->mode == LC_Full && delta_considered &&
-      ( lcp->show_reachable ||
-        Unreached == lr->key.state || 
-        ( lcp->show_possibly_lost && 
-          Possible  == lr->key.state ) );
+   *print_record = lcp->mode == LC_Full && delta_considered 
+      && RiS(lr->key.state,lcp->show_leak_kinds);
    // We don't count a leaks as errors with lcp->mode==LC_Summary.
    // Otherwise you can get high error counts with few or no error
-   // messages, which can be confusing.  Also, you could argue that
-   // indirect leaks should be counted as errors, but it seems better to
-   // make the counting criteria similar to the printing criteria.  So we
-   // don't count them.
-   *count_as_error = lcp->mode == LC_Full && delta_considered &&
-      ( Unreached == lr->key.state || 
-        Possible  == lr->key.state );
+   // messages, which can be confusing.  Otherwise, we count as errors
+   // the leak kinds requested by --errors-for-leak-kinds=...
+   *count_as_error = lcp->mode == LC_Full && delta_considered 
+      && RiS(lr->key.state,lcp->errors_for_leak_kinds);
 }
 
 static void print_results(ThreadId tid, LeakCheckParams* lcp)
@@ -1155,7 +1145,7 @@
                       "of leaked memory\n");
       }
       if (lcp->mode == LC_Full &&
-          MC_(blocks_reachable) > 0 && !lcp->show_reachable)
+          MC_(blocks_reachable) > 0 && !RiS(Reachable,lcp->show_leak_kinds))
       {
          VG_(umsg)("Reachable blocks (those to which a pointer "
                    "was found) are not shown.\n");
@@ -1163,7 +1153,7 @@
             VG_(umsg)("To see them, add 'reachable any' args to leak_check\n");
          else
             VG_(umsg)("To see them, rerun with: --leak-check=full "
-                      "--show-reachable=yes\n");
+                      "--show-leak-kinds=all\n");
       }
       VG_(umsg)("\n");
    }
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 2434de1..17123a2 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -4825,13 +4825,14 @@
 /*--- Command line args                                    ---*/
 /*------------------------------------------------------------*/
 
+
 Bool          MC_(clo_partial_loads_ok)       = False;
 Long          MC_(clo_freelist_vol)           = 20*1000*1000LL;
 Long          MC_(clo_freelist_big_blocks)    =  1*1000*1000LL;
 LeakCheckMode MC_(clo_leak_check)             = LC_Summary;
 VgRes         MC_(clo_leak_resolution)        = Vg_HighRes;
-Bool          MC_(clo_show_reachable)         = False;
-Bool          MC_(clo_show_possibly_lost)     = True;
+UInt          MC_(clo_show_leak_kinds)        = R2S(Possible) | R2S(Unreached);
+UInt          MC_(clo_error_for_leak_kinds)   = R2S(Possible) | R2S(Unreached);
 Bool          MC_(clo_workaround_gcc296_bugs) = False;
 Int           MC_(clo_malloc_fill)            = -1;
 Int           MC_(clo_free_fill)              = -1;
@@ -4840,6 +4841,7 @@
 static Bool mc_process_cmd_line_options(const HChar* arg)
 {
    const HChar* tmp_str;
+   Int   tmp_show;
 
    tl_assert( MC_(clo_mc_level) >= 1 && MC_(clo_mc_level) <= 3 );
 
@@ -4879,10 +4881,29 @@
       }
    }
 
-	if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {}
-   else if VG_BOOL_CLO(arg, "--show-reachable",   MC_(clo_show_reachable))   {}
-   else if VG_BOOL_CLO(arg, "--show-possibly-lost",
-                                            MC_(clo_show_possibly_lost))     {}
+        if VG_BOOL_CLO(arg, "--partial-loads-ok", MC_(clo_partial_loads_ok)) {}
+   else if VG_STR_CLO(arg, "--errors-for-leak-kinds" , tmp_str) {
+      if (!MC_(parse_leak_kinds)(tmp_str, &MC_(clo_error_for_leak_kinds)))
+         return False;
+   }
+   else if VG_STR_CLO(arg, "--show-leak-kinds", tmp_str) {
+      if (!MC_(parse_leak_kinds)(tmp_str, &MC_(clo_show_leak_kinds)))
+         return False;
+   }
+   else if (VG_BOOL_CLO(arg, "--show-reachable", tmp_show)) {
+      if (tmp_show) {
+         MC_(clo_show_leak_kinds) = RallS;
+      } else {
+         MC_(clo_show_leak_kinds) &= ~R2S(Reachable);
+      }
+   }
+   else if VG_BOOL_CLO(arg, "--show-possibly-lost", tmp_show) {
+      if (tmp_show) {
+         MC_(clo_show_leak_kinds) |= R2S(Possible);
+      } else {
+         MC_(clo_show_leak_kinds) &= ~R2S(Possible);
+      }
+   }
    else if VG_BOOL_CLO(arg, "--workaround-gcc296-bugs",
                                             MC_(clo_workaround_gcc296_bugs)) {}
 
@@ -4956,14 +4977,21 @@
    VG_(printf)(
 "    --leak-check=no|summary|full     search for memory leaks at exit?  [summary]\n"
 "    --leak-resolution=low|med|high   differentiation of leak stack traces [high]\n"
-"    --show-reachable=no|yes          show reachable blocks in leak check? [no]\n"
-"    --show-possibly-lost=no|yes      show possibly lost blocks in leak check?\n"
-"                                     [yes]\n"
+"    --show-leak-kinds=kind1,kind2,.. which leak kinds to show?\n"
+"                                            [definite,possible]\n"
+"    --errors-for-leak-kinds=kind1,kind2,..  which leak kinds are errors?\n"
+"                                            [definite,possible]\n"
+"        where kind is one of definite indirect possible reachable all none\n"
+"    --show-reachable=yes             same as --show-leak-kinds=all\n"
+"    --show-reachable=no --show-possibly-lost=yes\n"
+"                                     same as --show-leak-kinds=definite,possible\n"
+"    --show-reachable=no --show-possibly-lost=no\n"
+"                                     same as --show-leak-kinds=definite\n"
 "    --undef-value-errors=no|yes      check for undefined value errors [yes]\n"
 "    --track-origins=no|yes           show origins of undefined values? [no]\n"
 "    --partial-loads-ok=no|yes        too hard to explain here; see manual [no]\n"
-"    --freelist-vol=<number>          volume of freed blocks queue      [20000000]\n"
-"    --freelist-big-blocks=<number>   releases first blocks with size >= [1000000]\n"
+"    --freelist-vol=<number>          volume of freed blocks queue     [20000000]\n"
+"    --freelist-big-blocks=<number>   releases first blocks with size>= [1000000]\n"
 "    --workaround-gcc296-bugs=no|yes  self explanatory [no]\n"
 "    --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS]   assume given addresses are OK\n"
 "    --malloc-fill=<hexnumber>        fill malloc'd areas with given value\n"
@@ -5081,12 +5109,15 @@
 "  check_memory [addressable|defined] <addr> [<len>]\n"
 "        check that <len> (or 1) bytes at <addr> have the given accessibility\n"
 "            and outputs a description of <addr>\n"
-"  leak_check [full*|summary] [reachable|possibleleak*|definiteleak]\n"
+"  leak_check [full*|summary]\n"
+"                [kinds kind1,kind2,...|reachable|possibleleak*|definiteleak]\n"
 "                [increased*|changed|any]\n"
 "                [unlimited*|limited <max_loss_records_output>]\n"
 "            * = defaults\n"
+"        where kind is one of definite indirect possible reachable all none\n"
 "        Examples: leak_check\n"
 "                  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>\n"
 "        after a leak search, shows the list of blocks of <loss_record_nr>\n"
@@ -5163,8 +5194,8 @@
       HChar* kw;
       
       lcp.mode               = LC_Full;
-      lcp.show_reachable     = False;
-      lcp.show_possibly_lost = True;
+      lcp.show_leak_kinds    = R2S(Possible) | R2S(Unreached);
+      lcp.errors_for_leak_kinds = 0; /* no errors for interactive leak search. */
       lcp.deltamode          = LCD_Increased;
       lcp.max_loss_records_output = 999999999;
       lcp.requested_by_monitor_command = True;
@@ -5174,7 +5205,7 @@
            kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
          switch (VG_(keyword_id) 
                  ("full summary "
-                  "reachable possibleleak definiteleak "
+                  "kinds reachable possibleleak definiteleak "
                   "increased changed any "
                   "unlimited limited ",
                   kw, kwd_report_all)) {
@@ -5184,24 +5215,34 @@
             lcp.mode = LC_Full; break;
          case  1: /* summary */
             lcp.mode = LC_Summary; break;
-         case  2: /* reachable */
-            lcp.show_reachable = True; 
-            lcp.show_possibly_lost = True; break;
-         case  3: /* possibleleak */
-            lcp.show_reachable = False;
-            lcp.show_possibly_lost = True; break;
-         case  4: /* definiteleak */
-            lcp.show_reachable = False;
-            lcp.show_possibly_lost = False; break;
-         case  5: /* increased */
+         case  2: { /* kinds */
+            wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
+            if (wcmd == NULL || !MC_(parse_leak_kinds)(wcmd,
+                                                       &lcp.show_leak_kinds)) {
+               VG_(gdb_printf) ("missing or malformed leak kinds set\n");
+               err++;
+            }
+            break;
+         }
+         case  3: /* reachable */
+            lcp.show_leak_kinds = RallS;
+            break;
+         case  4: /* possibleleak */
+            lcp.show_leak_kinds 
+               = R2S(Possible) | R2S(IndirectLeak) | R2S(Unreached);
+            break;
+         case  5: /* definiteleak */
+            lcp.show_leak_kinds = R2S(Unreached);
+            break;
+         case  6: /* increased */
             lcp.deltamode = LCD_Increased; break;
-         case  6: /* changed */
+         case  7: /* changed */
             lcp.deltamode = LCD_Changed; break;
-         case  7: /* any */
+         case  8: /* any */
             lcp.deltamode = LCD_Any; break;
-         case  8: /* unlimited */
+         case  9: /* unlimited */
             lcp.max_loss_records_output = 999999999; break;
-         case  9: { /* limited */
+         case 10: { /* limited */
             Int int_value;
             const HChar* endptr;
 
@@ -5433,8 +5474,8 @@
             lcp.mode = LC_Full;
          }
           
-         lcp.show_reachable = MC_(clo_show_reachable);
-         lcp.show_possibly_lost = MC_(clo_show_possibly_lost);
+         lcp.show_leak_kinds = MC_(clo_show_leak_kinds);
+         lcp.errors_for_leak_kinds = MC_(clo_error_for_leak_kinds);
 
          if (arg[2] == 0)
             lcp.deltamode = LCD_Any;
@@ -6074,7 +6115,6 @@
       options so as to constrain the output somewhat. */
    if (VG_(clo_xml)) {
       /* Extract as much info as possible from the leak checker. */
-      /* MC_(clo_show_reachable) = True; */
       MC_(clo_leak_check) = LC_Full;
    }
 
@@ -6150,8 +6190,8 @@
    if (MC_(clo_leak_check) != LC_Off) {
       LeakCheckParams lcp;
       lcp.mode = MC_(clo_leak_check);
-      lcp.show_reachable = MC_(clo_show_reachable);
-      lcp.show_possibly_lost = MC_(clo_show_possibly_lost);
+      lcp.show_leak_kinds = MC_(clo_show_leak_kinds);
+      lcp.errors_for_leak_kinds = MC_(clo_error_for_leak_kinds);
       lcp.deltamode = LCD_Any;
       lcp.max_loss_records_output = 999999999;
       lcp.requested_by_monitor_command = False;
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index 8e5d9cd..018ecc0 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -116,6 +116,7 @@
 	leak-pool-5.vgtest leak-pool-5.stderr.exp \
 	leak-tree.vgtest leak-tree.stderr.exp \
 	leak-segv-jmp.vgtest leak-segv-jmp.stderr.exp \
+	lks.vgtest lks.stdout.exp lks.supp lks.stderr.exp \
 	long_namespace_xml.vgtest long_namespace_xml.stdout.exp \
 	long_namespace_xml.stderr.exp \
 	long-supps.vgtest long-supps.stderr.exp long-supps.supp \
diff --git a/memcheck/tests/leak-segv-jmp.stderr.exp b/memcheck/tests/leak-segv-jmp.stderr.exp
index ae4b786..4741204 100644
--- a/memcheck/tests/leak-segv-jmp.stderr.exp
+++ b/memcheck/tests/leak-segv-jmp.stderr.exp
@@ -9,7 +9,7 @@
    still reachable: 41,000 bytes in 2 blocks
         suppressed: 0 bytes in 0 blocks
 Reachable blocks (those to which a pointer was found) are not shown.
-To see them, rerun with: --leak-check=full --show-reachable=yes
+To see them, rerun with: --leak-check=full --show-leak-kinds=all
 
 expecting a leak
 1,000 bytes in 1 blocks are definitely lost in loss record ... of ...
@@ -24,7 +24,7 @@
    still reachable: 40,000 bytes in 1 blocks
         suppressed: 0 bytes in 0 blocks
 Reachable blocks (those to which a pointer was found) are not shown.
-To see them, rerun with: --leak-check=full --show-reachable=yes
+To see them, rerun with: --leak-check=full --show-leak-kinds=all
 
 mprotect result 0
 expecting a leak again
@@ -40,7 +40,7 @@
    still reachable: 40,000 bytes in 1 blocks
         suppressed: 0 bytes in 0 blocks
 Reachable blocks (those to which a pointer was found) are not shown.
-To see them, rerun with: --leak-check=full --show-reachable=yes
+To see them, rerun with: --leak-check=full --show-leak-kinds=all
 
 finished
 LEAK SUMMARY:
diff --git a/memcheck/tests/lks.stderr.exp b/memcheck/tests/lks.stderr.exp
new file mode 100644
index 0000000..8a52913
--- /dev/null
+++ b/memcheck/tests/lks.stderr.exp
@@ -0,0 +1,61 @@
+
+All heap blocks were freed -- no leaks are possible
+
+LEAK SUMMARY:
+   definitely lost: 48 bytes in 3 blocks
+   indirectly lost: 32 bytes in 2 blocks
+     possibly lost: 0 bytes in 0 blocks
+   still reachable: 64 bytes in 4 blocks
+        suppressed: 96 bytes in 6 blocks
+Rerun with --leak-check=full to see details of leaked memory
+
+leaked:      80 bytes in  5 blocks
+dubious:      0 bytes in  0 blocks
+reachable:   64 bytes in  4 blocks
+suppressed:  96 bytes in  6 blocks
+
+HEAP SUMMARY:
+    in use at exit: 240 bytes in 15 blocks
+  total heap usage: 15 allocs, 0 frees, 240 bytes allocated
+
+16 bytes in 1 blocks are indirectly lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: mk (leak-cases.c:52)
+   by 0x........: f (leak-cases.c:76)
+   by 0x........: main (leak-cases.c:107)
+
+16 bytes in 1 blocks are indirectly lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: mk (leak-cases.c:52)
+   by 0x........: f (leak-cases.c:91)
+   by 0x........: main (leak-cases.c:107)
+
+16 bytes in 1 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: mk (leak-cases.c:52)
+   by 0x........: f (leak-cases.c:74)
+   by 0x........: main (leak-cases.c:107)
+
+32 (16 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: mk (leak-cases.c:52)
+   by 0x........: f (leak-cases.c:76)
+   by 0x........: main (leak-cases.c:107)
+
+32 (16 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: mk (leak-cases.c:52)
+   by 0x........: f (leak-cases.c:91)
+   by 0x........: main (leak-cases.c:107)
+
+LEAK SUMMARY:
+   definitely lost: 48 bytes in 3 blocks
+   indirectly lost: 32 bytes in 2 blocks
+     possibly lost: 0 bytes in 0 blocks
+   still reachable: 64 bytes in 4 blocks
+        suppressed: 96 bytes in 6 blocks
+Reachable blocks (those to which a pointer was found) are not shown.
+To see them, rerun with: --leak-check=full --show-leak-kinds=all
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/lks.stdout.exp b/memcheck/tests/lks.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/lks.stdout.exp
diff --git a/memcheck/tests/lks.supp b/memcheck/tests/lks.supp
new file mode 100644
index 0000000..e7ac288
--- /dev/null
+++ b/memcheck/tests/lks.supp
@@ -0,0 +1,9 @@
+{
+   lks_suppress_only_possible
+   Memcheck:Leak
+   match-leak-kinds: possible
+   fun:malloc
+   fun:mk
+   fun:f
+   fun:main
+}
diff --git a/memcheck/tests/lks.vgtest b/memcheck/tests/lks.vgtest
new file mode 100644
index 0000000..49f2134
--- /dev/null
+++ b/memcheck/tests/lks.vgtest
@@ -0,0 +1,4 @@
+# verify leak-kind-set in arguments and suppressions
+prog: leak-cases
+vgopts: --leak-check=full --show-leak-kinds=definite,possible,indirect --errors-for-leak-kinds=definite,possible --suppressions=lks.supp
+stderr_filter_args: leak-cases.c