blob: 6ec58e6f7f9ffbf78e7d428dbf1af1837e806038 [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001/*
2 This file is part of drd, a data race detector.
3
4 Copyright (C) 2006-2007 Bart Van Assche
5 bart.vanassche@gmail.com
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23*/
24
25
26#include "drd_error.h"
27#include "drd_malloc_wrappers.h"
28#include "drd_mutex.h" // struct mutex_info
29#include "drd_suppression.h" // drd_start_suppression()
30#include "pub_drd_bitmap.h" // LHS_W, ...
31#include "pub_tool_vki.h"
32#include "pub_tool_basics.h"
33#include "pub_tool_libcassert.h" // tl_assert()
34#include "pub_tool_libcbase.h" // strlen()
35#include "pub_tool_libcfile.h" // VG_(get_startup_wd)()
36#include "pub_tool_libcprint.h" // VG_(printf)()
37#include "pub_tool_machine.h"
38#include "pub_tool_threadstate.h" // VG_(get_pthread_id)()
39#include "pub_tool_tooliface.h" // VG_(needs_tool_errors)()
40
41
42typedef enum {
43 ConflictingAccessSupp
44} DRD_SuppKind;
45
46
47static void make_path_relative(Char* const path)
48{
49 int offset = 0;
50 Char cwd[512];
51
52 if (! VG_(get_startup_wd)(cwd, sizeof(cwd)))
53 tl_assert(False);
54 if (VG_(strncmp)(path + offset, cwd, VG_(strlen)(cwd)) == 0)
55 {
56 offset += VG_(strlen)(cwd);
57 if (path[offset] == '/')
58 {
59 offset++;
60 }
61 }
62 VG_(memmove)(path, path + offset, VG_(strlen)(path + offset) + 1);
63}
64
65
66/* Describe a data address range [a,a+len[ as good as you can, for error */
67/* messages, putting the result in ai. */
68void describe_addr(Addr const a, SizeT const len, AddrInfo* const ai)
69{
70 Addr stack_min, stack_max;
71 SegInfo* sg;
72
73 /* Perhaps it's on a thread's stack? */
74 ai->stack_tid = thread_lookup_stackaddr(a, &stack_min, &stack_max);
75 if (ai->stack_tid != DRD_INVALID_THREADID)
76 {
77 ai->akind = eStack;
78 ai->size = len;
79 ai->rwoffset = a - stack_max;
80 tl_assert(a + ai->size <= stack_max);
81 tl_assert(ai->rwoffset < 0);
82 return;
83 }
84
85 /* Perhaps it's in a mapped segment ? */
86 sg = VG_(find_seginfo)(a);
87 if (sg)
88 {
89 int i, n;
90
91 ai->akind = eSegment;
92 ai->seginfo = sg;
93 ai->name[0] = 0;
94 ai->size = 1;
95 ai->rwoffset = 0;
96
97 n = VG_(seginfo_syms_howmany)(sg);
98 for (i = 0; i < n; i++)
99 {
100 Addr addr;
101 Addr tocptr;
102 UInt size;
103 HChar* name;
104 Char filename[256];
105 Int linenum;
106
107 VG_(seginfo_syms_getidx)(sg, i, &addr, &tocptr, &size, &name);
108 if (addr <= a && a < addr + size)
109 {
110 ai->size = size;
111 ai->rwoffset = a - addr;
112 tl_assert(name && name[0]);
113 VG_(snprintf)(ai->name, sizeof(ai->name), "%s", name);
114 if (VG_(get_filename_linenum)(addr,
115 filename, sizeof(filename),
116 0, 0, 0,
117 &linenum))
118 {
119 make_path_relative(filename);
120 VG_(snprintf)(ai->descr, sizeof(ai->descr),
121 " in %s:%d", filename, linenum);
122 }
123 else
124 {
125 i = n;
126 }
127 break;
128 }
129 }
130 if (i == n)
131 {
132 Char filename[512];
133 Char soname[512];
134 Char sect_kind_name[16];
135
136 VG_(seginfo_sect_kind_name)(a, sect_kind_name,
137 sizeof(sect_kind_name));
138 VG_(strncpy)(filename, VG_(seginfo_filename)(sg), sizeof(filename));
139 filename[sizeof(filename) - 1] = 0;
140 make_path_relative(filename);
141 VG_(strncpy)(soname, VG_(seginfo_soname)(sg), sizeof(soname));
142 soname[sizeof(soname) - 1] = 0;
143 make_path_relative(soname);
144 VG_(snprintf)(ai->descr, sizeof(ai->descr),
145 "%s, %s:%s",
146 filename,
147 soname,
148 sect_kind_name);
149 }
150 return;
151 }
152
153 /* Search for a currently malloc'd block which might bracket it. */
154 {
155 Addr data;
156 if (drd_heap_addrinfo(a, &data, &ai->size, &ai->lastchange))
157 {
158 ai->akind = eMallocd;
159 ai->rwoffset = a - data;
160 return;
161 }
162 }
163
164 /* Clueless ... */
165 ai->akind = eUnknown;
166 return;
167}
168
169/**
170 * Generate a description string for the data residing at address a.
171 */
172Char* describe_addr_text(Addr const a, SizeT const len, AddrInfo* const ai,
173 Char* const buf, UInt const n_buf)
174{
175 tl_assert(a);
176 tl_assert(ai);
177 tl_assert(buf);
178
179 describe_addr(a, len, ai);
180
181 switch (ai->akind)
182 {
183 case eStack: {
184 VG_(snprintf)(buf, n_buf,
185 "stack of %s, offset %d",
186 thread_get_name(ai->stack_tid), ai->rwoffset);
187 break;
188 }
189 case eSegment: {
190 if (ai->name[0])
191 {
192 VG_(snprintf)(buf, n_buf,
193 "%s (offset %ld, size %ld) in %s",
194 ai->name, ai->rwoffset, ai->size, ai->descr);
195 }
196 else
197 {
198 VG_(snprintf)(buf, n_buf,
199 "%s",
200 ai->descr);
201 }
202 break;
203 }
204 case eMallocd: {
205 VG_(snprintf)(buf, n_buf, "heap");
206 VG_(snprintf)(buf + VG_(strlen)(buf), n_buf - VG_(strlen)(buf),
207 ", offset %ld in block at 0x%lx of size %ld",
208 ai->rwoffset, a - ai->rwoffset, ai->size);
209 break;
210 }
211 case eUnknown:
212 VG_(snprintf)(buf, n_buf, "unknown");
213 break;
214 default:
215 tl_assert(0);
216 }
217 return buf;
218}
219
220#ifdef OLD_RACE_DETECTION_ALGORITHM
221void drd_report_data_race(const DataRaceInfo* const dri)
222{
223 AddrInfo ai;
224 Char descr[256];
225
226 tl_assert(dri);
227 tl_assert(dri->range_begin < dri->range_end);
228 describe_addr_text(dri->range_begin, dri->range_end - dri->range_begin,
229 &ai, descr, sizeof(descr));
230 VG_(message)(Vg_UserMsg,
231 "0x%08lx sz %ld %c %c (%s)",
232 dri->range_begin,
233 dri->range_end - dri->range_begin,
234 dri->range_access & LHS_W ? 'W' : 'R',
235 dri->range_access & RHS_W ? 'W' : 'R',
236 descr);
237 if (ai.akind == eMallocd && ai.lastchange)
238 {
239 VG_(message)(Vg_UserMsg, "Allocation context:");
240 VG_(pp_ExeContext)(ai.lastchange);
241 }
242 // Note: for stack and heap variables suppression should be
243 // stopped automatically as soon as the specified memory
244 // range has been freed.
245 tl_assert(dri->range_begin < dri->range_end);
246 drd_start_suppression(dri->range_begin, dri->range_end, "detected race");
247}
248#endif
249
250static
251void drd_report_data_race2(Error* const err, const DataRaceErrInfo* const dri)
252{
253 AddrInfo ai;
254 Char descr[256];
255
256 tl_assert(dri);
257 tl_assert(dri->addr);
258 tl_assert(dri->size > 0);
259 describe_addr_text(dri->addr, dri->size,
260 &ai, descr, sizeof(descr));
261 VG_(message)(Vg_UserMsg,
262 "Conflicting %s by %s at 0x%08lx size %ld",
263 dri->access_type == eStore ? "store" : "load",
264 thread_get_name(VgThreadIdToDrdThreadId(dri->tid)),
265 dri->addr,
266 dri->size);
267 VG_(pp_ExeContext)(VG_(get_error_where)(err));
268 VG_(message)(Vg_UserMsg, "Allocation context: %s", descr);
269 if (ai.akind == eMallocd && ai.lastchange)
270 {
271 VG_(pp_ExeContext)(ai.lastchange);
272 }
273 thread_report_conflicting_segments(VgThreadIdToDrdThreadId(dri->tid),
274 dri->addr, dri->size, dri->access_type);
275}
276
277static Bool drd_tool_error_eq(VgRes res, Error* e1, Error* e2)
278{
279 return False;
280}
281
282static void drd_tool_error_pp(Error* const e)
283{
284 switch (VG_(get_error_kind)(e))
285 {
286 case DataRaceErr: {
287 drd_report_data_race2(e, VG_(get_error_extra)(e));
288 break;
289 }
290 case MutexErr: {
291 MutexErrInfo* p = (MutexErrInfo*)(VG_(get_error_extra)(e));
292 VG_(message)(Vg_UserMsg,
293 "%s / mutex 0x%lx (recursion count %d, owner %d)",
294 VG_(get_error_string)(e),
295 p->mutex,
296 p->recursion_count,
297 p->owner);
298 VG_(pp_ExeContext)(VG_(get_error_where)(e));
299 break;
300 }
301 case CondRaceErr: {
302 CondRaceErrInfo* cei = (CondRaceErrInfo*)(VG_(get_error_extra)(e));
303 VG_(message)(Vg_UserMsg,
304 "Race condition: condition variable 0x%lx has been signalled"
305 " but the associated mutex 0x%lx is not locked by the"
306 " signalling thread",
307 cei->cond, cei->mutex);
308 VG_(pp_ExeContext)(VG_(get_error_where)(e));
309 break;
310 }
311 case CondErr: {
312 CondErrInfo* cdei =(CondErrInfo*)(VG_(get_error_extra)(e));
313 VG_(message)(Vg_UserMsg,
314 "cond 0x%lx: %s",
315 cdei->cond,
316 VG_(get_error_string)(e));
317 VG_(pp_ExeContext)(VG_(get_error_where)(e));
318 break;
319 }
320 default:
321 VG_(message)(Vg_UserMsg,
322 "%s",
323 VG_(get_error_string)(e));
324 VG_(pp_ExeContext)(VG_(get_error_where)(e));
325 break;
326 }
327}
328
329static UInt drd_tool_error_update_extra(Error* e)
330{
331 switch (VG_(get_error_kind)(e))
332 {
333 case DataRaceErr:
334 return sizeof(DataRaceErrInfo);
335 case MutexErr:
336 return sizeof(MutexErrInfo);
337 case CondRaceErr:
338 return sizeof(CondRaceErrInfo);
339 case CondErr:
340 return sizeof(CondErrInfo);
341 default:
342 tl_assert(False);
343 break;
344 }
345}
346
347static Bool drd_tool_error_recog(Char* const name, Supp* const supp)
348{
349 SuppKind skind;
350
351 if (VG_(strcmp)(name, "ConflictingAccess") == 0)
352 skind = ConflictingAccessSupp;
353 else
354 return False;
355
356 VG_(set_supp_kind)(supp, skind);
357 return True;
358}
359
360static Bool drd_tool_error_read_extra(Int fd, Char* buf, Int nBuf, Supp* supp)
361{
362 return True;
363}
364
365static Bool drd_tool_error_matches(Error* const e, Supp* const supp)
366{
367 switch (VG_(get_supp_kind)(supp))
368 {
369 }
370 return True;
371}
372
373static Char* drd_tool_error_name(Error* e)
374{
375 switch (VG_(get_error_kind)(e))
376 {
377 case DataRaceErr: return "ConflictingAccess";
378 case MutexErr: return "MutexErr";
379 case CondRaceErr: return "CondRaceErr";
380 default:
381 tl_assert(0);
382 }
383 return 0;
384}
385
386static void drd_tool_error_print_extra(Error* e)
387{
388 switch (VG_(get_error_kind)(e))
389 {
390 // VG_(printf)(" %s\n", VG_(get_error_string)(err));
391 }
392}
393
394void drd_register_error_handlers(void)
395{
396 // Tool error reporting.
397 VG_(needs_tool_errors)(drd_tool_error_eq,
398 drd_tool_error_pp,
399 True,
400 drd_tool_error_update_extra,
401 drd_tool_error_recog,
402 drd_tool_error_read_extra,
403 drd_tool_error_matches,
404 drd_tool_error_name,
405 drd_tool_error_print_extra);
406}
407
408/*
409 * Local variables:
410 * c-basic-offset: 3
411 * End:
412 */