2009-03-14 17:50:36 +01:00
|
|
|
/*
|
2006-11-11 19:31:04 +01:00
|
|
|
Copyright (C) 2006 Mandriva Conectiva S.A.
|
|
|
|
Copyright (C) 2006 Arnaldo Carvalho de Melo <acme@mandriva.com>
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of version 2 of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
|
2007-03-30 15:37:37 +02:00
|
|
|
#include <argp.h>
|
2006-11-11 19:31:04 +01:00
|
|
|
#include <assert.h>
|
|
|
|
#include <dwarf.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2008-01-31 13:05:02 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2007-01-11 19:07:05 +01:00
|
|
|
#include "dwarves.h"
|
2007-12-16 17:47:59 +01:00
|
|
|
#include "dutil.h"
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2006-11-12 15:41:44 +01:00
|
|
|
static int show_struct_diffs;
|
|
|
|
static int show_function_diffs;
|
2006-11-12 15:56:52 +01:00
|
|
|
static int verbose;
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
static int show_terse_type_changes;
|
|
|
|
|
2007-12-17 14:27:24 +01:00
|
|
|
static struct strlist *structs_printed;
|
|
|
|
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
#define TCHANGEF__SIZE (1 << 0)
|
|
|
|
#define TCHANGEF__NR_MEMBERS (1 << 1)
|
|
|
|
#define TCHANGEF__TYPE (1 << 2)
|
|
|
|
#define TCHANGEF__OFFSET (1 << 3)
|
|
|
|
#define TCHANGEF__BIT_OFFSET (1 << 4)
|
|
|
|
#define TCHANGEF__BIT_SIZE (1 << 5)
|
2009-03-03 14:55:25 +01:00
|
|
|
#define TCHANGEF__PADDING (1 << 6)
|
|
|
|
#define TCHANGEF__NR_HOLES (1 << 7)
|
|
|
|
#define TCHANGEF__NR_BIT_HOLES (1 << 8)
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static uint32_t terse_type_changes;
|
2006-11-12 15:41:44 +01:00
|
|
|
|
2006-12-28 14:18:43 +01:00
|
|
|
static uint32_t total_cus_changed;
|
|
|
|
static uint32_t total_nr_functions_changed;
|
|
|
|
static uint32_t total_function_bytes_added;
|
|
|
|
static uint32_t total_function_bytes_removed;
|
2006-11-12 02:14:02 +01:00
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
struct diff_info {
|
|
|
|
const struct tag *tag;
|
|
|
|
const struct cu *cu;
|
|
|
|
int32_t diff;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct diff_info *diff_info__new(const struct tag *twin,
|
|
|
|
const struct cu *cu,
|
|
|
|
int32_t diff)
|
|
|
|
{
|
|
|
|
struct diff_info *self = malloc(sizeof(*self));
|
|
|
|
|
|
|
|
if (self == NULL) {
|
|
|
|
puts("out of memory!");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
self->tag = twin;
|
|
|
|
self->cu = cu;
|
|
|
|
self->diff = diff;
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2007-01-04 00:57:35 +01:00
|
|
|
static void diff_function(const struct cu *new_cu, struct function *function,
|
|
|
|
struct cu *cu)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
2007-01-12 18:47:26 +01:00
|
|
|
struct tag *new_tag;
|
2007-01-07 20:13:39 +01:00
|
|
|
const char *name;
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2007-01-08 15:07:59 +01:00
|
|
|
if (function->inlined || function->abstract_origin != 0)
|
2006-11-11 19:31:04 +01:00
|
|
|
return;
|
|
|
|
|
2007-01-07 20:13:39 +01:00
|
|
|
name = function__name(function, cu);
|
2007-01-12 18:47:26 +01:00
|
|
|
new_tag = cu__find_function_by_name(new_cu, name);
|
|
|
|
if (new_tag != NULL) {
|
|
|
|
struct function *new_function = tag__function(new_tag);
|
2007-01-04 04:41:11 +01:00
|
|
|
int32_t diff = (function__size(new_function) -
|
|
|
|
function__size(function));
|
|
|
|
if (diff != 0) {
|
2007-01-07 20:13:39 +01:00
|
|
|
const size_t len = strlen(name);
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
function->priv = diff_info__new(&new_function->proto.tag, new_cu,
|
|
|
|
diff);
|
2007-01-04 00:57:35 +01:00
|
|
|
if (len > cu->max_len_changed_item)
|
|
|
|
cu->max_len_changed_item = len;
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2007-01-04 00:57:35 +01:00
|
|
|
++cu->nr_functions_changed;
|
2007-01-04 04:41:11 +01:00
|
|
|
if (diff > 0)
|
|
|
|
cu->function_bytes_added += diff;
|
2006-11-11 19:31:04 +01:00
|
|
|
else
|
2007-01-04 04:41:11 +01:00
|
|
|
cu->function_bytes_removed += -diff;
|
2008-08-06 18:48:28 +02:00
|
|
|
} else {
|
|
|
|
char proto[1024], twin_proto[1024];
|
|
|
|
|
|
|
|
if (strcmp(function__prototype(function, cu,
|
|
|
|
proto, sizeof(proto)),
|
|
|
|
function__prototype(new_function, new_cu,
|
|
|
|
twin_proto,
|
|
|
|
sizeof(twin_proto))) != 0) {
|
|
|
|
++cu->nr_functions_changed;
|
|
|
|
function->priv = diff_info__new(function__tag(new_function),
|
|
|
|
new_cu, 0);
|
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
2006-12-24 16:03:33 +01:00
|
|
|
} else {
|
2007-01-07 20:13:39 +01:00
|
|
|
const size_t len = strlen(name);
|
2007-01-04 04:41:11 +01:00
|
|
|
const uint32_t diff = -function__size(function);
|
|
|
|
|
2007-01-04 00:57:35 +01:00
|
|
|
if (len > cu->max_len_changed_item)
|
|
|
|
cu->max_len_changed_item = len;
|
2007-01-04 04:41:11 +01:00
|
|
|
function->priv = diff_info__new(NULL, NULL, diff);
|
2007-01-04 00:57:35 +01:00
|
|
|
++cu->nr_functions_changed;
|
2007-01-04 04:41:11 +01:00
|
|
|
cu->function_bytes_removed += -diff;
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
static int check_print_change(const struct class_member *old,
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct cu *old_cu,
|
|
|
|
const struct class_member *new,
|
|
|
|
const struct cu *new_cu,
|
|
|
|
int print)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
{
|
2007-01-09 18:10:57 +01:00
|
|
|
size_t old_size, new_size;
|
|
|
|
char old_type_name[128], new_type_name[128];
|
2009-03-18 16:17:07 +01:00
|
|
|
const struct tag *old_type = cu__type(old_cu, old->tag.type);
|
|
|
|
const struct tag *new_type = cu__type(new_cu, new->tag.type);
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
int changes = 0;
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
|
2007-01-09 18:10:57 +01:00
|
|
|
if (old_type == NULL || new_type == NULL)
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
return 0;
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
|
2009-03-17 17:57:40 +01:00
|
|
|
old_size = old->byte_size;
|
|
|
|
new_size = new->byte_size;
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
if (old_size != new_size)
|
|
|
|
changes = 1;
|
|
|
|
|
2009-03-17 15:43:17 +01:00
|
|
|
if (old->byte_offset != new->byte_offset) {
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
changes = 1;
|
|
|
|
terse_type_changes |= TCHANGEF__OFFSET;
|
|
|
|
}
|
|
|
|
|
2009-03-17 15:43:17 +01:00
|
|
|
if (old->bitfield_offset != new->bitfield_offset) {
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
changes = 1;
|
|
|
|
terse_type_changes |= TCHANGEF__BIT_OFFSET;
|
|
|
|
}
|
|
|
|
|
2009-03-17 15:43:17 +01:00
|
|
|
if (old->bitfield_size != new->bitfield_size) {
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
changes = 1;
|
|
|
|
terse_type_changes |= TCHANGEF__BIT_SIZE;
|
|
|
|
}
|
|
|
|
|
2007-01-09 18:10:57 +01:00
|
|
|
if (strcmp(tag__name(old_type, old_cu, old_type_name,
|
|
|
|
sizeof(old_type_name)),
|
|
|
|
tag__name(new_type, new_cu, new_type_name,
|
|
|
|
sizeof(new_type_name))) != 0) {
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
changes = 1;
|
|
|
|
terse_type_changes |= TCHANGEF__TYPE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changes && print && !show_terse_type_changes)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
printf(" %s\n"
|
2009-03-03 14:31:14 +01:00
|
|
|
" from: %-21s /* %5u(%2u) %5zd(%2d) */\n"
|
|
|
|
" to: %-21s /* %5u(%2u) %5zd(%2u) */\n",
|
2008-10-02 19:34:42 +02:00
|
|
|
class_member__name(old),
|
2009-03-17 15:43:17 +01:00
|
|
|
old_type_name, old->byte_offset, old->bitfield_offset,
|
|
|
|
old_size, old->bitfield_size,
|
|
|
|
new_type_name, new->byte_offset, new->bitfield_offset,
|
|
|
|
new_size, new->bitfield_size);
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
|
|
|
|
return changes;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_print_members_changes(const struct class *structure,
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct cu *cu,
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
const struct class *new_structure,
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct cu *new_cu,
|
2006-11-12 19:59:47 +01:00
|
|
|
int print)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
{
|
|
|
|
int changes = 0;
|
|
|
|
struct class_member *member;
|
2009-03-03 14:31:14 +01:00
|
|
|
uint16_t nr_twins_found = 0;
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(&structure->type, member) {
|
2009-03-03 14:31:14 +01:00
|
|
|
const char *member_name = class_member__name(member);
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
struct class_member *twin =
|
2009-03-03 14:31:14 +01:00
|
|
|
class__find_member_by_name(new_structure, member_name);
|
|
|
|
if (twin != NULL) {
|
2009-03-03 14:56:37 +01:00
|
|
|
twin->tag.visited = 1;
|
2009-03-03 14:31:14 +01:00
|
|
|
++nr_twins_found;
|
2007-01-04 04:41:11 +01:00
|
|
|
if (check_print_change(member, cu, twin, new_cu, print))
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
changes = 1;
|
2009-03-03 14:31:14 +01:00
|
|
|
} else {
|
|
|
|
changes = 1;
|
|
|
|
if (print) {
|
|
|
|
char name[128];
|
|
|
|
struct tag *type;
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(cu, member->tag.type);
|
2009-03-03 14:31:14 +01:00
|
|
|
printf(" %s\n"
|
|
|
|
" removed: %-21s /* %5u(%2u) %5zd(%2d) */\n",
|
|
|
|
class_member__name(member),
|
|
|
|
tag__name(type, cu, name, sizeof(name)),
|
2009-03-17 15:43:17 +01:00
|
|
|
member->byte_offset, member->bitfield_offset,
|
2009-03-17 17:57:40 +01:00
|
|
|
member->byte_size, member->bitfield_size);
|
2009-03-03 14:31:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nr_twins_found == new_structure->type.nr_members)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
changes = 1;
|
|
|
|
if (!print)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
type__for_each_member(&new_structure->type, member) {
|
2009-03-03 14:56:37 +01:00
|
|
|
if (!member->tag.visited) {
|
2009-03-03 14:31:14 +01:00
|
|
|
char name[128];
|
|
|
|
struct tag *type;
|
2009-03-18 16:17:07 +01:00
|
|
|
type = cu__type(new_cu, member->tag.type);
|
2009-03-03 14:31:14 +01:00
|
|
|
printf(" %s\n"
|
|
|
|
" added: %-21s /* %5u(%2u) %5zd(%2d) */\n",
|
|
|
|
class_member__name(member),
|
|
|
|
tag__name(type, new_cu, name, sizeof(name)),
|
2009-03-17 15:43:17 +01:00
|
|
|
member->byte_offset, member->bitfield_offset,
|
2009-03-17 17:57:40 +01:00
|
|
|
member->byte_size, member->bitfield_size);
|
2009-03-03 14:31:14 +01:00
|
|
|
}
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
}
|
2009-03-03 14:31:14 +01:00
|
|
|
out:
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
return changes;
|
|
|
|
}
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
static void diff_struct(const struct cu *new_cu, struct class *structure,
|
|
|
|
struct cu *cu)
|
2006-11-12 15:29:33 +01:00
|
|
|
{
|
2007-01-07 16:11:20 +01:00
|
|
|
struct tag *new_tag;
|
2007-03-30 15:59:04 +02:00
|
|
|
struct class *new_structure = NULL;
|
2006-11-12 15:29:33 +01:00
|
|
|
size_t len;
|
2007-01-04 04:41:11 +01:00
|
|
|
int32_t diff;
|
2006-11-12 15:29:33 +01:00
|
|
|
|
2007-05-31 06:53:01 +02:00
|
|
|
assert(class__is_struct(structure));
|
2006-11-12 15:29:33 +01:00
|
|
|
|
2009-03-06 14:57:41 +01:00
|
|
|
if (class__size(structure) == 0 || class__name(structure) == NULL)
|
2006-11-12 15:29:33 +01:00
|
|
|
return;
|
|
|
|
|
2009-03-06 14:57:41 +01:00
|
|
|
new_tag = cu__find_struct_by_name(new_cu,
|
|
|
|
class__name(structure), 0, NULL);
|
2007-09-26 19:23:11 +02:00
|
|
|
if (new_tag == NULL)
|
|
|
|
return;
|
2006-12-24 16:35:21 +01:00
|
|
|
|
2007-01-07 16:11:20 +01:00
|
|
|
new_structure = tag__class(new_tag);
|
2007-01-09 13:00:47 +01:00
|
|
|
if (class__size(new_structure) == 0)
|
2006-11-12 15:29:33 +01:00
|
|
|
return;
|
|
|
|
|
2007-05-31 06:53:01 +02:00
|
|
|
assert(class__is_struct(new_structure));
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
diff = class__size(structure) != class__size(new_structure) ||
|
|
|
|
class__nr_members(structure) != class__nr_members(new_structure) ||
|
2007-01-04 04:41:11 +01:00
|
|
|
check_print_members_changes(structure, cu,
|
2009-03-03 14:55:25 +01:00
|
|
|
new_structure, new_cu, 0) ||
|
|
|
|
structure->padding != new_structure->padding ||
|
|
|
|
structure->nr_holes != new_structure->nr_holes ||
|
|
|
|
structure->nr_bit_holes != new_structure->nr_bit_holes;
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
if (diff == 0)
|
2006-11-12 15:29:33 +01:00
|
|
|
return;
|
2007-12-08 04:50:25 +01:00
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
++cu->nr_structures_changed;
|
2009-03-06 14:57:41 +01:00
|
|
|
len = strlen(class__name(structure)) + sizeof("struct");
|
2007-01-04 04:41:11 +01:00
|
|
|
if (len > cu->max_len_changed_item)
|
|
|
|
cu->max_len_changed_item = len;
|
2007-01-07 15:30:58 +01:00
|
|
|
structure->priv = diff_info__new(class__tag(new_structure),
|
|
|
|
new_cu, diff);
|
2006-11-12 15:29:33 +01:00
|
|
|
}
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
static int diff_tag_iterator(struct tag *tag, struct cu *cu, void *new_cu)
|
2006-12-24 16:03:33 +01:00
|
|
|
{
|
2007-05-31 06:53:01 +02:00
|
|
|
if (tag__is_struct(tag))
|
2007-01-04 04:41:11 +01:00
|
|
|
diff_struct(new_cu, tag__class(tag), cu);
|
2009-03-06 15:14:26 +01:00
|
|
|
else if (tag__is_function(tag))
|
2007-01-04 00:57:35 +01:00
|
|
|
diff_function(new_cu, tag__function(tag), cu);
|
2007-01-04 00:29:24 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int find_new_functions_iterator(struct tag *tfunction, struct cu *cu,
|
|
|
|
void *old_cu)
|
|
|
|
{
|
|
|
|
struct function *function = tag__function(tfunction);
|
2008-01-03 16:03:32 +01:00
|
|
|
struct tag *old_function;
|
2007-01-07 20:13:39 +01:00
|
|
|
const char *name;
|
2006-12-24 16:03:33 +01:00
|
|
|
|
|
|
|
if (function->inlined)
|
|
|
|
return 0;
|
|
|
|
|
2007-01-07 20:13:39 +01:00
|
|
|
name = function__name(function, cu);
|
2008-01-03 16:03:32 +01:00
|
|
|
old_function = cu__find_function_by_name(old_cu, name);
|
|
|
|
|
|
|
|
if (old_function == NULL || tag__function(old_function)->inlined) {
|
2007-01-07 20:13:39 +01:00
|
|
|
const size_t len = strlen(name);
|
2007-01-04 04:41:11 +01:00
|
|
|
const int32_t diff = function__size(function);
|
|
|
|
|
2007-01-04 00:57:35 +01:00
|
|
|
if (len > cu->max_len_changed_item)
|
|
|
|
cu->max_len_changed_item = len;
|
|
|
|
++cu->nr_functions_changed;
|
2007-01-04 04:41:11 +01:00
|
|
|
cu->function_bytes_added += diff;
|
2008-01-03 16:03:32 +01:00
|
|
|
function->priv = diff_info__new(old_function, cu, diff);
|
2006-12-24 16:03:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_cu)
|
2006-12-24 16:35:21 +01:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct class *class;
|
2006-12-24 16:35:21 +01:00
|
|
|
size_t len;
|
|
|
|
|
2007-05-31 06:53:01 +02:00
|
|
|
if (!tag__is_struct(tag))
|
2006-12-29 18:28:58 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
class = tag__class(tag);
|
2009-03-06 14:57:41 +01:00
|
|
|
if (class__name(class) == NULL)
|
2006-12-24 16:35:21 +01:00
|
|
|
return 0;
|
|
|
|
|
2007-01-09 13:00:47 +01:00
|
|
|
if (class__size(class) == 0)
|
2006-12-24 16:35:21 +01:00
|
|
|
return 0;
|
|
|
|
|
2009-03-06 14:57:41 +01:00
|
|
|
if (cu__find_struct_by_name(old_cu,
|
|
|
|
class__name(class), 0, NULL) != NULL)
|
2006-12-24 16:35:21 +01:00
|
|
|
return 0;
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
class->priv = diff_info__new(NULL, NULL, 1);
|
|
|
|
++cu->nr_structures_changed;
|
2006-12-24 16:35:21 +01:00
|
|
|
|
2009-03-06 14:57:41 +01:00
|
|
|
len = strlen(class__name(class)) + sizeof("struct");
|
2007-01-04 04:41:11 +01:00
|
|
|
if (len > cu->max_len_changed_item)
|
|
|
|
cu->max_len_changed_item = len;
|
2006-12-24 16:35:21 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
static int find_new_tags_iterator(struct tag *tag, struct cu *cu, void *old_cu)
|
|
|
|
{
|
2009-03-06 15:14:26 +01:00
|
|
|
if (tag__is_function(tag)) {
|
2008-01-04 02:34:51 +01:00
|
|
|
/*
|
|
|
|
* We're not interested in aliases, just real function definitions,
|
|
|
|
* where we'll know if the kind of inlining
|
|
|
|
*/
|
|
|
|
if (tag__function(tag)->abstract_origin != 0)
|
|
|
|
return 0;
|
2007-01-04 00:29:24 +01:00
|
|
|
return find_new_functions_iterator(tag, cu, old_cu);
|
2008-01-04 02:34:51 +01:00
|
|
|
}
|
2007-01-04 00:29:24 +01:00
|
|
|
return find_new_classes_iterator(tag, cu, old_cu);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus)
|
2006-12-24 16:03:33 +01:00
|
|
|
{
|
|
|
|
struct cu *old_cu = cus__find_cu_by_name(old_cus, new_cu->name);
|
|
|
|
|
2008-01-31 13:05:02 +01:00
|
|
|
if (old_cu != NULL && cu__same_build_id(old_cu, new_cu))
|
|
|
|
return 0;
|
2006-12-24 16:03:33 +01:00
|
|
|
|
dwarves: Remove some more DWARF details from the core
Had to be a big sweeping change, but the regression tests shows just
improvements :-)
Now we stop using an id in struct tag, only storing the type, that now
uses 16 bits only, as CTF does.
Each format loader has to go on adding the types to the core, that
figures out if it is a tag that can be on the tag->type field
(tag__is_tag_type).
Formats that already have the types separated and in sequence, such as
CTF, just ask the core to insert in the types_table directly with its
original ID.
For DWARF, we ask the core to put it on the table, in sequence, and return the
index, that is then stashed with the DWARF specific info (original id, type,
decl_line, etc) and hashed by the original id. Later we recode everything,
looking up via the original type, getting the small_id to put on the tag->type.
The underlying debugging info not needed by the core is stashed in tag->priv,
and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of
the core tag and points it there, and makes that info available thru
cu->orig_info. In the future we can ask, when loading a cu, that this info be
trown away, so that we reduce the memory footprint for big multi-cu files such
as the Linux kernel.
There is also a routine to ask for inserting a NULL, as we still have
bugs in the CTF decoding and thus some entries are being lost, to avoid
using an undefined pointer when traversing the types_table the ctf
loader puts a NULL there via cu__table_nullify_type_entry() and then
cu__for_each_type skips those.
There is some more cleanups for leftovers that I avoided cleaning to
reduce this changeset.
And also while doing this I saw that enums can appear without any
enumerators and that an array with DW_TAG_GNU_vector is actually a
different tag, encoded this way till we get to DWARF4 ;-)
So now we don't have to lookup on a hash table looking for DWARF
offsets, we can do the more sensible thing of just indexing the
types_tags array.
Now to do some cleanups and try to get the per cu encoder done. Then
order all the cus per number of type entries, pick the one with more,
then go on merging/recoding the types of the others and putting the
parent linkage in place.
Just to show the extent of the changes:
$ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0
/home/acme/git/pahole/dwarves.c:
struct cu | -4048
struct tag | -32
struct ptr_to_member_type | -32
struct namespace | -32
struct type | -32
struct class | -32
struct base_type | -32
struct array_type | -32
struct class_member | -32
struct lexblock | -32
struct ftype | -32
struct function | -64
struct parameter | -32
struct variable | -32
struct inline_expansion | -32
struct label | -32
struct enumerator | -32
17 structs changed
tag__follow_typedef | +3
tag__fprintf_decl_info | +25
array_type__fprintf | +6
type__name | -126
type__find_first_biggest_size_base_type_member | -3
typedef__fprintf | +16
imported_declaration__fprintf | +6
imported_module__fprintf | +3
cu__new | +26
cu__delete | +26
hashtags__hash | -65
hash_64 | -124
hlist_add_head | -78
hashtags__find | -157
cu__hash | -80
cu__add_tag | +20
tag__prefix | -3
cu__find_tag_by_id | -2
cu__find_type_by_id | -3
cu__find_first_typedef_of_type | +38
cu__find_base_type_by_name | +68
cu__find_base_type_by_name_and_size | +72
cu__find_struct_by_name | +59
cus__find_struct_by_name | +8
cus__find_tag_by_id | +5
cus__find_cu_by_name | -6
lexblock__find_tag_by_id | -173
cu__find_variable_by_id | -197
list__find_tag_by_id | -308
cu__find_parameter_by_id | -60
tag__ptr_name | +6
tag__name | +15
variable__type | +13
variable__name | +7
class_member__size | +6
parameter__name | -119
tag__parameter | -14
parameter__type | -143
type__fprintf | -29
union__fprintf | +6
class__add_vtable_entry | -9
type__add_member | -6
type__clone_members | -3
enumeration__add | -6
function__name | -156
ftype__has_parm_of_type | -39
class__find_holes | -27
class__has_hole_ge | -3
type__nr_members_of_type | +3
lexblock__account_inline_expansions | +3
cu__account_inline_expansions | -18
ftype__fprintf_parms | +46
function__tag_fprintf | +24
lexblock__fprintf | -6
ftype__fprintf | +3
function__fprintf_stats | -18
function__size | -6
class__vtable_fprintf | -11
class__fprintf | -21
tag__fprintf | -35
60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541
/home/acme/git/pahole/ctf_loader.c:
struct ctf_short_type | +0
14 structs changed
type__init | -14
type__new | -9
class__new | -12
create_new_base_type | -7
create_new_base_type_float | -7
create_new_array | -8
create_new_subroutine_type | -9
create_full_members | -18
create_short_members | -18
create_new_class | +1
create_new_union | +1
create_new_enumeration | -19
create_new_forward_decl | -2
create_new_typedef | +3
create_new_tag | -5
load_types | +16
class__fixup_ctf_bitfields | -3
17 functions changed, 21 bytes added, 131 bytes removed, diff: -110
/home/acme/git/pahole/dwarf_loader.c:
17 structs changed
zalloc | -56
tag__init | +3
array_type__new | +20
type__init | -24
class_member__new | +46
inline_expansion__new | +12
class__new | +81
lexblock__init | +19
function__new | +43
die__create_new_array | +20
die__create_new_parameter | +4
die__create_new_label | +4
die__create_new_subroutine_type | +113
die__create_new_enumeration | -21
die__process_class | +79
die__process_namespace | +76
die__create_new_inline_expansion | +4
die__process_function | +147
__die__process_tag | +34
die__process_unit | +56
die__process | +90
21 functions changed, 851 bytes added, 101 bytes removed, diff: +750
/home/acme/git/pahole/dwarves.c:
struct ptr_table | +16
struct cu_orig_info | +32
2 structs changed
tag__decl_line | +68
tag__decl_file | +70
tag__orig_id | +71
ptr_table__init | +46
ptr_table__exit | +37
ptr_table__add | +183
ptr_table__add_with_id | +165
ptr_table__entry | +64
cu__table_add_tag | +171
cu__table_nullify_type_entry | +38
10 functions changed, 913 bytes added, diff: +913
/home/acme/git/pahole/ctf_loader.c:
2 structs changed
tag__alloc | +52
1 function changed, 52 bytes added, diff: +52
/home/acme/git/pahole/dwarf_loader.c:
struct dwarf_tag | +48
struct dwarf_cu | +4104
4 structs changed
dwarf_cu__init | +83
hashtags__hash | +61
hash_64 | +124
hlist_add_head | +78
hashtags__find | +161
cu__hash | +95
tag__is_tag_type | +171
tag__is_type | +85
tag__is_union | +28
tag__is_struct | +57
tag__is_typedef | +28
tag__is_enumeration | +28
dwarf_cu__find_tag_by_id | +56
dwarf_cu__find_type_by_id | +63
tag__alloc | +114
__tag__print_type_not_found | +108
namespace__recode_dwarf_types | +346
tag__namespace | +14
tag__has_namespace | +86
tag__is_namespace | +28
type__recode_dwarf_specification | +182
tag__type | +14
__tag__print_abstract_origin_not_found | +105
ftype__recode_dwarf_types | +322
tag__ftype | +14
tag__parameter | +14
lexblock__recode_dwarf_types | +736
tag__lexblock | +14
tag__label | +14
tag__recode_dwarf_type | +766
tag__ptr_to_member_type | +14
cu__recode_dwarf_types_table | +88
cu__recode_dwarf_types | +48
dwarf_tag__decl_file | +77
strings__ptr | +33
dwarf_tag__decl_line | +59
dwarf_tag__orig_id | +59
dwarf_tag__orig_type | +59
38 functions changed, 4432 bytes added, diff: +4432
build/libdwarves.so.1.0.0:
147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2009-03-06 00:29:35 +01:00
|
|
|
cu__for_each_tag(new_cu, find_new_tags_iterator, old_cu, NULL);
|
2006-12-24 16:03:33 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
static int cu_diff_iterator(struct cu *cu, void *new_cus)
|
|
|
|
{
|
|
|
|
struct cu *new_cu = cus__find_cu_by_name(new_cus, cu->name);
|
|
|
|
|
2008-01-31 13:05:02 +01:00
|
|
|
if (new_cu != NULL && cu__same_build_id(cu, new_cu))
|
|
|
|
return 0;
|
|
|
|
cu__for_each_tag(cu, diff_tag_iterator, new_cu, NULL);
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-01-09 15:16:46 +01:00
|
|
|
static void show_diffs_function(struct function *function, const struct cu *cu,
|
|
|
|
const void *cookie)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct diff_info *di = function->priv;
|
|
|
|
|
2007-01-08 15:21:47 +01:00
|
|
|
printf(" %-*.*s | %+4d",
|
2007-03-28 16:38:32 +02:00
|
|
|
(int)cu->max_len_changed_item, (int)cu->max_len_changed_item,
|
2007-01-07 20:13:39 +01:00
|
|
|
function__name(function, cu), di->diff);
|
2007-01-08 15:21:47 +01:00
|
|
|
|
|
|
|
if (!verbose) {
|
|
|
|
putchar('\n');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (di->tag == NULL)
|
2007-01-09 15:16:46 +01:00
|
|
|
puts(cookie ? " (added)" : " (removed)");
|
2007-01-08 15:21:47 +01:00
|
|
|
else {
|
2008-10-02 19:34:42 +02:00
|
|
|
struct function *twin = tag__function(di->tag);
|
2007-01-08 15:21:47 +01:00
|
|
|
|
2008-01-03 16:03:32 +01:00
|
|
|
if (twin->inlined)
|
|
|
|
puts(cookie ? " (uninlined)" : " (inlined)");
|
2008-10-02 19:34:42 +02:00
|
|
|
else if (strcmp(function__name(function, cu),
|
|
|
|
function__name(twin, di->cu)) != 0)
|
2007-01-08 15:21:47 +01:00
|
|
|
printf("%s: BRAIN FART ALERT: comparing %s to %s, "
|
|
|
|
"should be the same name\n", __FUNCTION__,
|
2008-10-02 19:34:42 +02:00
|
|
|
function__name(function, cu),
|
|
|
|
function__name(twin, di->cu));
|
2007-02-25 02:12:34 +01:00
|
|
|
else {
|
2008-08-06 18:48:28 +02:00
|
|
|
char proto[1024], twin_proto[1024];
|
|
|
|
|
2009-03-07 21:37:33 +01:00
|
|
|
printf(" # %d -> %d", function__size(function),
|
2007-01-08 15:21:47 +01:00
|
|
|
function__size(twin));
|
2007-02-25 02:12:34 +01:00
|
|
|
if (function->lexblock.nr_lexblocks !=
|
|
|
|
twin->lexblock.nr_lexblocks)
|
|
|
|
printf(", lexblocks: %d -> %d",
|
|
|
|
function->lexblock.nr_lexblocks,
|
|
|
|
twin->lexblock.nr_lexblocks);
|
|
|
|
if (function->lexblock.nr_inline_expansions !=
|
|
|
|
twin->lexblock.nr_inline_expansions)
|
|
|
|
printf(", # inlines: %d -> %d",
|
|
|
|
function->lexblock.nr_inline_expansions,
|
|
|
|
twin->lexblock.nr_inline_expansions);
|
|
|
|
if (function->lexblock.size_inline_expansions !=
|
|
|
|
twin->lexblock.size_inline_expansions)
|
2009-03-07 20:45:09 +01:00
|
|
|
printf(", size inlines: %d -> %d",
|
2007-02-25 02:12:34 +01:00
|
|
|
function->lexblock.size_inline_expansions,
|
|
|
|
twin->lexblock.size_inline_expansions);
|
2008-08-06 18:48:28 +02:00
|
|
|
|
|
|
|
if (strcmp(function__prototype(function, cu,
|
|
|
|
proto, sizeof(proto)),
|
|
|
|
function__prototype(twin, di->cu,
|
|
|
|
twin_proto, sizeof(twin_proto))) != 0)
|
|
|
|
printf(", prototype: %s -> %s", proto, twin_proto);
|
2007-02-25 02:12:34 +01:00
|
|
|
putchar('\n');
|
|
|
|
}
|
2007-01-08 15:21:47 +01:00
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
static void show_changed_member(char change, const struct class_member *member,
|
|
|
|
const struct cu *cu)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
{
|
2009-03-18 16:17:07 +01:00
|
|
|
const struct tag *type = cu__type(cu, member->tag.type);
|
2007-01-09 18:10:57 +01:00
|
|
|
char bf[128];
|
|
|
|
|
2008-04-20 23:56:36 +02:00
|
|
|
tag__assert_search_result(type);
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(" %c%-26s %-21s /* %5u %5zd */\n",
|
2008-10-02 19:34:42 +02:00
|
|
|
change, tag__name(type, cu, bf, sizeof(bf)),
|
|
|
|
class_member__name(member),
|
2009-03-17 17:57:40 +01:00
|
|
|
member->byte_offset, member->byte_size);
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void show_nr_members_changes(const struct class *structure,
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct cu *cu,
|
|
|
|
const struct class *new_structure,
|
|
|
|
const struct cu *new_cu)
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
{
|
|
|
|
struct class_member *member;
|
|
|
|
|
|
|
|
/* Find the removed ones */
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(&structure->type, member) {
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
struct class_member *twin =
|
2008-10-02 19:34:42 +02:00
|
|
|
class__find_member_by_name(new_structure,
|
|
|
|
class_member__name(member));
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
if (twin == NULL)
|
2007-01-04 04:41:11 +01:00
|
|
|
show_changed_member('-', member, cu);
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the new ones */
|
2007-05-24 02:43:01 +02:00
|
|
|
type__for_each_member(&new_structure->type, member) {
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
struct class_member *twin =
|
2008-10-02 19:34:42 +02:00
|
|
|
class__find_member_by_name(structure,
|
|
|
|
class_member__name(member));
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
if (twin == NULL)
|
2007-01-04 04:41:11 +01:00
|
|
|
show_changed_member('+', member, new_cu);
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-06 14:57:41 +01:00
|
|
|
static void print_terse_type_changes(struct class *structure)
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
{
|
|
|
|
const char *sep = "";
|
|
|
|
|
2009-03-06 14:57:41 +01:00
|
|
|
printf("struct %s: ", class__name(structure));
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
|
|
|
|
if (terse_type_changes & TCHANGEF__SIZE) {
|
|
|
|
fputs("size", stdout);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__NR_MEMBERS) {
|
|
|
|
printf("%snr_members", sep);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__TYPE) {
|
|
|
|
printf("%stype", sep);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__OFFSET) {
|
|
|
|
printf("%soffset", sep);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__BIT_OFFSET) {
|
|
|
|
printf("%sbit_offset", sep);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
2009-03-03 14:55:25 +01:00
|
|
|
if (terse_type_changes & TCHANGEF__BIT_SIZE) {
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
printf("%sbit_size", sep);
|
2009-03-03 14:55:25 +01:00
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__PADDING) {
|
|
|
|
printf("%spadding", sep);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__NR_HOLES) {
|
|
|
|
printf("%snr_holes", sep);
|
|
|
|
sep = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__NR_BIT_HOLES)
|
|
|
|
printf("%snr_bit_holes", sep);
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
|
|
|
|
putchar('\n');
|
|
|
|
}
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
static void show_diffs_structure(struct class *structure,
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct cu *cu)
|
2006-11-11 19:31:04 +01:00
|
|
|
{
|
2007-01-04 04:41:11 +01:00
|
|
|
const struct diff_info *di = structure->priv;
|
2007-09-26 19:23:11 +02:00
|
|
|
const struct class *new_structure;
|
|
|
|
int diff;
|
|
|
|
/*
|
|
|
|
* This is when the struct was not present in the new object file.
|
|
|
|
* Meaning that it either was not referenced or that it was completely
|
|
|
|
* removed.
|
|
|
|
*/
|
|
|
|
if (di == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
new_structure = tag__class(di->tag);
|
2007-09-27 15:18:42 +02:00
|
|
|
/*
|
|
|
|
* If there is a diff_info but its di->tag is NULL we have a new structure,
|
|
|
|
* one that didn't appears in the old object. See find_new_classes_iterator.
|
|
|
|
*/
|
|
|
|
if (new_structure == NULL)
|
|
|
|
diff = class__size(structure);
|
|
|
|
else
|
|
|
|
diff = class__size(new_structure) - class__size(structure);
|
2006-11-12 15:56:52 +01:00
|
|
|
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
terse_type_changes = 0;
|
|
|
|
|
|
|
|
if (!show_terse_type_changes)
|
|
|
|
printf(" struct %-*.*s | %+4d\n",
|
2007-03-28 16:38:32 +02:00
|
|
|
(int)(cu->max_len_changed_item - sizeof("struct")),
|
|
|
|
(int)(cu->max_len_changed_item - sizeof("struct")),
|
2009-03-06 14:57:41 +01:00
|
|
|
class__name(structure), diff);
|
2006-11-12 15:56:52 +01:00
|
|
|
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
if (diff != 0)
|
|
|
|
terse_type_changes |= TCHANGEF__SIZE;
|
|
|
|
|
|
|
|
if (!verbose && !show_terse_type_changes)
|
2006-11-12 15:56:52 +01:00
|
|
|
return;
|
|
|
|
|
2006-12-24 16:35:21 +01:00
|
|
|
if (new_structure == NULL)
|
2007-01-09 13:00:47 +01:00
|
|
|
diff = -class__nr_members(structure);
|
2006-12-24 16:35:21 +01:00
|
|
|
else
|
2007-01-09 13:00:47 +01:00
|
|
|
diff = (class__nr_members(new_structure) -
|
|
|
|
class__nr_members(structure));
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
if (diff != 0) {
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
terse_type_changes |= TCHANGEF__NR_MEMBERS;
|
|
|
|
if (!show_terse_type_changes) {
|
|
|
|
printf(" nr_members: %+d\n", diff);
|
2006-12-24 16:35:21 +01:00
|
|
|
if (new_structure != NULL)
|
2007-01-04 04:41:11 +01:00
|
|
|
show_nr_members_changes(structure, cu,
|
|
|
|
new_structure, di->cu);
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
}
|
[CODIFF]: Detect and print all sorts of changes in structs
[acme@newtoy examples]$ cat struct.c
static struct foo {
char a:2;
unsigned int b;
unsigned long c;
unsigned long d;
unsigned long e;
} bar;
int main(int argc, char *argv[])
{
printf("%d", bar.a);
}
[acme@newtoy examples]$
Then change "a:2" to "a:4":
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
1 struct changed
Now, on top of that move a after b:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 4(4) 1(4) */
b;
from: unsigned int /* 4(0) 4(0) */
to: unsigned int /* 0(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Move it back a to before b and change the type of e without changing its size,
i.e. from unsigned long to long:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | +0
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 16(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
Now on top of this lets delete the c member:
[acme@newtoy examples]$ codiff -V old_struct new_struct
struct.c:
struct foo | -4
nr_members: -1
-long unsigned int c; /* 8 4 */
a:2;
from: char /* 0(6) 1(2) */
to: char /* 0(4) 1(4) */
d;
from: long unsigned int /* 12(0) 4(0) */
to: long unsigned int /* 8(0) 4(0) */
e;
from: long unsigned int /* 16(0) 4(0) */
to: long int /* 12(0) 4(0) */
1 struct changed
[acme@newtoy examples]$
WOW, many changes, what an ABI breakage, no? :-)
It started as:
[acme@newtoy examples]$ pahole old_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:2; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int c; /* 8 4 */
long unsigned int d; /* 12 4 */
long unsigned int e; /* 16 4 */
}; /* size: 20, sum members: 17, holes: 1, sum holes: 3 */
And ended up as:
[acme@newtoy examples]$ pahole new_struct foo
/* /home/acme/pahole/examples/struct.c:3 */
struct foo {
char a:4; /* 0 1 */
/* XXX 3 bytes hole, try to pack */
unsigned int b; /* 4 4 */
long unsigned int d; /* 8 4 */
long int e; /* 12 4 */
}; /* size: 16, sum members: 13, holes: 1, sum holes: 3 */
[acme@newtoy examples]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 18:07:21 +01:00
|
|
|
}
|
2009-03-03 14:55:25 +01:00
|
|
|
if (new_structure != NULL) {
|
|
|
|
diff = (int)new_structure->padding - (int)structure->padding;
|
|
|
|
if (diff) {
|
|
|
|
terse_type_changes |= TCHANGEF__PADDING;
|
|
|
|
if (!show_terse_type_changes)
|
|
|
|
printf(" padding: %+d\n", diff);
|
|
|
|
}
|
|
|
|
diff = (int)new_structure->nr_holes - (int)structure->nr_holes;
|
|
|
|
if (diff) {
|
|
|
|
terse_type_changes |= TCHANGEF__NR_HOLES;
|
|
|
|
if (!show_terse_type_changes)
|
|
|
|
printf(" nr_holes: %+d\n", diff);
|
|
|
|
}
|
|
|
|
diff = ((int)new_structure->nr_bit_holes -
|
|
|
|
(int)structure->nr_bit_holes);
|
|
|
|
if (structure->nr_bit_holes != new_structure->nr_bit_holes) {
|
|
|
|
terse_type_changes |= TCHANGEF__NR_BIT_HOLES;
|
|
|
|
if (!show_terse_type_changes)
|
|
|
|
printf(" nr_bit_holes: %+d\n", diff);
|
|
|
|
}
|
2007-01-04 04:41:11 +01:00
|
|
|
check_print_members_changes(structure, cu,
|
|
|
|
new_structure, di->cu, 1);
|
2009-03-03 14:55:25 +01:00
|
|
|
}
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
if (show_terse_type_changes)
|
2009-03-06 14:57:41 +01:00
|
|
|
print_terse_type_changes(structure);
|
2006-11-12 15:29:33 +01:00
|
|
|
}
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
static int show_function_diffs_iterator(struct tag *tag, struct cu *cu,
|
2007-01-09 15:16:46 +01:00
|
|
|
void *cookie)
|
2006-11-12 15:29:33 +01:00
|
|
|
{
|
2007-01-04 00:29:24 +01:00
|
|
|
struct function *function = tag__function(tag);
|
|
|
|
|
2009-03-06 15:14:26 +01:00
|
|
|
if (tag__is_function(tag) && function->priv != NULL)
|
2007-01-09 15:16:46 +01:00
|
|
|
show_diffs_function(function, cu, cookie);
|
2006-11-12 15:29:33 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2006-12-29 18:28:58 +01:00
|
|
|
static int show_structure_diffs_iterator(struct tag *tag, struct cu *cu,
|
2007-01-29 13:42:03 +01:00
|
|
|
void *cookie __unused)
|
2006-11-12 15:29:33 +01:00
|
|
|
{
|
2006-12-29 18:28:58 +01:00
|
|
|
struct class *class;
|
|
|
|
|
2007-05-31 06:53:01 +02:00
|
|
|
if (!tag__is_struct(tag))
|
2006-12-29 18:28:58 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
class = tag__class(tag);
|
2007-12-17 14:27:24 +01:00
|
|
|
if (class->priv != NULL) {
|
2009-03-06 14:57:41 +01:00
|
|
|
const char *name = class__name(class);
|
2007-12-17 14:27:24 +01:00
|
|
|
if (!strlist__has_entry(structs_printed, name)) {
|
|
|
|
show_diffs_structure(class, cu);
|
|
|
|
strlist__add(structs_printed, name);
|
|
|
|
}
|
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cu_show_diffs_iterator(struct cu *cu, void *cookie)
|
|
|
|
{
|
|
|
|
static int first_cu_printed;
|
|
|
|
|
2006-11-12 15:29:33 +01:00
|
|
|
if (cu->nr_functions_changed == 0 &&
|
|
|
|
cu->nr_structures_changed == 0)
|
2006-11-11 19:31:04 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (first_cu_printed)
|
|
|
|
putchar('\n');
|
|
|
|
else
|
|
|
|
first_cu_printed = 1;
|
2006-11-12 02:14:02 +01:00
|
|
|
|
|
|
|
++total_cus_changed;
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
printf("%s:\n", cu->name);
|
2006-11-12 15:29:33 +01:00
|
|
|
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
if (show_terse_type_changes) {
|
2006-12-29 18:28:58 +01:00
|
|
|
cu__for_each_tag(cu, show_structure_diffs_iterator,
|
|
|
|
NULL, NULL);
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-12 15:41:44 +01:00
|
|
|
if (cu->nr_structures_changed != 0 && show_struct_diffs) {
|
2006-12-29 18:28:58 +01:00
|
|
|
cu__for_each_tag(cu, show_structure_diffs_iterator,
|
|
|
|
NULL, NULL);
|
2006-11-12 15:29:33 +01:00
|
|
|
printf(" %u struct%s changed\n", cu->nr_structures_changed,
|
|
|
|
cu->nr_structures_changed > 1 ? "s" : "");
|
2006-11-12 02:14:02 +01:00
|
|
|
}
|
2006-11-12 15:29:33 +01:00
|
|
|
|
2006-11-12 15:41:44 +01:00
|
|
|
if (cu->nr_functions_changed != 0 && show_function_diffs) {
|
2006-11-12 15:29:33 +01:00
|
|
|
total_nr_functions_changed += cu->nr_functions_changed;
|
|
|
|
|
2007-01-09 15:16:46 +01:00
|
|
|
cu__for_each_tag(cu, show_function_diffs_iterator, cookie, NULL);
|
2006-11-12 15:29:33 +01:00
|
|
|
printf(" %u function%s changed", cu->nr_functions_changed,
|
|
|
|
cu->nr_functions_changed > 1 ? "s" : "");
|
|
|
|
if (cu->function_bytes_added != 0) {
|
|
|
|
total_function_bytes_added += cu->function_bytes_added;
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(", %zd bytes added", cu->function_bytes_added);
|
2006-11-12 15:29:33 +01:00
|
|
|
}
|
|
|
|
if (cu->function_bytes_removed != 0) {
|
|
|
|
total_function_bytes_removed += cu->function_bytes_removed;
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(", %zd bytes removed",
|
|
|
|
cu->function_bytes_removed);
|
2006-11-12 15:29:33 +01:00
|
|
|
}
|
2008-01-03 17:55:20 +01:00
|
|
|
printf(", diff: %+zd",
|
|
|
|
cu->function_bytes_added - cu->function_bytes_removed);
|
2006-11-12 15:29:33 +01:00
|
|
|
putchar('\n');
|
2006-11-12 02:14:02 +01:00
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
static int cu_delete_priv(struct cu *cu, void *cookie __unused)
|
|
|
|
{
|
|
|
|
struct class *c;
|
|
|
|
struct function *f;
|
|
|
|
uint32_t id;
|
|
|
|
|
|
|
|
cu__for_each_struct(cu, id, c)
|
|
|
|
free(c->priv);
|
|
|
|
|
|
|
|
cu__for_each_function(cu, id, f)
|
|
|
|
free(f->priv);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-11-12 14:09:15 +01:00
|
|
|
static void print_total_function_diff(const char *filename)
|
|
|
|
{
|
|
|
|
printf("\n%s:\n", filename);
|
|
|
|
|
|
|
|
printf(" %u function%s changed", total_nr_functions_changed,
|
|
|
|
total_nr_functions_changed > 1 ? "s" : "");
|
|
|
|
|
2008-01-04 00:33:02 +01:00
|
|
|
if (total_function_bytes_added != 0)
|
2007-01-29 13:42:03 +01:00
|
|
|
printf(", %u bytes added", total_function_bytes_added);
|
2006-11-12 14:09:15 +01:00
|
|
|
|
2008-01-04 00:33:02 +01:00
|
|
|
if (total_function_bytes_removed != 0)
|
2007-01-29 13:42:03 +01:00
|
|
|
printf(", %u bytes removed", total_function_bytes_removed);
|
2009-03-14 17:50:36 +01:00
|
|
|
|
2008-01-04 00:33:02 +01:00
|
|
|
printf(", diff: %+d",
|
|
|
|
(total_function_bytes_added -
|
|
|
|
total_function_bytes_removed));
|
2006-11-12 14:09:15 +01:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
2009-02-13 13:57:23 +01:00
|
|
|
/* Name and version of program. */
|
|
|
|
ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version;
|
|
|
|
|
2007-03-30 15:37:37 +02:00
|
|
|
static const struct argp_option codiff__options[] = {
|
|
|
|
{
|
|
|
|
.key = 's',
|
|
|
|
.name = "structs",
|
|
|
|
.doc = "show struct diffs",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'f',
|
|
|
|
.name = "functions",
|
|
|
|
.doc = "show function diffs",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 't',
|
|
|
|
.name = "terse_type_changes",
|
|
|
|
.doc = "show terse type changes",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.key = 'V',
|
|
|
|
.name = "verbose",
|
|
|
|
.doc = "show diffs details",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = NULL,
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static error_t codiff__options_parser(int key, char *arg __unused,
|
|
|
|
struct argp_state *state __unused)
|
|
|
|
{
|
|
|
|
switch (key) {
|
|
|
|
case 'f': show_function_diffs = 1; break;
|
|
|
|
case 's': show_struct_diffs = 1; break;
|
|
|
|
case 't': show_terse_type_changes = 1; break;
|
|
|
|
case 'V': verbose = 1; break;
|
|
|
|
default: return ARGP_ERR_UNKNOWN;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-31 12:30:55 +01:00
|
|
|
static const char codiff__args_doc[] = "OLD_FILE NEW_FILE";
|
2007-03-30 15:37:37 +02:00
|
|
|
|
|
|
|
static struct argp codiff__argp = {
|
|
|
|
.options = codiff__options,
|
|
|
|
.parser = codiff__options_parser,
|
|
|
|
.args_doc = codiff__args_doc,
|
|
|
|
};
|
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2009-03-11 16:31:17 +01:00
|
|
|
int remaining, err, rc = EXIT_FAILURE;
|
2006-11-11 19:31:04 +01:00
|
|
|
struct cus *old_cus, *new_cus;
|
2007-04-30 20:44:11 +02:00
|
|
|
char *old_filename, *new_filename;
|
2009-02-10 00:43:56 +01:00
|
|
|
char *filenames[2];
|
2008-01-31 13:05:02 +01:00
|
|
|
struct stat st;
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2009-02-10 00:43:56 +01:00
|
|
|
if (argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL) ||
|
|
|
|
remaining < argc) {
|
2007-03-30 15:37:37 +02:00
|
|
|
switch (argc - remaining) {
|
|
|
|
case 2: old_filename = argv[remaining++];
|
|
|
|
new_filename = argv[remaining++]; break;
|
2006-11-11 19:31:04 +01:00
|
|
|
case 1:
|
2007-03-30 15:37:37 +02:00
|
|
|
default: goto failure;
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
|
|
|
} else {
|
2007-03-30 15:37:37 +02:00
|
|
|
failure:
|
2009-02-10 00:43:56 +01:00
|
|
|
argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, argv[0]);
|
2009-03-11 16:31:17 +01:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dwarves__init(0)) {
|
|
|
|
fputs("codiff: insufficient memory\n", stderr);
|
2006-11-11 19:31:04 +01:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
[CODIFF]: Terse mode
Well, needs to be a bit more terse, as prints the types per CU, i.e. for
types defined in multiple CUs we get them repeated, but using grep +
sort -u does the trick.
[acme@newtoy pahole]$ codiff -t /tmp/ipv6.ko.before /tmp/ipv6.ko.after | grep ^struct | sort -u
struct inet_connection_sock: size, offset
struct inet_sock: size, nr_members, offset
struct proto: nr_members, type
struct raw6_sock: size, offset
struct tcp6_sock: size
struct tcp_sock: size, offset
struct udp_sock: size, offset
[acme@newtoy pahole]$
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
2006-11-12 19:46:11 +01:00
|
|
|
if (show_function_diffs == 0 && show_struct_diffs == 0 &&
|
|
|
|
show_terse_type_changes == 0)
|
2006-11-12 15:41:44 +01:00
|
|
|
show_function_diffs = show_struct_diffs = 1;
|
|
|
|
|
2007-12-17 14:27:24 +01:00
|
|
|
structs_printed = strlist__new(false);
|
2008-10-01 17:47:42 +02:00
|
|
|
old_cus = cus__new();
|
|
|
|
new_cus = cus__new();
|
2007-12-17 14:27:24 +01:00
|
|
|
if (old_cus == NULL || new_cus == NULL || structs_printed == NULL) {
|
2006-11-11 19:31:04 +01:00
|
|
|
fputs("codiff: insufficient memory\n", stderr);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2008-01-31 13:05:02 +01:00
|
|
|
if (stat(old_filename, &st) != 0) {
|
|
|
|
fprintf(stderr, "codiff: %s (%s)\n", strerror(errno), old_filename);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2009-02-10 00:43:56 +01:00
|
|
|
filenames[1] = NULL;
|
2008-01-31 13:05:02 +01:00
|
|
|
|
|
|
|
/* If old_file is a character device, leave its cus empty */
|
|
|
|
if (!S_ISCHR(st.st_mode)) {
|
2009-03-13 14:49:01 +01:00
|
|
|
err = cus__load(old_cus, NULL, old_filename);
|
2008-01-31 13:05:02 +01:00
|
|
|
if (err != 0) {
|
2008-05-12 20:25:45 +02:00
|
|
|
cus__print_error_msg("codiff", old_cus, old_filename, err);
|
2008-01-31 13:05:02 +01:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|
|
|
|
|
2008-01-31 13:05:02 +01:00
|
|
|
if (stat(new_filename, &st) != 0) {
|
|
|
|
fprintf(stderr, "codiff: %s (%s)\n", strerror(errno), new_filename);
|
2006-11-11 19:31:04 +01:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2008-01-31 13:05:02 +01:00
|
|
|
/* If old_file is a character device, leave its cus empty */
|
|
|
|
if (!S_ISCHR(st.st_mode)) {
|
2009-03-13 14:49:01 +01:00
|
|
|
err = cus__load(new_cus, NULL, new_filename);
|
2008-01-31 13:05:02 +01:00
|
|
|
if (err != 0) {
|
2008-05-12 20:25:45 +02:00
|
|
|
cus__print_error_msg("codiff", new_cus, new_filename, err);
|
2008-01-31 13:05:02 +01:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-01 02:48:34 +01:00
|
|
|
cus__for_each_cu(old_cus, cu_diff_iterator, new_cus, NULL);
|
2007-01-04 00:29:24 +01:00
|
|
|
cus__for_each_cu(new_cus, cu_find_new_tags_iterator, old_cus, NULL);
|
2006-12-01 02:48:34 +01:00
|
|
|
cus__for_each_cu(old_cus, cu_show_diffs_iterator, NULL, NULL);
|
2007-01-06 18:17:58 +01:00
|
|
|
cus__for_each_cu(new_cus, cu_show_diffs_iterator, (void *)1, NULL);
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2006-11-12 15:41:44 +01:00
|
|
|
if (total_cus_changed > 1) {
|
|
|
|
if (show_function_diffs)
|
|
|
|
print_total_function_diff(new_filename);
|
|
|
|
}
|
2006-11-12 02:14:02 +01:00
|
|
|
|
2009-03-11 16:31:17 +01:00
|
|
|
rc = EXIT_SUCCESS;
|
|
|
|
out:
|
|
|
|
cus__for_each_cu(old_cus, cu_delete_priv, NULL, NULL);
|
|
|
|
cus__for_each_cu(new_cus, cu_delete_priv, NULL, NULL);
|
|
|
|
cus__delete(old_cus);
|
|
|
|
cus__delete(new_cus);
|
|
|
|
strlist__delete(structs_printed);
|
|
|
|
dwarves__exit();
|
|
|
|
return rc;
|
2006-11-11 19:31:04 +01:00
|
|
|
}
|