简体   繁体   中英

Circular Double Linked list visualization using natvis

I would like to write a natvis visualizer for a double linked list. The list does not have a count node stored, and the easy way does not work very well, as the expansion never stops (next is never null, the last item of the list is pointing to the list root).

<Type Name="TListBidir&lt;*&gt;">
    <Expand>
        <LinkedListItems>
            <HeadPointer>next</HeadPointer>
            <NextPointer>next</NextPointer>
            <ValueNode>($T1 *)this</ValueNode>
        </LinkedListItems>
    </Expand>
</Type>

I hoped I will be able to add a Condition attribute the the NextPointer comparing it with the list head, but as the NextPoint is evaluated in the context of the node, I do not know what to compare it with:

<NextPointer Condition="next!=XXXXXXXXX">next</NextPointer>

This is how it looked like with previous (2010) visualizers, using the skip directive, as the #list was handling this automatically :

#list is protected against infinite traversals and will cope gracefully with a circular list. Also, you can use a skip: expression to denote a sentinel node that should not be reported. Although the name implies that the node will be skipped, it actually causes traversal to stop, so if your sentinel node is first you should start traversal after it.

TListBidir<*,*,*>{
    children
    (
      #list(
        head: ((($T2 *)&$c)->next),
        next: next,
        skip : &($c)
      ): (($T1 *)(&$e))
    )
}

How can I explain in the natvis to the debugger it should stop expanding the list once it reaches the root element again?

I had a similar problem, not with a circular list, but with a sentinel node at the end that pointed at itself, and came up with an interesting solution that might be adaptable to your needs: You could use the ternary operator to fake out a real termination. The expressions inside <NextPointer> can be anything you can write in vanilla C, so you can do real computation in there (but sadly, no recursion).

(Note that you're not allowed to put a Condition attribute on <NextPointer> , so the ternary operator is the only way to accomplish conditions there.)

So in my case, the list terminated like this:

<LinkedListItems>
    <HeadPointer>this</HeadPointer>
    <NextPointer>next != this ? next : 0</NextPointer>
    <ValueNode>items</ValueNode>
</LinkedListItems>

In your case, if the nodes each have a pointer to their container, you can use that to compare against the head node:

<LinkedListItems>
    <HeadPointer>container-&gt;head</HeadPointer>
    <NextPointer>next != container-&gt;head ? next : 0</NextPointer>
    <ValueNode>items</ValueNode>
</LinkedListItems>

Or, without the &gt; entities and written as more traditional C, that's equivalent to:

next != container->head ? next : NULL

If you don't have some kind of container back-pointer, though, you're probably out of luck on this, since there's no way by looking at only a single node in a circularly-linked list to answer whether it's effectively the "last" node.

You can do this with a CustomListItems element:

<CustomListItems>
    <Variable Name="orig_head" InitialValue="head"/>
    <Variable Name="iter" InitialValue="first_elem"/>
    <Loop>
        <Break Condition="iter == orig_head || iter == 0"/>
        <Item>*iter</Item>
        <Exec>iter = iter-&gt;next_elem</Exec>
    </Loop>
</CustomListItems>

CustomListItems allows you to save the head in a variable so it can be used while traversing the list. If your head has a different type then the list nodes you will need to cast it to the node type.

The natvis framework does not currently support circular linked lists without a count provided. If you provide a count, it should work. However, without a count, there is no good way to prevent the expansion from just continuing on forever.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM