Need help finishing .Natvis XML file for viewing GRPC/Protobuf types in debugger

290 views
Skip to first unread message

Steven Peterson

unread,
Jan 26, 2023, 2:46:16 PM1/26/23
to grpc.io
I'm using GRPC for C++ with Visual Studio 2022, and trying to write a NatVis Framework XML file, so that GRPC data-type values are clearly displayed in the debugger. By default, string-values, and the values of elements in a collection are entirely unavailable in the C++ debugger, when dealing with GRPC datatypes. I need to be able to see these values.

(Natvis Framework is a Visual Studio feature: https://learn.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022 )

 As it is now:
1) I still can't resolve strings to see them in the debugger. My NatVis 'ArenaStringPtr' definition gets me a few chineses charecters, but I played with the MS 'Format Specifiers' "S, SU, S8, C" etc., and none got me any closer than this:
    Example Value shown in debugger:   { string={ptr_= L"鏰而Ǘ" } }    google::protobuf::internal::ArenaStringPtr

2) Anything defined as 'repeated' in the protobuf - I can now expand as a listing of numbered elements, but still not see the values, I get a listing like:
    [0] <struct at NULL> google::protobuf::Arena
[1] {impl_={tag_and_id_=??? alloc_policy_=??? threads_=??? ...} } google::protobuf::Arena
[2] {impl_={tag_and_id_=??? alloc_policy_=??? threads_=??? ...} } google::protobuf::Arena

    ...

I can't post my exact code, but I was able to copy a small group of definitions (whose pattern covers the majority of my use cases),  and change all of the property-names. I've been messing with this awhile and aren't makeing any further progress.

Q1) Are there any default GRPC .natvis files availble?
Q2) Is there either a way for protoc to generate the protobuf-specific .natvis for a .proto file, or another tool available to auto-generate these .natvis files for protobuf defined types?
Q3) How can I finish this .natvis to see the strings-values, and the values of my collection-elements in the debugger for Protobuf.

-----my.proto-------

syntax = "proto3";

package Acme.RPC;
option csharp_namespace = "Acme.RPC";

enum Color {
    RED = 0;
    GREEN =1;
    BLUE = 2;
    }

message Bar {
    string  description = 1;
    float   score = 2;
    int64   max = 3;
    int64   min = 4;
    bool    isFinal = 5;
    Color color = 6;
}

message FooResult {
    repeated Bar scoreValues = 1;
    float    totalScore = 2;
    string   name = 3;
}

message FooGroup {
    repeated FooResult details = 1;
    FooResult answer = 2;
}
------------


-------------my.natvis-------------
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
   
    <Type Name="Acme::RPC::FooGroup">
        <DisplayString>{{ Groups={details.current_size_} Has Final Answer={has_answer()} }}</DisplayString> <!-- display true/false based on
                                                                                                            if the 'answer' value is populated? -->
        <Expand>
            <Item Name="[Details&lt;Bar&gt;]">details_</Item>
            <Item Name="[Answer]">answer_</Item>
        </Expand>
    </Type>
   
    <Type Name="Acme::RPC::FooResult">        
        <DisplayString>{{ Name={name_} Score={totalscore_} }}</DisplayString>
        <Expand>
            <Item Name="[Score Values&lt;Bar&gt;]">scorevalues_</Item>
            <Item Name="[Total Score]">totalscore_</Item>
            <Item Name="[name]">name_</Item>
        </Expand>
    </Type>

    <Type Name="google::protobuf::internal::RepeatedPtrFieldBase">
        <DisplayString>{{ size={current_size_} }}</DisplayString>
        <Expand>
            <ArrayItems>
                <Size>current_size_</Size>
                <ValuePointer>arena_</ValuePointer>     <!-- So close, and yet so far -->
            </ArrayItems>
        </Expand>
    </Type>

    <Type Name="Acme::RPC::Bar">        
        <DisplayString>{{ Phrase={phrase_} }}</DisplayString>
        <Expand>
            <Item Name="[Description]">description</Item>       <!-- doesn't work -->
            <Item Name="[Description 2]">description_</Item>    <1-- still not correct -->
            <Item Name="[Score]">score_</Item>
            <Item Name="[Max]">max_</Item>
            <Item Name="[Min]">min_</Item>
            <Item Name="[IsFinal]">isfinal_</Item>
            <Item Name="[Color]">color_</Item>
        </Expand>
    </Type>
       
    <Type Name="google::protobuf::Arena">        
        <DisplayString>{{ Hi={42} }}</DisplayString>        
        <Expand>            
            <Item Name="[my Impl]">impl_</Item>
        </Expand>
    </Type>
   
    <Type Name="google::protobuf::internal::ArenaStringPtr">
        <DisplayString>{{ string={tagged_ptr_,su} }}</DisplayString>
        <StringView>tagged_ptr_,su</StringView>
       
        <!-- (This seems to fail, preventing the above line from taking effect)
        <Expand>
            <Item Name="[tagged_ptr_]">tagged_ptr_,su</Item>
            <Item Name="[ptr_]">ptr_,s</Item>
        </Expand>
        -->            
    </Type>
</AutoVisualizer>

Sam Riesland

unread,
Sep 18, 2024, 6:00:38 PM9/18/24
to grpc.io
The following natvis works for me. I added a bit to what I found here: https://github.com/KindDragon/CPPDebuggerVisualizers/issues/11

<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">

  <Type Name="google::protobuf::RepeatedField&lt;*&gt;">

    <DisplayString>{{ size={current_size_} }}</DisplayString>
    <Expand>
      <Item Name="[size]" ExcludeView="simple">current_size_</Item>
      <Item Name="[capacity]" ExcludeView="simple">total_size_</Item>
      <Item Name="[arena]" Condition="total_size_ == 0 &amp;&amp; arena_or_elements_" ExcludeView="simple">arena_or_elements_</Item>
      <ArrayItems Condition="total_size_ != 0">
        <Size>current_size_</Size>
        <ValuePointer>($T1*)arena_or_elements_</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <Type Name="google::protobuf::RepeatedPtrField&lt;*&gt;">

    <DisplayString>{{ size={current_size_} }}</DisplayString>
    <Expand>
      <Item Name="[size]" ExcludeView="simple">current_size_</Item>
      <Item Name="[capacity]" ExcludeView="simple">total_size_</Item>
      <Item Name="[arena]" Condition="arena_" ExcludeView="simple">arena_</Item>
      <ArrayItems Condition="rep_ != 0">
        <Size>current_size_</Size>
        <ValuePointer>($T1**)rep_->elements</ValuePointer>
      </ArrayItems>
    </Expand>
  </Type>

  <Type Name="google::protobuf::internal::TaggedStringPtr">
      <DisplayString>{string={*(std::string*)((uint64_t)(ptr_) &amp; ~0x3)}}}</DisplayString>
      <Expand>
        <Item Name="[string ptr]">(std::string*)((uint64_t)(ptr_) &amp; ~0x3)</Item>
        <Item Name="[raw ptr_]">ptr_</Item>

      </Expand>
  </Type>
 
  <Type Name="google::protobuf::internal::ArenaStringPtr">
    <DisplayString>{{{*(std::string*)((uint64_t)(tagged_ptr_.ptr_) &amp; ~0x3)}}}</DisplayString>
  </Type>

</AutoVisualizer>

Reply all
Reply to author
Forward
0 new messages