-
Notifications
You must be signed in to change notification settings - Fork 92
/
debug_reg_printer.c
109 lines (90 loc) · 3.24 KB
/
debug_reg_printer.c
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
107
108
109
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdio.h>
#include <inttypes.h>
#include <assert.h>
#include <stdarg.h>
#include "debug_reg_printer.h"
static unsigned int get_len_or_sprintf(char *buf, unsigned int curr, const char *format, ...)
{
assert(format);
va_list args;
int length;
va_start(args, format);
if (buf)
length = vsprintf(buf + curr, format, args);
else
length = vsnprintf(NULL, 0, format, args);
va_end(args);
assert(length >= 0);
return (unsigned int)length;
}
static unsigned int print_number(char *buf, unsigned int offset, uint64_t value)
{
const char * const format = value > 9 ? "0x%" PRIx64 : "%" PRIx64;
return get_len_or_sprintf(buf, offset, format, value);
}
static unsigned int riscv_debug_reg_field_value_to_s(char *buf, unsigned int offset,
const char * const *field_value_names, uint64_t field_value)
{
const char * const field_value_name = field_value_names ?
field_value_names[field_value] :
NULL;
if (!field_value_name)
return print_number(buf, offset, field_value);
return get_len_or_sprintf(buf, offset, "%s", field_value_name);
}
static unsigned int riscv_debug_reg_field_to_s(char *buf, unsigned int offset,
riscv_debug_reg_field_info_t field, riscv_debug_reg_ctx_t context,
uint64_t field_value)
{
const unsigned int name_len = get_len_or_sprintf(buf, offset, "%s=", field.name);
return name_len + riscv_debug_reg_field_value_to_s(buf, offset + name_len,
field.values, field_value);
}
static uint64_t riscv_debug_reg_field_value(riscv_debug_reg_field_info_t field, uint64_t value)
{
assert(field.msb < 64);
assert(field.msb >= field.lsb);
const uint64_t trailing_ones_mask = (uint64_t)(-1) >> (63 - field.msb);
return (value & trailing_ones_mask) >> field.lsb;
}
static unsigned int riscv_debug_reg_fields_to_s(char *buf, unsigned int offset,
struct riscv_debug_reg_field_list_t (*get_next)(riscv_debug_reg_ctx_t contex),
riscv_debug_reg_ctx_t context, uint64_t value,
enum riscv_debug_reg_show show)
{
unsigned int curr = offset;
curr += get_len_or_sprintf(buf, curr, " {");
char *separator = "";
for (struct riscv_debug_reg_field_list_t list; get_next; get_next = list.get_next) {
list = get_next(context);
uint64_t field_value = riscv_debug_reg_field_value(list.field, value);
if (show == RISCV_DEBUG_REG_SHOW_ALL ||
(show == RISCV_DEBUG_REG_HIDE_UNNAMED_0 &&
(field_value != 0 ||
(list.field.values && list.field.values[0]))) ||
(show == RISCV_DEBUG_REG_HIDE_ALL_0 && field_value != 0)) {
curr += get_len_or_sprintf(buf, curr, separator);
curr += riscv_debug_reg_field_to_s(buf, curr, list.field, context,
field_value);
separator = " ";
}
}
curr += get_len_or_sprintf(buf, curr, "}");
return curr - offset;
}
unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal,
riscv_debug_reg_ctx_t context, uint64_t value,
enum riscv_debug_reg_show show)
{
unsigned int length = 0;
riscv_debug_reg_info_t reg = get_riscv_debug_reg_info(reg_ordinal);
length += get_len_or_sprintf(buf, length, "%s=", reg.name);
length += print_number(buf, length, value);
if (reg.get_fields_head)
length += riscv_debug_reg_fields_to_s(buf, length,
reg.get_fields_head, context, value, show);
if (buf)
buf[length] = '\0';
return length;
}