1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Error management for Helgrind.                               ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                  hg_errors.c ---*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Helgrind, a Valgrind tool for detecting errors
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in threaded programs.
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   Copyright (C) 2007-2013 OpenWorks Ltd
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      info@open-works.co.uk
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02111-1307, USA.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_basics.h"
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcbase.h"
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcassert.h"
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_libcprint.h"
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_execontext.h"
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_errormgr.h"
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_wordfm.h"
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_xarray.h"
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_debuginfo.h"
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_threadstate.h"
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "pub_tool_options.h"     // VG_(clo_xml)
43eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov#include "pub_tool_addrinfo.h"
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_basics.h"
46eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov#include "hg_addrdescr.h"
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_wordset.h"
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_lock_n_thread.h"
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libhb.h"
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "hg_errors.h"            /* self */
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Error management -- storage                              ---*/
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* maps (by value) strings to a copy of them in ARENA_TOOL */
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* string_table = NULL;
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong HG_(stats__string_table_queries) = 0;
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong HG_(stats__string_table_get_map_size) ( void ) {
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return string_table ? (ULong)VG_(sizeFM)(string_table) : 0;
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word string_table_cmp ( UWord s1, UWord s2 ) {
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Word)VG_(strcmp)( (HChar*)s1, (HChar*)s2 );
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic HChar* string_table_strdup ( const HChar* str ) {
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar* copy = NULL;
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(stats__string_table_queries)++;
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!str)
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      str = "(null)";
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!string_table) {
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      string_table = VG_(newFM)( HG_(zalloc), "hg.sts.1",
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 HG_(free), string_table_cmp );
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(string_table);
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(lookupFM)( string_table,
82436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                      NULL, (UWord*)&copy, (UWord)str )) {
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(copy);
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0) VG_(printf)("string_table_strdup: %p -> %p\n", str, copy );
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return copy;
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      copy = HG_(strdup)("hg.sts.2", str);
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(copy);
89436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(addToFM)( string_table, (UWord)copy, (UWord)copy );
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return copy;
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* maps from Lock .unique fields to LockP*s */
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic WordFM* map_LockN_to_P = NULL;
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong HG_(stats__LockN_to_P_queries) = 0;
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong HG_(stats__LockN_to_P_get_map_size) ( void ) {
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return map_LockN_to_P ? (ULong)VG_(sizeFM)(map_LockN_to_P) : 0;
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Word lock_unique_cmp ( UWord lk1W, UWord lk2W )
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk1 = (Lock*)lk1W;
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lk2 = (Lock*)lk2W;
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockNorP)(lk1) );
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockNorP)(lk2) );
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk1->unique < lk2->unique) return -1;
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (lk1->unique > lk2->unique) return 1;
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return 0;
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Given a normal Lock (LockN), convert it to a persistent Lock
116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   (LockP).  In some cases the LockN could be invalid (if it's been
117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   freed), so we enquire, in hg_main.c's admin_locks list, whether it
118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   is in fact valid.  If allowed_to_be_invalid is True, then it's OK
119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for the LockN to be invalid, in which case Lock_INVALID is
120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   returned.  In all other cases, we insist that the LockN is a valid
121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   lock, and return its corresponding LockP.
122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Why can LockNs sometimes be invalid?  Because they are harvested
124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   from locksets that are attached to the OldRef info for conflicting
125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   threads.  By the time we detect a race, the some of the elements of
126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   the lockset may have been destroyed by the client, in which case
127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   the corresponding Lock structures we maintain will have been freed.
128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   So we check that each LockN is a member of the admin_locks double
130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   linked list of all Lock structures.  That stops us prodding around
131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   in potentially freed-up Lock structures.  However, it's not quite a
132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   proper check: if a new Lock has been reallocated at the same
133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   address as one which was previously freed, we'll wind up copying
134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   the new one as the basis for the LockP, which is completely bogus
135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   because it is unrelated to the previous Lock that lived there.
136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Let's hope that doesn't happen too often.
137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov*/
138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Lock* mk_LockP_from_LockN ( Lock* lkn,
139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                   Bool allowed_to_be_invalid )
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Lock* lkp = NULL;
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(stats__LockN_to_P_queries)++;
143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* First off, let's do some sanity checks.  If
145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      allowed_to_be_invalid is False, we _must_ be able to find 'lkn'
146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      in admin_locks; else we must assert.  If it is True, it's OK for
147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      it not to be findable, but in that case we must return
148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      Lock_INVALID right away. */
149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Lock* lock_list = HG_(get_admin_locks)();
150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   while (lock_list) {
151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (lock_list == lkn)
152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         break;
153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lock_list = lock_list->admin_next;
154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (lock_list == NULL) {
156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* We didn't find it.  That possibility has to be OK'd by the
157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         caller. */
158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(allowed_to_be_invalid);
159b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return Lock_INVALID;
160b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
161b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
162b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* So we must be looking at a valid LockN. */
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockN)(lkn) );
164b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!map_LockN_to_P) {
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      map_LockN_to_P = VG_(newFM)( HG_(zalloc), "hg.mLPfLN.1",
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HG_(free), lock_unique_cmp );
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(map_LockN_to_P);
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
170436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (!VG_(lookupFM)( map_LockN_to_P, NULL, (UWord*)&lkp, (UWord)lkn)) {
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lkp = HG_(zalloc)( "hg.mLPfLN.2", sizeof(Lock) );
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *lkp = *lkn;
173b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lkp->admin_next = NULL;
174b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lkp->admin_prev = NULL;
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lkp->magic = LockP_MAGIC;
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Forget about the bag of lock holders - don't copy that.
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Also, acquired_at should be NULL whenever heldBy is, and vice
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         versa.  Also forget about the associated libhb synch object. */
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lkp->heldW  = False;
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lkp->heldBy = NULL;
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lkp->acquired_at = NULL;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lkp->hbso = NULL;
183436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      VG_(addToFM)( map_LockN_to_P, (UWord)lkp, (UWord)lkp );
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockP)(lkp) );
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return lkp;
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
189b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Expand a WordSet of LockN*'s into a NULL-terminated vector of
190b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   LockP*'s.  Any LockN's that can't be converted into a LockP
191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   (because they have been freed, see comment on mk_LockP_from_LockN)
192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   are converted instead into the value Lock_INVALID.  Hence the
193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   returned vector is a sequence: zero or more (valid LockP* or
194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   LockN_INVALID), terminated by a NULL. */
195b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic
196b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy StepanovLock** enumerate_WordSet_into_LockP_vector( WordSetU* univ_lsets,
197b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            WordSetID lockset,
198b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                            Bool allowed_to_be_invalid )
199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(univ_lsets);
201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert( HG_(plausibleWS)(univ_lsets, lockset) );
202b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord  nLocks = HG_(cardinalityWS)(univ_lsets, lockset);
203b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Lock** lockPs = HG_(zalloc)( "hg.eWSiLPa",
204b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                (nLocks+1) * sizeof(Lock*) );
205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(lockPs);
206b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(lockPs[nLocks] == NULL); /* pre-NULL terminated */
207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord* lockNs  = NULL;
208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord  nLockNs = 0;
209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (nLocks > 0)  {
210b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* HG_(getPayloadWS) doesn't assign non-NULL to &lockNs if the
211b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         lockset is empty; hence the guarding "if".  Sigh. */
212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      HG_(getPayloadWS)( &lockNs, &nLockNs, univ_lsets, lockset );
213b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(lockNs);
214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord i;
216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* Convert to LockPs. */
217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; i < nLockNs; i++) {
218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      lockPs[i] = mk_LockP_from_LockN( (Lock*)lockNs[i],
219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                       allowed_to_be_invalid );
220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
221b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return lockPs;
222b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
223b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
224b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Get the number of useful elements in a vector created by
225b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   enumerate_WordSet_into_LockP_vector.  Returns both the total number
226b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   of elements (not including the terminating NULL) and the number of
227b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   non-Lock_INVALID elements. */
228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void count_LockP_vector ( /*OUT*/UWord* nLocks,
229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 /*OUT*/UWord* nLocksValid,
230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Lock** vec )
231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(vec);
233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   *nLocks = *nLocksValid = 0;
234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord n = 0;
235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   while (vec[n]) {
236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      (*nLocks)++;
237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (vec[n] != Lock_INVALID)
238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         (*nLocksValid)++;
239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      n++;
240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
242b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
243b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Find out whether 'lk' is in 'vec'. */
244b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic Bool elem_LockP_vector ( Lock** vec, Lock* lk )
245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
246b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(vec);
247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(lk);
248b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord n = 0;
249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   while (vec[n]) {
250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (vec[n] == lk)
251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         return True;
252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      n++;
253b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
254b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   return False;
255b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
256b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
257b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Errors:
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      race: program counter
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            read or write
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            data size
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            previous state
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            current state
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      FIXME: how does state printing interact with lockset gc?
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Are the locksets in prev/curr state always valid?
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Ditto question for the threadsets
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ThreadSets - probably are always valid if Threads
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          are never thrown away.
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          LockSets - could at least print the lockset elements that
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          correspond to actual locks at the time of printing.  Hmm.
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Error kinds */
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum {
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_Race=1101,      // race
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_UnlockUnlocked, // unlocking a not-locked lock
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_UnlockForeign,  // unlocking a lock held by some other thread
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_UnlockBogus,    // unlocking an address not known to be a lock
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_PthAPIerror,    // error from the POSIX pthreads API
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_LockOrder,      // lock order error
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XE_Misc            // misc other error (w/ string to describe it)
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XErrorTag;
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extra contexts for kinds */
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   struct  {
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XErrorTag tag;
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      union {
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Addr        data_addr;
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Int         szB;
296eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov            AddrInfo    data_addrinfo;
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool        isWrite;
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread*     thr;
299b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Lock**      locksHeldW;
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* h1_* and h2_* provide some description of a previously
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               observed access with which we are conflicting. */
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread*     h1_ct; /* non-NULL means h1 info present */
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ExeContext* h1_ct_mbsegstartEC;
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ExeContext* h1_ct_mbsegendEC;
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread*     h2_ct; /* non-NULL means h2 info present */
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ExeContext* h2_ct_accEC;
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Int         h2_ct_accSzB;
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Bool        h2_ct_accIsW;
309b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Lock**      h2_ct_locksHeldW;
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } Race;
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread* thr;  /* doing the unlocking */
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Lock*   lock; /* lock (that is already unlocked) */
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } UnlockUnlocked;
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread* thr;    /* doing the unlocking */
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread* owner;  /* thread that actually holds the lock */
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Lock*   lock;   /* lock (that is held by 'owner') */
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } UnlockForeign;
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread* thr;     /* doing the unlocking */
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Addr    lock_ga; /* purported address of the lock */
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } UnlockBogus;
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread* thr;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            HChar*  fnname; /* persistent, in tool-arena */
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Word    err;    /* pth error code */
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            HChar*  errstr; /* persistent, in tool-arena */
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } PthAPIerror;
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread*     thr;
332b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            /* The first 4 fields describe the previously observed
333b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               (should-be) ordering. */
334b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Addr        shouldbe_earlier_ga;
335b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            Addr        shouldbe_later_ga;
336b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            ExeContext* shouldbe_earlier_ec;
337b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            ExeContext* shouldbe_later_ec;
338b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            /* In principle we need to record two more stacks, from
339b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               this thread, when acquiring the locks in the "wrong"
340b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               order.  In fact the wallclock-later acquisition by this
341b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               thread is recorded in the main stack for this error.
342b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               So we only need a stack for the earlier acquisition by
343b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               this thread. */
344b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            ExeContext* actual_earlier_ec;
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } LockOrder;
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         struct {
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread*     thr;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            HChar*      errstr; /* persistent, in tool-arena */
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            HChar*      auxstr; /* optional, persistent, in tool-arena */
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ExeContext* auxctx; /* optional */
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } Misc;
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } XE;
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError;
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void init_XError ( XError* xe ) {
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(memset)(xe, 0, sizeof(*xe) );
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe->tag = XE_Race-1; /* bogus */
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extensions of suppressions */
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   enum {
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_Race=1201, /* race */
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_FreeMemLock,
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_UnlockUnlocked,
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_UnlockForeign,
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_UnlockBogus,
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_PthAPIerror,
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_LockOrder,
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      XS_Misc
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XSuppTag;
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Updates the copy with address info if necessary. */
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownUInt HG_(update_extra) ( Error* err )
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError* xe = (XError*)VG_(get_error_extra)(err);
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xe);
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //if (extra != NULL && Undescribed == extra->addrinfo.akind) {
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //   describe_addr ( VG_(get_error_address)(err), &(extra->addrinfo) );
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //}
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (xe->tag == XE_Race) {
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
388b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Note the set of locks that the thread is (w-)holding.
389b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Convert the WordSetID of LockN*'s into a NULL-terminated
390b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         vector of LockP*'s.  We don't expect to encounter any invalid
391b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         LockNs in this conversion. */
392b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tl_assert(xe->XE.Race.thr);
393b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      xe->XE.Race.locksHeldW
394b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         = enumerate_WordSet_into_LockP_vector(
395b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              HG_(get_univ_lsets)(),
396b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              xe->XE.Race.thr->locksetW,
397b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              False/*!allowed_to_be_invalid*/
398b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           );
399b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* See if we can come up with a source level description of the
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         raced-upon address.  This is potentially expensive, which is
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         why it's only done at the update_extra point, not when the
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         error is initially created. */
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      static Int xxx = 0;
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xxx++;
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0)
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf)("HG_(update_extra): "
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     "%d conflicting-event queries\n", xxx);
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
410eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov      HG_(describe_addr) (xe->XE.Race.data_addr, &xe->XE.Race.data_addrinfo);
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And poke around in the conflicting-event map, to see if we
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         can rustle up a plausible-looking conflicting memory access
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to show. */
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (HG_(clo_history_level) >= 2) {
416b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Thr*        thrp            = NULL;
417b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         ExeContext* wherep          = NULL;
418b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Addr        acc_addr        = xe->XE.Race.data_addr;
419b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Int         acc_szB         = xe->XE.Race.szB;
420b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Thr*        acc_thr         = xe->XE.Race.thr->hbthr;
421b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Bool        acc_isW         = xe->XE.Race.isWrite;
422b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         SizeT       conf_szB        = 0;
423b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Bool        conf_isW        = False;
424b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         WordSetID   conf_locksHeldW = 0;
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(!xe->XE.Race.h2_ct_accEC);
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(!xe->XE.Race.h2_ct);
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (libhb_event_map_lookup(
428b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                &wherep, &thrp, &conf_szB, &conf_isW, &conf_locksHeldW,
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                acc_thr, acc_addr, acc_szB, acc_isW )) {
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Thread* threadp;
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(wherep);
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(thrp);
433b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            threadp = libhb_get_Thr_hgthread( thrp );
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(threadp);
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xe->XE.Race.h2_ct_accEC  = wherep;
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xe->XE.Race.h2_ct        = threadp;
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xe->XE.Race.h2_ct_accSzB = (Int)conf_szB;
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xe->XE.Race.h2_ct_accIsW = conf_isW;
439b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            xe->XE.Race.h2_ct_locksHeldW
440b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               = enumerate_WordSet_into_LockP_vector(
441b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    HG_(get_univ_lsets)(),
442b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    conf_locksHeldW,
443b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    True/*allowed_to_be_invalid*/
444b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 );
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        }
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // both NULL or both non-NULL
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( (!!xe->XE.Race.h2_ct) == (!!xe->XE.Race.h2_ct_accEC) );
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return sizeof(XError);
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(record_error_Race) ( Thread* thr,
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              Addr data_addr, Int szB, Bool isWrite,
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              Thread* h1_ct,
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              ExeContext* h1_ct_segstart,
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              ExeContext* h1_ct_mbsegendEC )
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  if defined(VGO_linux)
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip any races on locations apparently in GOTPLT sections.  This
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      is said to be caused by ld.so poking PLT table entries (or
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      whatever) when it writes the resolved address of a dynamically
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      linked routine, into the table (or whatever) when it is called
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for the first time. */
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     VgSectKind sect = VG_(DebugInfo_sect_kind)( NULL, 0, data_addr );
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (0) VG_(printf)("XXXXXXXXX RACE on %#lx %s\n",
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        data_addr, VG_(pp_SectKind)(sect));
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* SectPLT is required on ???-linux */
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (sect == Vg_SectGOTPLT) return;
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     /* SectPLT is required on ppc32/64-linux */
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if (sect == Vg_SectPLT) return;
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  endif
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_Race;
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.data_addr   = data_addr;
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.szB         = szB;
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.isWrite     = isWrite;
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.thr         = thr;
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(isWrite == False || isWrite == True);
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(szB == 8 || szB == 4 || szB == 2 || szB == 1);
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Skip on the detailed description of the raced-on address at this
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      point; it's expensive.  Leave it for the update_extra function
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if we ever make it that far. */
492eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov   xe.XE.Race.data_addrinfo.tag = Addr_Undescribed;
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Skip on any of the conflicting-access info at this point.
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // It's expensive to obtain, and this error is more likely than
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // not to be discarded.  We'll fill these fields in in
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // HG_(update_extra) just above, assuming the error ever makes
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // it that far (unlikely).
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h2_ct_accSzB = 0;
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h2_ct_accIsW = False;
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h2_ct_accEC  = NULL;
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h2_ct        = NULL;
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h1_ct              = h1_ct;
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h1_ct_mbsegstartEC = h1_ct_segstart;
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Race.h1_ct_mbsegendEC   = h1_ct_mbsegendEC;
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_Race, data_addr, NULL, &xe );
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(record_error_UnlockUnlocked) ( Thread* thr, Lock* lk )
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockN)(lk) );
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_UnlockUnlocked;
521b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.UnlockUnlocked.thr
522b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      = thr;
523b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.UnlockUnlocked.lock
524b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      = mk_LockP_from_LockN(lk, False/*!allowed_to_be_invalid*/);
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_UnlockUnlocked, 0, NULL, &xe );
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(record_error_UnlockForeign) ( Thread* thr,
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       Thread* owner, Lock* lk )
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(owner) );
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_LockN)(lk) );
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_UnlockForeign;
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.UnlockForeign.thr   = thr;
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.UnlockForeign.owner = owner;
543b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.UnlockForeign.lock
544b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      = mk_LockP_from_LockN(lk, False/*!allowed_to_be_invalid*/);
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_UnlockForeign, 0, NULL, &xe );
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(record_error_UnlockBogus) ( Thread* thr, Addr lock_ga )
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_UnlockBogus;
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.UnlockBogus.thr     = thr;
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.UnlockBogus.lock_ga = lock_ga;
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_UnlockBogus, 0, NULL, &xe );
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(record_error_LockOrder)(
568b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        Thread*     thr,
569b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        Addr        shouldbe_earlier_ga,
570b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        Addr        shouldbe_later_ga,
571b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        ExeContext* shouldbe_earlier_ec,
572b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        ExeContext* shouldbe_later_ec,
573b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        ExeContext* actual_earlier_ec
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     )
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
578b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(HG_(clo_track_lockorders));
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_LockOrder;
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.LockOrder.thr       = thr;
582b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.LockOrder.shouldbe_earlier_ga = shouldbe_earlier_ga;
583b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.LockOrder.shouldbe_earlier_ec = shouldbe_earlier_ec;
584b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.LockOrder.shouldbe_later_ga   = shouldbe_later_ga;
585b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.LockOrder.shouldbe_later_ec   = shouldbe_later_ec;
586b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   xe.XE.LockOrder.actual_earlier_ec   = actual_earlier_ec;
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_LockOrder, 0, NULL, &xe );
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
594436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid HG_(record_error_PthAPIerror) ( Thread* thr, const HChar* fnname,
595436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                     Word err, const HChar* errstr )
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(fnname);
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(errstr);
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_PthAPIerror;
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.PthAPIerror.thr    = thr;
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.PthAPIerror.fnname = string_table_strdup(fnname);
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.PthAPIerror.err    = err;
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.PthAPIerror.errstr = string_table_strdup(errstr);
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_PthAPIerror, 0, NULL, &xe );
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
614436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid HG_(record_error_Misc_w_aux) ( Thread* thr, const HChar* errstr,
615436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                    const HChar* auxstr, ExeContext* auxctx )
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError xe;
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_Thread)(thr) );
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(errstr);
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   init_XError(&xe);
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.tag = XE_Misc;
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Misc.thr    = thr;
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Misc.errstr = string_table_strdup(errstr);
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Misc.auxstr = auxstr ? string_table_strdup(auxstr) : NULL;
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe.XE.Misc.auxctx = auxctx;
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // FIXME: tid vs thr
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( HG_(is_sane_ThreadId)(thr->coretid) );
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert( thr->coretid != VG_INVALID_THREADID );
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   VG_(maybe_record_error)( thr->coretid,
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            XE_Misc, 0, NULL, &xe );
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
633436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid HG_(record_error_Misc) ( Thread* thr, const HChar* errstr )
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HG_(record_error_Misc_w_aux)(thr, errstr, NULL, NULL);
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool HG_(eq_Error) ( VgRes not_used, Error* e1, Error* e2 )
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError *xe1, *xe2;
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2));
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe1 = (XError*)VG_(get_error_extra)(e1);
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe2 = (XError*)VG_(get_error_extra)(e2);
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xe1);
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xe2);
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_(get_error_kind)(e1)) {
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_Race:
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.Race.szB == xe2->XE.Race.szB
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && xe1->XE.Race.isWrite == xe2->XE.Race.isWrite
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && (HG_(clo_cmp_race_err_addrs)
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ? xe1->XE.Race.data_addr == xe2->XE.Race.data_addr
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       : True);
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockUnlocked:
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.UnlockUnlocked.thr == xe2->XE.UnlockUnlocked.thr
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && xe1->XE.UnlockUnlocked.lock == xe2->XE.UnlockUnlocked.lock;
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockForeign:
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.UnlockForeign.thr == xe2->XE.UnlockForeign.thr
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && xe1->XE.UnlockForeign.owner == xe2->XE.UnlockForeign.owner
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && xe1->XE.UnlockForeign.lock == xe2->XE.UnlockForeign.lock;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockBogus:
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.UnlockBogus.thr == xe2->XE.UnlockBogus.thr
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && xe1->XE.UnlockBogus.lock_ga == xe2->XE.UnlockBogus.lock_ga;
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_PthAPIerror:
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.PthAPIerror.thr == xe2->XE.PthAPIerror.thr
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && 0==VG_(strcmp)(xe1->XE.PthAPIerror.fnname,
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  xe2->XE.PthAPIerror.fnname)
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && xe1->XE.PthAPIerror.err == xe2->XE.PthAPIerror.err;
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_LockOrder:
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.LockOrder.thr == xe2->XE.LockOrder.thr;
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_Misc:
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return xe1->XE.Misc.thr == xe2->XE.Misc.thr
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                && 0==VG_(strcmp)(xe1->XE.Misc.errstr, xe2->XE.Misc.errstr);
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(0);
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(0);
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Error management -- printing                             ---*/
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*----------------------------------------------------------------*/
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Do a printf-style operation on either the XML or normal output
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   channel, depending on the setting of VG_(clo_xml).
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
692436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void emit_WRK ( const HChar* format, va_list vargs )
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_xml)) {
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(vprintf_xml)(format, vargs);
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(vmessage)(Vg_UserMsg, format, vargs);
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
700436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void emit ( const HChar* format, ... ) PRINTF_CHECK(1, 2);
701436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void emit ( const HChar* format, ... )
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   va_list vargs;
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   va_start(vargs, format);
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   emit_WRK(format, vargs);
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   va_end(vargs);
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Announce (that is, print the point-of-creation) of 'thr'.  Only do
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this once, as we only want to see these announcements once per
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thread.  Returned Bool indicates whether or not an announcement was
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   made.
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool announce_one_thread ( Thread* thr )
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(HG_(is_sane_Thread)(thr));
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(thr->errmsg_index >= 1);
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (thr->announced)
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return False;
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (VG_(clo_xml)) {
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf_xml)("<announcethread>\n");
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf_xml)("  <hthreadid>%d</hthreadid>\n", thr->errmsg_index);
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (thr->errmsg_index == 1) {
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(thr->created_at == NULL);
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(printf_xml)("  <isrootthread></isrootthread>\n");
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(thr->created_at != NULL);
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( thr->created_at );
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(printf_xml)("</announcethread>\n\n");
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
737b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("---Thread-Announcement----------"
738b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                "--------------------------------" "\n");
739b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\n");
740b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (thr->errmsg_index == 1) {
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(thr->created_at == NULL);
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg,
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "Thread #%d is the program's root thread\n",
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       thr->errmsg_index);
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(thr->created_at != NULL);
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(message)(Vg_UserMsg, "Thread #%d was created\n",
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  thr->errmsg_index);
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( thr->created_at );
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      VG_(message)(Vg_UserMsg, "\n");
753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   thr->announced = True;
757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
760b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Announce 'lk'. */
761b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void announce_LockP ( Lock* lk )
762b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
763b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(lk);
764b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (lk == Lock_INVALID)
765b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      return; /* Can't be announced -- we know nothing about it. */
766b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(lk->magic == LockP_MAGIC);
767b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (!lk->appeared_at)
768b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov     return; /* There's nothing we can show */
769b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
770b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (VG_(clo_xml)) {
771b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* fixme: add announcement */
772b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
773b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)( "Lock at %p was first observed\n",
774b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 (void*)lk->guestaddr );
775b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(pp_ExeContext)( lk->appeared_at );
776b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\n");
777b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
778b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
779b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
780b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov/* Announce (that is, print point-of-first-observation) for the
781b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   locks in 'lockvec' and, if non-NULL, 'lockvec2'. */
782b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void announce_combined_LockP_vecs ( Lock** lockvec,
783b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                           Lock** lockvec2 )
784b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
785b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord i;
786b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(lockvec);
787b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   for (i = 0; lockvec[i]; i++) {
788b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      announce_LockP(lockvec[i]);
789b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
790b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (lockvec2) {
791b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      for (i = 0; lockvec2[i]; i++) {
792b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Lock* lk = lockvec2[i];
793b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (!elem_LockP_vector(lockvec, lk))
794b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            announce_LockP(lk);
795b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
796b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
797b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
798b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
799b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
800436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovstatic void show_LockP_summary_textmode ( Lock** locks, const HChar* pre )
801b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
802b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(locks);
803b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord i;
804b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   UWord nLocks = 0, nLocksValid = 0;
805b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   count_LockP_vector(&nLocks, &nLocksValid, locks);
806b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   tl_assert(nLocksValid <= nLocks);
807b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
808b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (nLocks == 0) {
809b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)( "%sLocks held: none", pre );
810b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
811b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)( "%sLocks held: %lu, at address%s ",
812b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 pre, nLocks, nLocksValid == 1 ? "" : "es" );
813b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
814b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
815b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (nLocks > 0) {
816b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      for (i = 0; i < nLocks; i++) {
817b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (locks[i] == Lock_INVALID)
818b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            continue;
819b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(umsg)( "%p", (void*)locks[i]->guestaddr);
820b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (locks[i+1] != NULL)
821b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(umsg)(" ");
822b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
823b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (nLocksValid < nLocks)
824b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         VG_(umsg)(" (and %lu that can't be shown)", nLocks - nLocksValid);
825b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
826b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   VG_(umsg)("\n");
827b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
828b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
829b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the "this error is due to be printed shortly; so have a
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   look at it any print any preamble you want" function.  We use it to
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   announce any previously un-announced threads in the upcoming error
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   message.
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(before_pp_Error) ( Error* err )
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError* xe;
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(err);
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   xe = (XError*)VG_(get_error_extra)(err);
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xe);
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_(get_error_kind)(err)) {
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_Misc:
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.Misc.thr );
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_LockOrder:
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.LockOrder.thr );
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_PthAPIerror:
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.PthAPIerror.thr );
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockBogus:
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.UnlockBogus.thr );
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockForeign:
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.UnlockForeign.thr );
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.UnlockForeign.owner );
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockUnlocked:
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.UnlockUnlocked.thr );
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_Race:
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         announce_one_thread( xe->XE.Race.thr );
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Race.h2_ct)
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            announce_one_thread( xe->XE.Race.h2_ct );
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Race.h1_ct)
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            announce_one_thread( xe->XE.Race.h1_ct );
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert(0);
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid HG_(pp_Error) ( Error* err )
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   const Bool xml = VG_(clo_xml); /* a shorthand, that's all */
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
878b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (!xml) {
879b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("--------------------------------"
880b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                "--------------------------------" "\n");
881b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      VG_(umsg)("\n");
882b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
883b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XError *xe = (XError*)VG_(get_error_extra)(err);
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tl_assert(xe);
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
887b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (xml)
888b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      emit( "  <kind>%s</kind>\n", HG_(get_error_name)(err));
889b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_(get_error_kind)(err)) {
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_Misc: {
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.Misc.thr ) );
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <text>Thread #%d: %s</text>\n",
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.Misc.thr->errmsg_index,
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xe->XE.Misc.errstr );
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.Misc.thr->errmsg_index );
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Misc.auxstr) {
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit("  <auxwhat>%s</auxwhat>\n", xe->XE.Misc.auxstr);
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (xe->XE.Misc.auxctx)
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(pp_ExeContext)( xe->XE.Misc.auxctx );
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "Thread #%d: %s\n",
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.Misc.thr->errmsg_index,
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xe->XE.Misc.errstr );
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Misc.auxstr) {
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit(" %s\n", xe->XE.Misc.auxstr);
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (xe->XE.Misc.auxctx)
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(pp_ExeContext)( xe->XE.Misc.auxctx );
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_LockOrder: {
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.LockOrder.thr ) );
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <text>Thread #%d: lock order \"%p before %p\" "
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "violated</text>\n",
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.LockOrder.thr->errmsg_index,
936b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               (void*)xe->XE.LockOrder.shouldbe_earlier_ga,
937b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               (void*)xe->XE.LockOrder.shouldbe_later_ga );
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.LockOrder.thr->errmsg_index );
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
942b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (xe->XE.LockOrder.shouldbe_earlier_ec
943b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             && xe->XE.LockOrder.shouldbe_later_ec) {
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <auxwhat>Required order was established by "
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "acquisition of lock at %p</auxwhat>\n",
946b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  (void*)xe->XE.LockOrder.shouldbe_earlier_ga );
947b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_earlier_ec );
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <auxwhat>followed by a later acquisition "
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "of lock at %p</auxwhat>\n",
950b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  (void*)xe->XE.LockOrder.shouldbe_later_ga );
951b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_later_ec );
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "Thread #%d: lock order \"%p before %p\" violated\n",
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.LockOrder.thr->errmsg_index,
958b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               (void*)xe->XE.LockOrder.shouldbe_earlier_ga,
959b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               (void*)xe->XE.LockOrder.shouldbe_later_ga );
960b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         emit( "\n" );
961b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         emit( "Observed (incorrect) order is: "
962b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "acquisition of lock at %p\n",
963b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               (void*)xe->XE.LockOrder.shouldbe_later_ga);
964b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (xe->XE.LockOrder.actual_earlier_ec) {
965b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             VG_(pp_ExeContext)(xe->XE.LockOrder.actual_earlier_ec);
966b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         } else {
967b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit("   (stack unavailable)\n");
968b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         }
969b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         emit( "\n" );
970b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         emit(" followed by a later acquisition of lock at %p\n",
971b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              (void*)xe->XE.LockOrder.shouldbe_earlier_ga);
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
973b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (xe->XE.LockOrder.shouldbe_earlier_ec
974b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov             && xe->XE.LockOrder.shouldbe_later_ec) {
975b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit("\n");
976b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit( "Required order was established by "
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "acquisition of lock at %p\n",
978b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  (void*)xe->XE.LockOrder.shouldbe_earlier_ga );
979b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_earlier_ec );
980b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit( "\n" );
981b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit( " followed by a later acquisition of lock at %p\n",
982b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  (void*)xe->XE.LockOrder.shouldbe_later_ga );
983b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            VG_(pp_ExeContext)( xe->XE.LockOrder.shouldbe_later_ec );
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_PthAPIerror: {
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.PthAPIerror.thr ) );
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
997b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         emit(
998b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            "    <text>Thread #%d's call to %pS failed</text>\n",
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (Int)xe->XE.PthAPIerror.thr->errmsg_index,
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xe->XE.PthAPIerror.fnname );
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.PthAPIerror.thr->errmsg_index );
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <what>with error code %ld (%s)</what>\n",
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr );
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1010b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         emit( "Thread #%d's call to %pS failed\n",
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)xe->XE.PthAPIerror.thr->errmsg_index,
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      xe->XE.PthAPIerror.fnname );
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "   with error code %ld (%s)\n",
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               xe->XE.PthAPIerror.err, xe->XE.PthAPIerror.errstr );
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_UnlockBogus: {
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockBogus.thr ) );
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <text>Thread #%d unlocked an invalid "
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "lock at %p</text>\n",
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockBogus.thr->errmsg_index,
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)xe->XE.UnlockBogus.lock_ga );
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockBogus.thr->errmsg_index );
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "Thread #%d unlocked an invalid lock at %p\n",
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockBogus.thr->errmsg_index,
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)xe->XE.UnlockBogus.lock_ga );
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_UnlockForeign: {
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockP)( xe->XE.UnlockForeign.lock ) );
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockForeign.owner ) );
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockForeign.thr ) );
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <text>Thread #%d unlocked lock at %p "
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "currently held by thread #%d</text>\n",
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockForeign.thr->errmsg_index,
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)xe->XE.UnlockForeign.lock->guestaddr,
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockForeign.owner->errmsg_index );
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockForeign.thr->errmsg_index );
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockForeign.owner->errmsg_index );
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.UnlockForeign.lock->appeared_at) {
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <auxwhat>Lock at %p was first observed</auxwhat>\n",
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)xe->XE.UnlockForeign.lock->guestaddr );
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at );
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "Thread #%d unlocked lock at %p "
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               "currently held by thread #%d\n",
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockForeign.thr->errmsg_index,
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)xe->XE.UnlockForeign.lock->guestaddr,
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockForeign.owner->errmsg_index );
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.UnlockForeign.lock->appeared_at) {
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  Lock at %p was first observed\n",
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)xe->XE.UnlockForeign.lock->guestaddr );
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)( xe->XE.UnlockForeign.lock->appeared_at );
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_UnlockUnlocked: {
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_LockP)( xe->XE.UnlockUnlocked.lock ) );
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.UnlockUnlocked.thr ) );
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <text>Thread #%d unlocked a "
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "not-locked lock at %p</text>\n",
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockUnlocked.thr->errmsg_index );
1107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
1108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.UnlockUnlocked.lock->appeared_at) {
1110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <auxwhat>Lock at %p was first observed</auxwhat>\n",
1111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
1112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at );
1113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "Thread #%d unlocked a not-locked lock at %p\n",
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.UnlockUnlocked.thr->errmsg_index,
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.UnlockUnlocked.lock->appeared_at) {
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  Lock at %p was first observed\n",
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (void*)xe->XE.UnlockUnlocked.lock->guestaddr );
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)( xe->XE.UnlockUnlocked.lock->appeared_at );
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XE_Race: {
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Addr      err_ga;
1134436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      const HChar* what;
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int       szB;
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      what      = xe->XE.Race.isWrite ? "write" : "read";
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      szB       = xe->XE.Race.szB;
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      err_ga = VG_(get_error_address)(err);
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert( HG_(is_sane_Thread)( xe->XE.Race.thr ));
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xe->XE.Race.h2_ct)
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         tl_assert( HG_(is_sane_Thread)( xe->XE.Race.h2_ct ));
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (xml) {
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* ------ XML ------ */
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  <xwhat>\n" );
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <text>Possible data race during %s of size %d "
1149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                    "at %p by thread #%d</text>\n",
1150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               what, szB, (void*)err_ga, (Int)xe->XE.Race.thr->errmsg_index );
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "    <hthreadid>%d</hthreadid>\n",
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               (Int)xe->XE.Race.thr->errmsg_index );
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "  </xwhat>\n" );
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Race.h2_ct) {
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(xe->XE.Race.h2_ct_accEC); // assured by update_extra
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <xauxwhat>\n");
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "    <text>This conflicts with a previous %s of size %d "
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "by thread #%d</text>\n",
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct_accIsW ? "write" : "read",
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct_accSzB,
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct->errmsg_index );
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "    <hthreadid>%d</hthreadid>\n",
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct->errmsg_index);
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit("  </xauxwhat>\n");
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)( xe->XE.Race.h2_ct_accEC );
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Race.h1_ct) {
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <xauxwhat>\n");
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "    <text>This conflicts with a previous access "
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "by thread #%d, after</text>\n",
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h1_ct->errmsg_index );
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "    <hthreadid>%d</hthreadid>\n",
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h1_ct->errmsg_index );
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit("  </xauxwhat>\n");
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (xe->XE.Race.h1_ct_mbsegstartEC) {
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegstartEC );
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               emit( "  <auxwhat>(the start of the thread)</auxwhat>\n" );
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( "  <auxwhat>but before</auxwhat>\n" );
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (xe->XE.Race.h1_ct_mbsegendEC) {
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegendEC );
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               emit( "  <auxwhat>(the end of the the thread)</auxwhat>\n" );
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* ------ Text ------ */
1194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         announce_combined_LockP_vecs( xe->XE.Race.locksHeldW,
1195b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                       xe->XE.Race.h2_ct_locksHeldW );
1196b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         emit( "Possible data race during %s of size %d "
1198b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               "at %p by thread #%d\n",
1199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov               what, szB, (void*)err_ga, (Int)xe->XE.Race.thr->errmsg_index );
1200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         tl_assert(xe->XE.Race.locksHeldW);
1202b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         show_LockP_summary_textmode( xe->XE.Race.locksHeldW, "" );
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(pp_ExeContext)( VG_(get_error_where)(err) );
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Race.h2_ct) {
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            tl_assert(xe->XE.Race.h2_ct_accEC); // assured by update_extra
1207b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            tl_assert(xe->XE.Race.h2_ct_locksHeldW);
1208b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit( "\n" );
1209b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            emit( "This conflicts with a previous %s of size %d "
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "by thread #%d\n",
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct_accIsW ? "write" : "read",
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct_accSzB,
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h2_ct->errmsg_index );
1214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov            show_LockP_summary_textmode( xe->XE.Race.h2_ct_locksHeldW, "" );
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            VG_(pp_ExeContext)( xe->XE.Race.h2_ct_accEC );
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (xe->XE.Race.h1_ct) {
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( " This conflicts with a previous access by thread #%d, "
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  "after\n",
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  xe->XE.Race.h1_ct->errmsg_index );
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (xe->XE.Race.h1_ct_mbsegstartEC) {
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegstartEC );
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               emit( "   (the start of the thread)\n" );
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            emit( " but before\n" );
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (xe->XE.Race.h1_ct_mbsegendEC) {
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               VG_(pp_ExeContext)( xe->XE.Race.h1_ct_mbsegendEC );
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               emit( "   (the end of the the thread)\n" );
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1236eb0bae136f4eeaaf29761dddb148b118fb824632Dmitriy Ivanov      VG_(pp_addrinfo) (err_ga, &xe->XE.Race.data_addrinfo);
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break; /* case XE_Race */
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* case XE_Race */
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default:
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      tl_assert(0);
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (VG_(get_error_kind)(err)) */
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1245436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovconst HChar* HG_(get_error_name) ( Error* err )
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_(get_error_kind)(err)) {
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_Race:           return "Race";
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockUnlocked: return "UnlockUnlocked";
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockForeign:  return "UnlockForeign";
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_UnlockBogus:    return "UnlockBogus";
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_PthAPIerror:    return "PthAPIerror";
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_LockOrder:      return "LockOrder";
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case XE_Misc:           return "Misc";
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: tl_assert(0); /* fill in missing case */
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1259436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool HG_(recognised_suppression) ( const HChar* name, Supp *su )
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define TRY(_name,_xskind)                   \
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (0 == VG_(strcmp)(name, (_name))) {   \
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         VG_(set_supp_kind)(su, (_xskind));    \
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return True;                          \
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("Race",           XS_Race);
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("FreeMemLock",    XS_FreeMemLock);
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("UnlockUnlocked", XS_UnlockUnlocked);
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("UnlockForeign",  XS_UnlockForeign);
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("UnlockBogus",    XS_UnlockBogus);
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("PthAPIerror",    XS_PthAPIerror);
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("LockOrder",      XS_LockOrder);
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   TRY("Misc",           XS_Misc);
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef TRY
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1278436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool HG_(read_extra_suppression_info) ( Int fd, HChar** bufpp, SizeT* nBufp,
1279436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                        Int* lineno, Supp* su )
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* do nothing -- no extra suppression info present.  Return True to
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      indicate nothing bad happened. */
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return True;
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool HG_(error_matches_suppression) ( Error* err, Supp* su )
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (VG_(get_supp_kind)(su)) {
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_Race:           return VG_(get_error_kind)(err) == XE_Race;
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_UnlockUnlocked: return VG_(get_error_kind)(err) == XE_UnlockUnlocked;
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_UnlockForeign:  return VG_(get_error_kind)(err) == XE_UnlockForeign;
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_UnlockBogus:    return VG_(get_error_kind)(err) == XE_UnlockBogus;
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_PthAPIerror:    return VG_(get_error_kind)(err) == XE_PthAPIerror;
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_LockOrder:      return VG_(get_error_kind)(err) == XE_LockOrder;
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case XS_Misc:           return VG_(get_error_kind)(err) == XE_Misc;
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   //case XS_: return VG_(get_error_kind)(err) == XE_;
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   default: tl_assert(0); /* fill in missing cases */
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownBool HG_(get_extra_suppression_info) ( Error* err,
1302436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                       /*OUT*/HChar* buf, Int nBuf )
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Do nothing */
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1308436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy IvanovBool HG_(print_extra_suppression_use) ( Supp* su,
1309436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                                        /*OUT*/HChar* buf, Int nBuf )
1310436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
1311436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Do nothing */
1312436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return False;
1313436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
1314436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1315436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid HG_(update_extra_suppression_use) ( Error* err, Supp* su )
1316436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
1317436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* Do nothing */
1318436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return;
1319436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
1320436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                              hg_errors.c ---*/
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
1325