1
2/*--------------------------------------------------------------------*/
3/*--- Ptrcheck: a pointer-use checker.                             ---*/
4/*--- Provides stuff shared between sg_ and h_ subtools.           ---*/
5/*---                                                  pc_common.c ---*/
6/*--------------------------------------------------------------------*/
7
8/*
9   This file is part of Ptrcheck, a Valgrind tool for checking pointer
10   use in programs.
11
12   Copyright (C) 2008-2013 OpenWorks Ltd
13      info@open-works.co.uk
14
15   This program is free software; you can redistribute it and/or
16   modify it under the terms of the GNU General Public License as
17   published by the Free Software Foundation; either version 2 of the
18   License, or (at your option) any later version.
19
20   This program is distributed in the hope that it will be useful, but
21   WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   General Public License for more details.
24
25   You should have received a copy of the GNU General Public License
26   along with this program; if not, write to the Free Software
27   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
28   02111-1307, USA.
29
30   The GNU General Public License is contained in the file COPYING.
31
32   Neither the names of the U.S. Department of Energy nor the
33   University of California nor the names of its contributors may be
34   used to endorse or promote products derived from this software
35   without prior written permission.
36*/
37
38#include "pub_tool_basics.h"
39#include "pub_tool_libcbase.h"
40#include "pub_tool_libcprint.h"
41#include "pub_tool_xarray.h"
42#include "pub_tool_mallocfree.h"
43#include "pub_tool_libcassert.h"
44#include "pub_tool_options.h"
45#include "pub_tool_replacemalloc.h"
46#include "pub_tool_execontext.h"
47#include "pub_tool_tooliface.h"    // CorePart
48#include "pub_tool_threadstate.h"  // VG_(get_running_tid)
49#include "pub_tool_debuginfo.h"
50
51#include "pc_common.h"   // self, & Seg
52
53#include "h_main.h"      // NONPTR, BOTTOM, UNKNOWN
54
55
56//////////////////////////////////////////////////////////////
57//                                                          //
58// Command line options                                     //
59//                                                          //
60//////////////////////////////////////////////////////////////
61
62Bool h_clo_partial_loads_ok  = True;   /* user visible */
63/* Bool h_clo_lossage_check     = False; */ /* dev flag only */
64Bool sg_clo_enable_sg_checks = True;   /* user visible */
65
66Bool pc_process_cmd_line_options(const HChar* arg)
67{
68        if VG_BOOL_CLO(arg, "--partial-loads-ok", h_clo_partial_loads_ok) {}
69   /* else if VG_BOOL_CLO(arg, "--lossage-check",    h_clo_lossage_check) {} */
70   else if VG_BOOL_CLO(arg, "--enable-sg-checks", sg_clo_enable_sg_checks) {}
71   else
72      return VG_(replacement_malloc_process_cmd_line_option)(arg);
73
74   return True;
75}
76
77void pc_print_usage(void)
78{
79   VG_(printf)(
80   "    --partial-loads-ok=no|yes  same as for Memcheck [yes]\n"
81   "    --enable-sg-checks=no|yes  enable stack & global array checking? [yes]\n"
82   );
83}
84
85void pc_print_debug_usage(void)
86{
87   VG_(printf)(
88"    (none)\n"
89//"    --lossage-check=no|yes    gather stats for quality control [no]\n"
90   );
91}
92
93
94
95//////////////////////////////////////////////////////////////
96//                                                          //
97// Error management -- storage                              //
98//                                                          //
99//////////////////////////////////////////////////////////////
100
101/* What kind of error it is. */
102typedef
103   enum {
104      XE_SorG=1202, // sg: stack or global array inconsistency
105      XE_Heap,      // h: mismatched ptr/addr segments on load/store
106      XE_Arith,     // h: bad arithmetic between two segment pointers
107      XE_SysParam   // h: block straddling >1 segment passed to syscall
108   }
109   XErrorTag;
110
111typedef
112   enum {
113      XS_SorG=2021,
114      XS_Heap,
115      XS_Arith,
116      XS_SysParam
117   }
118   XSuppTag;
119
120typedef
121   struct {
122      XErrorTag tag;
123      union {
124         struct {
125            Addr   addr;
126            SSizeT sszB;  /* -ve is write, +ve is read */
127            HChar  expect[128];
128            HChar  actual[128];
129            HChar  delta[32]; // text showing relation to expected
130         } SorG;
131         struct {
132            Addr     addr;
133            SSizeT   sszB;  /* -ve is write, +ve is read */
134            Seg*     vseg;
135            XArray*  descr1; /* XArray* of HChar */
136            XArray*  descr2; /* XArray* of HChar */
137            HChar    datasym[96];
138            PtrdiffT datasymoff;
139         } Heap;
140         struct {
141            Seg* seg1;
142            Seg* seg2;
143            const HChar* opname; // user-understandable text name
144         } Arith;
145         struct {
146            CorePart part;
147            Addr lo;
148            Addr hi;
149            Seg* seglo;
150            Seg* seghi;
151         } SysParam;
152      } XE;
153   }
154   XError;
155
156
157void sg_record_error_SorG ( ThreadId tid,
158                            Addr addr, SSizeT sszB,
159                            HChar* expect, HChar* actual, HChar* delta )
160{
161   XError xe;
162   VG_(memset)(&xe, 0, sizeof(xe));
163   xe.tag = XE_SorG;
164   xe.XE.SorG.addr = addr;
165   xe.XE.SorG.sszB = sszB;
166   VG_(strncpy)( &xe.XE.SorG.expect[0],
167                 expect, sizeof(xe.XE.SorG.expect) );
168   VG_(strncpy)( &xe.XE.SorG.actual[0],
169                 actual, sizeof(xe.XE.SorG.actual) );
170   VG_(strncpy)( &xe.XE.SorG.delta[0],
171                 delta, sizeof(xe.XE.SorG.delta) );
172   xe.XE.SorG.expect[ sizeof(xe.XE.SorG.expect)-1 ] = 0;
173   xe.XE.SorG.actual[ sizeof(xe.XE.SorG.actual)-1 ] = 0;
174   xe.XE.SorG.delta[ sizeof(xe.XE.SorG.delta)-1 ] = 0;
175   VG_(maybe_record_error)( tid, XE_SorG, 0, NULL, &xe );
176}
177
178void h_record_heap_error( Addr a, SizeT size, Seg* vseg, Bool is_write )
179{
180   XError xe;
181   tl_assert(size > 0);
182   VG_(memset)(&xe, 0, sizeof(xe));
183   xe.tag = XE_Heap;
184   xe.XE.Heap.addr = a;
185   xe.XE.Heap.sszB = is_write ? -size : size;
186   xe.XE.Heap.vseg = vseg;
187   VG_(maybe_record_error)( VG_(get_running_tid)(), XE_Heap,
188                            /*a*/0, /*str*/NULL, /*extra*/(void*)&xe);
189}
190
191void h_record_arith_error( Seg* seg1, Seg* seg2, HChar* opname )
192{
193   XError xe;
194   VG_(memset)(&xe, 0, sizeof(xe));
195   xe.tag = XE_Arith;
196   xe.XE.Arith.seg1   = seg1;
197   xe.XE.Arith.seg2   = seg2;
198   xe.XE.Arith.opname = opname;
199   VG_(maybe_record_error)( VG_(get_running_tid)(), XE_Arith,
200                            /*a*/0, /*str*/NULL, /*extra*/(void*)&xe);
201}
202
203void h_record_sysparam_error( ThreadId tid, CorePart part, const HChar* s,
204                              Addr lo, Addr hi, Seg* seglo, Seg* seghi )
205{
206   XError xe;
207   VG_(memset)(&xe, 0, sizeof(xe));
208   xe.tag = XE_SysParam;
209   xe.XE.SysParam.part = part;
210   xe.XE.SysParam.lo = lo;
211   xe.XE.SysParam.hi = hi;
212   xe.XE.SysParam.seglo = seglo;
213   xe.XE.SysParam.seghi = seghi;
214   VG_(maybe_record_error)( tid, XE_SysParam, /*a*/(Addr)0, /*str*/s,
215                            /*extra*/(void*)&xe);
216}
217
218
219Bool pc_eq_Error ( VgRes res, Error* e1, Error* e2 )
220{
221   XError *xe1, *xe2;
222   tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
223   //tl_assert(VG_(get_error_string)(e1) == NULL);
224   //tl_assert(VG_(get_error_string)(e2) == NULL);
225
226   xe1 = (XError*)VG_(get_error_extra)(e1);
227   xe2 = (XError*)VG_(get_error_extra)(e2);
228   tl_assert(xe1);
229   tl_assert(xe2);
230
231   if (xe1->tag != xe2->tag)
232      return False;
233
234   switch (xe1->tag) {
235      case XE_SorG:
236         return //xe1->XE.SorG.addr == xe2->XE.SorG.addr
237                //&&
238                xe1->XE.SorG.sszB == xe2->XE.SorG.sszB
239                && 0 == VG_(strncmp)( &xe1->XE.SorG.expect[0],
240                                      &xe2->XE.SorG.expect[0],
241                                      sizeof(xe1->XE.SorG.expect) )
242                && 0 == VG_(strncmp)( &xe1->XE.SorG.actual[0],
243                                      &xe2->XE.SorG.actual[0],
244                                      sizeof(xe1->XE.SorG.actual) );
245      case XE_Heap:
246      case XE_Arith:
247      case XE_SysParam:
248         return True;
249      default:
250         VG_(tool_panic)("eq_Error: unrecognised error kind");
251   }
252}
253
254
255//////////////////////////////////////////////////////////////
256//                                                          //
257// Error management -- printing                             //
258//                                                          //
259//////////////////////////////////////////////////////////////
260
261/* This is the "this error is due to be printed shortly; so have a
262   look at it any print any preamble you want" function.  Which, in
263   Ptrcheck, we don't use.  Hence a no-op.
264*/
265void pc_before_pp_Error ( Error* err ) {
266}
267
268/* Do a printf-style operation on either the XML or normal output
269   channel, depending on the setting of VG_(clo_xml).
270*/
271static void emit_WRK ( const HChar* format, va_list vargs )
272{
273   if (VG_(clo_xml)) {
274      VG_(vprintf_xml)(format, vargs);
275   } else {
276      VG_(vmessage)(Vg_UserMsg, format, vargs);
277   }
278}
279static void emit ( const HChar* format, ... ) PRINTF_CHECK(1, 2);
280static void emit ( const HChar* format, ... )
281{
282   va_list vargs;
283   va_start(vargs, format);
284   emit_WRK(format, vargs);
285   va_end(vargs);
286}
287static void emiN ( const HChar* format, ... ) /* With NO FORMAT CHECK */
288{
289   va_list vargs;
290   va_start(vargs, format);
291   emit_WRK(format, vargs);
292   va_end(vargs);
293}
294
295
296static const HChar* readwrite(SSizeT sszB)
297{
298   return ( sszB < 0 ? "write" : "read" );
299}
300
301static Word Word__abs ( Word w ) {
302   return w < 0 ? -w : w;
303}
304
305void pc_pp_Error ( Error* err )
306{
307   const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
308
309   XError *xe = (XError*)VG_(get_error_extra)(err);
310   tl_assert(xe);
311
312   if (xml)
313      emit( "  <kind>%s</kind>\n", pc_get_error_name(err));
314
315   switch (VG_(get_error_kind)(err)) {
316
317   //----------------------------------------------------------
318   case XE_SorG:
319
320      if (xml) {
321
322         emit( "  <what>Invalid %s of size %ld</what>\n",
323               xe->XE.SorG.sszB < 0 ? "write" : "read",
324               Word__abs(xe->XE.SorG.sszB) );
325         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
326
327         emit( "  <auxwhat>Address %#lx expected vs actual:</auxwhat>\n",
328               xe->XE.SorG.addr );
329         emiN( "  <auxwhat>Expected: %pS</auxwhat>\n",
330               &xe->XE.SorG.expect[0] );
331         emiN( "  <auxwhat>Actual:   %pS</auxwhat>\n",
332               &xe->XE.SorG.actual[0] );
333
334      } else {
335
336         emit( "Invalid %s of size %ld\n",
337               xe->XE.SorG.sszB < 0 ? "write" : "read",
338               Word__abs(xe->XE.SorG.sszB) );
339         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
340
341         emit( " Address %#lx expected vs actual:\n", xe->XE.SorG.addr );
342         emit( " Expected: %s\n", &xe->XE.SorG.expect[0] );
343         emit( " Actual:   %s\n", &xe->XE.SorG.actual[0] );
344         if (xe->XE.SorG.delta[0] != 0)
345            emit(" Actual:   is %s Expected\n", &xe->XE.SorG.delta[0]);
346      }
347      break;
348
349   //----------------------------------------------------------
350   case XE_Heap: {
351      const HChar *place, *legit, *how_invalid;
352      Addr a    = xe->XE.Heap.addr;
353      Seg* vseg = xe->XE.Heap.vseg;
354
355      tl_assert(is_known_segment(vseg) || NONPTR == vseg);
356
357      if (NONPTR == vseg) {
358         // Access via a non-pointer
359
360         if (xml) {
361
362            emit( "  <what>Invalid %s of size %ld</what>\n",
363                  readwrite(xe->XE.Heap.sszB),
364                  Word__abs(xe->XE.Heap.sszB) );
365            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
366
367            emit( "  <auxwhat>Address %#lx is not derived from "
368                  "any known block</auxwhat>\n", a );
369
370         } else {
371
372            emit( "Invalid %s of size %ld\n",
373                  readwrite(xe->XE.Heap.sszB),
374                  Word__abs(xe->XE.Heap.sszB) );
375            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
376
377            emit( " Address %#lx is not derived from "
378                  "any known block\n", a );
379
380         }
381
382      } else {
383         // Access via a pointer, but outside its range.
384         Int cmp;
385         UWord miss_size;
386         Seg__cmp(vseg, a, &cmp, &miss_size);
387         if      (cmp  < 0) place = "before";
388         else if (cmp == 0) place = "inside";
389         else               place = "after";
390         how_invalid = ( ( Seg__is_freed(vseg) && 0 != cmp )
391                       ? "Doubly-invalid" : "Invalid" );
392         legit = ( Seg__is_freed(vseg) ? "once-" : "" );
393
394         if (xml) {
395
396            emit( "  <what>%s %s of size %ld</what>\n",
397                  how_invalid,
398                  readwrite(xe->XE.Heap.sszB),
399                  Word__abs(xe->XE.Heap.sszB) );
400            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
401
402            emit( "  <auxwhat>Address %#lx is %lu bytes %s "
403                     "the accessing pointer's</auxwhat>\n",
404                  a, miss_size, place );
405            emit( "  <auxwhat>%slegitimate range, "
406                     "a block of size %lu %s</auxwhat>\n",
407                  legit, Seg__size(vseg),
408                  Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
409            VG_(pp_ExeContext)(Seg__where(vseg));
410
411         } else {
412
413            emit( "%s %s of size %ld\n",
414                  how_invalid,
415                  readwrite(xe->XE.Heap.sszB),
416                  Word__abs(xe->XE.Heap.sszB) );
417            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
418
419            emit( " Address %#lx is %lu bytes %s the accessing pointer's\n",
420                  a, miss_size, place );
421            emit( " %slegitimate range, a block of size %lu %s\n",
422                  legit, Seg__size(vseg),
423                  Seg__is_freed(vseg) ? "free'd" : "alloc'd" );
424            VG_(pp_ExeContext)(Seg__where(vseg));
425
426         }
427      }
428
429      /* If we have a better description of the address, show it.
430         Note that in XML mode, it will already by nicely wrapped up
431         in tags, either <auxwhat> or <xauxwhat>, so we can just emit
432         it verbatim. */
433      if (xml) {
434
435         if (xe->XE.Heap.descr1)
436            emiN( "  %pS\n",
437                  (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
438         if (xe->XE.Heap.descr2)
439            emiN( "  %pS\n",
440                  (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
441         if (xe->XE.Heap.datasym[0] != 0)
442            emiN( "  <auxwhat>Address 0x%llx is %llu bytes "
443                  "inside data symbol \"%pS\"</auxwhat>\n",
444                  (ULong)xe->XE.Heap.addr,
445                  (ULong)xe->XE.Heap.datasymoff,
446                  xe->XE.Heap.datasym );
447
448      } else {
449
450         if (xe->XE.Heap.descr1)
451            emit( " %s\n",
452                  (HChar*)VG_(indexXA)( xe->XE.Heap.descr1, 0 ) );
453         if (xe->XE.Heap.descr2)
454            emit( " %s\n",
455                  (HChar*)VG_(indexXA)( xe->XE.Heap.descr2, 0 ) );
456         if (xe->XE.Heap.datasym[0] != 0)
457            emit( " Address 0x%llx is %llu bytes "
458                  "inside data symbol \"%s\"\n",
459                  (ULong)xe->XE.Heap.addr,
460                  (ULong)xe->XE.Heap.datasymoff,
461                  xe->XE.Heap.datasym );
462
463      }
464      break;
465   }
466
467   //----------------------------------------------------------
468   case XE_Arith: {
469      Seg*   seg1   = xe->XE.Arith.seg1;
470      Seg*   seg2   = xe->XE.Arith.seg2;
471      const HChar*  which;
472
473      tl_assert(BOTTOM != seg1);
474      tl_assert(BOTTOM != seg2 && UNKNOWN != seg2);
475
476      if (xml) {
477
478         emit( "  <what>Invalid arguments to %s</what>\n",
479               xe->XE.Arith.opname );
480         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
481
482         if (seg1 != seg2) {
483            if (NONPTR == seg1) {
484               emit( "  <auxwhat>First arg not a pointer</auxwhat>\n" );
485            } else if (UNKNOWN == seg1) {
486               emit( "  <auxwhat>First arg may be a pointer</auxwhat>\n" );
487            } else {
488               emit( "  <auxwhat>First arg derived from address %#lx of "
489                     "%lu-byte block alloc'd</auxwhat>\n",
490                     Seg__addr(seg1), Seg__size(seg1) );
491               VG_(pp_ExeContext)(Seg__where(seg1));
492            }
493            which = "Second arg";
494         } else {
495            which = "Both args";
496         }
497         if (NONPTR == seg2) {
498            emit( "  <auxwhat>%s not a pointer</auxwhat>\n", which );
499         } else {
500            emit( "  <auxwhat>%s derived from address %#lx of "
501                  "%lu-byte block alloc'd</auxwhat>\n",
502                  which, Seg__addr(seg2), Seg__size(seg2) );
503            VG_(pp_ExeContext)(Seg__where(seg2));
504         }
505
506      } else {
507
508         emit( "Invalid arguments to %s\n",
509               xe->XE.Arith.opname );
510         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
511
512         if (seg1 != seg2) {
513            if (NONPTR == seg1) {
514               emit( " First arg not a pointer\n" );
515            } else if (UNKNOWN == seg1) {
516               emit( " First arg may be a pointer\n" );
517            } else {
518               emit( " First arg derived from address %#lx of "
519                     "%lu-byte block alloc'd\n",
520                     Seg__addr(seg1), Seg__size(seg1) );
521               VG_(pp_ExeContext)(Seg__where(seg1));
522            }
523            which = "Second arg";
524         } else {
525            which = "Both args";
526         }
527         if (NONPTR == seg2) {
528            emit( " %s not a pointer\n", which );
529         } else {
530            emit( " %s derived from address %#lx of "
531                  "%lu-byte block alloc'd\n",
532                  which, Seg__addr(seg2), Seg__size(seg2) );
533            VG_(pp_ExeContext)(Seg__where(seg2));
534         }
535
536      }
537
538      break;
539   }
540
541   //----------------------------------------------------------
542   case XE_SysParam: {
543      Addr  lo    = xe->XE.SysParam.lo;
544      Addr  hi    = xe->XE.SysParam.hi;
545      Seg*  seglo = xe->XE.SysParam.seglo;
546      Seg*  seghi = xe->XE.SysParam.seghi;
547      const HChar* s = VG_(get_error_string) (err);
548      const HChar* what;
549
550      tl_assert(BOTTOM != seglo && BOTTOM != seghi);
551
552      if      (Vg_CoreSysCall == xe->XE.SysParam.part)
553                 what = "Syscall param ";
554      else    VG_(tool_panic)("bad CorePart");
555
556      if (seglo == seghi) {
557         // freed block
558         tl_assert(is_known_segment(seglo));
559         tl_assert(Seg__is_freed(seglo)); // XXX what if it's now recycled?
560
561         if (xml) {
562
563            emit( "  <what>%s%s contains unaddressable byte(s)</what>\n",
564                  what, s );
565            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
566
567            emit( "  <auxwhat>Address %#lx is %ld bytes inside a "
568                  "%ld-byte block free'd</auxwhat>\n",
569                  lo, lo-Seg__addr(seglo), Seg__size(seglo) );
570            VG_(pp_ExeContext)(Seg__where(seglo));
571
572         } else {
573
574            emit( " %s%s contains unaddressable byte(s)\n",
575                  what, s );
576            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
577
578            emit( " Address %#lx is %ld bytes inside a "
579                  "%ld-byte block free'd\n",
580                  lo, lo-Seg__addr(seglo), Seg__size(seglo) );
581            VG_(pp_ExeContext)(Seg__where(seglo));
582
583         }
584
585      } else {
586         // mismatch
587
588         if (xml) {
589
590            emit( "  <what>%s%s is non-contiguous</what>\n",
591                  what, s );
592            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
593
594            if (UNKNOWN == seglo) {
595               emit( "  <auxwhat>First byte is "
596                        "not inside a known block</auxwhat>\n" );
597            } else {
598               emit( "  <auxwhat>First byte (%#lx) is %ld bytes inside a "
599                     "%ld-byte block alloc'd</auxwhat>\n",
600                     lo, lo-Seg__addr(seglo), Seg__size(seglo) );
601               VG_(pp_ExeContext)(Seg__where(seglo));
602            }
603
604            if (UNKNOWN == seghi) {
605               emit( "  <auxwhat>Last byte is "
606                        "not inside a known block</auxwhat>\n" );
607            } else {
608               emit( "  <auxwhat>Last byte (%#lx) is %ld bytes inside a "
609                     "%ld-byte block alloc'd</auxwhat>\n",
610                     hi, hi-Seg__addr(seghi), Seg__size(seghi) );
611               VG_(pp_ExeContext)(Seg__where(seghi));
612            }
613
614         } else {
615
616            emit( "%s%s is non-contiguous\n",
617                  what, s );
618            VG_(pp_ExeContext)( VG_(get_error_where)(err) );
619
620            if (UNKNOWN == seglo) {
621               emit( " First byte is not inside a known block\n" );
622            } else {
623               emit( " First byte (%#lx) is %ld bytes inside a "
624                     "%ld-byte block alloc'd\n",
625                     lo, lo-Seg__addr(seglo), Seg__size(seglo) );
626               VG_(pp_ExeContext)(Seg__where(seglo));
627            }
628
629            if (UNKNOWN == seghi) {
630               emit( " Last byte is not inside a known block\n" );
631            } else {
632               emit( " Last byte (%#lx) is %ld bytes inside a "
633                     "%ld-byte block alloc'd\n",
634                     hi, hi-Seg__addr(seghi), Seg__size(seghi) );
635               VG_(pp_ExeContext)(Seg__where(seghi));
636            }
637
638         }
639
640      }
641      break;
642   }
643
644   default:
645      VG_(tool_panic)("pp_Error: unrecognised error kind");
646   }
647}
648
649
650UInt pc_update_Error_extra ( Error* err )
651{
652   XError *xe = (XError*)VG_(get_error_extra)(err);
653   tl_assert(xe);
654   switch (xe->tag) {
655      case XE_SorG:
656         break;
657      case XE_Heap: {
658         Bool have_descr;
659
660         tl_assert(sizeof(xe->XE.Heap.datasym) > 0);
661         xe->XE.Heap.datasymoff = 0;
662         xe->XE.Heap.datasym[0] = 0;
663
664         tl_assert(!xe->XE.Heap.descr1);
665         tl_assert(!xe->XE.Heap.descr2);
666
667         xe->XE.Heap.descr1
668            = VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
669                          VG_(free), sizeof(HChar) );
670         xe->XE.Heap.descr2
671            = VG_(newXA)( VG_(malloc), "pc.update_extra.Heap.descr1",
672                          VG_(free), sizeof(HChar) );
673
674         VG_(memset)(&xe->XE.Heap.datasym, 0, sizeof(xe->XE.Heap.datasym));
675         xe->XE.Heap.datasymoff = 0;
676
677         have_descr
678            = VG_(get_data_description)( xe->XE.Heap.descr1,
679                                         xe->XE.Heap.descr2,
680                                         xe->XE.Heap.addr );
681
682         /* If there's nothing in descr1/2, free it.  Why is it safe to
683            to VG_(indexXA) at zero here?  Because
684            VG_(get_data_description) guarantees to zero terminate
685            descr1/2 regardless of the outcome of the call.  So there's
686            always at least one element in each XA after the call.
687         */
688         if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr1, 0 ))
689             || !have_descr) {
690            VG_(deleteXA)( xe->XE.Heap.descr1 );
691            xe->XE.Heap.descr1 = NULL;
692         }
693         if (0 == VG_(strlen)( VG_(indexXA)( xe->XE.Heap.descr2, 0 ))
694             || !have_descr) {
695            VG_(deleteXA)( xe->XE.Heap.descr2 );
696            xe->XE.Heap.descr2 = NULL;
697         }
698
699         /* If Dwarf3 info produced nothing useful, see at least if
700            we can fish something useful out of the ELF symbol info. */
701         if (!have_descr) {
702            if (VG_(get_datasym_and_offset)(
703                   xe->XE.Heap.addr, &xe->XE.Heap.datasym[0],
704                   sizeof(xe->XE.Heap.datasym)-1,
705                   &xe->XE.Heap.datasymoff )
706               ) {
707               tl_assert(xe->XE.Heap.datasym[sizeof(xe->XE.Heap.datasym)-1]
708                         == 0);
709            }
710         }
711         break;
712      }
713      case XE_Arith:
714         break;
715      case XE_SysParam:
716         break;
717      default:
718         VG_(tool_panic)("update_extra");
719   }
720   return sizeof(XError);
721}
722
723Bool pc_is_recognised_suppression ( const HChar* name, Supp *su )
724{
725   SuppKind skind;
726
727   if      (VG_STREQ(name, "SorG"))     skind = XS_SorG;
728   else if (VG_STREQ(name, "Heap"))     skind = XS_Heap;
729   else if (VG_STREQ(name, "Arith"))    skind = XS_Arith;
730   else if (VG_STREQ(name, "SysParam")) skind = XS_SysParam;
731   else
732      return False;
733
734   VG_(set_supp_kind)(su, skind);
735   return True;
736}
737
738Bool pc_read_extra_suppression_info ( Int fd, HChar** bufpp,
739                                      SizeT* nBufp, Int* lineno, Supp* su )
740{
741   Bool eof;
742   if (VG_(get_supp_kind)(su) == XS_SysParam) {
743      eof = VG_(get_line) ( fd, bufpp, nBufp, lineno );
744      if (eof) return False;
745      VG_(set_supp_string)(su, VG_(strdup)("pc.common.presi.1", *bufpp));
746   }
747   return True;
748}
749
750Bool pc_error_matches_suppression (Error* err, Supp* su)
751{
752   ErrorKind ekind = VG_(get_error_kind)(err);
753   switch (VG_(get_supp_kind)(su)) {
754      case XS_SorG:     return ekind == XE_SorG;
755      case XS_Heap:     return ekind == XE_Heap;
756      case XS_Arith:    return ekind == XE_Arith;
757      case XS_SysParam: return ekind == XE_SysParam;
758      default:
759         VG_(printf)("Error:\n"
760                     "  unknown suppression type %d\n",
761                     VG_(get_supp_kind)(su));
762         VG_(tool_panic)("unknown suppression type in "
763                         "pc_error_matches_suppression");
764   }
765}
766
767const HChar* pc_get_error_name ( Error* err )
768{
769   XError *xe = (XError*)VG_(get_error_extra)(err);
770   tl_assert(xe);
771   switch (xe->tag) {
772      case XE_SorG:     return "SorG";
773      case XE_Heap:     return "Heap";
774      case XE_Arith:    return "Arith";
775      case XE_SysParam: return "SysParam";
776      default:          VG_(tool_panic)("get_error_name: unexpected type");
777   }
778}
779
780Bool pc_get_extra_suppression_info ( Error* err,
781                                     /*OUT*/HChar* buf, Int nBuf )
782{
783   ErrorKind ekind = VG_(get_error_kind )(err);
784   tl_assert(buf);
785   tl_assert(nBuf >= 16); // stay sane
786   if (XE_SysParam == ekind) {
787      const HChar* errstr = VG_(get_error_string)(err);
788      tl_assert(errstr);
789      VG_(snprintf)(buf, nBuf-1, "%s", errstr);
790      return True;
791   } else {
792      return False;
793   }
794}
795
796Bool pc_print_extra_suppression_use ( Supp* su,
797                                      /*OUT*/HChar* buf, Int nBuf )
798{
799   return False;
800}
801
802void pc_update_extra_suppression_use (Error* err, Supp* su)
803{
804   return;
805}
806
807/*--------------------------------------------------------------------*/
808/*--- end                                              pc_common.c ---*/
809/*--------------------------------------------------------------------*/
810