Reputation: 99
I try to print Linux linked list in user friendly way in Trace32.
1. Is there already any known method available?
If not then let me show an example with modules list.
I have global variable
static struct list_head modules;
where
struct list_head {
struct list_head *next, *prev;
};
So, in T32 I just see list of next and prev pointers when doing v.v modules
, no useful info in fact. However, every node of modules list is a part of a container type. In this case struct module
struct module {
...
struct list_head list;
...
}
Normally, to extract container pointer Linux uses container_of macro.
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
In our example we know the pointer to struct list_head
which is a list
member in struct module
then we should call container_of(modules->next, struct module, list)
to get a pointer to the container.
To be able to archive this in T32 I need to calculate offset of the list
member in container type.
Anyone knows how to achieve this?
Upvotes: 1
Views: 1857
Reputation: 9
Between Var.CHAIN and VAR.FixedCHAIN command, I guess Var.CHAIN displayed more detailed linked list information.
In case of linux kernel system, the following command allows for the complete list of linked list.
v.chain %m %l %tree.open %hex init_task.tasks init_task.tasks.next
0x0 (0)| [D:0xC1612588] (
| [D:0xC1612588] next = 0xEE058220,
| [D:0xC161258C] prev = 0xE5C0B3A0),
0x1 (1)| [D:0xEE058220] (
| [D:0xEE058220] next = 0xEE0587A0,
| [D:0xEE058224] prev = 0xC1612588),
0x2 (2)| [D:0xEE0587A0] (
| [D:0xEE0587A0] next = 0xEE058D20,
| [D:0xEE0587A4] prev = 0xEE058220),
0x3 (3)| [D:0xEE058D20] (
| [D:0xEE058D20] next = 0xEE0592A0,
| [D:0xEE058D24] prev = 0xEE0587A0),
0x4 (4)| [D:0xEE0592A0] (
| [D:0xEE0592A0] next = 0xEE059820,
| [D:0xEE0592A4] prev = 0xEE058D20),
0x5 (5)| [D:0xEE059820] (
| [D:0xEE059820] next = 0xEE059DA0,
| [D:0xEE059824] prev = 0xEE0592A0),
0x6 (6)| [D:0xEE059DA0] (
| [D:0xEE059DA0] next = 0xEE05A320,
| [D:0xEE059DA4] prev = 0xEE059820),
0x7 (7)| [D:0xEE05A320] (
| [D:0xEE05A320] next = 0xEE05A8A0,
| [D:0xEE05A324] prev = 0xEE059DA0),
0x8 (8)| [D:0xEE05A8A0] (
| [D:0xEE05A8A0] next = 0xEE05AE20,
| [D:0xEE05A8A4] prev = 0xEE05A320),
0x9 (9)| [D:0xEE05AE20] (
| [D:0xEE05AE20] next = 0xEE05B3A0,
| [D:0xEE05AE24] prev = 0xEE05A8A0),
0x0A (10)| [D:0xEE05B3A0] (
| [D:0xEE05B3A0] next = 0xEE05B920,
| [D:0xEE05B3A4] prev = 0xEE05AE20),
0x0B (11)| [D:0xEE05B920] (
| [D:0xEE05B920] next = 0xEE05BEA0,
| [D:0xEE05B924] prev = 0xEE05B3A0),
0x0C (12)| [D:0xEE05BEA0] (
| [D:0xEE05BEA0] next = 0xEE05C420,
| [D:0xEE05BEA4] prev = 0xEE05B920),
0x0D (13)| [D:0xEE05C420] (
| [D:0xEE05C420] next = 0xEE05DA20,
| [D:0xEE05C424] prev = 0xEE05BEA0),
0x0E (14)| [D:0xEE05DA20] (
| [D:0xEE05DA20] next = 0xEE05DFA0,
| [D:0xEE05DA24] prev = 0xEE05C420),
0x0F (15)| [D:0xEE05DFA0] (
| [D:0xEE05DFA0] next = 0xEE05E520,
| [D:0xEE05DFA4] prev = 0xEE05DA20),
Upvotes: 0
Reputation: 4183
Well, sounds for me that you have two questions:
For displaying linked lists I suggest the command Var.CHAIN or VAR.FixedCHAIN. Both commands have two mandatory arguments: Variable name of the struct and name of the next element. (You can look up all the optional arguments and format options in the TRACE32 manual.)
So, view your first simple case with
Var.CHAIN modules modules.next
A window will open with a table showing you the complete list until 'next' points to NULL.
Note: As stated by Wrymarki below in the comments, this first part of the answer is actually wrong. Var.CHAIN works for ordinary linked lists, but not for "Linux linked lists". Solution for "Linux linked lists" (by Wrymarki) is to write a PRACTICE script which loops through the list and adds the list entries with Var.AddWatch to a watch-window by using the container_of() macro (see below).
For getting the offsset of of a member in a struct I recommend to declare preprocessor macros just like you do in your source code. Or almost like in your source code since TRACE32 does not know GCC specific extensions like typeof() or statement expressions.
Anyway, we can get the offsetof() macro with
sYmbol.NEW.MACRO offsetof(type,member) ((int)(&((type*)0)->member))
A preprocessor macro can be used inside every HLL expression in TRACE32 (with all Var.* commands and functions). E.g.:
Var.AddWatch offsetof(struct module,list)
Note: sYmbol.NEW.MACRO does not accept spaces in the macro name: You have to write offsetof(type,member)
instead of offsetof(type, member)
.
You can view your macros in window sYmbol.List.MACRO
You can also get the macros from your source code if your compiler support this (GCC does with option -g3) when loading your ELF with option /MACRO: Data.LOAD.Elf * /MACRO
. But again: TRACE32 will not understand GCC specific extensions or internal macros like '__builtin_offsetof()'.
You can also declare a container_of() preprocessor macro with
sYmbol.NEW.MACRO container_of(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
Use it e.g. as follows:
Var.View container_of(modules->next,struct module,list)
Upvotes: 4