1

I want to do the same as in How to watch a member of a struct for every struct variable that has that type? - but I am on embedded, and have a problem. Say, I want to watch ((TCB_t*)pxReadyTasksLists[1].pxIndex.pxNext.pvOwner).xTaskRunState, however, pxReadyTasksLists is dynamically allocated array of structs, and so I don't have an absolute address I can use at "compile" time. So I tried this in gdb after my main function has advanced enough, so pxReadyTasksLists is allocated:

(gdb) p &(((TCB_t*)pxReadyTasksLists[1].pxIndex.pxNext.pvOwner))
$41 = (TCB_t **) 0x200015c4 <pxReadyTasksLists+40>

Good, so I have what looks like an accessible address here; however, if I try to find the address of the field:

(gdb) p &(((TCB_t*)pxReadyTasksLists[1].pxIndex.pxNext.pvOwner).xTaskRunState)
$43 = (volatile TaskRunning_t *) 0x38

(gdb) ptype TaskRunning_t
type = long int

... I get 0x38, which is kind of suspicious to me; in fact, that is the offset of the field in the struct:

(gdb) ptype /o (TCB_t*)pxReadyTasksLists[1].pxIndex.pxNext.pvOwner
type = struct tskTaskControlBlock {
/*      0      |       4 */    volatile StackType_t *pxTopOfStack;
/*      4      |       4 */    UBaseType_t uxCoreAffinityMask;
/*      8      |      20 */    ListItem_t xStateListItem;
/*     28      |      20 */    ListItem_t xEventListItem;
/*     48      |       4 */    UBaseType_t uxPriority;
/*     52      |       4 */    StackType_t *pxStack;
/*     56      |       4 */    volatile TaskRunning_t xTaskRunState;
/*     60      |       4 */    BaseType_t xIsIdle;
/*     64      |      16 */    char pcTaskName[16];
/*     80      |       4 */    UBaseType_t uxCriticalNesting;
/*     84      |       4 */    UBaseType_t uxTCBNumber;
/*     88      |       4 */    UBaseType_t uxTaskNumber;
/*     92      |       4 */    UBaseType_t uxBasePriority;
/*     96      |       4 */    UBaseType_t uxMutexesHeld;
/*    100      |      20 */    void *pvThreadLocalStoragePointers[5];
/*    120      |      12 */    volatile uint32_t ulNotifiedValue[3];
/*    132      |       3 */    volatile uint8_t ucNotifyState[3];
/*    135      |       1 */    uint8_t ucDelayAborted;

                               /* total size (bytes):  136 */
                             } *

(gdb) p /x 56
$46 = 0x38

So, obviously a watchpoint on address 0x38 would not (and does not) trigger.

I can of course calculate 0x200015c4+0x38 and set a "long int" watch there; but then, if I re-run the program in gdb, as pxReadyTasksLists is dynamically allocated, its base address will change, and so will ultimately the address of the particular xTaskRunState that I want to watch.

So in this case, is it possible to craft an expression, which gdb can use to derive the absolute address of (here) pxReadyTasksLists[1].pxIndex.pxNext.pvOwner.xTaskRunState, such that I can set a watchpoint on that address?

sdbbs
  • 4,270
  • 5
  • 32
  • 87
  • 2
    Here `&(((TCB_t*)pxReadyTasksLists[1].pxIndex.pxNext.pvOwner))` you get the address of `pvOwner` inside `pxNext`, not the value of `pvOwner`. Remove the `&`, I'm pretty sure it's actually NULL. – ssbssa Jun 23 '22 at 16:31
  • Many thanks @ssbssa - that was it; turns out pvOwner can be dynamically allocated too, and I did not take that into account; now things make sense ... – sdbbs Jun 24 '22 at 15:06

0 Answers0