xref: /onnv-gate/usr/src/cmd/mdb/common/modules/libproc/libproc.c (revision 2712:f74a135872bc)
1*2712Snn35248 /*
2*2712Snn35248  * CDDL HEADER START
3*2712Snn35248  *
4*2712Snn35248  * The contents of this file are subject to the terms of the
5*2712Snn35248  * Common Development and Distribution License (the "License").
6*2712Snn35248  * You may not use this file except in compliance with the License.
7*2712Snn35248  *
8*2712Snn35248  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2712Snn35248  * or http://www.opensolaris.org/os/licensing.
10*2712Snn35248  * See the License for the specific language governing permissions
11*2712Snn35248  * and limitations under the License.
12*2712Snn35248  *
13*2712Snn35248  * When distributing Covered Code, include this CDDL HEADER in each
14*2712Snn35248  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2712Snn35248  * If applicable, add the following below this CDDL HEADER, with the
16*2712Snn35248  * fields enclosed by brackets "[]" replaced with your own identifying
17*2712Snn35248  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2712Snn35248  *
19*2712Snn35248  * CDDL HEADER END
20*2712Snn35248  */
21*2712Snn35248 /*
22*2712Snn35248  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*2712Snn35248  * Use is subject to license terms.
24*2712Snn35248  */
25*2712Snn35248 
26*2712Snn35248 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*2712Snn35248 
28*2712Snn35248 #include <libproc.h>
29*2712Snn35248 #include <Pcontrol.h>
30*2712Snn35248 #include <stddef.h>
31*2712Snn35248 
32*2712Snn35248 #include <mdb/mdb_modapi.h>
33*2712Snn35248 
34*2712Snn35248 typedef struct ps_prochandle ps_prochandle_t;
35*2712Snn35248 
36*2712Snn35248 /*
37*2712Snn35248  * addr::pr_symtab [-a | n]
38*2712Snn35248  *
39*2712Snn35248  * 	-a	Sort symbols by address
40*2712Snn35248  * 	-n	Sort symbols by name
41*2712Snn35248  *
42*2712Snn35248  * Given a sym_tbl_t, dump its contents in tabular form.  When given '-a' or
43*2712Snn35248  * '-n', we use the sorted tables 'sym_byaddr' or 'sym_byname', respectively.
44*2712Snn35248  */
45*2712Snn35248 static int
46*2712Snn35248 pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
47*2712Snn35248 {
48*2712Snn35248 	sym_tbl_t symtab;
49*2712Snn35248 	Elf_Data data;
50*2712Snn35248 #ifdef _LP64
51*2712Snn35248 	Elf64_Sym sym;
52*2712Snn35248 	int width = 16;
53*2712Snn35248 #else
54*2712Snn35248 	Elf32_Sym sym;
55*2712Snn35248 	int width = 8;
56*2712Snn35248 #endif
57*2712Snn35248 	int i, idx, count;
58*2712Snn35248 	char name[128];
59*2712Snn35248 	int byaddr = FALSE;
60*2712Snn35248 	int byname = FALSE;
61*2712Snn35248 	uint_t *symlist;
62*2712Snn35248 	size_t symlistsz;
63*2712Snn35248 
64*2712Snn35248 	if (mdb_getopts(argc, argv,
65*2712Snn35248 	    'a', MDB_OPT_SETBITS, TRUE, &byaddr,
66*2712Snn35248 	    'n', MDB_OPT_SETBITS, TRUE, &byname,
67*2712Snn35248 	    NULL) != argc)
68*2712Snn35248 		return (DCMD_USAGE);
69*2712Snn35248 
70*2712Snn35248 	if (byaddr && byname) {
71*2712Snn35248 		mdb_warn("only one of '-a' or '-n' can be specified\n");
72*2712Snn35248 		return (DCMD_USAGE);
73*2712Snn35248 	}
74*2712Snn35248 
75*2712Snn35248 	if (!(flags & DCMD_ADDRSPEC))
76*2712Snn35248 		return (DCMD_USAGE);
77*2712Snn35248 
78*2712Snn35248 	if (mdb_vread(&symtab, sizeof (sym_tbl_t), addr) == -1) {
79*2712Snn35248 		mdb_warn("failed to read sym_tbl_t at %p", addr);
80*2712Snn35248 		return (DCMD_ERR);
81*2712Snn35248 	}
82*2712Snn35248 
83*2712Snn35248 	if (symtab.sym_count == 0) {
84*2712Snn35248 		mdb_warn("no symbols present\n");
85*2712Snn35248 		return (DCMD_ERR);
86*2712Snn35248 	}
87*2712Snn35248 
88*2712Snn35248 	if (mdb_vread(&data, sizeof (Elf_Data),
89*2712Snn35248 	    (uintptr_t)symtab.sym_data) == -1) {
90*2712Snn35248 		mdb_warn("failed to read Elf_Data at %p", symtab.sym_data);
91*2712Snn35248 		return (DCMD_ERR);
92*2712Snn35248 	}
93*2712Snn35248 
94*2712Snn35248 	symlist = NULL;
95*2712Snn35248 	if (byaddr || byname) {
96*2712Snn35248 		uintptr_t src = byaddr ? (uintptr_t)symtab.sym_byaddr :
97*2712Snn35248 		    (uintptr_t)symtab.sym_byname;
98*2712Snn35248 
99*2712Snn35248 		symlistsz = symtab.sym_count * sizeof (uint_t);
100*2712Snn35248 		symlist = mdb_alloc(symlistsz, UM_SLEEP);
101*2712Snn35248 		if (mdb_vread(symlist, symlistsz, src) == -1) {
102*2712Snn35248 			mdb_warn("failed to read sorted symbols at %p", src);
103*2712Snn35248 			return (DCMD_ERR);
104*2712Snn35248 		}
105*2712Snn35248 		count = symtab.sym_count;
106*2712Snn35248 	} else {
107*2712Snn35248 		count = symtab.sym_symn;
108*2712Snn35248 	}
109*2712Snn35248 
110*2712Snn35248 	mdb_printf("%<u>%*s  %*s  %s%</u>\n", width, "ADDRESS", width,
111*2712Snn35248 	    "SIZE", "NAME");
112*2712Snn35248 
113*2712Snn35248 	for (i = 0; i < count; i++) {
114*2712Snn35248 		if (byaddr | byname)
115*2712Snn35248 			idx = symlist[i];
116*2712Snn35248 		else
117*2712Snn35248 			idx = i;
118*2712Snn35248 
119*2712Snn35248 		if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data.d_buf +
120*2712Snn35248 		    idx * sizeof (sym)) == -1) {
121*2712Snn35248 			mdb_warn("failed to read symbol at %p",
122*2712Snn35248 			    (uintptr_t)data.d_buf + idx * sizeof (sym));
123*2712Snn35248 			if (symlist)
124*2712Snn35248 				mdb_free(symlist, symlistsz);
125*2712Snn35248 			return (DCMD_ERR);
126*2712Snn35248 		}
127*2712Snn35248 
128*2712Snn35248 		if (mdb_readstr(name, sizeof (name),
129*2712Snn35248 		    (uintptr_t)symtab.sym_strs + sym.st_name) == -1) {
130*2712Snn35248 			mdb_warn("failed to read symbol name at %p",
131*2712Snn35248 			    symtab.sym_strs + sym.st_name);
132*2712Snn35248 			name[0] = '\0';
133*2712Snn35248 		}
134*2712Snn35248 
135*2712Snn35248 		mdb_printf("%0?p  %0?p  %s\n", sym.st_value, sym.st_size,
136*2712Snn35248 		    name);
137*2712Snn35248 	}
138*2712Snn35248 
139*2712Snn35248 	if (symlist)
140*2712Snn35248 		mdb_free(symlist, symlistsz);
141*2712Snn35248 
142*2712Snn35248 	return (DCMD_OK);
143*2712Snn35248 }
144*2712Snn35248 
145*2712Snn35248 /*
146*2712Snn35248  * addr::pr_addr2map search
147*2712Snn35248  *
148*2712Snn35248  * Given a ps_prochandle_t, convert the given address to the corresponding
149*2712Snn35248  * map_info_t.  Functionally equivalent to Paddr2mptr().
150*2712Snn35248  */
151*2712Snn35248 static int
152*2712Snn35248 pr_addr2map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
153*2712Snn35248 {
154*2712Snn35248 	uintptr_t search;
155*2712Snn35248 	ps_prochandle_t psp;
156*2712Snn35248 	map_info_t *mp;
157*2712Snn35248 	int lo, hi, mid;
158*2712Snn35248 
159*2712Snn35248 	if (!(flags & DCMD_ADDRSPEC) || argc != 1)
160*2712Snn35248 		return (DCMD_USAGE);
161*2712Snn35248 
162*2712Snn35248 	if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
163*2712Snn35248 		search = argv[0].a_un.a_val;
164*2712Snn35248 	else
165*2712Snn35248 		search = mdb_strtoull(argv[0].a_un.a_str);
166*2712Snn35248 
167*2712Snn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), addr) == -1) {
168*2712Snn35248 		mdb_warn("failed to read ps_prochandle at %p", addr);
169*2712Snn35248 		return (DCMD_ERR);
170*2712Snn35248 	}
171*2712Snn35248 
172*2712Snn35248 	lo = 0;
173*2712Snn35248 	hi = psp.map_count;
174*2712Snn35248 	while (lo <= hi) {
175*2712Snn35248 		mid = (lo + hi) / 2;
176*2712Snn35248 		mp = &psp.mappings[mid];
177*2712Snn35248 
178*2712Snn35248 		if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size) {
179*2712Snn35248 			mdb_printf("%#lr\n", addr + offsetof(ps_prochandle_t,
180*2712Snn35248 			    mappings) + (mp - psp.mappings) *
181*2712Snn35248 			    sizeof (map_info_t));
182*2712Snn35248 			return (DCMD_OK);
183*2712Snn35248 		}
184*2712Snn35248 
185*2712Snn35248 		if (addr < mp->map_pmap.pr_vaddr)
186*2712Snn35248 			hi = mid - 1;
187*2712Snn35248 		else
188*2712Snn35248 			lo = mid + 1;
189*2712Snn35248 	}
190*2712Snn35248 
191*2712Snn35248 	mdb_warn("no corresponding map for %p\n", search);
192*2712Snn35248 	return (DCMD_ERR);
193*2712Snn35248 }
194*2712Snn35248 
195*2712Snn35248 /*
196*2712Snn35248  * ::walk pr_file_info
197*2712Snn35248  *
198*2712Snn35248  * Given a ps_prochandle_t, walk all its file_info_t structures.
199*2712Snn35248  */
200*2712Snn35248 typedef struct {
201*2712Snn35248 	uintptr_t	fiw_next;
202*2712Snn35248 	int		fiw_count;
203*2712Snn35248 } file_info_walk_t;
204*2712Snn35248 
205*2712Snn35248 static int
206*2712Snn35248 pr_file_info_walk_init(mdb_walk_state_t *wsp)
207*2712Snn35248 {
208*2712Snn35248 	ps_prochandle_t psp;
209*2712Snn35248 	file_info_walk_t *fiw;
210*2712Snn35248 
211*2712Snn35248 	if (wsp->walk_addr == NULL) {
212*2712Snn35248 		mdb_warn("pr_file_info doesn't support global walks\n");
213*2712Snn35248 		return (WALK_ERR);
214*2712Snn35248 	}
215*2712Snn35248 
216*2712Snn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
217*2712Snn35248 		mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
218*2712Snn35248 		return (WALK_ERR);
219*2712Snn35248 	}
220*2712Snn35248 
221*2712Snn35248 	fiw = mdb_alloc(sizeof (file_info_walk_t), UM_SLEEP);
222*2712Snn35248 
223*2712Snn35248 	fiw->fiw_next = (uintptr_t)psp.file_head.list_forw;
224*2712Snn35248 	fiw->fiw_count = psp.num_files;
225*2712Snn35248 	wsp->walk_data = fiw;
226*2712Snn35248 
227*2712Snn35248 	return (WALK_NEXT);
228*2712Snn35248 }
229*2712Snn35248 
230*2712Snn35248 static int
231*2712Snn35248 pr_file_info_walk_step(mdb_walk_state_t *wsp)
232*2712Snn35248 {
233*2712Snn35248 	file_info_walk_t *fiw = wsp->walk_data;
234*2712Snn35248 	file_info_t f;
235*2712Snn35248 	int status;
236*2712Snn35248 
237*2712Snn35248 	if (fiw->fiw_count == 0)
238*2712Snn35248 		return (WALK_DONE);
239*2712Snn35248 
240*2712Snn35248 	if (mdb_vread(&f, sizeof (file_info_t), fiw->fiw_next) == -1) {
241*2712Snn35248 		mdb_warn("failed to read file_info_t at %p", fiw->fiw_next);
242*2712Snn35248 		return (WALK_ERR);
243*2712Snn35248 	}
244*2712Snn35248 
245*2712Snn35248 	status = wsp->walk_callback(fiw->fiw_next, &f, wsp->walk_cbdata);
246*2712Snn35248 
247*2712Snn35248 	fiw->fiw_next = (uintptr_t)f.file_list.list_forw;
248*2712Snn35248 	fiw->fiw_count--;
249*2712Snn35248 
250*2712Snn35248 	return (status);
251*2712Snn35248 }
252*2712Snn35248 
253*2712Snn35248 static void
254*2712Snn35248 pr_file_info_walk_fini(mdb_walk_state_t *wsp)
255*2712Snn35248 {
256*2712Snn35248 	file_info_walk_t *fiw = wsp->walk_data;
257*2712Snn35248 	mdb_free(fiw, sizeof (file_info_walk_t));
258*2712Snn35248 }
259*2712Snn35248 
260*2712Snn35248 /*
261*2712Snn35248  * ::walk pr_map_info
262*2712Snn35248  *
263*2712Snn35248  * Given a ps_prochandle_t, walk all its map_info_t structures.
264*2712Snn35248  */
265*2712Snn35248 typedef struct {
266*2712Snn35248 	uintptr_t	miw_next;
267*2712Snn35248 	int		miw_count;
268*2712Snn35248 	int		miw_current;
269*2712Snn35248 } map_info_walk_t;
270*2712Snn35248 
271*2712Snn35248 static int
272*2712Snn35248 pr_map_info_walk_init(mdb_walk_state_t *wsp)
273*2712Snn35248 {
274*2712Snn35248 	ps_prochandle_t psp;
275*2712Snn35248 	map_info_walk_t *miw;
276*2712Snn35248 
277*2712Snn35248 	if (wsp->walk_addr == NULL) {
278*2712Snn35248 		mdb_warn("pr_map_info doesn't support global walks\n");
279*2712Snn35248 		return (WALK_ERR);
280*2712Snn35248 	}
281*2712Snn35248 
282*2712Snn35248 	if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
283*2712Snn35248 		mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
284*2712Snn35248 		return (WALK_ERR);
285*2712Snn35248 	}
286*2712Snn35248 
287*2712Snn35248 	miw = mdb_alloc(sizeof (map_info_walk_t), UM_SLEEP);
288*2712Snn35248 
289*2712Snn35248 	miw->miw_next = (uintptr_t)psp.mappings;
290*2712Snn35248 	miw->miw_count = psp.map_count;
291*2712Snn35248 	miw->miw_current = 0;
292*2712Snn35248 	wsp->walk_data = miw;
293*2712Snn35248 
294*2712Snn35248 	return (WALK_NEXT);
295*2712Snn35248 }
296*2712Snn35248 
297*2712Snn35248 static int
298*2712Snn35248 pr_map_info_walk_step(mdb_walk_state_t *wsp)
299*2712Snn35248 {
300*2712Snn35248 	map_info_walk_t *miw = wsp->walk_data;
301*2712Snn35248 	map_info_t m;
302*2712Snn35248 	int status;
303*2712Snn35248 
304*2712Snn35248 	if (miw->miw_current == miw->miw_count)
305*2712Snn35248 		return (WALK_DONE);
306*2712Snn35248 
307*2712Snn35248 	if (mdb_vread(&m, sizeof (map_info_t), miw->miw_next) == -1) {
308*2712Snn35248 		mdb_warn("failed to read map_info_t at %p", miw->miw_next);
309*2712Snn35248 		return (WALK_DONE);
310*2712Snn35248 	}
311*2712Snn35248 
312*2712Snn35248 	status = wsp->walk_callback(miw->miw_next, &m, wsp->walk_cbdata);
313*2712Snn35248 
314*2712Snn35248 	miw->miw_current++;
315*2712Snn35248 	miw->miw_next += sizeof (map_info_t);
316*2712Snn35248 
317*2712Snn35248 	return (status);
318*2712Snn35248 }
319*2712Snn35248 
320*2712Snn35248 static void
321*2712Snn35248 pr_map_info_walk_fini(mdb_walk_state_t *wsp)
322*2712Snn35248 {
323*2712Snn35248 	map_info_walk_t *miw = wsp->walk_data;
324*2712Snn35248 	mdb_free(miw, sizeof (map_info_walk_t));
325*2712Snn35248 }
326*2712Snn35248 
327*2712Snn35248 static const mdb_dcmd_t dcmds[] = {
328*2712Snn35248 	{ "pr_addr2map",  ":addr", "convert an adress into a map_info_t",
329*2712Snn35248 	    pr_addr2map },
330*2712Snn35248 	{ "pr_symtab",	":[-a | -n]", "print the contents of a sym_tbl_t",
331*2712Snn35248 	    pr_symtab },
332*2712Snn35248 	{ NULL }
333*2712Snn35248 };
334*2712Snn35248 
335*2712Snn35248 static const mdb_walker_t walkers[] = {
336*2712Snn35248 	{ "pr_file_info", "given a ps_prochandle, walk its file_info "
337*2712Snn35248 	    "structures", pr_file_info_walk_init, pr_file_info_walk_step,
338*2712Snn35248 	    pr_file_info_walk_fini },
339*2712Snn35248 	{ "pr_map_info", "given a ps_prochandle, walk its map_info structures",
340*2712Snn35248 	    pr_map_info_walk_init, pr_map_info_walk_step,
341*2712Snn35248 	    pr_map_info_walk_fini },
342*2712Snn35248 	{ NULL }
343*2712Snn35248 };
344*2712Snn35248 
345*2712Snn35248 static const mdb_modinfo_t modinfo = {
346*2712Snn35248 	MDB_API_VERSION, dcmds, walkers
347*2712Snn35248 };
348*2712Snn35248 
349*2712Snn35248 const mdb_modinfo_t *
350*2712Snn35248 _mdb_init(void)
351*2712Snn35248 {
352*2712Snn35248 	return (&modinfo);
353*2712Snn35248 }
354