Skip to content

Commit

Permalink
Add lens "bitvec" for displaying objects as bit vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
Petr Machata committed Nov 20, 2012
1 parent 3219c86 commit ec4ab25
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 2 deletions.
4 changes: 4 additions & 0 deletions NEWS
Expand Up @@ -29,6 +29,10 @@
Please read ltrace.conf(5) man page, chapter "recursive
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
** Tracing
*** Full support for tracing multi-threaded processes
Expand Down
126 changes: 126 additions & 0 deletions lens_default.c
Expand Up @@ -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
guess_lens_format_cb(struct lens *lens, FILE *stream,
struct value *value, struct value_dict *arguments)
Expand Down Expand Up @@ -576,3 +588,117 @@ string_lens_format_cb(struct lens *lens, FILE *stream,
struct lens string_lens = {
.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,
};
5 changes: 4 additions & 1 deletion lens_default.h
@@ -1,6 +1,6 @@
/*
* 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
* modify it under the terms of the GNU General Public License as
Expand Down Expand Up @@ -46,4 +46,7 @@ extern struct lens guess_lens;
/* A lens for strings. */
extern struct lens string_lens;

/* A lens for bit vector. */
extern struct lens bitvect_lens;

#endif /* LENS_DEFAULT_H */
22 changes: 22 additions & 0 deletions ltrace.conf.5
Expand Up @@ -139,6 +139,28 @@ The argument is not shown in argument list.
Arguments with zero value are shown as "false", other are shown as
"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
.B string(\fITYPE\fB)
.br
Expand Down
1 change: 1 addition & 0 deletions read_config_file.c
Expand Up @@ -954,6 +954,7 @@ static struct named_lens {
} lenses[] = {
{ "hide", &blind_lens },
{ "octal", &octal_lens },
{ "bitvec", &bitvect_lens },
{ "hex", &hex_lens },
{ "bool", &bool_lens },
{ "guess", &guess_lens },
Expand Down
29 changes: 28 additions & 1 deletion testsuite/ltrace.main/parameters2.exp
Expand Up @@ -126,7 +126,7 @@ proc ltraceParamTest {conf cdecl libcode maincode match} {
}

ltraceParamTest {
typedef hexptr = hex(uint);
typedef hexptr = hex(uint*);
void fun(hexptr);
} {
void fun(unsigned *arg);
Expand All @@ -139,4 +139,31 @@ ltraceParamTest {
{{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

0 comments on commit ec4ab25

Please sign in to comment.