1 // $Header$
2 //
3 // Copyright (C) 2002 - 2004, by
4 //
5 // Carlo Wood, Run on IRC <carlo@alinoe.com>
6 // RSA-1024 0x624ACAD5 1997-01-26                    Sign & Encrypt
7 // Fingerprint16 = 32 EC A7 B6 AC DB 65 A6  F6 F6 55 DD 1C DC FF 61
8 //
9 // This file may be distributed under the terms of the Q Public License
10 // version 1.0 as appearing in the file LICENSE.QPL included in the
11 // packaging of this file.
12 //
13 
14 #include "sys.h"
15 #include <libcwd/config.h>
16 #if CWDEBUG_ALLOC
17 #include "cwd_debug.h"
18 #include "cwd_bfd.h"
19 #ifndef LIBCWD_PRIVATE_THREADING_H
20 #include <libcwd/private_threading.h>
21 #endif
22 #ifndef LIBCWD_CLASS_ALLOC_FILTER_H
23 #include <libcwd/class_alloc_filter.h>
24 #endif
25 
26 namespace libcwd {
27 
28 #if LIBCWD_THREAD_SAFE
29 #define ACQUIRE_LISTALLOC_LOCK mutex_tct<list_allocations_instance>::lock()
30 #define RELEASE_LISTALLOC_LOCK mutex_tct<list_allocations_instance>::unlock()
31 using _private_::mutex_tct;
32 using _private_::list_allocations_instance;
33 
34 #else
35 #define ACQUIRE_LISTALLOC_LOCK
36 #define RELEASE_LISTALLOC_LOCK
37 #endif
38 
39 #if CWDEBUG_LOCATION
40 int alloc_filter_ct::S_id = 0;			// Id of alloc_filter_ct object that is currently synchronized with the other
41 						// global variables of the critical area(s) of list_allocations_instance.
42 int alloc_filter_ct::S_next_id = 0;		// Id of the last alloc_filter_ct object that was created.
43 #endif
44 
45 // Use '1' instead of '0' because 0 is more likely to be used by the user
46 // as an extreme but real limit.
47 struct timeval const alloc_filter_ct::no_time_limit = { 1, 0 };
48 
set_flags(alloc_format_t flags)49 void alloc_filter_ct::set_flags(alloc_format_t flags)
50 {
51 #if CWDEBUG_DEBUGT
52   LIBCWD_TSD_DECLARATION;
53 #endif
54   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
55   ACQUIRE_LISTALLOC_LOCK;
56   M_flags &= ~format_mask;
57   M_flags |= flags;
58   RELEASE_LISTALLOC_LOCK;
59   LIBCWD_CLEANUP_POP_RESTORE(false);
60 }
61 
get_flags(void) const62 alloc_format_t alloc_filter_ct::get_flags(void) const
63 {
64   // Makes little sense to add locking here (alloc_format_t is an atomic type).
65   return (M_flags & format_mask);
66 }
67 
set_time_interval(struct timeval const & start,struct timeval const & end)68 void alloc_filter_ct::set_time_interval(struct timeval const& start, struct timeval const& end)
69 {
70 #if CWDEBUG_DEBUGT
71   LIBCWD_TSD_DECLARATION;
72 #endif
73   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
74   ACQUIRE_LISTALLOC_LOCK;
75   M_start = start;
76   M_end = end;
77   RELEASE_LISTALLOC_LOCK;
78   LIBCWD_CLEANUP_POP_RESTORE(false);
79 }
80 
get_time_start(void) const81 struct timeval alloc_filter_ct::get_time_start(void) const
82 {
83 #if CWDEBUG_DEBUGT
84   LIBCWD_TSD_DECLARATION;
85 #endif
86   struct timeval res;
87   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
88   ACQUIRE_LISTALLOC_LOCK;
89   res = M_start;
90   RELEASE_LISTALLOC_LOCK;
91   LIBCWD_CLEANUP_POP_RESTORE(false);
92   return res;
93 }
94 
get_time_end(void) const95 struct timeval alloc_filter_ct::get_time_end(void) const
96 {
97 #if CWDEBUG_DEBUGT
98   LIBCWD_TSD_DECLARATION;
99 #endif
100   struct timeval res;
101   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
102   ACQUIRE_LISTALLOC_LOCK;
103   res = M_end;
104   RELEASE_LISTALLOC_LOCK;
105   LIBCWD_CLEANUP_POP_RESTORE(false);
106   return res;
107 }
108 
109 #if CWDEBUG_LOCATION
get_objectfile_list(void) const110 std::vector<std::string> alloc_filter_ct::get_objectfile_list(void) const
111 {
112 #if CWDEBUG_DEBUGT
113   LIBCWD_TSD_DECLARATION;
114 #endif
115   std::vector<std::string> res;
116   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
117   ACQUIRE_LISTALLOC_LOCK;
118   for(vector_type::const_iterator iter = M_objectfile_masks.begin(); iter != M_objectfile_masks.end(); ++iter)
119     res.push_back(std::string(iter->data(), iter->length()));
120   RELEASE_LISTALLOC_LOCK;
121   LIBCWD_CLEANUP_POP_RESTORE(false);
122   return res;
123 }
124 
get_sourcefile_list(void) const125 std::vector<std::string> alloc_filter_ct::get_sourcefile_list(void) const
126 {
127 #if CWDEBUG_DEBUGT
128   LIBCWD_TSD_DECLARATION;
129 #endif
130   std::vector<std::string> res;
131   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
132   ACQUIRE_LISTALLOC_LOCK;
133   for(vector_type::const_iterator iter = M_sourcefile_masks.begin(); iter != M_sourcefile_masks.end(); ++iter)
134     res.push_back(std::string(iter->data(), iter->length()));
135   RELEASE_LISTALLOC_LOCK;
136   LIBCWD_CLEANUP_POP_RESTORE(false);
137   return res;
138 }
139 
get_function_list(void) const140 std::vector<std::pair<std::string, std::string> > alloc_filter_ct::get_function_list(void) const
141 {
142 #if CWDEBUG_DEBUGT
143   LIBCWD_TSD_DECLARATION;
144 #endif
145   std::vector<std::pair<std::string, std::string> > res;
146   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
147   ACQUIRE_LISTALLOC_LOCK;
148   for(vector_pair_type::const_iterator iter = M_function_masks.begin(); iter != M_function_masks.end(); ++iter)
149     res.push_back(std::pair<std::string, std::string>(std::string(iter->first.data(), iter->first.length()),
150                                                       std::string(iter->second.data(), iter->second.length())));
151   RELEASE_LISTALLOC_LOCK;
152   LIBCWD_CLEANUP_POP_RESTORE(false);
153   return res;
154 }
155 
hide_objectfiles_matching(std::vector<std::string> const & masks)156 void alloc_filter_ct::hide_objectfiles_matching(std::vector<std::string> const& masks)
157 {
158 #if CWDEBUG_DEBUGT
159   LIBCWD_TSD_DECLARATION;
160 #endif
161   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
162   ACQUIRE_LISTALLOC_LOCK;
163   M_objectfile_masks.clear();
164   for(std::vector<std::string>::const_iterator iter = masks.begin(); iter != masks.end(); ++iter)
165     M_objectfile_masks.push_back(string_type(iter->data(), iter->length()));
166   S_id = -1;			// Force resynchronization.
167   RELEASE_LISTALLOC_LOCK;
168   LIBCWD_CLEANUP_POP_RESTORE(false);
169 }
170 
hide_sourcefiles_matching(std::vector<std::string> const & masks)171 void alloc_filter_ct::hide_sourcefiles_matching(std::vector<std::string> const& masks)
172 {
173 #if CWDEBUG_DEBUGT
174   LIBCWD_TSD_DECLARATION;
175 #endif
176   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
177   ACQUIRE_LISTALLOC_LOCK;
178   M_sourcefile_masks.clear();
179   for(std::vector<std::string>::const_iterator iter = masks.begin(); iter != masks.end(); ++iter)
180     M_sourcefile_masks.push_back(string_type(iter->data(), iter->length()));
181   S_id = -1;			// Force resynchronization.
182   RELEASE_LISTALLOC_LOCK;
183   LIBCWD_CLEANUP_POP_RESTORE(false);
184 }
185 
hide_functions_matching(std::vector<std::pair<std::string,std::string>> const & masks)186 void alloc_filter_ct::hide_functions_matching(std::vector<std::pair<std::string, std::string> > const& masks)
187 {
188 #if CWDEBUG_DEBUGT
189   LIBCWD_TSD_DECLARATION;
190 #endif
191   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
192   ACQUIRE_LISTALLOC_LOCK;
193   M_sourcefile_masks.clear();
194   for(std::vector<std::pair<std::string, std::string> >::const_iterator iter = masks.begin(); iter != masks.end(); ++iter)
195     M_function_masks.push_back(std::pair<string_type, string_type>
196         (string_type(iter->first.data(), iter->first.length()), string_type(iter->second.data(), iter->second.length())));
197   S_id = -1;			// Force resynchronization.
198   RELEASE_LISTALLOC_LOCK;
199   LIBCWD_CLEANUP_POP_RESTORE(false);
200 }
201 
check_hide(char const * filepath) const202 _private_::hidden_st alloc_filter_ct::check_hide(char const* filepath) const
203 {
204   for (vector_type::const_iterator iter(M_sourcefile_masks.begin()); iter != M_sourcefile_masks.end(); ++iter)
205     if (_private_::match(iter->data(), iter->length(), filepath))
206       return _private_::filtered_location;
207   return _private_::unfiltered_location;
208 }
209 
check_hide(object_file_ct const * object_file,char const * mangled_function_name) const210 _private_::hidden_st alloc_filter_ct::check_hide(object_file_ct const* object_file, char const* mangled_function_name) const
211 {
212   char const* file_path = object_file->filepath();
213   char const* file_name = object_file->filename();
214   for (vector_pair_type::const_iterator iter = M_function_masks.begin(); iter != M_function_masks.end(); ++iter)
215   {
216     char const* objectfile_mask = iter->first.data();
217     size_t objectfile_mask_length = iter->first.length();
218     char c;
219     if ((objectfile_mask_length == 0 ||
220           (((c = *objectfile_mask) == '/' || c == '*') &&
221 	    _private_::match(objectfile_mask, objectfile_mask_length, file_path)) ||
222 	  (!(c == '/' || c == '*') &&
223 	    _private_::match(objectfile_mask, objectfile_mask_length, file_name))) &&
224         (iter->second.length() == 0 ||
225           _private_::match(iter->second.data(), iter->second.length(), mangled_function_name)))
226       return _private_::filtered_location;
227   }
228   return _private_::unfiltered_location;
229 }
230 #endif // CWDEBUG_LOCATION
231 
232 #if CWDEBUG_LOCATION
M_synchronize(void) const233 void alloc_filter_ct::M_synchronize(void) const
234 {
235 #if LIBCWD_THREAD_SAFE && CWDEBUG_DEBUG
236   LIBCWD_ASSERT( _private_::is_locked(list_allocations_instance) );
237 #endif
238   BFD_ACQUIRE_WRITE_LOCK;
239   // First clear the list, unhiding everything.
240   for (cwbfd::object_files_ct::iterator iter = cwbfd::NEEDS_WRITE_LOCK_object_files().begin();
241        iter != cwbfd::NEEDS_WRITE_LOCK_object_files().end();
242        ++iter)
243     (*iter)->get_object_file()->M_hide = false;
244   // Next hide what matches.
245   if (!M_objectfile_masks.empty())
246   {
247     for (cwbfd::object_files_ct::iterator iter = cwbfd::NEEDS_WRITE_LOCK_object_files().begin();
248 	 iter != cwbfd::NEEDS_WRITE_LOCK_object_files().end();
249 	 ++iter)
250     {
251       for (vector_type::const_iterator iter2(M_objectfile_masks.begin()); iter2 != M_objectfile_masks.end(); ++iter2)
252 	if (_private_::match((*iter2).data(), (*iter2).length(), (*iter)->get_object_file()->M_filename))
253 	{
254 	  (*iter)->get_object_file()->M_hide = true;
255 	  break;
256 	}
257     }
258   }
259   BFD_RELEASE_WRITE_LOCK;
260   M_synchronize_locations();
261   S_id = M_id;
262 }
263 #endif
264 
alloc_filter_ct(alloc_format_t flags)265 alloc_filter_ct::alloc_filter_ct(alloc_format_t flags) : M_flags(flags & format_mask), M_start(no_time_limit), M_end(no_time_limit)
266 {
267 #if CWDEBUG_LOCATION
268 #if CWDEBUG_DEBUGT
269   LIBCWD_TSD_DECLARATION;
270 #endif
271   LIBCWD_DEFER_CLEANUP_PUSH(&mutex_tct<list_allocations_instance>::cleanup, NULL);
272   ACQUIRE_LISTALLOC_LOCK;
273   M_id = ++S_next_id;
274   RELEASE_LISTALLOC_LOCK;
275   LIBCWD_CLEANUP_POP_RESTORE(false);
276 #endif
277 }
278 
279 } // namespace libcwd
280 
281 #endif // CWDEBUG_ALLOC
282