#include <sys/types.h>
#include <assert.h>
#include <stdlib.h>
#include "rcapd_mapping.h"
#include "utils.h"
typedef struct lmapping_find_cb_arg {
uintptr_t lmfa_addr;
size_t lmfa_size;
lmapping_t *lmfa_prior;
lmapping_t *lmfa_ret;
} lmapping_find_cb_arg_t;
#ifdef DEBUG
static void
lmapping_verify(lmapping_t *lm)
{
while (lm != NULL) {
if (lm->lm_next != NULL)
ASSERT(lm->lm_next->lm_addr > lm->lm_addr);
lm = lm->lm_next;
}
}
#else
#define lmapping_verify(x) ((void)0)
#endif
static int
lmapping_find_cb(lmapping_t *lm, void *arg)
{
lmapping_find_cb_arg_t *lmfa = arg;
if (lm->lm_addr >= lmfa->lmfa_addr) {
if (lmfa->lmfa_addr == lm->lm_addr && lmfa->lmfa_size ==
lm->lm_size)
lmfa->lmfa_ret = lm;
return (1);
} else
lmfa->lmfa_prior = lm;
return (0);
}
static void
lmapping_walk(lmapping_t *lm, int(*lmapping_walk_cb)(lmapping_t *, void *),
void *arg)
{
lmapping_t *next;
while (lm != NULL) {
next = lm->lm_next;
lmapping_verify(lm);
if (lmapping_walk_cb(lm, arg) != 0) {
lmapping_verify(lm);
return;
}
lm = next;
}
}
int
lmapping_remove(lmapping_t **lm, uintptr_t addr, size_t size)
{
lmapping_find_cb_arg_t lmfa;
lmfa.lmfa_addr = addr;
lmfa.lmfa_size = size;
lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
lmapping_verify(*lm);
lmapping_walk(*lm, lmapping_find_cb, &lmfa);
if (lmfa.lmfa_ret == NULL)
return (-1);
if (lmfa.lmfa_prior != NULL)
lmfa.lmfa_prior->lm_next = lmfa.lmfa_ret->lm_next;
else if (*lm == lmfa.lmfa_ret)
*lm = lmfa.lmfa_ret->lm_next;
free(lmfa.lmfa_ret);
lmapping_verify(*lm);
return (0);
}
int
lmapping_insert(lmapping_t **lm, uintptr_t addr, size_t size)
{
lmapping_find_cb_arg_t lmfa;
lmapping_t *cur;
cur = malloc(sizeof (*cur));
if (cur == NULL)
return (-1);
cur->lm_addr = addr;
cur->lm_size = size;
cur->lm_next = NULL;
lmfa.lmfa_addr = addr;
lmfa.lmfa_size = size;
lmfa.lmfa_prior = lmfa.lmfa_ret = NULL;
lmapping_verify(*lm);
lmapping_walk(*lm, lmapping_find_cb, &lmfa);
ASSERT(lmfa.lmfa_ret == NULL);
if (lmfa.lmfa_prior != NULL) {
cur->lm_next = lmfa.lmfa_prior->lm_next;
lmfa.lmfa_prior->lm_next = cur;
} else {
cur->lm_next = *lm;
*lm = cur;
}
lmapping_verify(*lm);
return (0);
}
int
lmapping_contains(lmapping_t *lm, uintptr_t addr, size_t size)
{
lmapping_find_cb_arg_t lmfa;
lmfa.lmfa_addr = addr;
lmfa.lmfa_size = size;
lmfa.lmfa_ret = NULL;
lmapping_walk(lm, lmapping_find_cb, &lmfa);
return (lmfa.lmfa_ret != NULL);
}
static int
lmapping_free_cb(lmapping_t *lm, void *arg)
{
free(lm);
return (0);
}
void
lmapping_free(lmapping_t **lm)
{
lmapping_walk(*lm, lmapping_free_cb, NULL);
*lm = NULL;
}
#ifdef DEBUG
int
lmapping_dump_diff(lmapping_t *lm1, lmapping_t *lm2)
{
lmapping_t **lmv;
int res = 0;
int ch = 0;
int label_printed = 0;
#define OUTPUT_LABEL() \
if (label_printed == 0) { \
debug("changes in mappings:\n"); \
label_printed++; \
}
while (lm1 != NULL && lm2 != NULL) {
if ((lm1->lm_addr != lm2->lm_addr) || (lm1->lm_size !=
lm2->lm_size)) {
res = -1;
if (lm1->lm_addr == lm2->lm_addr && lm1->lm_size <
lm2->lm_size || lm1->lm_addr < lm2->lm_addr) {
lmv = &lm1;
ch = '-';
} else {
lmv = &lm2;
ch = '+';
}
OUTPUT_LABEL();
debug("%c%p+0x%llx\n", ch, (void *)(*lmv)->lm_addr,
(long long)(*lmv)->lm_size);
*lmv = (*lmv)->lm_next;
} else {
lm1 = lm1->lm_next;
lm2 = lm2->lm_next;
}
}
while (lm1 != NULL) {
OUTPUT_LABEL();
debug("%c%p+0x%llx\n", '-', (void *)lm1->lm_addr,
(unsigned long long)lm1->lm_size);
lm1 = lm1->lm_next;
res = 1;
}
while (lm2 != NULL) {
OUTPUT_LABEL();
debug("%c%p+0x%llx\n", '+', (void *)lm2->lm_addr,
(long long)lm2->lm_size);
lm2 = lm2->lm_next;
res = 1;
}
return (res);
#undef OUTPUT_LABEL
}
#endif