Commit ec4ab256 authored by Petr Machata's avatar Petr Machata

Add lens "bitvec" for displaying objects as bit vectors

parent 3219c86c
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
Please read ltrace.conf(5) man page, chapter "recursive Please read ltrace.conf(5) man page, chapter "recursive
structures", to learn about this new feature. structures", to learn about this new feature.
*** New lens "bitvec" is available
This allows displaying various data types as bit vectors. Please
read ltrace.conf(5) to learn more.
* Version 0.7.0 * Version 0.7.0
** Tracing ** Tracing
*** Full support for tracing multi-threaded processes *** Full support for tracing multi-threaded processes
......
...@@ -467,6 +467,18 @@ struct lens hex_lens = { ...@@ -467,6 +467,18 @@ struct lens hex_lens = {
}; };
static int
dec_lens_format_cb(struct lens *lens, FILE *stream,
struct value *value, struct value_dict *arguments)
{
return toplevel_format_lens(lens, stream, value, arguments, INT_FMT_u);
}
struct lens dec_lens = {
.format_cb = dec_lens_format_cb,
};
static int static int
guess_lens_format_cb(struct lens *lens, FILE *stream, guess_lens_format_cb(struct lens *lens, FILE *stream,
struct value *value, struct value_dict *arguments) struct value *value, struct value_dict *arguments)
...@@ -576,3 +588,117 @@ string_lens_format_cb(struct lens *lens, FILE *stream, ...@@ -576,3 +588,117 @@ string_lens_format_cb(struct lens *lens, FILE *stream,
struct lens string_lens = { struct lens string_lens = {
.format_cb = string_lens_format_cb, .format_cb = string_lens_format_cb,
}; };
static int
out_bits(FILE *stream, size_t low, size_t high)
{
if (low == high)
return fprintf(stream, "%zd", low);
else
return fprintf(stream, "%zd-%zd", low, high);
}
static unsigned
bitcount(unsigned u)
{
int c = 0;
for (; u > 0; u &= u - 1)
c++;
return c;
}
static int
bitvect_lens_format_cb(struct lens *lens, FILE *stream,
struct value *value, struct value_dict *arguments)
{
unsigned char *data = value_get_data(value, arguments);
if (data == NULL)
return -1;
size_t sz = type_sizeof(value->inferior, value->type);
if (sz == (size_t)-1)
return -1;
size_t i;
unsigned char buf[sz];
switch ((int)value->type->type) {
union bitvect_integral_64
{
uint8_t u8;
uint16_t u16;
uint32_t u32;
uint64_t u64;
unsigned char buf[0];
} bv;
case ARGTYPE_POINTER:
return format_pointer(stream, value, arguments);
case ARGTYPE_STRUCT:
case ARGTYPE_ARRAY:
break;
default:
assert(sz <= sizeof(bv));
memmove(bv.buf, data, sz);
if (sz == 1)
bv.u64 = bv.u8;
else if (sz == 2)
bv.u64 = bv.u16;
else if (sz == 4)
bv.u64 = bv.u32;
for (i = 0; i < sz; ++i) {
buf[i] = bv.u64 & 0xff;
bv.u64 >>= 8;
}
data = buf;
}
size_t bits = 0;
for (i = 0; i < sz; ++i)
bits += bitcount(data[i]);
/* If there's more 1's than 0's, show inverse. */
unsigned neg = bits > sz * 4 ? 0xff : 0x00;
int o = 0;
if (acc_fprintf(&o, stream, "%s<", "~" + (neg == 0x00)) < 0)
return -1;
size_t bitno = 0;
ssize_t low = -1;
for (i = 0; i < sz; ++i) {
unsigned char m;
unsigned char d = data[i] ^ neg;
for (m = 0x01; m != 0; m <<= 1) {
int bit = !!(m & d);
if (low < 0) {
if (bit) {
if (low == -2
&& acc_fprintf(&o, stream, ",") < 0)
return -1;
low = bitno;
}
} else if (!bit) {
if (account_output(&o, out_bits(stream, low,
bitno-1)) < 0)
return -1;
low = -2;
}
bitno++;
}
}
if (low >= 0 && account_output(&o, out_bits(stream, low, bitno-1)) < 0)
return -1;
if (fputc('>', stream) < 0)
return -1;
o += 1;
return o;
}
struct lens bitvect_lens = {
.format_cb = bitvect_lens_format_cb,
};
/* /*
* This file is part of ltrace. * This file is part of ltrace.
* Copyright (C) 2011 Petr Machata, Red Hat Inc. * Copyright (C) 2011, 2012 Petr Machata, Red Hat Inc.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -46,4 +46,7 @@ extern struct lens guess_lens; ...@@ -46,4 +46,7 @@ extern struct lens guess_lens;
/* A lens for strings. */ /* A lens for strings. */
extern struct lens string_lens; extern struct lens string_lens;
/* A lens for bit vector. */
extern struct lens bitvect_lens;
#endif /* LENS_DEFAULT_H */ #endif /* LENS_DEFAULT_H */
...@@ -139,6 +139,28 @@ The argument is not shown in argument list. ...@@ -139,6 +139,28 @@ The argument is not shown in argument list.
Arguments with zero value are shown as "false", other are shown as Arguments with zero value are shown as "false", other are shown as
"true". "true".
.TP
.B bitvec(\fITYPE\fB)
Underlying argument is interpreted as a bit vector and a summary of
bits set in the vector is displayed. For example if bits 3,4,5 and 7
of the bit vector are set, ltrace shows <3-5,7>. Empty bit vector is
displayed as <>. If there are more bits set than unset, inverse is
shown instead: e.g. ~<0> when a number 0xfffffffe is displayed. Full
set is thus displayed ~<>.
If the underlying type is integral, then bits are shown in their
natural little-endian order, with LSB being bit 0.
E.g. \fBbitvec(ushort)\fR with value 0x0102 would be displayed as
<1,8>, irrespective of underlying byte order.
For other data types (notably structures and arrays), the underlying
data is interpreted byte after byte. Bit 0 of first byte has number
0, bit 0 of second byte number 8, and so on. Thus
\fBbitvec(struct(int))\fR is endian sensitive, and will show bytes
comprising the integer in their memory order. Pointers are first
dereferenced, thus \fBbitvec(array(char, \fR32\fB)*)\fR is actually a
pointer to 256-bit bit vector.
.PP .PP
.B string(\fITYPE\fB) .B string(\fITYPE\fB)
.br .br
......
...@@ -954,6 +954,7 @@ static struct named_lens { ...@@ -954,6 +954,7 @@ static struct named_lens {
} lenses[] = { } lenses[] = {
{ "hide", &blind_lens }, { "hide", &blind_lens },
{ "octal", &octal_lens }, { "octal", &octal_lens },
{ "bitvec", &bitvect_lens },
{ "hex", &hex_lens }, { "hex", &hex_lens },
{ "bool", &bool_lens }, { "bool", &bool_lens },
{ "guess", &guess_lens }, { "guess", &guess_lens },
......
...@@ -126,7 +126,7 @@ proc ltraceParamTest {conf cdecl libcode maincode match} { ...@@ -126,7 +126,7 @@ proc ltraceParamTest {conf cdecl libcode maincode match} {
} }
ltraceParamTest { ltraceParamTest {
typedef hexptr = hex(uint); typedef hexptr = hex(uint*);
void fun(hexptr); void fun(hexptr);
} { } {
void fun(unsigned *arg); void fun(unsigned *arg);
...@@ -139,4 +139,31 @@ ltraceParamTest { ...@@ -139,4 +139,31 @@ ltraceParamTest {
{{fun\(0x123\) *= <void>} == 1} {{fun\(0x123\) *= <void>} == 1}
} }
ltraceParamTest {
void fun(bitvec(uint));
void fun2(bitvec(array(char, 32)*));
} {
void fun(unsigned i);
void fun2(unsigned char *arr);
} {
void fun(unsigned i) {}
void fun2(unsigned char *arr) {}
} {
fun(0);
fun(0x123);
fun(0xfffffffe);
fun(0xffffffff);
unsigned char bytes[32] = {0x00};
bytes[1] = 0xff;
bytes[31] = 0x80;
fun2(bytes);
} {
{{fun\(<>\) *= <void>} == 1}
{{fun\(<0-1,5,8>\) *= <void>} == 1}
{{fun\(~<0>\) *= <void>} == 1}
{{fun\(~<>\) *= <void>} == 1}
{{fun2\(<8-15,255>\) *= <void>} == 1}
}
ltraceDone ltraceDone
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment