summaryrefslogtreecommitdiff
path: root/usr/src/cmd/mdb/common/modules/genunix/qqcache.c
blob: a2ba1463b9f27be032ebf95b174ade1a027fec70 (plain)
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
/*
 * This file and its contents are supplied under the terms of the
 * Common Development and Distribution License ("CDDL"), version 1.0.
 * You may only use this file in accordance with the terms of version
 * 1.0 of the CDDL.
 *
 * A full copy of the text of the CDDL should have accompanied this
 * source.  A copy of the CDDL is also available via the Internet at
 * http://www.illumos.org/license/CDDL.
 */

/*
 * Copyright 2018, Joyent, Inc.
 */

#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>

#include <sys/qqcache.h>
#include <sys/qqcache_impl.h>

#include "qqcache.h"

typedef struct qqcache_walk_data {
	size_t	qwd_link_off;
} qqcache_walk_data_t;

typedef struct mdb_qqcache {
	size_t qqc_link_off;
	size_t qqc_nbuckets;
} mdb_qqcache_t;

static int
qqcache_walk_init(mdb_walk_state_t *wsp, boolean_t use_hash)
{
	qqcache_walk_data_t *qwd;
	uintptr_t base;
	size_t i, n, qqc_list_sz;
	int cache_off, bucket_off, list_off;
	mdb_qqcache_t qc;

	/*  mdb_ctf_offsetof_by_name will print any errors */
	cache_off = mdb_ctf_offsetof_by_name("qqcache_t", "qqc_lists");
	if (cache_off == -1)
		return (WALK_ERR);

	bucket_off = mdb_ctf_offsetof_by_name("qqcache_t", "qqc_buckets");
	if (bucket_off == -1)
		return (WALK_ERR);

	list_off = mdb_ctf_offsetof_by_name("qqcache_list_t", "qqcl_list");
	if (list_off == -1)
		return (WALK_ERR);

	/* mdb_ctf_sizeof_by_name will print any errors */
	qqc_list_sz = mdb_ctf_sizeof_by_name("qqcache_list_t");
	if (qqc_list_sz == -1)
		return (WALK_ERR);

	if (mdb_ctf_vread(&qc, "qqcache_t", "mdb_qqcache_t", wsp->walk_addr,
	    0) == -1) {
		mdb_warn("failed to read qqcache_t at %#lx", wsp->walk_addr);
		return (WALK_ERR);
	}

	qwd = wsp->walk_data = mdb_zalloc(sizeof (*qwd), UM_SLEEP);
	qwd->qwd_link_off = qc.qqc_link_off;

	if (use_hash) {
		base = wsp->walk_addr + bucket_off;
		n = qc.qqc_nbuckets;
	} else {
		base = wsp->walk_addr + cache_off;
		n = QQCACHE_NUM_LISTS;
	}

	for (i = 0; i < n; i++) {
		wsp->walk_addr = base + i * qqc_list_sz + list_off;

		if (mdb_layered_walk("list", wsp) == -1) {
			mdb_warn("can't walk qqcache_t");
			mdb_free(qwd, sizeof (*qwd));
			return (WALK_ERR);
		}
	}

	return (WALK_NEXT);
}

int
qqcache_walk_init_cache(mdb_walk_state_t *wsp)
{
	return (qqcache_walk_init(wsp, B_FALSE));
}

int
qqcache_walk_init_hash(mdb_walk_state_t *wsp)
{
	return (qqcache_walk_init(wsp, B_TRUE));
}

int
qqcache_walk_step(mdb_walk_state_t *wsp)
{
	qqcache_walk_data_t *qwd = wsp->walk_data;
	uintptr_t addr = wsp->walk_addr - qwd->qwd_link_off;

	return (wsp->walk_callback(addr, wsp->walk_layer, wsp->walk_cbdata));
}

void
qqcache_walk_fini(mdb_walk_state_t *wsp)
{
	qqcache_walk_data_t *qwd = wsp->walk_data;

	mdb_free(qwd, sizeof (*qwd));
}