1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2016 Joyent, Inc. 14 */ 15 16 #include "dnlc.h" 17 18 #include <mdb/mdb_modapi.h> 19 #include <sys/dnlc.h> 20 21 typedef struct dnlc_walk { 22 int dw_hashsz; 23 int dw_index; 24 uintptr_t dw_hash; 25 uintptr_t dw_head; 26 } dnlc_walk_t; 27 28 29 int 30 dnlc_walk_init(mdb_walk_state_t *wsp) 31 { 32 dnlc_walk_t *dwp; 33 34 if (wsp->walk_addr != NULL) { 35 mdb_warn("dnlc walk doesn't support global walks\n"); 36 return (WALK_ERR); 37 } 38 39 dwp = mdb_zalloc(sizeof (dnlc_walk_t), UM_SLEEP); 40 if (mdb_readvar(&dwp->dw_hashsz, "nc_hashsz") == -1 || 41 dwp->dw_hashsz <= 0) { 42 mdb_warn("failed to read 'nc_hashsz'\n"); 43 mdb_free(dwp, sizeof (dnlc_walk_t)); 44 return (WALK_ERR); 45 } 46 if (dwp->dw_hashsz <= 0) { 47 mdb_warn("invalid 'nc_hashsz' value\n"); 48 mdb_free(dwp, sizeof (dnlc_walk_t)); 49 return (WALK_ERR); 50 } 51 if (mdb_readvar(&dwp->dw_hash, "nc_hash") == -1) { 52 mdb_warn("failed to read 'nc_hash'\n"); 53 mdb_free(dwp, sizeof (dnlc_walk_t)); 54 return (WALK_ERR); 55 } 56 57 wsp->walk_data = dwp; 58 return (WALK_NEXT); 59 } 60 61 int 62 dnlc_walk_step(mdb_walk_state_t *wsp) 63 { 64 dnlc_walk_t *dwp = wsp->walk_data; 65 nc_hash_t hash; 66 uintptr_t result, addr = wsp->walk_addr; 67 68 next: 69 while (addr == dwp->dw_head || addr == NULL) { 70 if (dwp->dw_index >= dwp->dw_hashsz) { 71 return (WALK_DONE); 72 } 73 dwp->dw_head = dwp->dw_hash + 74 (sizeof (nc_hash_t) * dwp->dw_index); 75 if (mdb_vread(&hash, sizeof (hash), dwp->dw_head) == -1) { 76 mdb_warn("failed to read nc_hash_t at %#lx", 77 dwp->dw_hash); 78 return (WALK_ERR); 79 } 80 dwp->dw_index++; 81 addr = (uintptr_t)hash.hash_next; 82 } 83 84 result = addr; 85 if (mdb_vread(&addr, sizeof (uintptr_t), addr) == -1) { 86 /* 87 * This entry may have become bogus since acquiring the address 88 * from its neighbor. Continue on if that is the case. 89 */ 90 addr = NULL; 91 goto next; 92 } 93 wsp->walk_addr = addr; 94 95 return (wsp->walk_callback(result, &result, wsp->walk_cbdata)); 96 } 97 98 void 99 dnlc_walk_fini(mdb_walk_state_t *wsp) 100 { 101 dnlc_walk_t *dwp = wsp->walk_data; 102 103 mdb_free(dwp, sizeof (dnlc_walk_t)); 104 } 105