mirror of https://github.com/crash-utility/crash
616 lines
17 KiB
C
616 lines
17 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Maple Tree implementation
|
|
* Copyright (c) 2018-2022 Oracle Corporation
|
|
* Authors: Liam R. Howlett <Liam.Howlett@oracle.com>
|
|
* Matthew Wilcox <willy@infradead.org>
|
|
*
|
|
* The following are copied and modified from lib/maple_tree.c
|
|
*/
|
|
|
|
#include "maple_tree.h"
|
|
#include "defs.h"
|
|
|
|
unsigned char *mt_slots = NULL;
|
|
unsigned char *mt_pivots = NULL;
|
|
ulong mt_max[4] = {0};
|
|
|
|
#define MAPLE_BUFSIZE 512
|
|
|
|
static inline ulong mte_to_node(ulong maple_enode_entry)
|
|
{
|
|
return maple_enode_entry & ~MAPLE_NODE_MASK;
|
|
}
|
|
|
|
static inline enum maple_type mte_node_type(ulong maple_enode_entry)
|
|
{
|
|
return (maple_enode_entry >> MAPLE_NODE_TYPE_SHIFT) &
|
|
MAPLE_NODE_TYPE_MASK;
|
|
}
|
|
|
|
static inline ulong mt_slot(void **slots, unsigned char offset)
|
|
{
|
|
return (ulong)slots[offset];
|
|
}
|
|
|
|
static inline bool ma_is_leaf(const enum maple_type type)
|
|
{
|
|
return type < maple_range_64;
|
|
}
|
|
|
|
/*************** For cmd_tree ********************/
|
|
|
|
struct do_maple_tree_info {
|
|
ulong maxcount;
|
|
ulong count;
|
|
void *data;
|
|
};
|
|
|
|
struct maple_tree_ops {
|
|
void (*entry)(ulong node, ulong slot, const char *path,
|
|
ulong index, void *private);
|
|
void *private;
|
|
bool is_td;
|
|
};
|
|
|
|
static const char spaces[] = " ";
|
|
|
|
static void do_mt_range64(ulong, ulong, ulong, uint, char *, ulong *,
|
|
struct maple_tree_ops *);
|
|
static void do_mt_arange64(ulong, ulong, ulong, uint, char *, ulong *,
|
|
struct maple_tree_ops *);
|
|
static void do_mt_entry(ulong, ulong, ulong, uint, uint, char *, ulong *,
|
|
struct maple_tree_ops *);
|
|
static void do_mt_node(ulong, ulong, ulong, uint, char *, ulong *,
|
|
struct maple_tree_ops *);
|
|
struct req_entry *fill_member_offsets(char *);
|
|
void dump_struct_members_fast(struct req_entry *, int, ulong);
|
|
void dump_struct_members_for_tree(struct tree_data *, int, ulong);
|
|
|
|
static void mt_dump_range(ulong min, ulong max, uint depth)
|
|
{
|
|
if (min == max)
|
|
fprintf(fp, "%.*s%lu: ", depth * 2, spaces, min);
|
|
else
|
|
fprintf(fp, "%.*s%lu-%lu: ", depth * 2, spaces, min, max);
|
|
}
|
|
|
|
static inline bool mt_is_reserved(ulong entry)
|
|
{
|
|
return (entry < MAPLE_RESERVED_RANGE) && xa_is_internal(entry);
|
|
}
|
|
|
|
static inline bool mte_is_leaf(ulong maple_enode_entry)
|
|
{
|
|
return ma_is_leaf(mte_node_type(maple_enode_entry));
|
|
}
|
|
|
|
static uint mt_height(char *mt_buf)
|
|
{
|
|
return (UINT(mt_buf + OFFSET(maple_tree_ma_flags)) &
|
|
MT_FLAGS_HEIGHT_MASK)
|
|
>> MT_FLAGS_HEIGHT_OFFSET;
|
|
}
|
|
|
|
static void dump_mt_range64(char *mr64_buf)
|
|
{
|
|
int i;
|
|
|
|
fprintf(fp, " contents: ");
|
|
for (i = 0; i < mt_slots[maple_range_64] - 1; i++)
|
|
fprintf(fp, "%p %lu ",
|
|
VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot)
|
|
+ sizeof(void *) * i),
|
|
ULONG(mr64_buf + OFFSET(maple_range_64_pivot)
|
|
+ sizeof(ulong) * i));
|
|
fprintf(fp, "%p\n", VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot)
|
|
+ sizeof(void *) * i));
|
|
}
|
|
|
|
static void dump_mt_arange64(char *ma64_buf)
|
|
{
|
|
int i;
|
|
|
|
fprintf(fp, " contents: ");
|
|
for (i = 0; i < mt_slots[maple_arange_64]; i++)
|
|
fprintf(fp, "%lu ", ULONG(ma64_buf + OFFSET(maple_arange_64_gap)
|
|
+ sizeof(ulong) * i));
|
|
|
|
fprintf(fp, "| %02X %02X| ",
|
|
UCHAR(ma64_buf + OFFSET(maple_arange_64_meta) +
|
|
OFFSET(maple_metadata_end)),
|
|
UCHAR(ma64_buf + OFFSET(maple_arange_64_meta) +
|
|
OFFSET(maple_metadata_gap)));
|
|
|
|
for (i = 0; i < mt_slots[maple_arange_64] - 1; i++)
|
|
fprintf(fp, "%p %lu ",
|
|
VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
|
|
sizeof(void *) * i),
|
|
ULONG(ma64_buf + OFFSET(maple_arange_64_pivot) +
|
|
sizeof(ulong) * i));
|
|
fprintf(fp, "%p\n", VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
|
|
sizeof(void *) * i));
|
|
}
|
|
|
|
static void dump_mt_entry(ulong entry, ulong min, ulong max, uint depth)
|
|
{
|
|
mt_dump_range(min, max, depth);
|
|
|
|
if (xa_is_value(entry))
|
|
fprintf(fp, "value %ld (0x%lx) [0x%lx]\n", xa_to_value(entry),
|
|
xa_to_value(entry), entry);
|
|
else if (xa_is_zero(entry))
|
|
fprintf(fp, "zero (%ld)\n", xa_to_internal(entry));
|
|
else if (mt_is_reserved(entry))
|
|
fprintf(fp, "UNKNOWN ENTRY (0x%lx)\n", entry);
|
|
else
|
|
fprintf(fp, "0x%lx\n", entry);
|
|
}
|
|
|
|
static void dump_mt_node(ulong maple_node, char *node_data, uint type,
|
|
ulong min, ulong max, uint depth)
|
|
{
|
|
mt_dump_range(min, max, depth);
|
|
|
|
fprintf(fp, "node 0x%lx depth %d type %d parent %p",
|
|
maple_node, depth, type,
|
|
maple_node ? VOID_PTR(node_data + OFFSET(maple_node_parent)) :
|
|
NULL);
|
|
}
|
|
|
|
static void do_mt_range64(ulong entry, ulong min, ulong max,
|
|
uint depth, char *path, ulong *global_index,
|
|
struct maple_tree_ops *ops)
|
|
{
|
|
ulong maple_node_m_node = mte_to_node(entry);
|
|
char node_buf[MAPLE_BUFSIZE];
|
|
bool leaf = mte_is_leaf(entry);
|
|
ulong first = min, last;
|
|
int i;
|
|
int len = strlen(path);
|
|
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
|
|
char *mr64_buf;
|
|
|
|
if (SIZE(maple_node) > MAPLE_BUFSIZE)
|
|
error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
|
|
|
|
readmem(maple_node_m_node, KVADDR, node_buf, SIZE(maple_node),
|
|
"mt_dump_range64 read maple_node", FAULT_ON_ERROR);
|
|
|
|
mr64_buf = node_buf + OFFSET(maple_node_mr64);
|
|
|
|
if (td && td->flags & TREE_STRUCT_VERBOSE) {
|
|
dump_mt_range64(mr64_buf);
|
|
}
|
|
|
|
for (i = 0; i < mt_slots[maple_range_64]; i++) {
|
|
last = max;
|
|
|
|
if (i < (mt_slots[maple_range_64] - 1))
|
|
last = ULONG(mr64_buf + OFFSET(maple_range_64_pivot) +
|
|
sizeof(ulong) * i);
|
|
|
|
else if (!VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot) +
|
|
sizeof(void *) * i) &&
|
|
max != mt_max[mte_node_type(entry)])
|
|
break;
|
|
if (last == 0 && i > 0)
|
|
break;
|
|
if (leaf)
|
|
do_mt_entry(mt_slot((void **)(mr64_buf +
|
|
OFFSET(maple_range_64_slot)), i),
|
|
first, last, depth + 1, i, path, global_index, ops);
|
|
else if (VOID_PTR(mr64_buf + OFFSET(maple_range_64_slot) +
|
|
sizeof(void *) * i)) {
|
|
sprintf(path + len, "/%d", i);
|
|
do_mt_node(mt_slot((void **)(mr64_buf +
|
|
OFFSET(maple_range_64_slot)), i),
|
|
first, last, depth + 1, path, global_index, ops);
|
|
}
|
|
|
|
if (last == max)
|
|
break;
|
|
if (last > max) {
|
|
fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
|
|
mr64_buf, last, max, i);
|
|
break;
|
|
}
|
|
first = last + 1;
|
|
}
|
|
}
|
|
|
|
static void do_mt_arange64(ulong entry, ulong min, ulong max,
|
|
uint depth, char *path, ulong *global_index,
|
|
struct maple_tree_ops *ops)
|
|
{
|
|
ulong maple_node_m_node = mte_to_node(entry);
|
|
char node_buf[MAPLE_BUFSIZE];
|
|
bool leaf = mte_is_leaf(entry);
|
|
ulong first = min, last;
|
|
int i;
|
|
int len = strlen(path);
|
|
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
|
|
char *ma64_buf;
|
|
|
|
if (SIZE(maple_node) > MAPLE_BUFSIZE)
|
|
error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
|
|
|
|
readmem(maple_node_m_node, KVADDR, node_buf, SIZE(maple_node),
|
|
"mt_dump_arange64 read maple_node", FAULT_ON_ERROR);
|
|
|
|
ma64_buf = node_buf + OFFSET(maple_node_ma64);
|
|
|
|
if (td && td->flags & TREE_STRUCT_VERBOSE) {
|
|
dump_mt_arange64(ma64_buf);
|
|
}
|
|
|
|
for (i = 0; i < mt_slots[maple_arange_64]; i++) {
|
|
last = max;
|
|
|
|
if (i < (mt_slots[maple_arange_64] - 1))
|
|
last = ULONG(ma64_buf + OFFSET(maple_arange_64_pivot) +
|
|
sizeof(ulong) * i);
|
|
else if (!VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
|
|
sizeof(void *) * i))
|
|
break;
|
|
if (last == 0 && i > 0)
|
|
break;
|
|
|
|
if (leaf)
|
|
do_mt_entry(mt_slot((void **)(ma64_buf +
|
|
OFFSET(maple_arange_64_slot)), i),
|
|
first, last, depth + 1, i, path, global_index, ops);
|
|
else if (VOID_PTR(ma64_buf + OFFSET(maple_arange_64_slot) +
|
|
sizeof(void *) * i)) {
|
|
sprintf(path + len, "/%d", i);
|
|
do_mt_node(mt_slot((void **)(ma64_buf +
|
|
OFFSET(maple_arange_64_slot)), i),
|
|
first, last, depth + 1, path, global_index, ops);
|
|
}
|
|
|
|
if (last == max)
|
|
break;
|
|
if (last > max) {
|
|
fprintf(fp, "node %p last (%lu) > max (%lu) at pivot %d!\n",
|
|
ma64_buf, last, max, i);
|
|
break;
|
|
}
|
|
first = last + 1;
|
|
}
|
|
}
|
|
|
|
static void do_mt_entry(ulong entry, ulong min, ulong max, uint depth,
|
|
uint index, char *path, ulong *global_index,
|
|
struct maple_tree_ops *ops)
|
|
{
|
|
int print_radix = 0, i;
|
|
static struct req_entry **e = NULL;
|
|
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
|
|
|
|
if (ops->entry && entry)
|
|
ops->entry(entry, entry, path, max, ops->private);
|
|
|
|
if (!td)
|
|
return;
|
|
|
|
if (!td->count && td->structname_args) {
|
|
/*
|
|
* Retrieve all members' info only once (count == 0)
|
|
* After last iteration all memory will be freed up
|
|
*/
|
|
e = (struct req_entry **)GETBUF(sizeof(*e) * td->structname_args);
|
|
for (i = 0; i < td->structname_args; i++)
|
|
e[i] = fill_member_offsets(td->structname[i]);
|
|
}
|
|
|
|
td->count++;
|
|
|
|
if (td->flags & TREE_STRUCT_VERBOSE) {
|
|
dump_mt_entry(entry, min, max, depth);
|
|
} else if (td->flags & VERBOSE && entry)
|
|
fprintf(fp, "%lx\n", entry);
|
|
if (td->flags & TREE_POSITION_DISPLAY && entry)
|
|
fprintf(fp, " index: %ld position: %s/%u\n",
|
|
++(*global_index), path, index);
|
|
|
|
if (td->structname && entry) {
|
|
if (td->flags & TREE_STRUCT_RADIX_10)
|
|
print_radix = 10;
|
|
else if (td->flags & TREE_STRUCT_RADIX_16)
|
|
print_radix = 16;
|
|
else
|
|
print_radix = 0;
|
|
|
|
for (i = 0; i < td->structname_args; i++) {
|
|
switch (count_chars(td->structname[i], '.')) {
|
|
case 0:
|
|
dump_struct(td->structname[i], entry, print_radix);
|
|
break;
|
|
default:
|
|
if (td->flags & TREE_PARSE_MEMBER)
|
|
dump_struct_members_for_tree(td, i, entry);
|
|
else if (td->flags & TREE_READ_MEMBER)
|
|
dump_struct_members_fast(e[i], print_radix, entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (e)
|
|
FREEBUF(e);
|
|
}
|
|
|
|
static void do_mt_node(ulong entry, ulong min, ulong max,
|
|
uint depth, char *path, ulong *global_index,
|
|
struct maple_tree_ops *ops)
|
|
{
|
|
ulong maple_node = mte_to_node(entry);
|
|
uint type = mte_node_type(entry);
|
|
uint i;
|
|
char node_buf[MAPLE_BUFSIZE];
|
|
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
|
|
|
|
if (SIZE(maple_node) > MAPLE_BUFSIZE)
|
|
error(FATAL, "MAPLE_BUFSIZE should be larger than maple_node struct");
|
|
|
|
readmem(maple_node, KVADDR, node_buf, SIZE(maple_node),
|
|
"mt_dump_node read maple_node", FAULT_ON_ERROR);
|
|
|
|
if (td && td->flags & TREE_STRUCT_VERBOSE) {
|
|
dump_mt_node(maple_node, node_buf, type, min, max, depth);
|
|
}
|
|
|
|
switch (type) {
|
|
case maple_dense:
|
|
for (i = 0; i < mt_slots[maple_dense]; i++) {
|
|
if (min + i > max)
|
|
fprintf(fp, "OUT OF RANGE: ");
|
|
do_mt_entry(mt_slot((void **)(node_buf + OFFSET(maple_node_slot)), i),
|
|
min + i, min + i, depth, i, path, global_index, ops);
|
|
}
|
|
break;
|
|
case maple_leaf_64:
|
|
case maple_range_64:
|
|
do_mt_range64(entry, min, max, depth, path, global_index, ops);
|
|
break;
|
|
case maple_arange_64:
|
|
do_mt_arange64(entry, min, max, depth, path, global_index, ops);
|
|
break;
|
|
default:
|
|
fprintf(fp, " UNKNOWN TYPE\n");
|
|
}
|
|
}
|
|
|
|
static int do_maple_tree_traverse(ulong ptr, int is_root,
|
|
struct maple_tree_ops *ops)
|
|
{
|
|
char path[BUFSIZE] = {0};
|
|
char tree_buf[MAPLE_BUFSIZE];
|
|
ulong entry;
|
|
struct tree_data *td = ops->is_td ? (struct tree_data *)ops->private : NULL;
|
|
ulong global_index = 0;
|
|
|
|
if (SIZE(maple_tree) > MAPLE_BUFSIZE)
|
|
error(FATAL, "MAPLE_BUFSIZE should be larger than maple_tree struct");
|
|
|
|
if (!is_root) {
|
|
strcpy(path, "direct");
|
|
do_mt_node(ptr, 0, mt_max[mte_node_type(ptr)],
|
|
0, path, &global_index, ops);
|
|
} else {
|
|
readmem(ptr, KVADDR, tree_buf, SIZE(maple_tree),
|
|
"mt_dump read maple_tree", FAULT_ON_ERROR);
|
|
entry = ULONG(tree_buf + OFFSET(maple_tree_ma_root));
|
|
|
|
if (td && td->flags & TREE_STRUCT_VERBOSE) {
|
|
fprintf(fp, "maple_tree(%lx) flags %X, height %u root 0x%lx\n\n",
|
|
ptr, UINT(tree_buf + OFFSET(maple_tree_ma_flags)),
|
|
mt_height(tree_buf), entry);
|
|
}
|
|
|
|
if (!xa_is_node(entry))
|
|
do_mt_entry(entry, 0, 0, 0, 0, path, &global_index, ops);
|
|
else if (entry) {
|
|
strcpy(path, "root");
|
|
do_mt_node(entry, 0, mt_max[mte_node_type(entry)], 0,
|
|
path, &global_index, ops);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int do_mptree(struct tree_data *td)
|
|
{
|
|
struct maple_tree_ops ops = {
|
|
.entry = NULL,
|
|
.private = td,
|
|
.is_td = true,
|
|
};
|
|
|
|
int is_root = !(td->flags & TREE_NODE_POINTER);
|
|
|
|
do_maple_tree_traverse(td->start, is_root, &ops);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/************* For do_maple_tree *****************/
|
|
static void do_maple_tree_count(ulong node, ulong slot, const char *path,
|
|
ulong index, void *private)
|
|
{
|
|
struct do_maple_tree_info *info = private;
|
|
info->count++;
|
|
}
|
|
|
|
static void do_maple_tree_search(ulong node, ulong slot, const char *path,
|
|
ulong index, void *private)
|
|
{
|
|
struct do_maple_tree_info *info = private;
|
|
struct list_pair *lp = info->data;
|
|
|
|
if (lp->index == index) {
|
|
lp->value = (void *)slot;
|
|
info->count = 1;
|
|
}
|
|
}
|
|
|
|
static void do_maple_tree_dump(ulong node, ulong slot, const char *path,
|
|
ulong index, void *private)
|
|
{
|
|
struct do_maple_tree_info *info = private;
|
|
fprintf(fp, "[%lu] %lx\n", index, slot);
|
|
info->count++;
|
|
}
|
|
|
|
static void do_maple_tree_gather(ulong node, ulong slot, const char *path,
|
|
ulong index, void *private)
|
|
{
|
|
struct do_maple_tree_info *info = private;
|
|
struct list_pair *lp = info->data;
|
|
|
|
if (info->maxcount) {
|
|
lp[info->count].index = index;
|
|
lp[info->count].value = (void *)slot;
|
|
|
|
info->count++;
|
|
info->maxcount--;
|
|
}
|
|
}
|
|
|
|
static void do_maple_tree_dump_cb(ulong node, ulong slot, const char *path,
|
|
ulong index, void *private)
|
|
{
|
|
struct do_maple_tree_info *info = private;
|
|
struct list_pair *lp = info->data;
|
|
int (*cb)(ulong) = lp->value;
|
|
|
|
/* Caller defined operation */
|
|
if (!cb(slot)) {
|
|
error(FATAL, "do_maple_tree: callback "
|
|
"operation failed: entry: %ld item: %lx\n",
|
|
info->count, slot);
|
|
}
|
|
info->count++;
|
|
}
|
|
|
|
/*
|
|
* do_maple_tree argument usage:
|
|
*
|
|
* root: Address of a maple_tree_root structure
|
|
*
|
|
* flag: MAPLE_TREE_COUNT - Return the number of entries in the tree.
|
|
* MAPLE_TREE_SEARCH - Search for an entry at lp->index; if found,
|
|
* store the entry in lp->value and return a count of 1; otherwise
|
|
* return a count of 0.
|
|
* MAPLE_TREE_DUMP - Dump all existing index/value pairs.
|
|
* MAPLE_TREE_GATHER - Store all existing index/value pairs in the
|
|
* passed-in array of list_pair structs starting at lp,
|
|
* returning the count of entries stored; the caller can/should
|
|
* limit the number of returned entries by putting the array size
|
|
* (max count) in the lp->index field of the first structure
|
|
* in the passed-in array.
|
|
* MAPLE_TREE_DUMP_CB - Similar with MAPLE_TREE_DUMP, but for each
|
|
* maple tree entry, a user defined callback at lp->value will
|
|
* be invoked.
|
|
*
|
|
* lp: Unused by MAPLE_TREE_COUNT and MAPLE_TREE_DUMP.
|
|
* A pointer to a list_pair structure for MAPLE_TREE_SEARCH.
|
|
* A pointer to an array of list_pair structures for
|
|
* MAPLE_TREE_GATHER; the dimension (max count) of the array may
|
|
* be stored in the index field of the first structure to avoid
|
|
* any chance of an overrun.
|
|
* For MAPLE_TREE_DUMP_CB, the lp->value must be initialized as a
|
|
* callback function. The callback prototype must be: int (*)(ulong);
|
|
*/
|
|
ulong
|
|
do_maple_tree(ulong root, int flag, struct list_pair *lp)
|
|
{
|
|
struct do_maple_tree_info info = {
|
|
.count = 0,
|
|
.data = lp,
|
|
};
|
|
struct maple_tree_ops ops = {
|
|
.private = &info,
|
|
.is_td = false,
|
|
};
|
|
|
|
switch (flag)
|
|
{
|
|
case MAPLE_TREE_COUNT:
|
|
ops.entry = do_maple_tree_count;
|
|
break;
|
|
|
|
case MAPLE_TREE_SEARCH:
|
|
ops.entry = do_maple_tree_search;
|
|
break;
|
|
|
|
case MAPLE_TREE_DUMP:
|
|
ops.entry = do_maple_tree_dump;
|
|
break;
|
|
|
|
case MAPLE_TREE_GATHER:
|
|
if (!(info.maxcount = lp->index))
|
|
info.maxcount = (ulong)(-1); /* caller beware */
|
|
|
|
ops.entry = do_maple_tree_gather;
|
|
break;
|
|
|
|
case MAPLE_TREE_DUMP_CB:
|
|
if (lp->value == NULL) {
|
|
error(FATAL, "do_maple_tree: need set callback function");
|
|
}
|
|
ops.entry = do_maple_tree_dump_cb;
|
|
break;
|
|
|
|
default:
|
|
error(FATAL, "do_maple_tree: invalid flag: %lx\n", flag);
|
|
}
|
|
|
|
do_maple_tree_traverse(root, true, &ops);
|
|
return info.count;
|
|
}
|
|
|
|
/***********************************************/
|
|
void maple_init(void)
|
|
{
|
|
int array_len;
|
|
|
|
STRUCT_SIZE_INIT(maple_tree, "maple_tree");
|
|
STRUCT_SIZE_INIT(maple_node, "maple_node");
|
|
|
|
MEMBER_OFFSET_INIT(maple_tree_ma_root, "maple_tree", "ma_root");
|
|
MEMBER_OFFSET_INIT(maple_tree_ma_flags, "maple_tree", "ma_flags");
|
|
|
|
MEMBER_OFFSET_INIT(maple_node_parent, "maple_node", "parent");
|
|
MEMBER_OFFSET_INIT(maple_node_ma64, "maple_node", "ma64");
|
|
MEMBER_OFFSET_INIT(maple_node_mr64, "maple_node", "mr64");
|
|
MEMBER_OFFSET_INIT(maple_node_slot, "maple_node", "slot");
|
|
|
|
MEMBER_OFFSET_INIT(maple_arange_64_pivot, "maple_arange_64", "pivot");
|
|
MEMBER_OFFSET_INIT(maple_arange_64_slot, "maple_arange_64", "slot");
|
|
MEMBER_OFFSET_INIT(maple_arange_64_gap, "maple_arange_64", "gap");
|
|
MEMBER_OFFSET_INIT(maple_arange_64_meta, "maple_arange_64", "meta");
|
|
|
|
MEMBER_OFFSET_INIT(maple_range_64_pivot, "maple_range_64", "pivot");
|
|
MEMBER_OFFSET_INIT(maple_range_64_slot, "maple_range_64", "slot");
|
|
|
|
MEMBER_OFFSET_INIT(maple_metadata_end, "maple_metadata", "end");
|
|
MEMBER_OFFSET_INIT(maple_metadata_gap, "maple_metadata", "gap");
|
|
|
|
array_len = get_array_length("mt_slots", NULL, sizeof(char));
|
|
mt_slots = calloc(array_len, sizeof(char));
|
|
readmem(symbol_value("mt_slots"), KVADDR, mt_slots,
|
|
array_len * sizeof(char), "maple_init read mt_slots",
|
|
RETURN_ON_ERROR);
|
|
|
|
array_len = get_array_length("mt_pivots", NULL, sizeof(char));
|
|
mt_pivots = calloc(array_len, sizeof(char));
|
|
readmem(symbol_value("mt_pivots"), KVADDR, mt_pivots,
|
|
array_len * sizeof(char), "maple_init read mt_pivots",
|
|
RETURN_ON_ERROR);
|
|
|
|
mt_max[maple_dense] = mt_slots[maple_dense];
|
|
mt_max[maple_leaf_64] = ULONG_MAX;
|
|
mt_max[maple_range_64] = ULONG_MAX;
|
|
mt_max[maple_arange_64] = ULONG_MAX;
|
|
}
|