xref: /illumos-gate/usr/src/cmd/mdb/common/modules/mm/mm.c (revision 915c848a)
1*915c848aSBryan Cantrill /*
2*915c848aSBryan Cantrill  * This file and its contents are supplied under the terms of the
3*915c848aSBryan Cantrill  * Common Development and Distribution License ("CDDL"), version 1.0.
4*915c848aSBryan Cantrill  * You may only use this file in accordance with the terms of version
5*915c848aSBryan Cantrill  * 1.0 of the CDDL.
6*915c848aSBryan Cantrill  *
7*915c848aSBryan Cantrill  * A full copy of the text of the CDDL should have accompanied this
8*915c848aSBryan Cantrill  * source.  A copy of the CDDL is also available via the Internet at
9*915c848aSBryan Cantrill  * http://www.illumos.org/license/CDDL.
10*915c848aSBryan Cantrill  */
11*915c848aSBryan Cantrill 
12*915c848aSBryan Cantrill /*
13*915c848aSBryan Cantrill  * Copyright (c) 2015, Joyent, Inc.  All rights reserved.
14*915c848aSBryan Cantrill  */
15*915c848aSBryan Cantrill 
16*915c848aSBryan Cantrill #include <sys/mdb_modapi.h>
17*915c848aSBryan Cantrill #include <sys/time.h>
18*915c848aSBryan Cantrill #include <sys/mem.h>
19*915c848aSBryan Cantrill 
20*915c848aSBryan Cantrill typedef struct kmemlog_walk {
21*915c848aSBryan Cantrill 	uintptr_t kmlw_addr;
22*915c848aSBryan Cantrill 	mm_logentry_t *kmlw_entries;
23*915c848aSBryan Cantrill 	int kmlw_nentries;
24*915c848aSBryan Cantrill 	int kmlw_entry;
25*915c848aSBryan Cantrill 	int kmlw_oldest;
26*915c848aSBryan Cantrill } kmemlog_walk_t;
27*915c848aSBryan Cantrill 
28*915c848aSBryan Cantrill static int
kmemlog_walk_init(mdb_walk_state_t * wsp)29*915c848aSBryan Cantrill kmemlog_walk_init(mdb_walk_state_t *wsp)
30*915c848aSBryan Cantrill {
31*915c848aSBryan Cantrill 	kmemlog_walk_t *kw;
32*915c848aSBryan Cantrill 	GElf_Sym sym;
33*915c848aSBryan Cantrill 
34*915c848aSBryan Cantrill 	if (mdb_lookup_by_name("mm_kmemlog", &sym) != 0) {
35*915c848aSBryan Cantrill 		mdb_warn("couldn't find symbol 'mm_kmemlog'");
36*915c848aSBryan Cantrill 		return (WALK_ERR);
37*915c848aSBryan Cantrill 	}
38*915c848aSBryan Cantrill 
39*915c848aSBryan Cantrill 	kw = mdb_zalloc(sizeof (kmemlog_walk_t), UM_SLEEP);
40*915c848aSBryan Cantrill 	kw->kmlw_entries = mdb_zalloc(sym.st_size, UM_SLEEP);
41*915c848aSBryan Cantrill 	kw->kmlw_addr = sym.st_value;
42*915c848aSBryan Cantrill 
43*915c848aSBryan Cantrill 	if (mdb_vread(kw->kmlw_entries, sym.st_size, sym.st_value) == -1) {
44*915c848aSBryan Cantrill 		mdb_warn("couldn't read log at %p", sym.st_value);
45*915c848aSBryan Cantrill 		mdb_free(kw->kmlw_entries, sym.st_size);
46*915c848aSBryan Cantrill 		mdb_free(kw, sizeof (kmemlog_walk_t));
47*915c848aSBryan Cantrill 		return (WALK_ERR);
48*915c848aSBryan Cantrill 	}
49*915c848aSBryan Cantrill 
50*915c848aSBryan Cantrill 	kw->kmlw_nentries = sym.st_size / sizeof (mm_logentry_t);
51*915c848aSBryan Cantrill 
52*915c848aSBryan Cantrill 	mdb_readvar(&kw->kmlw_entry, "mm_kmemlogent");
53*915c848aSBryan Cantrill 	kw->kmlw_oldest = kw->kmlw_entry;
54*915c848aSBryan Cantrill 	wsp->walk_data = kw;
55*915c848aSBryan Cantrill 
56*915c848aSBryan Cantrill 	return (WALK_NEXT);
57*915c848aSBryan Cantrill }
58*915c848aSBryan Cantrill 
59*915c848aSBryan Cantrill static int
kmemlog_walk_step(mdb_walk_state_t * wsp)60*915c848aSBryan Cantrill kmemlog_walk_step(mdb_walk_state_t *wsp)
61*915c848aSBryan Cantrill {
62*915c848aSBryan Cantrill 	kmemlog_walk_t *kw = wsp->walk_data;
63*915c848aSBryan Cantrill 	mm_logentry_t *ent;
64*915c848aSBryan Cantrill 	int rval = WALK_NEXT;
65*915c848aSBryan Cantrill 
66*915c848aSBryan Cantrill 	ent = &kw->kmlw_entries[kw->kmlw_entry];
67*915c848aSBryan Cantrill 
68*915c848aSBryan Cantrill 	if (++kw->kmlw_entry == kw->kmlw_nentries)
69*915c848aSBryan Cantrill 		kw->kmlw_entry = 0;
70*915c848aSBryan Cantrill 
71*915c848aSBryan Cantrill 	if (ent->mle_hrtime != 0) {
72*915c848aSBryan Cantrill 		rval = wsp->walk_callback(kw->kmlw_addr + ((uintptr_t)ent -
73*915c848aSBryan Cantrill 		    (uintptr_t)kw->kmlw_entries), ent, wsp->walk_cbdata);
74*915c848aSBryan Cantrill 	}
75*915c848aSBryan Cantrill 
76*915c848aSBryan Cantrill 	if (rval == WALK_NEXT && kw->kmlw_entry == kw->kmlw_oldest)
77*915c848aSBryan Cantrill 		return (WALK_DONE);
78*915c848aSBryan Cantrill 
79*915c848aSBryan Cantrill 	return (rval);
80*915c848aSBryan Cantrill }
81*915c848aSBryan Cantrill 
82*915c848aSBryan Cantrill static void
kmemlog_walk_fini(mdb_walk_state_t * wsp)83*915c848aSBryan Cantrill kmemlog_walk_fini(mdb_walk_state_t *wsp)
84*915c848aSBryan Cantrill {
85*915c848aSBryan Cantrill 	kmemlog_walk_t *kw = wsp->walk_data;
86*915c848aSBryan Cantrill 
87*915c848aSBryan Cantrill 	mdb_free(kw->kmlw_entries, kw->kmlw_nentries * sizeof (mm_logentry_t));
88*915c848aSBryan Cantrill 	mdb_free(kw, sizeof (kmemlog_walk_t));
89*915c848aSBryan Cantrill }
90*915c848aSBryan Cantrill 
91*915c848aSBryan Cantrill static int
kmemlog(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)92*915c848aSBryan Cantrill kmemlog(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
93*915c848aSBryan Cantrill {
94*915c848aSBryan Cantrill 	mm_logentry_t ent;
95*915c848aSBryan Cantrill 
96*915c848aSBryan Cantrill 	if (!(flags & DCMD_ADDRSPEC)) {
97*915c848aSBryan Cantrill 		if (mdb_walk_dcmd("kmemlog", "kmemlog", argc, argv) == -1) {
98*915c848aSBryan Cantrill 			mdb_warn("can't walk 'kmemlog'");
99*915c848aSBryan Cantrill 			return (DCMD_ERR);
100*915c848aSBryan Cantrill 		}
101*915c848aSBryan Cantrill 		return (DCMD_OK);
102*915c848aSBryan Cantrill 	}
103*915c848aSBryan Cantrill 
104*915c848aSBryan Cantrill 	if (DCMD_HDRSPEC(flags)) {
105*915c848aSBryan Cantrill 		mdb_printf("%?s %-20s %?s %5s %s\n",
106*915c848aSBryan Cantrill 		    "ADDR", "TIME", "VADDR", "PID", "PSARGS");
107*915c848aSBryan Cantrill 	}
108*915c848aSBryan Cantrill 
109*915c848aSBryan Cantrill 	if (mdb_vread(&ent, sizeof (ent), addr) == -1) {
110*915c848aSBryan Cantrill 		mdb_warn("can't read mm_logentry_t at %p", addr);
111*915c848aSBryan Cantrill 		return (DCMD_ERR);
112*915c848aSBryan Cantrill 	}
113*915c848aSBryan Cantrill 
114*915c848aSBryan Cantrill 	mdb_printf("%?p %-20Y %?p %5d %s\n",
115*915c848aSBryan Cantrill 	    addr, ent.mle_hrestime.tv_sec, ent.mle_vaddr, ent.mle_pid,
116*915c848aSBryan Cantrill 	    ent.mle_psargs);
117*915c848aSBryan Cantrill 
118*915c848aSBryan Cantrill 	return (DCMD_OK);
119*915c848aSBryan Cantrill }
120*915c848aSBryan Cantrill 
121*915c848aSBryan Cantrill static const mdb_dcmd_t dcmds[] = {
122*915c848aSBryan Cantrill 	{ "kmemlog", NULL, "print log of writes via /dev/kmem", kmemlog },
123*915c848aSBryan Cantrill 	{ NULL }
124*915c848aSBryan Cantrill };
125*915c848aSBryan Cantrill 
126*915c848aSBryan Cantrill static const mdb_walker_t walkers[] = {
127*915c848aSBryan Cantrill 	{ "kmemlog", "walk entries in /dev/kmem write log",
128*915c848aSBryan Cantrill 		kmemlog_walk_init, kmemlog_walk_step, kmemlog_walk_fini },
129*915c848aSBryan Cantrill 	{ NULL }
130*915c848aSBryan Cantrill };
131*915c848aSBryan Cantrill 
132*915c848aSBryan Cantrill static const mdb_modinfo_t modinfo = {
133*915c848aSBryan Cantrill 	MDB_API_VERSION, dcmds, walkers
134*915c848aSBryan Cantrill };
135*915c848aSBryan Cantrill 
136*915c848aSBryan Cantrill const mdb_modinfo_t *
_mdb_init(void)137*915c848aSBryan Cantrill _mdb_init(void)
138*915c848aSBryan Cantrill {
139*915c848aSBryan Cantrill 	return (&modinfo);
140*915c848aSBryan Cantrill }
141