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