Stackdb
Stackdb is a stackable, multi-target and -level source debugger and memory forensics library.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
common.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, 2012, 2013, 2014 The University of Utah
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef __COMMON_H__
20 #define __COMMON_H__
21 
22 #include <stdint.h>
23 #include <inttypes.h>
24 
25 typedef enum {
29 } result_t;
30 
31 /*
32  * For now, thread ids are a 32-bit int. This is enough, for instance,
33  * to do TIDs on Linux (because pids on 64-bit are still int32_ts. Note
34  * that we have reserved INT32_MAX as our "global" identifier.
35  */
36 typedef int32_t tid_t;
37 #define PRIiTID PRIi32
38 
39 /* Might have to split these out into platform-specific stuff later; for
40  * now, just make them big enough for anything.
41  *
42  * Also, we only support debugging 32-bit targets on a 32-bit host. We
43  * support 32-bit targets on a 64-bit host, but not the reverse for
44  * now. That case would only have meaning if we wanted to investigate a
45  * non-live target (i.e., a 64-bit memory dump) on a 32-bit host. Even
46  * then, we would still need all the 64-bit debuginfo files... and they
47  * wouldn't be likely to be on a 32-bit host. SO, for now, we don't
48  * support this case.
49  */
50 #if __WORDSIZE == 64
51 typedef uint64_t ADDR;
52 typedef int64_t OFFSET;
53 typedef uint64_t REGVAL;
54 #define PRIxADDR PRIx64
55 #define PRIxFULLADDR "016"PRIx64
56 #define PRIuADDR PRIu64
57 #define PRIiOFFSET PRIi64
58 #define PRIxOFFSET PRIx64
59 #define PRIxREGVAL PRIx64
60 #define PRIuREGVAL PRIu64
61 #define ADDRMAX UINT64_MAX
62 #define OFFSETMAX UINT64_MAX
63 #else
64 typedef uint32_t ADDR;
65 typedef int32_t OFFSET;
66 typedef uint32_t REGVAL;
67 #define PRIxADDR PRIx32
68 #define PRIxFULLADDR "016"PRIx32
69 #define PRIuADDR PRIu32
70 #define PRIiOFFSET PRIi32
71 #define PRIxOFFSET PRIx32
72 #define PRIxREGVAL PRIx32
73 #define PRIuREGVAL PRIu32
74 #define ADDRMAX UINT32_MAX
75 #define OFFSETMAX UINT32_MAX
76 #endif
77 
78 #ifndef ptr_t
79 #define ptr_t unsigned long int
80 #endif
81 
82 /*
83  * Define a "numeric" type; size should be the largest int for any
84  * target, for now. Later we might need something more
85  * flexible... sigh.
86  */
87 typedef int64_t num_t;
88 typedef uint64_t unum_t;
89 #define PRIuNUM PRIu64
90 #define PRIiNUM PRIi64
91 #define PRIxNUM PRIx64
92 
93 typedef int8_t REG;
94 #define PRIiREG PRIi8
95 
96 /*
97  * We use small offsets for DWARF offset addrs. Saves mem in symbol
98  * structures, which is very important.
99  */
100 typedef int32_t SMOFFSET;
101 #define PRIiSMOFFSET PRIi32
102 #define PRIxSMOFFSET PRIx32
103 
104 #define __PAGE_SIZE 0x1000
105 
106 #define PROT_READ 0x1
107 #define PROT_WRITE 0x2
108 #define PROT_EXEC 0x4
109 #define PROT_SHARED 0x8
110 
111 /*
112  * Reference count stuff.
113  *
114  * The way this stuff works is a bit unfortunate. I tried to hide it
115  * from the users, so that what they think they get is a simple
116  * lookup/release interface. They *can* call RHOLD themselves, but they
117  * should not need to if they go through the public functions in each
118  * sub-library that state that they claim locks for the object they are
119  * returning (i.e., some symbol lookup functions).
120  *
121  * So, it's good for users. It's not so good for debugging refcnt
122  * leaks; see below!
123  */
124 typedef uint32_t REFCNT;
125 #define PRIiREFCNT PRIu32
126 
127 /*
128  * Reference count debugging is hard because of the ways we use it. We
129  * try to keep the use entirely internal, and hidden from user, but what
130  * this means is that we inevitably take locks on behalf of the user.
131  * This means we don't have good tracking for lock owners (we don't know
132  * the address of the "owning" object). So, when the user releases a
133  * lock on an object, we do not know who the "owning" object was. For
134  * these cases, we just keep a separate count, so we can determine in a
135  * rough sense whether the leak was internal or external.
136  *
137  * HOWEVER, this means that *inside* our libraries, we must not call the
138  * functions that RHOLD on the user's behalf. We must act more
139  * manually. In this way, we can know that our internal refcnting is
140  * sound, which is what we're really after -- because then both owners
141  * and their referents can be tracked. We can fix the user-side refcnt
142  * debugging more later if we ever care. But that is small potatoes.
143  *
144  * Also, inside our libraries, we must never call (objtype)_release
145  * functions! Those are intended for external use only. We must always
146  * call RPUT* directly.
147  *
148  * XXX: need to change user-API calls to a _lookup()/_release()
149  * paradigm. This will make the REFCNT stuff more obvious to them.
150  * Basically, any call that ends in _lookup() needs to have a )release()
151  * done on _lookup()'s return value.
152  *
153  *
154  * NB: this is important! Objects cannot reference each other; such
155  * objects may not get deleted since we do maintain data structures that
156  * contain any such object (i.e., a referenced object may not be on some
157  * global hashtable, but one it references may not be -- it may be
158  * buried in some symtab tree -- and if we deleted the top of that tree,
159  * we'll be left with a dangling ref). To solve this, we would need
160  * some library-wide, global, type-aware reftab -- more memory usage.
161  *
162  * So, avoid it for now by only allowing top-down refs. This means that
163  * objects that hold refs to lower ones must clear the lower objects'
164  * backrefs to them. This may or not break the object model, of course.
165  * For now, it's ok for the way this library uses objects. The real
166  * problem is symbol tables -- it is very possible that the symtab an
167  * object is on will go away during debugfile free operations. But, if
168  * we always only partially free debugfiles by freeing root symtabs,
169  * this problem won't matter. As a matter of fact, we already don't do
170  * partial free (only incremental load), so this doesn't matter. Just
171  * notes for the future...
172  *
173  * Ok, unfortunately, the future is now.
174  *
175  * In early versions of this library, we tried to get away with keeping
176  * non-cyclic, hierarchical parent->child refs only. But unfortunately,
177  * some of our objects keep refs to the parent and operations on them
178  * end up requiring a parent deref. So we have to make sure that the
179  * parent does not get dealloc'd until its children are gone. But, this
180  * brings up the cyclic ref problem. If an object gets unlinked from
181  * our global data structures, and it is no longer reachable but still
182  * need to be freed, we still have to know it needs to be freed -- but
183  * even this situation will never be arrived at for two objects that
184  * hold each other. One must hold weakly to the other, so we know when
185  * it is safe to deallocate the first.
186  *
187  * Imagine the scenario where symbols hold symbols/symtabs, are on
188  * symtabs, which are on either debugfiles or binfiles. Symbols hold
189  * symtabs/symbols; symtabs hold debugfiles/binfiles/symbols; debugfiles
190  * hold symtabs.
191  *
192  * Here's what we do. We keep two counts for each object. Strong refs
193  * are the parent->child refs; weak refs are the child->parent refs.
194  * Basically, the idea is that when any object's strong ref counter
195  * becomes 0, we can start deallocating the object. Deallocation must
196  * first 1) remove itself from all global data structures, such as
197  * caches, and 2) release refs to any of its children (any objects it
198  * has strong refs to), and remove them from its structures IFF they are
199  * freed themselves. If all children are freed, and there are no more
200  * weak refs to the object, we can finish freeing it (we need both
201  * constraints to know which children we must save and not remove from
202  * our object's data structures); else we must place the object on a
203  * global "to-free" hashtable. Then, when weak refs are released, the
204  * object that was weakly held must be checked to see if it can be
205  * released. That's how we will do this. This frees us from having to
206  * track ref holders.
207  */
208 
209 /*
210  * NB for internal users that use refcnts to protect objects:
211  *
212  * If an object maintains its own refcnt, plus it allows other objects
213  * to take weak refs to it, when it frees itself after its refcnt goes
214  * to 0, it must protect itself from getting double-freed by RPUTW,
215  * which will get called on it as it frees its children. So these
216  * functions just temporarily jack up its own refcnt temporarily to do
217  * that. By the time these are called, its refcnt is already 0, or
218  * we're forcing a free.
219  */
220 #define RWGUARD(x) ++((x)->refcnt)
221 #define RWUNGUARD(x) --((x)->refcnt)
222 
223 #ifdef REF_DEBUG
224 
225 #include <glib.h>
226 /*
227  * NB: this table never gets freed unless you call REF_DEBUG_REPORT_FINISH().
228  *
229  * Oh, and this is NOT thread-safe, obviously. Make it so if you need it...
230  */
231 
232 /* This one holds data for distinct obj/owner pairs. */
233 extern GHashTable *greftab;
234 /* This one holds data for self-owning objects (i.e., user-inspired refs). */
235 extern GHashTable *grefstab;
236 
237 /* This one holds data for distinct obj/owner pairs. */
238 extern GHashTable *grefwtab;
239 /* This one holds data for self-owning objects (i.e., user-inspired refs). */
240 extern GHashTable *grefwstab;
241 
242 #define REFCNTDECL(trefcnt) REFCNT trefcnt
243 
244 #define RHOLD(x,hx) \
245  do { \
246  GHashTable *htab; \
247  char *buf; \
248  unsigned int count; \
249  void *_hx = (hx); \
250  \
251  ++((x)->refcnt); \
252  \
253  /* If self-ref, just save by caller function address. */ \
254  if ((x) == _hx) { \
255  _hx = (void *)__builtin_return_address(1); \
256  fprintf(stderr,"REFDEBUG: hold %p,%p (%d) (self)\n", \
257  (x),_hx,(x)->refcnt); \
258  \
259  if (unlikely(!grefstab)) { \
260  grefstab = g_hash_table_new(g_direct_hash,g_direct_equal); \
261  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
262  NULL,NULL); \
263  g_hash_table_insert(grefstab,(gpointer)(x),htab); \
264  } \
265  else if (!(htab = (GHashTable *)g_hash_table_lookup(grefstab,(x)))) { \
266  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
267  NULL,NULL); \
268  g_hash_table_insert(grefstab,(gpointer)(x),htab); \
269  } \
270  count = (unsigned int)(ptr_t)g_hash_table_lookup(htab,(gpointer)_hx); \
271  ++count; \
272  g_hash_table_insert(htab,(gpointer)_hx,(void *)(ptr_t)count); \
273  /* XXX: we should track more than caller addr? */ \
274  } \
275  else { \
276  fprintf(stderr,"REFDEBUG: hold %p,%p (%d)\n", \
277  (x),_hx,(x)->refcnt); \
278  \
279  if (unlikely(!greftab)) { \
280  greftab = g_hash_table_new(g_direct_hash,g_direct_equal); \
281  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
282  NULL,NULL); \
283  g_hash_table_insert(greftab,(gpointer)(x),htab); \
284  } \
285  else if (!(htab = (GHashTable *)g_hash_table_lookup(greftab,(x)))) { \
286  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
287  NULL,free); \
288  g_hash_table_insert(greftab,(gpointer)(x),htab); \
289  } \
290  \
291  buf = malloc(sizeof(__FUNCTION__)+sizeof(__LINE__)+1+1); \
292  snprintf(buf,sizeof(__FUNCTION__)+sizeof(__LINE__)+1+1, \
293  "%s:%d",__FUNCTION__,__LINE__); \
294  g_hash_table_insert(htab,(gpointer)_hx,buf); \
295  } \
296  } while (0);
297 #define RHOLDW(x,hx) \
298  do { \
299  GHashTable *htab; \
300  char *buf; \
301  unsigned int count; \
302  void *_hx = (hx); \
303  \
304  ++((x)->refcntw); \
305  \
306  /* If self-ref, just save by caller function address. */ \
307  if ((x) == _hx) { \
308  _hx = (void *)__builtin_return_address(1); \
309  fprintf(stderr,"REFDEBUG: holdw %p,%p (%d) (self)\n", \
310  (x),_hx,(x)->refcnt); \
311  \
312  if (unlikely(!grefwstab)) { \
313  grefwstab = g_hash_table_new(g_direct_hash,g_direct_equal); \
314  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
315  NULL,NULL); \
316  g_hash_table_insert(grefwstab,(gpointer)(x),htab); \
317  } \
318  else if (!(htab = (GHashTable *)g_hash_table_lookup(grefwstab,(x)))) { \
319  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
320  NULL,NULL); \
321  g_hash_table_insert(grefwstab,(gpointer)(x),htab); \
322  } \
323  count = (unsigned int)g_hash_table_lookup(htab,(gpointer)_hx); \
324  ++count; \
325  g_hash_table_insert(htab,(gpointer)_hx,(void *)(ptr_t)count); \
326  /* XXX: we should track more than caller addr? */ \
327  } \
328  else { \
329  fprintf(stderr,"REFDEBUG: holdw %p,%p (%d)\n", \
330  (x),_hx,(x)->refcnt); \
331  \
332  if (unlikely(!grefwtab)) { \
333  grefwtab = g_hash_table_new(g_direct_hash,g_direct_equal); \
334  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
335  NULL,NULL); \
336  g_hash_table_insert(grefwtab,(gpointer)(x),htab); \
337  } \
338  else if (!(htab = (GHashTable *)g_hash_table_lookup(grefwtab,(x)))) { \
339  htab = g_hash_table_new_full(g_direct_hash,g_direct_equal, \
340  NULL,free); \
341  g_hash_table_insert(grefwtab,(gpointer)(x),htab); \
342  } \
343  \
344  buf = malloc(sizeof(__FUNCTION__)+sizeof(__LINE__)+1+1); \
345  snprintf(buf,sizeof(__FUNCTION__)+sizeof(__LINE__)+1+1, \
346  "%s:%d",__FUNCTION__,__LINE__); \
347  g_hash_table_insert(htab,(gpointer)_hx,buf); \
348  } \
349  } while (0);
350 #define RPUT(x,objtype,hx,rc) \
351  do { \
352  typeof(x) _x = (x); \
353  void *_hx = (hx); \
354  GHashTable *htab; \
355  /*unsigned int count; */ \
356  \
357  /* if ((x)->refcnt == 0) */ \
358  /* asm("int $3"); */ \
359  \
360  (rc) = (--((x)->refcnt) == 0) \
361  ? objtype ## _free(x,0) : ((x)->refcnt); \
362  \
363  if (_x == _hx) { \
364  if (!grefstab) \
365  break; \
366  \
367  fprintf(stderr,"REFDEBUG: put %p,%p (%d) (self)\n",(x),_hx,(rc)); \
368  \
369  htab = (GHashTable *)g_hash_table_lookup(grefstab,_x); \
370  if (!htab) \
371  break; \
372  /* Can't track holder; just nuke hashtable. */ \
373  if ((rc) == 0) { \
374  g_hash_table_destroy(htab); \
375  g_hash_table_remove(grefstab,_x); \
376  } \
377  /*count = (unsigned int)g_hash_table_remove(htab,_hx); */ \
378  /*if (--count == 0) { */ \
379  /* if (g_hash_table_size(htab) == 0) */ \
380  /* g_hash_table_destroy(htab); */ \
381  /*} */ \
382  /*else */ \
383  /* g_hash_table_insert(htab,_hx,(gpointer)(ptr_t)count); */ \
384  } \
385  else { \
386  if (!greftab) \
387  break; \
388  \
389  fprintf(stderr,"REFDEBUG: put %p,%p (%d)\n",(x),_hx,(rc)); \
390  \
391  htab = (GHashTable *)g_hash_table_lookup(greftab,_x); \
392  if (!htab) \
393  break; \
394  g_hash_table_remove(htab,_hx); \
395  if (g_hash_table_size(htab) == 0) { \
396  g_hash_table_destroy(htab); \
397  g_hash_table_remove(greftab,_x); \
398  } \
399  } \
400  } while (0);
401 #define RPUTW(x,objtype,hx,rc) \
402  do { \
403  typeof(x) _x = (x); \
404  void *_hx = (hx); \
405  GHashTable *htab; \
406  \
407  /* if ((x)->refcntw == 0) */ \
408  /* asm("int $3"); */ \
409  \
410  (rc) = ((--((x)->refcntw) + (x)->refcnt) == 0) \
411  ? objtype ## _free(x,0) : ((x)->refcntw + (x)->refcnt); \
412  \
413  if (_x == _hx) { \
414  if (!grefwstab) \
415  break; \
416  \
417  fprintf(stderr,"REFDEBUG: putw %p,%p (%d) (self)\n",(x),_hx,(rc)); \
418  \
419  htab = (GHashTable *)g_hash_table_lookup(grefwstab,_x); \
420  if (!htab) \
421  break; \
422  /* Can't track holder; just nuke hashtable. */ \
423  if ((rc) == 0) { \
424  g_hash_table_destroy(htab); \
425  g_hash_table_remove(grefwstab,_x); \
426  } \
427  } \
428  else { \
429  if (!grefwtab) \
430  break; \
431  \
432  fprintf(stderr,"REFDEBUG: putw %p,%p (%d)\n",(x),_hx,(rc)); \
433  \
434  htab = (GHashTable *)g_hash_table_lookup(grefwtab,_x); \
435  if (!htab) \
436  break; \
437  g_hash_table_remove(htab,_hx); \
438  if (g_hash_table_size(htab) == 0) { \
439  g_hash_table_destroy(htab); \
440  g_hash_table_remove(grefwtab,_x); \
441  } \
442  } \
443  } while (0);
444 /*
445  * Nobody should use RPUTNF/RPUTFF at all, ever -- it means you are not
446  * using refcnts appropriately. Do not enable them without talking to
447  * David, and you better have a darn good reason.
448  */
449 //#if 0
450 #define RPUTFF(x,objtype,hx,rc) \
451  do { \
452  typeof(x) _x = (x); \
453  void *_hx = (hx); \
454  GHashTable *htab; \
455  unsigned int count; \
456  \
457  (rc) = (--((x)->refcnt) == 0) \
458  ? objtype ## _free(x,1) : objtype ## _free(x,1); \
459  \
460  if (_x == _hx) { \
461  if (!grefstab) \
462  break; \
463  \
464  fprintf(stderr,"REFDEBUG: putf %p,%p (%d) (self)\n",(x),_hx,(rc)); \
465  \
466  htab = (GHashTable *)g_hash_table_lookup(grefstab,_x); \
467  if (!htab) \
468  break; \
469  count = (unsigned int)g_hash_table_remove(htab,_hx); \
470  if (--count == 0) { \
471  if (g_hash_table_size(htab) == 0) \
472  g_hash_table_destroy(htab); \
473  } \
474  else \
475  g_hash_table_insert(htab,_hx,(gpointer)(ptr_t)count); \
476  } \
477  else { \
478  if (!greftab) \
479  break; \
480  \
481  fprintf(stderr,"REFDEBUG: putf %p,%p (%d)\n",(x),_hx,(rc)); \
482  \
483  htab = (GHashTable *)g_hash_table_lookup(greftab,_x); \
484  if (!htab) \
485  break; \
486  g_hash_table_remove(htab,_hx); \
487  if (g_hash_table_size(htab) == 0) { \
488  g_hash_table_destroy(htab); \
489  g_hash_table_remove(greftab,_x); \
490  } \
491  } \
492  } while (0);
493 #define RPUTNF(x,hx,rc) \
494  do { \
495  typeof(x) _x = (x); \
496  void *_hx = (hx); \
497  GHashTable *htab; \
498  unsigned int count; \
499  \
500  (rc) = (--((x)->refcnt)); \
501  \
502  if (_x == _hx) { \
503  if (!grefstab) \
504  break; \
505  \
506  fprintf(stderr,"REFDEBUG: putn %p,%p (%d) (self)\n",(x),_hx,(rc)); \
507  \
508  htab = (GHashTable *)g_hash_table_lookup(grefstab,_x); \
509  if (!htab) \
510  break; \
511  count = (unsigned int)g_hash_table_remove(htab,_hx); \
512  if (--count == 0) { \
513  if (g_hash_table_size(htab) == 0) \
514  g_hash_table_destroy(htab); \
515  } \
516  else \
517  g_hash_table_insert(htab,_hx,(gpointer)(ptr_t)count); \
518  } \
519  else { \
520  if (!greftab) \
521  break; \
522  \
523  fprintf(stderr,"REFDEBUG: putn %p,%p (%d)\n",(x),_hx,(rc)); \
524  \
525  htab = (GHashTable *)g_hash_table_lookup(greftab,_x); \
526  if (!htab) \
527  break; \
528  g_hash_table_remove(htab,_hx); \
529  if (g_hash_table_size(htab) == 0) { \
530  g_hash_table_destroy(htab); \
531  g_hash_table_remove(greftab,_x); \
532  } \
533  } \
534  } while (0);
535 //#endif /* 0 */
536 /*
537  * You should call this when your main program terminates.
538  */
539 #define REF_DEBUG_REPORT_FINISH() \
540  do { \
541  GHashTableIter iter,iter2; \
542  GHashTable *htab; \
543  void *_x,*_hx; \
544  char *info; \
545  unsigned int count; \
546  if (greftab) { \
547  g_hash_table_iter_init(&iter,greftab); \
548  while (g_hash_table_iter_next(&iter,&_x,(gpointer)&htab)) { \
549  fprintf(stderr,"REFDEBUG: %d refs held for %p :\n", \
550  g_hash_table_size(htab),_x); \
551  g_hash_table_iter_init(&iter2,htab); \
552  while (g_hash_table_iter_next(&iter2,&_hx,(gpointer)&info)) { \
553  fprintf(stderr," %p held %p : %s\n", \
554  _hx,_x,info); \
555  g_hash_table_iter_remove(&iter2); \
556  } \
557  g_hash_table_destroy(htab); \
558  \
559  /* asm("int $3"); */ \
560  } \
561  g_hash_table_destroy(greftab); \
562  greftab = NULL; \
563  } \
564  if (grefstab) { \
565  g_hash_table_iter_init(&iter,grefstab); \
566  while (g_hash_table_iter_next(&iter,&_x,(gpointer)&htab)) { \
567  fprintf(stderr,"REFDEBUG: %d refs self-held for %p :\n", \
568  g_hash_table_size(htab),_x); \
569  g_hash_table_iter_init(&iter2,htab); \
570  while (g_hash_table_iter_next(&iter2,&_hx,(gpointer)&info)) { \
571  count = (unsigned int)(ptr_t)info; \
572  fprintf(stderr," %p self-held %p : %d\n", \
573  _hx,_x,count); \
574  g_hash_table_iter_remove(&iter2); \
575  } \
576  g_hash_table_destroy(htab); \
577  \
578  /* asm("int $3"); */ \
579  } \
580  g_hash_table_destroy(grefstab); \
581  grefstab = NULL; \
582  } \
583  if (grefwtab) { \
584  g_hash_table_iter_init(&iter,grefwtab); \
585  while (g_hash_table_iter_next(&iter,&_x,(gpointer)&htab)) { \
586  fprintf(stderr,"REFDEBUG: %d weak refs held for %p :\n", \
587  g_hash_table_size(htab),_x); \
588  g_hash_table_iter_init(&iter2,htab); \
589  while (g_hash_table_iter_next(&iter2,&_hx,(gpointer)&info)) { \
590  fprintf(stderr," %p weakly held %p : %s\n", \
591  _hx,_x,info); \
592  g_hash_table_iter_remove(&iter2); \
593  } \
594  g_hash_table_destroy(htab); \
595  \
596  /* asm("int $3"); */ \
597  } \
598  g_hash_table_destroy(grefwtab); \
599  grefwtab = NULL; \
600  } \
601  if (grefwstab) { \
602  g_hash_table_iter_init(&iter,grefwstab); \
603  while (g_hash_table_iter_next(&iter,&_x,(gpointer)&htab)) { \
604  fprintf(stderr,"REFDEBUG: %d weak refs self-held for %p :\n", \
605  g_hash_table_size(htab),_x); \
606  g_hash_table_iter_init(&iter2,htab); \
607  while (g_hash_table_iter_next(&iter2,&_hx,(gpointer)&info)) { \
608  fprintf(stderr," %p weakly self-held %p : %s\n", \
609  _hx,_x,info); \
610  g_hash_table_iter_remove(&iter2); \
611  } \
612  g_hash_table_destroy(htab); \
613  \
614  /* asm("int $3"); */ \
615  } \
616  g_hash_table_destroy(grefwstab); \
617  grefwstab = NULL; \
618  } \
619  } while (0);
620 #else
621 #define REFCNTDECL(trefcnt)
622 #define RHOLD(x,hx) ++((x)->refcnt)
623 #define RHOLDW(x,hx) ++((x)->refcntw)
624 #define RPUT(x,objtype,hx,rc) ((rc) = (--((x)->refcnt) == 0) \
625  ? objtype ## _free(x,0) \
626  : (x)->refcnt); \
627  (rc) += 0
628 #define RPUTW(x,objtype,hx,rc) ((rc) = ((--((x)->refcntw) + (x)->refcnt) == 0) \
629  ? objtype ## _free(x,0) \
630  : (x)->refcntw + (x)->refcnt); \
631  (rc) += 0
632 /*
633  * Allows the caller to free the object even if the refcnt has gone
634  * negative. This is nice for the case that the caller allocates an
635  * object, and passes it into the library where something in there holds
636  * one or more refs to it. But, if the caller later decides it wants to
637  * "release" it because from its perspective it is no longer needed,
638  * then it can call this sloppy release mechanism which allows it to
639  * release an "implicit" ref.
640  *
641  * A cleaner way would be to hold a temp ref to it, and release that.
642  * But if an algorithm is multi-part, it may be hard to follow that
643  * strategy.
644  */
645 #define RPUTIFZERO(x,objtype,rc) ((rc) = (x)->refcnt == 0 \
646  ? objtype ## _free(x,0) \
647  : (x)->refcnt)
648 #define RPUTFF(x,objtype,hx,rc) ((rc) = (--((x)->refcnt) == 0) \
649  ? objtype ## _free(x,1) \
650  : objtype ## _free(x,1)
651 #define RPUTNF(x,hx,rc) ((rc) = (--((x)->refcnt)))
652 
653 #define REF_DEBUG_REPORT_FINISH() (void)
654 #endif
655 
656 #endif /* __COMMON_H__ */
int32_t tid_t
Definition: common.h:36
int64_t num_t
Definition: common.h:87
int32_t SMOFFSET
Definition: common.h:100
int32_t OFFSET
Definition: common.h:65
result_t
Definition: common.h:25
uint32_t REGVAL
Definition: common.h:66
int8_t REG
Definition: common.h:93
uint32_t ADDR
Definition: common.h:64
uint32_t REFCNT
Definition: common.h:124
uint64_t unum_t
Definition: common.h:88