views:

299

answers:

3

Is there any easy way to view the data in an STL std::list<T> in the Metrowerks CodeWarrior debugger? I can view data near the beginning or end of the list by looking at expressions such as

instances->__list_imp.__list_deleter.end_.compressed_pair_imp.second_.prev_->data_

I can expand the little '+' signs next to the struct members to walk the list an element at a time, but this is tedious, and after about 20-30 elements, the tree gets too wide for the debugger window. The list I'm examining has over 2000 elements.

The CodeWarrior debugger does not support calling functions in expressions, so I can't examine the value of (++(++instances.begin())) or somesuch. I can only look at struct members, which have very long and inconvenient names.

The debugger window is also limited to about 245 characters, so I can't write a script to generate a ridiculously long expression that will expand to the Nth node.

I'm trying to debug a problem that requires several hours of soaking to reproduce, so anything that requires adding code incrementally, recompiling, and redebugging will not be very helpful. If there's no other option, though, then I may have to do that.

+1  A: 

This definitely isn't an "easy way" (it may not be easier than what you're doing with "+"), but I do find it more helpful than dealing with the watch view in some cases. It also may allow you to debug in really bad circumstances (where the watch view is nearly non-functional for whatever reason, or where you just have a binary memory dump file).

With a std::list, you typically have an implementation that looks something like this in memory (consult <list> for specifics if necessary):

struct List
{
  Node * next;
  Node * prev;
  size_t size;
}

template 
struct Node
{
  Node * next;  // last node will point to list rather than another node
  Node * prev;  // first node will point to list rather than another node
  T payload; // e.g. in a std::list this would be a Foo * payload
}

Note that next and prev may be in the opposite order in your implementation.

&myList is basically equivalent to "end()" in most implementations.

If you use memory view, you can poke around near &myList. This will let you find the value of the myList.prev or myList.next pointer, then change memory view to look at that. You've then gotten to the last or first node in your list, respectively.

Once you get to a node, you can look at prev, next, or payload, then go to prev or next; lather, rinse, repeat. If you end up back at &myList, you know you've traversed the whole thing.

Painful and boring? Possibly. But you do get a lot of familiarity with your stl implementation, you can "see" possible stomps easily in some cases, and it's a useful skill to have when all other possibilities fly out the window.

(Keep notes of where you've been, it's really easy to get confused.)

leander
A: 

Debuggers could certainly be a lot more STL-friendly. I'm not familiar with CodeWarrior specifically, but is it the case that you can't call any functions at all from the debug window? Or is it more like other debuggers I have used, where you (1) can't call functions if the program has already terminated (ABORT, segfault, ...), and (2) can't call functions that involve template expansions (which might need to add code to the image), but (3) can call statically-linked functions if the code is stopped at a breakpoint?

In the latter case, you might want to add one or more non-templated functions to your code that copy a list<T> into a C-style array of T, for the specific types you are interested in. If you can call that kind of function from your debug window, do that, and then examine the array elements to find out what's in your list. If you can't call the function from the debug window, you may need to put some calls to that function in your code close to the point of error, and look at the results. If possible, guard those calls so they only get called when you have some debug flag set.

dewtell
A: 

It turns out the problem I was having was due to the very fact that the list had several thousand elements -- it should only have had a couple dozen elements, max.

In this particular STL implementation, the prev pointers were stored at offset 0 of each node, so I could follow back links by just repeatedly dereferencing. The following monstrosity looks backwards 20 links:

********************((Metrowerks::node_base**********************)instances->__list_imp.__list_deleter.end_.compressed_pair_imp.second_)

Following forward links is even uglier, since you have to offset by 4 bytes after each dereference.

Adam Rosenfield