• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
2 /*
3   This file is part of drd, a thread error detector.
4 
5   Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
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_clientobj.h"
27 #include "drd_error.h"
28 #include "drd_suppression.h"
29 #include "pub_tool_basics.h"
30 #include "pub_tool_libcassert.h"
31 #include "pub_tool_libcbase.h"
32 #include "pub_tool_libcprint.h"   // VG_(message)()
33 #include "pub_tool_mallocfree.h"
34 #include "pub_tool_options.h"     // VG_(clo_backtrace_size)
35 #include "pub_tool_oset.h"
36 #include "pub_tool_stacktrace.h"
37 #include "pub_tool_threadstate.h" // VG_(get_running_tid)()
38 
39 
40 /* Local variables. */
41 
42 static OSet* s_clientobj_set;
43 static Bool s_trace_clientobj;
44 
45 
46 /* Local functions. */
47 
48 static Bool clientobj_remove_obj(DrdClientobj* const p);
49 
50 
51 /* Function definitions. */
52 
DRD_(clientobj_set_trace)53 void DRD_(clientobj_set_trace)(const Bool trace)
54 {
55    s_trace_clientobj = trace;
56 }
57 
58 /** Initialize the client object set. */
DRD_(clientobj_init)59 void DRD_(clientobj_init)(void)
60 {
61    tl_assert(s_clientobj_set == 0);
62    s_clientobj_set = VG_(OSetGen_Create)(0, 0, VG_(malloc),
63                                          "drd.clientobj.ci.1", VG_(free));
64    tl_assert(s_clientobj_set);
65 }
66 
67 /**
68  * Free the memory allocated for the client object set.
69  *
70  * @pre Client object set is empty.
71  */
DRD_(clientobj_cleanup)72 void DRD_(clientobj_cleanup)(void)
73 {
74    tl_assert(s_clientobj_set);
75    tl_assert(VG_(OSetGen_Size)(s_clientobj_set) == 0);
76    VG_(OSetGen_Destroy)(s_clientobj_set);
77    s_clientobj_set = 0;
78 }
79 
80 /**
81  * Return the data associated with the client object at client address addr.
82  * Return 0 if there is no client object in the set with the specified start
83  * address.
84  */
DRD_(clientobj_get_any)85 DrdClientobj* DRD_(clientobj_get_any)(const Addr addr)
86 {
87    return VG_(OSetGen_Lookup)(s_clientobj_set, &addr);
88 }
89 
90 /**
91  * Return the data associated with the client object at client address addr
92  * and that has object type t. Return 0 if there is no client object in the
93  * set with the specified start address.
94  */
DRD_(clientobj_get)95 DrdClientobj* DRD_(clientobj_get)(const Addr addr, const ObjType t)
96 {
97    DrdClientobj* p;
98    p = VG_(OSetGen_Lookup)(s_clientobj_set, &addr);
99    if (p && p->any.type == t)
100       return p;
101    return 0;
102 }
103 
104 /** Return true if and only if the address range of any client object overlaps
105  *  with the specified address range.
106  */
DRD_(clientobj_present)107 Bool DRD_(clientobj_present)(const Addr a1, const Addr a2)
108 {
109    DrdClientobj *p;
110 
111    tl_assert(a1 <= a2);
112    VG_(OSetGen_ResetIter)(s_clientobj_set);
113    for ( ; (p = VG_(OSetGen_Next)(s_clientobj_set)) != 0; )
114    {
115       if (a1 <= p->any.a1 && p->any.a1 < a2)
116       {
117          return True;
118       }
119    }
120    return False;
121 }
122 
123 /**
124  * Add state information for the client object at client address addr and
125  * of type t. Suppress data race reports on the address range [addr,addr+size[.
126  *
127  * @pre No other client object is present in the address range [addr,addr+size[.
128  */
DRD_(clientobj_add)129 DrdClientobj* DRD_(clientobj_add)(const Addr a1, const ObjType t)
130 {
131    DrdClientobj* p;
132 
133    tl_assert(! DRD_(clientobj_present)(a1, a1 + 1));
134    tl_assert(VG_(OSetGen_Lookup)(s_clientobj_set, &a1) == 0);
135 
136    if (s_trace_clientobj)
137       DRD_(trace_msg)("Adding client object 0x%lx of type %d", a1, t);
138 
139    p = VG_(OSetGen_AllocNode)(s_clientobj_set, sizeof(*p));
140    VG_(memset)(p, 0, sizeof(*p));
141    p->any.a1   = a1;
142    p->any.type = t;
143    p->any.first_observed_at = VG_(record_ExeContext)(VG_(get_running_tid)(), 0);
144    VG_(OSetGen_Insert)(s_clientobj_set, p);
145    tl_assert(VG_(OSetGen_Lookup)(s_clientobj_set, &a1) == p);
146    if (t == ClientHbvar)
147       DRD_(mark_hbvar)(a1);
148    else
149       DRD_(start_suppression)(a1, a1 + 1, "clientobj");
150    return p;
151 }
152 
153 /**
154  * Remove the information that was stored about the client object.
155  *
156  * @param[in] addr Address of the client object in the client address space.
157  * @param[in] t    Type of the client object.
158  */
DRD_(clientobj_remove)159 Bool DRD_(clientobj_remove)(const Addr addr, const ObjType t)
160 {
161    DrdClientobj* p;
162 
163    p = VG_(OSetGen_Lookup)(s_clientobj_set, &addr);
164    tl_assert(p);
165    tl_assert(p->any.type == t);
166    return clientobj_remove_obj(p);
167 }
168 
169 /**
170  * Remove the information that was stored about the client object p.
171  *
172  * @note The order of operations below is important. The client object is
173  *   removed from the client object set after the cleanup function has been
174  *   called such that if the cleanup function can still use the function
175  *   DRD_(clientobj_get_any)(). This happens e.g. in the function
176  *   first_observed() in drd_error.c.
177  */
clientobj_remove_obj(DrdClientobj * const p)178 static Bool clientobj_remove_obj(DrdClientobj* const p)
179 {
180    tl_assert(p);
181 
182    if (s_trace_clientobj) {
183       DRD_(trace_msg)("Removing client object 0x%lx of type %d", p->any.a1,
184                       p->any.type);
185 #if 0
186       VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(),
187                                  VG_(clo_backtrace_size));
188 #endif
189    }
190 
191    tl_assert(p->any.cleanup);
192    (*p->any.cleanup)(p);
193    VG_(OSetGen_Remove)(s_clientobj_set, &p->any.a1);
194    VG_(OSetGen_FreeNode)(s_clientobj_set, p);
195    return True;
196 }
197 
198 /**
199  * Clean up all client objects p for which their start address p->any.a1 fits
200  * inside the address range [ a1, a2 [.
201  *
202  * @note The implementation of this function relies on the fact that the
203  *   data in s_clientobj_set is sorted on the start address of client objects.
204  */
DRD_(clientobj_stop_using_mem)205 void DRD_(clientobj_stop_using_mem)(const Addr a1, const Addr a2)
206 {
207    Addr removed_at;
208    DrdClientobj* p;
209 
210    tl_assert(s_clientobj_set);
211 
212    if (! DRD_(range_contains_suppression_or_hbvar)(a1, a2))
213       return;
214 
215    VG_(OSetGen_ResetIterAt)(s_clientobj_set, &a1);
216    for ( ; (p = VG_(OSetGen_Next)(s_clientobj_set)) != 0 && p->any.a1 < a2; )
217    {
218       tl_assert(a1 <= p->any.a1);
219       removed_at = p->any.a1;
220       clientobj_remove_obj(p);
221       /*
222        * The above call removes an element from the oset and hence
223        * invalidates the iterator. Restore the iterator.
224        */
225       VG_(OSetGen_ResetIterAt)(s_clientobj_set, &removed_at);
226    }
227 }
228 
229 /**
230  * Delete the per-thread information stored in client objects for the
231  * specified thread.
232  */
DRD_(clientobj_delete_thread)233 void DRD_(clientobj_delete_thread)(const DrdThreadId tid)
234 {
235    DrdClientobj *p;
236 
237    VG_(OSetGen_ResetIter)(s_clientobj_set);
238    for ( ; (p = VG_(OSetGen_Next)(s_clientobj_set)) != 0; )
239    {
240       if (p->any.delete_thread)
241       {
242          (*p->any.delete_thread)(p, tid);
243       }
244    }
245 }
246 
DRD_(clientobj_type_name)247 const char* DRD_(clientobj_type_name)(const ObjType t)
248 {
249    switch (t)
250    {
251    case ClientMutex:     return "mutex";
252    case ClientCondvar:   return "cond";
253    case ClientHbvar:     return "order annotation";
254    case ClientSemaphore: return "semaphore";
255    case ClientBarrier:   return "barrier";
256    case ClientRwlock:    return "rwlock";
257    }
258    return "(unknown)";
259 }
260