File: cfi.c

package info (click to toggle)
drgn 0.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 7,852 kB
  • sloc: python: 74,992; ansic: 54,589; awk: 423; makefile: 351; sh: 99
file content (106 lines) | stat: -rw-r--r-- 2,941 bytes parent folder | download | duplicates (3)
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
// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later

#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;
}