drgn/libdrgn/cfi.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

107 lines
2.9 KiB
C
Raw Normal View History

// Copyright (c) Facebook, Inc. and its affiliates.
// SPDX-License-Identifier: GPL-3.0+
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "cfi.h"
const struct drgn_cfi_row drgn_empty_cfi_row_impl;
bool drgn_cfi_row_copy(struct drgn_cfi_row **dst,
const struct drgn_cfi_row *src)
{
if (src->num_regs + 1 > (*dst)->allocated_rules) {
if ((*dst)->allocated_rules == 0 && src->allocated_rules == 0) {
*dst = (struct drgn_cfi_row *)src;
return true;
}
struct drgn_cfi_row *tmp =
malloc(sizeof(struct drgn_cfi_row) +
src->num_regs * sizeof(struct drgn_cfi_rule));
if (!tmp)
return false;
tmp->allocated_rules = src->num_regs + 1;
drgn_cfi_row_destroy(*dst);
*dst = tmp;
}
(*dst)->num_regs = src->num_regs;
(*dst)->cfa_rule = src->cfa_rule;
memcpy((*dst)->reg_rules, src->reg_rules,
(*dst)->num_regs * sizeof((*dst)->reg_rules[0]));
return true;
}
static bool drgn_cfi_row_reserve(struct drgn_cfi_row **row, uint16_t num_rules)
{
if ((*row)->allocated_rules < num_rules) {
if (num_rules < (*row)->num_regs + 1)
num_rules = (*row)->num_regs + 1;
size_t size;
if (__builtin_mul_overflow((uint16_t)(num_rules - 1),
sizeof(struct drgn_cfi_rule),
&size) ||
__builtin_add_overflow(sizeof(struct drgn_cfi_row), size,
&size))
return false;
struct drgn_cfi_row *tmp;
if ((*row)->allocated_rules == 0) {
tmp = malloc(size);
if (!tmp)
return false;
tmp->num_regs = (*row)->num_regs;
tmp->cfa_rule = (*row)->cfa_rule;
memcpy(tmp->reg_rules, (*row)->reg_rules,
tmp->num_regs * sizeof(tmp->reg_rules[0]));
} else {
tmp = realloc(*row, size);
if (!tmp)
return false;
}
tmp->allocated_rules = num_rules;
*row = tmp;
}
return true;
}
bool drgn_cfi_row_set_cfa(struct drgn_cfi_row **row,
const struct drgn_cfi_rule *rule)
{
assert(rule->kind != DRGN_CFI_RULE_AT_CFA_PLUS_OFFSET);
assert(rule->kind != DRGN_CFI_RULE_CFA_PLUS_OFFSET);
if (!drgn_cfi_row_reserve(row, 1))
return false;
(*row)->cfa_rule = *rule;
return true;
}
void drgn_cfi_row_get_register(const struct drgn_cfi_row *row,
drgn_register_number regno,
struct drgn_cfi_rule *ret)
{
if (regno < row->num_regs)
*ret = row->reg_rules[regno];
else
ret->kind = DRGN_CFI_RULE_UNDEFINED;
}
bool drgn_cfi_row_set_register(struct drgn_cfi_row **row,
drgn_register_number regno,
const struct drgn_cfi_rule *rule)
{
assert(regno <= DRGN_MAX_REGISTER_NUMBER);
if (!drgn_cfi_row_reserve(row, regno + 2))
return false;
if (regno >= (*row)->num_regs) {
static_assert(DRGN_CFI_RULE_UNDEFINED == 0,
"DRGN_CFI_RULE_UNDEFINED must be zero");
memset(&(*row)->reg_rules[(*row)->num_regs], 0,
(regno - (*row)->num_regs) *
sizeof((*row)->reg_rules[0]));
(*row)->num_regs = regno + 1;
}
(*row)->reg_rules[regno] = *rule;
return true;
}