mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
libdrgn: add DRGN_FORMAT_OBJECT_CHAR
This commit is contained in:
parent
7cee597fff
commit
89307c532a
@ -797,6 +797,10 @@ Objects
|
||||
For C, this applies to pointers to and arrays of ``char``, ``signed
|
||||
char``, and ``unsigned char``. Defaults to ``True``.
|
||||
:type string: bool or None
|
||||
:param char: Format objects with character type as character literals.
|
||||
For C, this applies to ``char``, ``signed char``, and ``unsigned
|
||||
char``. Defaults to ``False``.
|
||||
:type char: bool or None
|
||||
:rtype: str
|
||||
|
||||
.. function:: NULL(prog, type)
|
||||
|
@ -2005,11 +2005,12 @@ enum drgn_format_object_flags {
|
||||
DRGN_FORMAT_OBJECT_DEREFERENCE = 1 << 0,
|
||||
DRGN_FORMAT_OBJECT_SYMBOLIZE = 1 << 1,
|
||||
DRGN_FORMAT_OBJECT_STRING = 1 << 2,
|
||||
DRGN_FORMAT_OBJECT_CHAR = 1 << 3,
|
||||
/** Default "pretty" flags. */
|
||||
DRGN_FORMAT_OBJECT_PRETTY = (DRGN_FORMAT_OBJECT_DEREFERENCE |
|
||||
DRGN_FORMAT_OBJECT_SYMBOLIZE |
|
||||
DRGN_FORMAT_OBJECT_STRING),
|
||||
DRGN_FORMAT_OBJECT_VALID_FLAGS = (1 << 3) - 1,
|
||||
DRGN_FORMAT_OBJECT_VALID_FLAGS = (1 << 4) - 1,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -127,7 +127,8 @@ static inline enum drgn_format_object_flags
|
||||
drgn_passthrough_format_object_flags(enum drgn_format_object_flags flags)
|
||||
{
|
||||
return (flags & (DRGN_FORMAT_OBJECT_SYMBOLIZE |
|
||||
DRGN_FORMAT_OBJECT_STRING));
|
||||
DRGN_FORMAT_OBJECT_STRING |
|
||||
DRGN_FORMAT_OBJECT_CHAR));
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
@ -584,11 +584,126 @@ c_format_object_impl(const struct drgn_object *obj, bool cast,
|
||||
enum drgn_format_object_flags flags,
|
||||
struct string_builder *sb);
|
||||
|
||||
static bool is_character_type(struct drgn_type *type)
|
||||
{
|
||||
switch (drgn_type_primitive(type)) {
|
||||
case DRGN_C_TYPE_CHAR:
|
||||
case DRGN_C_TYPE_SIGNED_CHAR:
|
||||
case DRGN_C_TYPE_UNSIGNED_CHAR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_format_int_object(const struct drgn_object *obj, struct string_builder *sb)
|
||||
c_format_character(unsigned char c, bool escape_single_quote,
|
||||
bool escape_double_quote, struct string_builder *sb)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
switch (c) {
|
||||
case '\0':
|
||||
ret = string_builder_append(sb, "\\0");
|
||||
break;
|
||||
case '\a':
|
||||
ret = string_builder_append(sb, "\\a");
|
||||
break;
|
||||
case '\b':
|
||||
ret = string_builder_append(sb, "\\b");
|
||||
break;
|
||||
case '\t':
|
||||
ret = string_builder_append(sb, "\\t");
|
||||
break;
|
||||
case '\n':
|
||||
ret = string_builder_append(sb, "\\n");
|
||||
break;
|
||||
case '\v':
|
||||
ret = string_builder_append(sb, "\\v");
|
||||
break;
|
||||
case '\f':
|
||||
ret = string_builder_append(sb, "\\f");
|
||||
break;
|
||||
case '\r':
|
||||
ret = string_builder_append(sb, "\\r");
|
||||
break;
|
||||
case '"':
|
||||
if (!escape_double_quote)
|
||||
goto no_escape;
|
||||
ret = string_builder_append(sb, "\\\"");
|
||||
break;
|
||||
case '\'':
|
||||
if (!escape_single_quote)
|
||||
goto no_escape;
|
||||
ret = string_builder_append(sb, "\\'");
|
||||
break;
|
||||
case '\\':
|
||||
ret = string_builder_append(sb, "\\\\");
|
||||
break;
|
||||
default:
|
||||
if (c <= '\x1f' || c >= '\x7f') {
|
||||
ret = string_builder_appendf(sb, "\\x%02x", c);
|
||||
} else {
|
||||
no_escape:
|
||||
ret = string_builder_appendc(sb, c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret ? NULL : &drgn_enomem;
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_format_string(struct drgn_memory_reader *reader, uint64_t address,
|
||||
uint64_t length, struct string_builder *sb)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
|
||||
if (!string_builder_appendc(sb, '"'))
|
||||
return &drgn_enomem;
|
||||
while (length) {
|
||||
unsigned char c;
|
||||
|
||||
err = drgn_memory_reader_read(reader, &c, address++, 1, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (c == '\0') {
|
||||
break;
|
||||
} else {
|
||||
err = c_format_character(c, false, true, sb);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
length--;
|
||||
}
|
||||
if (!string_builder_appendc(sb, '"'))
|
||||
return &drgn_enomem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_format_int_object(const struct drgn_object *obj,
|
||||
enum drgn_format_object_flags flags,
|
||||
struct string_builder *sb)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
|
||||
if ((flags & DRGN_FORMAT_OBJECT_CHAR) && is_character_type(obj->type)) {
|
||||
union drgn_value value;
|
||||
|
||||
if (!string_builder_appendc(sb, '\''))
|
||||
return &drgn_enomem;
|
||||
err = drgn_object_read_integer(obj, &value);
|
||||
if (err)
|
||||
return err;
|
||||
err = c_format_character(value.uvalue, true, false, sb);
|
||||
if (err)
|
||||
return err;
|
||||
if (!string_builder_appendc(sb, '\''))
|
||||
return &drgn_enomem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (obj->kind) {
|
||||
case DRGN_OBJECT_SIGNED: {
|
||||
int64_t svalue;
|
||||
@ -813,90 +928,6 @@ c_format_enum_object(const struct drgn_object *obj,
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_character_type(struct drgn_type *type)
|
||||
{
|
||||
switch (drgn_type_primitive(type)) {
|
||||
case DRGN_C_TYPE_CHAR:
|
||||
case DRGN_C_TYPE_SIGNED_CHAR:
|
||||
case DRGN_C_TYPE_UNSIGNED_CHAR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_format_character(unsigned char c, struct string_builder *sb)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
switch (c) {
|
||||
case '\a':
|
||||
ret = string_builder_append(sb, "\\a");
|
||||
break;
|
||||
case '\b':
|
||||
ret = string_builder_append(sb, "\\b");
|
||||
break;
|
||||
case '\t':
|
||||
ret = string_builder_append(sb, "\\t");
|
||||
break;
|
||||
case '\n':
|
||||
ret = string_builder_append(sb, "\\n");
|
||||
break;
|
||||
case '\v':
|
||||
ret = string_builder_append(sb, "\\v");
|
||||
break;
|
||||
case '\f':
|
||||
ret = string_builder_append(sb, "\\f");
|
||||
break;
|
||||
case '\r':
|
||||
ret = string_builder_append(sb, "\\r");
|
||||
break;
|
||||
case '"':
|
||||
ret = string_builder_append(sb, "\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
ret = string_builder_append(sb, "\\\\");
|
||||
break;
|
||||
default:
|
||||
if (c <= '\x1f' || c >= '\x7f')
|
||||
ret = string_builder_appendf(sb, "\\x%02x", c);
|
||||
else
|
||||
ret = string_builder_appendc(sb, c);
|
||||
break;
|
||||
}
|
||||
return ret ? NULL : &drgn_enomem;
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_format_string(struct drgn_memory_reader *reader, uint64_t address,
|
||||
uint64_t length, struct string_builder *sb)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
|
||||
if (!string_builder_appendc(sb, '"'))
|
||||
return &drgn_enomem;
|
||||
while (length) {
|
||||
unsigned char c;
|
||||
|
||||
err = drgn_memory_reader_read(reader, &c, address++, 1, false);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (c == '\0') {
|
||||
break;
|
||||
} else {
|
||||
err = c_format_character(c, sb);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
length--;
|
||||
}
|
||||
if (!string_builder_appendc(sb, '"'))
|
||||
return &drgn_enomem;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct drgn_error *
|
||||
c_format_pointer_object(const struct drgn_object *obj,
|
||||
struct drgn_type *underlying_type, bool cast,
|
||||
@ -1042,7 +1073,8 @@ c_format_array_object(const struct drgn_object *obj,
|
||||
for (i = 0; i < size; i++) {
|
||||
if (buf[i] == '\0')
|
||||
break;
|
||||
err = c_format_character(buf[i], sb);
|
||||
err = c_format_character(buf[i], false, true,
|
||||
sb);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -1279,7 +1311,7 @@ c_format_object_impl(const struct drgn_object *obj, bool cast, size_t indent,
|
||||
"cannot format void object");
|
||||
case DRGN_TYPE_INT:
|
||||
case DRGN_TYPE_BOOL:
|
||||
return c_format_int_object(obj, sb);
|
||||
return c_format_int_object(obj, flags, sb);
|
||||
case DRGN_TYPE_FLOAT:
|
||||
return c_format_float_object(obj, sb);
|
||||
case DRGN_TYPE_COMPLEX:
|
||||
|
@ -972,7 +972,8 @@ static PyObject *DrgnObject_format(DrgnObject *self, PyObject *args,
|
||||
#define FLAGS \
|
||||
X(dereference, DRGN_FORMAT_OBJECT_DEREFERENCE) \
|
||||
X(symbolize, DRGN_FORMAT_OBJECT_SYMBOLIZE) \
|
||||
X(string, DRGN_FORMAT_OBJECT_STRING)
|
||||
X(string, DRGN_FORMAT_OBJECT_STRING) \
|
||||
X(char, DRGN_FORMAT_OBJECT_CHAR)
|
||||
|
||||
static char *keywords[] = {
|
||||
#define X(name, value) #name,
|
||||
|
@ -1228,6 +1228,22 @@ class TestCPretty(ObjectTestCase):
|
||||
self.assertEqual(str(Object(self.prog, 'const int', value=-99)),
|
||||
'(const int)-99')
|
||||
|
||||
def test_char(self):
|
||||
obj = Object(self.prog, 'char', value=65)
|
||||
self.assertEqual(str(obj), '(char)65')
|
||||
self.assertEqual(obj.format_(char=True), "(char)'A'")
|
||||
self.assertEqual(
|
||||
Object(self.prog, 'signed char', value=65).format_(char=True),
|
||||
"(signed char)'A'")
|
||||
self.assertEqual(
|
||||
Object(self.prog, 'unsigned char', value=65).format_(char=True),
|
||||
"(unsigned char)'A'")
|
||||
self.assertEqual(
|
||||
Object(self.prog,
|
||||
typedef_type('uint8_t', self.prog.type('unsigned char')),
|
||||
value=65).format_(char=True),
|
||||
"(uint8_t)65")
|
||||
|
||||
def test_bool(self):
|
||||
self.assertEqual(str(Object(self.prog, '_Bool', value=False)),
|
||||
'(_Bool)0')
|
||||
|
Loading…
Reference in New Issue
Block a user