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>
|
|
|
|
|
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)
|
|
|
|
|
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
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
assert(function->proto.tag.tag == DW_TAG_subprogram);
|
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;
|
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];
|
|
|
|
const struct tag *old_type = cu__find_tag_by_id(old_cu, old->tag.type);
|
|
|
|
const struct tag *new_type = cu__find_tag_by_id(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
|
|
|
|
2007-01-09 18:10:57 +01:00
|
|
|
old_size = tag__size(old_type, old_cu);
|
|
|
|
new_size = tag__size(new_type, new_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
|
|
|
if (old_size != new_size)
|
|
|
|
changes = 1;
|
|
|
|
|
|
|
|
if (old->offset != new->offset) {
|
|
|
|
changes = 1;
|
|
|
|
terse_type_changes |= TCHANGEF__OFFSET;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old->bit_offset != new->bit_offset) {
|
|
|
|
changes = 1;
|
|
|
|
terse_type_changes |= TCHANGEF__BIT_OFFSET;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old->bit_size != new->bit_size) {
|
|
|
|
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"
|
2007-03-28 16:38:32 +02:00
|
|
|
" from: %-21s /* %5u(%u) %5zd(%d) */\n"
|
|
|
|
" to: %-21s /* %5u(%u) %5zd(%u) */\n",
|
2007-01-09 18:10:57 +01:00
|
|
|
old->name,
|
|
|
|
old_type_name, old->offset, old->bit_offset,
|
2006-12-28 13:09:18 +01:00
|
|
|
old_size, old->bit_size,
|
2007-01-09 18:10:57 +01:00
|
|
|
new_type_name, new->offset, new->bit_offset,
|
2006-12-28 13:09:18 +01:00
|
|
|
new_size, new->bit_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;
|
|
|
|
|
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 =
|
|
|
|
class__find_member_by_name(new_structure, member->name);
|
|
|
|
if (twin != NULL)
|
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;
|
|
|
|
}
|
|
|
|
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
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
if (class__size(structure) == 0 || class__name(structure, cu) == NULL)
|
2006-11-12 15:29:33 +01:00
|
|
|
return;
|
|
|
|
|
2007-11-16 21:16:56 +01:00
|
|
|
new_tag = cu__find_struct_by_name(new_cu, class__name(structure, cu), 0);
|
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,
|
|
|
|
new_structure, new_cu, 0);
|
|
|
|
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;
|
2007-05-24 23:45:34 +02:00
|
|
|
len = strlen(class__name(structure, cu)) + 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);
|
2007-01-04 00:29:24 +01:00
|
|
|
else if (tag->tag == DW_TAG_subprogram)
|
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
|
|
|
|
2006-12-30 19:34:20 +01:00
|
|
|
assert(function->proto.tag.tag == DW_TAG_subprogram);
|
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);
|
2007-05-24 23:45:34 +02:00
|
|
|
if (class__name(class, cu) == 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;
|
|
|
|
|
2007-11-16 21:16:56 +01:00
|
|
|
if (cu__find_struct_by_name(old_cu, class__name(class, cu), 0) != 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
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
len = strlen(class__name(class, cu)) + 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)
|
|
|
|
{
|
|
|
|
if (tag->tag == DW_TAG_subprogram)
|
|
|
|
return find_new_functions_iterator(tag, cu, old_cu);
|
|
|
|
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);
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
if (old_cu != NULL)
|
|
|
|
cu__for_each_tag(new_cu, find_new_tags_iterator,
|
2006-12-29 18:28:58 +01:00
|
|
|
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);
|
|
|
|
|
2007-01-04 00:29:24 +01:00
|
|
|
if (new_cu != NULL)
|
|
|
|
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 {
|
|
|
|
const struct function *twin = tag__function(di->tag);
|
|
|
|
|
2008-01-03 16:03:32 +01:00
|
|
|
if (twin->inlined)
|
|
|
|
puts(cookie ? " (uninlined)" : " (inlined)");
|
|
|
|
else if (strcmp(function->name, twin->name) != 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__,
|
|
|
|
function->name, twin->name);
|
2007-02-25 02:12:34 +01:00
|
|
|
else {
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(" # %zd -> %zd", 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)
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(", size inlines: %zd -> %zd",
|
2007-02-25 02:12:34 +01:00
|
|
|
function->lexblock.size_inline_expansions,
|
|
|
|
twin->lexblock.size_inline_expansions);
|
|
|
|
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
|
|
|
{
|
2007-01-09 18:10:57 +01:00
|
|
|
const struct tag *type = cu__find_tag_by_id(cu, member->tag.type);
|
|
|
|
char bf[128];
|
|
|
|
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(" %c%-26s %-21s /* %5u %5zd */\n",
|
2007-01-09 18:10:57 +01:00
|
|
|
change, tag__name(type, cu, bf, sizeof(bf)), member->name,
|
|
|
|
member->offset, tag__size(type, 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
|
|
|
}
|
|
|
|
|
|
|
|
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 =
|
|
|
|
class__find_member_by_name(new_structure, member->name);
|
|
|
|
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 =
|
|
|
|
class__find_member_by_name(structure, member->name);
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
static void print_terse_type_changes(struct class *structure,
|
|
|
|
const struct cu *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
|
|
|
{
|
|
|
|
const char *sep = "";
|
|
|
|
|
2007-05-24 23:45:34 +02:00
|
|
|
printf("struct %s: ", class__name(structure, 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
|
|
|
|
|
|
|
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 = ", ";
|
|
|
|
}
|
|
|
|
if (terse_type_changes & TCHANGEF__BIT_SIZE)
|
|
|
|
printf("%sbit_size", sep);
|
|
|
|
|
|
|
|
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")),
|
2007-05-24 23:45:34 +02:00
|
|
|
class__name(structure, cu), 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
|
|
|
}
|
2006-12-24 16:35:21 +01:00
|
|
|
if (new_structure != NULL)
|
2007-01-04 04:41:11 +01:00
|
|
|
check_print_members_changes(structure, cu,
|
|
|
|
new_structure, di->cu, 1);
|
[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)
|
2007-05-24 23:45:34 +02:00
|
|
|
print_terse_type_changes(structure, cu);
|
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);
|
|
|
|
|
2007-01-04 04:41:11 +01:00
|
|
|
if (tag->tag == DW_TAG_subprogram && 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) {
|
|
|
|
const char *name = class__name(class, cu);
|
|
|
|
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) {
|
2007-01-09 15:22:03 +01:00
|
|
|
int kind = 0;
|
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) {
|
2007-01-09 15:22:03 +01:00
|
|
|
++kind;
|
2006-11-12 15:29:33 +01:00
|
|
|
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) {
|
2007-01-09 15:22:03 +01:00
|
|
|
++kind;
|
2006-11-12 15:29:33 +01:00
|
|
|
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
|
|
|
}
|
2007-01-09 15:22:03 +01:00
|
|
|
if (kind == 2)
|
2007-03-28 16:38:32 +02:00
|
|
|
printf(", diff: %+zd",
|
2007-01-09 15:22:03 +01:00
|
|
|
(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;
|
|
|
|
}
|
|
|
|
|
2006-11-12 14:09:15 +01:00
|
|
|
static void print_total_function_diff(const char *filename)
|
|
|
|
{
|
2007-01-09 15:22:03 +01:00
|
|
|
int kind = 0;
|
|
|
|
|
2006-11-12 14:09:15 +01:00
|
|
|
printf("\n%s:\n", filename);
|
|
|
|
|
|
|
|
printf(" %u function%s changed", total_nr_functions_changed,
|
|
|
|
total_nr_functions_changed > 1 ? "s" : "");
|
|
|
|
|
2007-01-09 15:22:03 +01:00
|
|
|
if (total_function_bytes_added != 0) {
|
|
|
|
++kind;
|
2007-01-29 13:42:03 +01:00
|
|
|
printf(", %u bytes added", total_function_bytes_added);
|
2007-01-09 15:22:03 +01:00
|
|
|
}
|
2006-11-12 14:09:15 +01:00
|
|
|
|
2007-01-09 15:22:03 +01:00
|
|
|
if (total_function_bytes_removed != 0) {
|
|
|
|
++kind;
|
2007-01-29 13:42:03 +01:00
|
|
|
printf(", %u bytes removed", total_function_bytes_removed);
|
2007-01-09 15:22:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (kind == 2)
|
2007-01-29 13:42:03 +01:00
|
|
|
printf(", diff: %+d",
|
2007-01-09 15:22:03 +01:00
|
|
|
(total_function_bytes_added -
|
|
|
|
total_function_bytes_removed));
|
2006-11-12 14:09:15 +01:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char codiff__args_doc[] = "[OLD_FILE] [NEW_FILE]";
|
|
|
|
|
|
|
|
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[])
|
|
|
|
{
|
2007-03-30 15:37:37 +02:00
|
|
|
int remaining, err;
|
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;
|
|
|
|
char *dwfl_argv[4];
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2007-03-30 15:37:37 +02:00
|
|
|
argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL);
|
2006-11-11 19:31:04 +01:00
|
|
|
|
2007-03-30 15:37:37 +02:00
|
|
|
if (remaining < argc) {
|
|
|
|
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:
|
|
|
|
argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, "codiff");
|
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-01-19 00:41:25 +01:00
|
|
|
dwarves__init(0);
|
|
|
|
|
2007-12-17 14:27:24 +01:00
|
|
|
structs_printed = strlist__new(false);
|
2007-01-07 15:30:58 +01:00
|
|
|
old_cus = cus__new(NULL, NULL);
|
|
|
|
new_cus = cus__new(NULL, NULL);
|
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;
|
|
|
|
}
|
|
|
|
|
2007-04-30 20:44:11 +02:00
|
|
|
dwfl_argv[0] = argv[0];
|
|
|
|
dwfl_argv[1] = "-e";
|
|
|
|
dwfl_argv[2] = old_filename;
|
|
|
|
dwfl_argv[3] = NULL;
|
|
|
|
err = cus__loadfl(old_cus, NULL, 3, dwfl_argv);
|
2007-03-28 17:54:46 +02:00
|
|
|
if (err != 0) {
|
|
|
|
cus__print_error_msg("codiff", old_filename, err);
|
2006-11-11 19:31:04 +01:00
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2007-04-30 20:44:11 +02:00
|
|
|
dwfl_argv[2] = new_filename;
|
|
|
|
err = cus__loadfl(new_cus, NULL, 3, dwfl_argv);
|
2007-03-28 17:54:46 +02:00
|
|
|
if (err != 0) {
|
|
|
|
cus__print_error_msg("codiff", new_filename, err);
|
2006-11-11 19:31:04 +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
|
|
|
|
2006-11-11 19:31:04 +01:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|