dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / mdb / common / modules / libproc / libproc.c
blob6f8a0a524869db7cc0034e2378febd34ba12cf3b
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <libproc.h>
27 #include <Pcontrol.h>
28 #include <stddef.h>
30 #include <mdb/mdb_modapi.h>
32 typedef struct ps_prochandle ps_prochandle_t;
35 * addr::pr_symtab [-a | n]
37 * -a Sort symbols by address
38 * -n Sort symbols by name
40 * Given a sym_tbl_t, dump its contents in tabular form. When given '-a' or
41 * '-n', we use the sorted tables 'sym_byaddr' or 'sym_byname', respectively.
43 static int
44 pr_symtab(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
46 sym_tbl_t symtab;
47 Elf_Data data_pri;
48 Elf_Data data_aux;
49 Elf_Data *data;
50 #ifdef _LP64
51 Elf64_Sym sym;
52 int width = 16;
53 #else
54 Elf32_Sym sym;
55 int width = 8;
56 #endif
57 int i, idx, count;
58 char name[128];
59 int byaddr = FALSE;
60 int byname = FALSE;
61 uint_t *symlist;
62 size_t symlistsz;
64 if (mdb_getopts(argc, argv,
65 'a', MDB_OPT_SETBITS, TRUE, &byaddr,
66 'n', MDB_OPT_SETBITS, TRUE, &byname,
67 NULL) != argc)
68 return (DCMD_USAGE);
70 if (byaddr && byname) {
71 mdb_warn("only one of '-a' or '-n' can be specified\n");
72 return (DCMD_USAGE);
75 if (!(flags & DCMD_ADDRSPEC))
76 return (DCMD_USAGE);
78 if (mdb_vread(&symtab, sizeof (sym_tbl_t), addr) == -1) {
79 mdb_warn("failed to read sym_tbl_t at %p", addr);
80 return (DCMD_ERR);
83 if (symtab.sym_count == 0) {
84 mdb_warn("no symbols present\n");
85 return (DCMD_ERR);
89 * As described in the libproc header Pcontrol.h, a sym_tbl_t
90 * contains a primary and an optional auxiliary symbol table.
91 * We treat the combination as a single table, with the auxiliary
92 * values coming before the primary ones.
94 * Read the primary and auxiliary Elf_Data structs.
96 if (mdb_vread(&data_pri, sizeof (Elf_Data),
97 (uintptr_t)symtab.sym_data_pri) == -1) {
98 mdb_warn("failed to read primary Elf_Data at %p",
99 symtab.sym_data_pri);
100 return (DCMD_ERR);
102 if ((symtab.sym_symn_aux > 0) &&
103 (mdb_vread(&data_aux, sizeof (Elf_Data),
104 (uintptr_t)symtab.sym_data_aux) == -1)) {
105 mdb_warn("failed to read auxiliary Elf_Data at %p",
106 symtab.sym_data_aux);
107 return (DCMD_ERR);
110 symlist = NULL;
111 if (byaddr || byname) {
112 uintptr_t src = byaddr ? (uintptr_t)symtab.sym_byaddr :
113 (uintptr_t)symtab.sym_byname;
115 symlistsz = symtab.sym_count * sizeof (uint_t);
116 symlist = mdb_alloc(symlistsz, UM_SLEEP);
117 if (mdb_vread(symlist, symlistsz, src) == -1) {
118 mdb_warn("failed to read sorted symbols at %p", src);
119 return (DCMD_ERR);
121 count = symtab.sym_count;
122 } else {
123 count = symtab.sym_symn;
126 mdb_printf("%<u>%*s %*s %s%</u>\n", width, "ADDRESS", width,
127 "SIZE", "NAME");
129 for (i = 0; i < count; i++) {
130 if (byaddr | byname)
131 idx = symlist[i];
132 else
133 idx = i;
135 /* If index is in range of primary symtab, look it up there */
136 if (idx >= symtab.sym_symn_aux) {
137 data = &data_pri;
138 idx -= symtab.sym_symn_aux;
139 } else { /* Look it up in the auxiliary symtab */
140 data = &data_aux;
143 if (mdb_vread(&sym, sizeof (sym), (uintptr_t)data->d_buf +
144 idx * sizeof (sym)) == -1) {
145 mdb_warn("failed to read symbol at %p",
146 (uintptr_t)data->d_buf + idx * sizeof (sym));
147 if (symlist)
148 mdb_free(symlist, symlistsz);
149 return (DCMD_ERR);
152 if (mdb_readstr(name, sizeof (name),
153 (uintptr_t)symtab.sym_strs + sym.st_name) == -1) {
154 mdb_warn("failed to read symbol name at %p",
155 symtab.sym_strs + sym.st_name);
156 name[0] = '\0';
159 mdb_printf("%0?p %0?p %s\n", sym.st_value, sym.st_size,
160 name);
163 if (symlist)
164 mdb_free(symlist, symlistsz);
166 return (DCMD_OK);
170 * addr::pr_addr2map search
172 * Given a ps_prochandle_t, convert the given address to the corresponding
173 * map_info_t. Functionally equivalent to Paddr2mptr().
175 static int
176 pr_addr2map(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
178 uintptr_t search;
179 ps_prochandle_t psp;
180 map_info_t *mp;
181 int lo, hi, mid;
183 if (!(flags & DCMD_ADDRSPEC) || argc != 1)
184 return (DCMD_USAGE);
186 if (argv[0].a_type == MDB_TYPE_IMMEDIATE)
187 search = argv[0].a_un.a_val;
188 else
189 search = mdb_strtoull(argv[0].a_un.a_str);
191 if (mdb_vread(&psp, sizeof (ps_prochandle_t), addr) == -1) {
192 mdb_warn("failed to read ps_prochandle at %p", addr);
193 return (DCMD_ERR);
196 lo = 0;
197 hi = psp.map_count;
198 while (lo <= hi) {
199 mid = (lo + hi) / 2;
200 mp = &psp.mappings[mid];
202 if ((addr - mp->map_pmap.pr_vaddr) < mp->map_pmap.pr_size) {
203 mdb_printf("%#lr\n", addr + offsetof(ps_prochandle_t,
204 mappings) + (mp - psp.mappings) *
205 sizeof (map_info_t));
206 return (DCMD_OK);
209 if (addr < mp->map_pmap.pr_vaddr)
210 hi = mid - 1;
211 else
212 lo = mid + 1;
215 mdb_warn("no corresponding map for %p\n", search);
216 return (DCMD_ERR);
220 * ::walk pr_file_info
222 * Given a ps_prochandle_t, walk all its file_info_t structures.
224 typedef struct {
225 uintptr_t fiw_next;
226 int fiw_count;
227 } file_info_walk_t;
229 static int
230 pr_file_info_walk_init(mdb_walk_state_t *wsp)
232 ps_prochandle_t psp;
233 file_info_walk_t *fiw;
235 if (wsp->walk_addr == (uintptr_t)NULL) {
236 mdb_warn("pr_file_info doesn't support global walks\n");
237 return (WALK_ERR);
240 if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
241 mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
242 return (WALK_ERR);
245 fiw = mdb_alloc(sizeof (file_info_walk_t), UM_SLEEP);
247 fiw->fiw_next = (uintptr_t)psp.file_head.list_forw;
248 fiw->fiw_count = psp.num_files;
249 wsp->walk_data = fiw;
251 return (WALK_NEXT);
254 static int
255 pr_file_info_walk_step(mdb_walk_state_t *wsp)
257 file_info_walk_t *fiw = wsp->walk_data;
258 file_info_t f;
259 int status;
261 if (fiw->fiw_count == 0)
262 return (WALK_DONE);
264 if (mdb_vread(&f, sizeof (file_info_t), fiw->fiw_next) == -1) {
265 mdb_warn("failed to read file_info_t at %p", fiw->fiw_next);
266 return (WALK_ERR);
269 status = wsp->walk_callback(fiw->fiw_next, &f, wsp->walk_cbdata);
271 fiw->fiw_next = (uintptr_t)f.file_list.list_forw;
272 fiw->fiw_count--;
274 return (status);
277 static void
278 pr_file_info_walk_fini(mdb_walk_state_t *wsp)
280 file_info_walk_t *fiw = wsp->walk_data;
281 mdb_free(fiw, sizeof (file_info_walk_t));
285 * ::walk pr_map_info
287 * Given a ps_prochandle_t, walk all its map_info_t structures.
289 typedef struct {
290 uintptr_t miw_next;
291 int miw_count;
292 int miw_current;
293 } map_info_walk_t;
295 static int
296 pr_map_info_walk_init(mdb_walk_state_t *wsp)
298 ps_prochandle_t psp;
299 map_info_walk_t *miw;
301 if (wsp->walk_addr == (uintptr_t)NULL) {
302 mdb_warn("pr_map_info doesn't support global walks\n");
303 return (WALK_ERR);
306 if (mdb_vread(&psp, sizeof (ps_prochandle_t), wsp->walk_addr) == -1) {
307 mdb_warn("failed to read ps_prochandle at %p", wsp->walk_addr);
308 return (WALK_ERR);
311 miw = mdb_alloc(sizeof (map_info_walk_t), UM_SLEEP);
313 miw->miw_next = (uintptr_t)psp.mappings;
314 miw->miw_count = psp.map_count;
315 miw->miw_current = 0;
316 wsp->walk_data = miw;
318 return (WALK_NEXT);
321 static int
322 pr_map_info_walk_step(mdb_walk_state_t *wsp)
324 map_info_walk_t *miw = wsp->walk_data;
325 map_info_t m;
326 int status;
328 if (miw->miw_current == miw->miw_count)
329 return (WALK_DONE);
331 if (mdb_vread(&m, sizeof (map_info_t), miw->miw_next) == -1) {
332 mdb_warn("failed to read map_info_t at %p", miw->miw_next);
333 return (WALK_DONE);
336 status = wsp->walk_callback(miw->miw_next, &m, wsp->walk_cbdata);
338 miw->miw_current++;
339 miw->miw_next += sizeof (map_info_t);
341 return (status);
344 static void
345 pr_map_info_walk_fini(mdb_walk_state_t *wsp)
347 map_info_walk_t *miw = wsp->walk_data;
348 mdb_free(miw, sizeof (map_info_walk_t));
351 static const mdb_dcmd_t dcmds[] = {
352 { "pr_addr2map", ":addr", "convert an adress into a map_info_t",
353 pr_addr2map },
354 { "pr_symtab", ":[-a | -n]", "print the contents of a sym_tbl_t",
355 pr_symtab },
356 { NULL }
359 static const mdb_walker_t walkers[] = {
360 { "pr_file_info", "given a ps_prochandle, walk its file_info "
361 "structures", pr_file_info_walk_init, pr_file_info_walk_step,
362 pr_file_info_walk_fini },
363 { "pr_map_info", "given a ps_prochandle, walk its map_info structures",
364 pr_map_info_walk_init, pr_map_info_walk_step,
365 pr_map_info_walk_fini },
366 { NULL }
369 static const mdb_modinfo_t modinfo = {
370 MDB_API_VERSION, dcmds, walkers
373 const mdb_modinfo_t *
374 _mdb_init(void)
376 return (&modinfo);