1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _LEAKY_IMPL_H
#define _LEAKY_IMPL_H
#pragma ident "%Z%%M% %I% %E% SMI"
#ifdef __cplusplus
extern "C" {
#endif
#define LK_NUM_TYPES 8 /* arbitrary */
#ifdef _KERNEL
typedef pc_t leak_pc_t;
#else
typedef uintptr_t leak_pc_t;
#endif
typedef struct leak_mtab {
uintptr_t lkm_base;
uintptr_t lkm_limit;
uintptr_t lkm_bufctl; /* target-defined */
} leak_mtab_t;
typedef struct leak_bufctl {
struct leak_bufctl *lkb_hash_next; /* internal use only */
struct leak_bufctl *lkb_next;
uintptr_t lkb_addr; /* should be unique */
uintptr_t lkb_bufaddr;
uintptr_t lkb_data;
uintptr_t lkb_cid;
hrtime_t lkb_timestamp;
int lkb_dups;
uint8_t lkb_type;
uint8_t lkb_depth;
leak_pc_t lkb_stack[1]; /* actually lkb_depth */
} leak_bufctl_t;
#define LEAK_BUFCTL_SIZE(d) (OFFSETOF(leak_bufctl_t, lkb_stack[(d)]))
/*
* callbacks for target to use
*/
extern void leaky_grep(uintptr_t, size_t); /* grep a vaddr range */
extern void leaky_grep_ptr(uintptr_t); /* grep a pointer */
extern void leaky_mark_ptr(uintptr_t); /* mark a pointer */
extern int leaky_lookup_marked(uintptr_t, uintptr_t *, size_t *);
extern void leaky_add_leak(int, uintptr_t, uintptr_t, hrtime_t,
leak_pc_t *, uint_t, uintptr_t, uintptr_t);
/*
* ::findleaks target interface
*
* int leaky_subr_estimate(estp)
* Validate that any debugging options ::findleaks needs are active,
* and store an upper bound on the number of buffers in the system into
* estp.
*
* Returns DCMD_OK to proceed, DCMD_ERR to abort ::findleaks.
*
* int leaky_subr_fill(mtpp)
* Passes a pointer to an mtab pointer, which points to the beginning
* of the mtab array. Target should add an entry for each buffer in
* the system to the array, and update the pointer to point at the end
* of the table (i.e. one mtab beyond the last valid entry).
*
* The lkm_bufctl entry in each mtab is target-defined.
*
* Returns DCMD_OK to proceed, DCMD_ERR to abort ::findleaks.
*
* int leaky_subr_run(void)
* Target should invoke leaky_grep() or one of its variants on the
* root portions of the virtual address space. Any pointers which
* are not reachable from those roots will be reported as leaks.
*
* Returns DCMD_OK to proceed, DCMD_ERR to abort ::findleaks.
*
* void leaky_subr_add_leak(mtp)
* Invoked once for each leak. Target should call leaky_add_leak()
* with the full details of the leak, which will be copied into a
* leak_bufctl_t. That will be used in subsequent target invocations
* to identify the buffer.
*
* leaky_add_leak() takes the following arguments:
* type target-defined, 0 <= type < LK_NUM_TYPES. Leaks are
* grouped by type.
*
* addr Address of the control structure for this leak.
* Should be unique across all types -- ::walk leak and
* ::walk leakbuf use this field to identify leaks.
*
* bufaddr Address of the beginning of the buffer -- reported by
* ::walk leakbuf.
*
* timestamp
* High-resolution timestamp, usually of the time of
* allocation. Coalesced leaks are represented by
* the leak with the earliest timestamp.
*
* stack, depth
* The stack trace for this leak. Leaks with
* identical stack traces will be coalesced.
*
* cid coalesce identifier -- leaks with differing
* cids will not be coalesced.
*
* data target-defined data
*
* int leaky_subr_bufctl_cmp(lhs, rhs)
* Target-defined display order for two leaks. Both leaks will have
* the same lkb_type -- full display order is type (lowest-to-highest),
* then whatever order this function defines.
*
* void leaky_subr_dump_start(type)
* void leaky_subr_dump(lkb, verbose)
* void leaky_subr_dump_end(type)
* Used to dump the table of discovered leaks. invoked as:
*
* for i in 0 .. LK_NUM_TYPES
* leaky_subr_dump_start(i)
* for lkb in (possibly a subset of) the type i leaks
* leaky_subr_dump(lkb, 0)
* leaky_subr_dump_end(i)
*
* if (-d was passed to ::findleaks)
* for i in 0 .. LK_NUM_TYPES
* for lkb of type i, same subset/order as above
* leaky_subr_dump(lkb, 1)
*
* leaky_subr_dump_start()/end() are always invoked for each type, even
* if there are no leaks of that type. leaky_subr_dump() can use the
* leaks chained off of lkb_next to access coalesced leaks. lkb_dups
* is the length of the dup list.
*
* int leaky_subr_invoke_callback(lkb, cb, cbarg)
* Underlying implementation of '::walk leak' walker -- target should
* invoke cb for the passed in leak_bufctl_t.
*/
extern int leaky_subr_estimate(size_t *);
extern int leaky_subr_fill(leak_mtab_t **);
extern int leaky_subr_run(void);
extern void leaky_subr_add_leak(leak_mtab_t *);
extern int leaky_subr_bufctl_cmp(const leak_bufctl_t *, const leak_bufctl_t *);
extern void leaky_subr_dump_start(int);
extern void leaky_subr_dump(const leak_bufctl_t *, int verbose);
extern void leaky_subr_dump_end(int);
extern int leaky_subr_invoke_callback(const leak_bufctl_t *, mdb_walk_cb_t,
void *);
#ifdef __cplusplus
}
#endif
#endif /* _LEAKY_IMPL_H */
|