1

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?

wrymarkX
  • 99
  • 8

2 Answers2

4

Well, sounds for me that you have two questions:

  1. How to display linked lists?
  2. How to get the byte offset of a member in a struct?

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)
Holger
  • 3,920
  • 1
  • 13
  • 35
  • Just to clarify. Question 1 was how to display **Linux** linked lists. `Var.CHAIN` does not do the job in this case. Answer to question 2 was to the point. Many thanks. – wrymarkX Nov 11 '15 at 13:24
  • OK, just learned what "Linux linked lists" are. I am pretty sure that a nice list viewing of the modules chained together via list_head is not possible with TRACE32. Furthermore I assume a debugger is only able to view such a list, if the offset of the 'next' element within the containing module is fixed for all modules in the linked list. I suggest to contact the Lauterbach support. Maybe they can add a suitable feature if possible (they usually do). – Holger Nov 11 '15 at 13:40
  • 1
    With `container_of()` macro you proposed and a loop I can do the job pretty well. Another aspect is that the list does not end with null, instead I see next=0x55555555. Don't understand yet if this is linux specific handling. – wrymarkX Nov 12 '15 at 16:18
  • BTW. I use `var.VIEW` to display every node in the loop. Obviously, every call to `var.VIEW` opens a window. Is there any quick method to put results in one window in T32? – wrymarkX Nov 12 '15 at 16:22
  • Use `Var.AddWatch` instead of `Var.View`. Same syntax but appends the variable to an existing watch-window (or opens a new one if no watch-window is yet open) – Holger Nov 12 '15 at 18:12
  • Works as a charm. Thanks. – wrymarkX Nov 17 '15 at 09:59
0

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),