[lldb-dev] Using data formatters to display QString

Eran Ifrah eran.ifrah at gmail.com
Tue Apr 29 14:07:49 PDT 2014


Hi,
I have tried to follow the Driver.cpp file (lldb main?) code and see what
it does that I am not doing properly.
The only difference that I could tell was that it creates the debugger like
this:

m_debugger( SBDebugger::Create(false) );

and later it manually does this:

sb_interpreter.SourceInitFileInHomeDirectory(result);

So I tried to use this approach as well - it failed (for me calling
SourceInitFileInHomeDirectory did not work at all, i.e. I could not see
QString registered)
However, sourcing the ~/.lldbinit file after the target creation did the
trick:

wxString source_command;
source_command << "command source '" << ::wxGetHomeDir() << "/.lldbinit" <<
"'";
DoExecutueShellCommand( source_command, true );

worked!
I can now view QString as pure strings in my plugin

Thanks for the help
Eran




On Tue, Apr 29, 2014 at 11:30 PM, Enrico Granata <egranata at apple.com> wrote:

> Well that seems to imply we don't know what the qstring module is when
> trying to use it to run the formatter
>
> How are you loading the python script from your plugin?
>
> Another thing that you could try is debug LLDB and see what happens when
> we try fetching the summary. I am expecting we will fail to find the
> function object and then we can take it from there.
>
>
> Sent from the iPhone of
> *Enrico Granata* <egranata@🍎.com>
>
> On Apr 29, 2014, at 1:20 PM, Eran Ifrah <eran.ifrah at gmail.com> wrote:
>
>
>
>
> On Tue, Apr 29, 2014 at 8:15 PM, Enrico Granata <egranata at apple.com>wrote:
>
>>
>> On Apr 29, 2014, at 6:50 AM, Eran Ifrah <eran.ifrah at gmail.com> wrote:
>>
>> Hi Enrico and all,
>> Thanks for the references, it helped me a lot.
>> I am now able to view QString within lldb from the *command line*, but
>> not from within my plugin :P (this was my intention all the way)
>>
>> I created the following 2 files:
>> ~/.lldbinit, with this single line:
>>
>> command script import /home/eran/.lldb/qstring.py
>>
>> In the script: ~/.lldb/qstring.py, I placed the following content (a
>> slightly modified printer based on your example):
>>
>> import lldb
>>
>> def utf16string_summary(value, *rest):
>>     f = open('/tmp/py.log','w+b')
>>     f.write('inside utf16string_summary\n')
>>     f.close()
>>     str_data =
>> value.GetChildMemberWithName("d").GetChildMemberWithName("data")
>>     length_vo =
>> value.GetChildMemberWithName("d").GetChildMemberWithName("size")
>>     length = length_vo.GetValueAsUnsigned(0)
>>     if length == 0:
>>         return '""'
>>     data = str_data.GetPointeeData(0, length)
>>     error = lldb.SBError()
>>     bytes = data.ReadRawData(error, 0, 2*length)
>>     return '"%s"' % (bytes.decode('utf-16').encode('utf-8'))
>>
>> def __lldb_init_module(debugger, *rest):
>>     summary =
>> lldb.SBTypeSummary.CreateWithFunctionName("qstring.utf16string_summary")
>>     summary.SetOptions(lldb.eTypeOptionHideChildren)
>>     debugger.GetDefaultCategory().AddTypeSummary(
>> lldb.SBTypeNameSpecifier("QString", False), summary )
>>
>> This setup works when I am using lldb-3.5 from the command line (i.e.
>> QString is displayed in the following format: m_stringMemeber = "some
>> content")
>>
>>
>> How recent/non recent is lldb-3.5?
>> Did you try with trunk at all?
>>
>
> On this VirtualBox, ​I am using the Ubuntu 14.04 packages (the package
> name is lldb-3.5-dev, but I am not sure of which revision is it...)
>
>>
>> Now, this is how I set it up from within my plugin:
>>
>> I tried both:
>> m_debugger = lldb::SBDebugger::Create(true); // source init files
>>
>> and I have also tried this:
>>
>> m_debugger = lldb::SBDebugger::Create();
>> ...
>> lldb::SBCommandReturnObject ret;
>> m_debugger.GetCommandInterpreter().HandleCommand("command source
>> /home/eran/.lldbinit", ret);
>> if ( !ret.Succeeded() ) {
>>     // print error here if any
>> }
>>
>> Both did not have any affect, i.e. when I view the content of QString in
>> the IDE, I don't see the summary as it should
>> Any hints?
>>
>>
>> Well, I see two - or rather three - potential issues
>> First of all, Is the summary loaded?
>>
> ​Yes, it does.
> After the debug session I added a call for debug purposes:
> m_debugger.GetCommandInterpreter().HandleCommand("type summary list", ret);
> And here are the relevant parts:
>>
> ​[ 22:55:49:193 DBG ] codelite-lldb: type summary list returned:
> [ 22:55:49:193 DBG ] -----------------------
> [ 22:55:49:193 DBG ] Category: default (enabled)
> [ 22:55:49:193 DBG ] -----------------------
> [ 22:55:49:193 DBG ] QString:  (not cascading)
> [ 22:55:49:193 DBG ] wxPoint: `x = ${var.x}, y = ${var.y}`
> [ 22:55:49:193 DBG ] wxRect: `(x = ${var.x}, y = ${var.y}) (width =
> ${var.width}, height = ${var.height})`
> [ 22:55:49:193 DBG ] wxString: `${var.m_impl._M_dataplus._M_p}`
> [ 22:55:49:193 DBG ] -----------------------
> [ 22:55:49:193 DBG ] Category: objc (enabled)
> [ 22:55:49:193 DBG ] -----------------------
>
> ​The first one "QString" was added using python script, the following 3
> (wxPoint, wxString and wxRect) were added using 'type summary add..' simple
> command all 3 are working (from within my plugin). The fact that the wx*
> summaries are working properly within the plugin give me confident that the
> method I am using to retrieve the data is correct.
>
>
>
> To check if it is, run “type summary list” and make sure you see a
>> formatter for QString listed in the default category - and that the default
>> category is enabled
>> Second, is the summary working? If it is loaded, we can test it manually:
>> do something like this while you’re stopped in a frame with a QString
>> variable
>> (lldb)
>> ​​
>> script value = lldb.frame.FindVariable(“myQStringThingNameHere”)
>> (lldb)
>> ​​
>> script print qstring.utf16string_summary(value,None)
>>
>> ​Arg, I don't have a 'console' where I can free type commands ( I will
> definitely add one to the plugin)​
> For now, I added the above commands manually for debug purposes and here
> are the results:
>
> [ 23:13:24:029 DBG ] codelite-lldb: output of command 'script print
> qstring.utf16string_summary(value, None)':
> [ 23:13:24:029 DBG ] Traceback (most recent call last):
> [ 23:13:24:029 DBG ]   File "<input>", line 1, in <module>
> [ 23:13:24:029 DBG ] NameError: name 'qstring' is not defined
>
>  The log clearly shows that it does not know what 'qstring' is... but
> what?
>
> Does anything come out with a manual invocation?
>>
>> Assuming the summary is registered, and manually calling it works - how
>> are you fetching the summary in your plugin?
>>
> ​I don't think that this is the case as it works for other summaries (e.g.
> wxString)
>>
>
>> Since it works at the command line, I assume the type name for QString is
>> just plain QString with no namespaces in front. Is that correct?
>>
> ​Yes, the same code (with the same ~/.lldbinit) running from command line:
>
> (lldb)
> Process 21809 stopped
> * thread #1: tid = 21809, 0x0000000000400ae5 TestQString`main(argc=1,
> argv=0x00007fff922a8688) + 184 at main.cpp:11, name = 'TestQString', stop
> reason = step over
>     frame #0: 0x0000000000400ae5 TestQString`main(argc=1,
> argv=0x00007fff922a8688) + 184 at main.cpp:11
>    8        Q_UNUSED( argv );
>    9        QString str;
>    10       str = QString("Hello %1").arg("world");
> -> 11       printf("%s\n", str.toLocal8Bit().constData());
>    12       return 0;
>    13   }
> (lldb) p str
> (QString) $0 = "Hello world"
>
> Note that the 'lldb' from the command line is was also installed from the
> Ubuntu package lldb-3.5-dev, so we can also rule that one out...
>
>
>> Thanks
>>
>>
>> On Tue, Apr 29, 2014 at 3:38 AM, Enrico Granata <egranata at apple.com>wrote:
>>
>>> On Apr 28, 2014, at 3:01 PM, Poenitz Andre <Andre.Poenitz at digia.com>
>>> wrote:
>>>
>>>
>>> Enrico Granata wrote:
>>> > Eran Ifrah wrote:
>>> > You can't use expressions in summary strings.
>>> > We have thought about this several times and have a couple ideas on how
>>>
>>> > it could be done but for now it's not there.
>>> >
>>> > If you need to resort to an expression, you can use a python formatter
>>> > instead and then you are free to call as many expressions as you like.
>>> >
>>> > However, this will cause a slowdown - running expressions is not
>>> > free - and if you ever need to make sure nothing is altering your
>>> > program state, running expressions might not be a safe bet.
>>> > Is there really no other way to get to those UTF8 bytes?
>>>
>>> QString is stored in UTF16 internally. It can be accessed directly
>>> through structure member access and pointer arithmetic and converted
>>> using Python. "Running expressions" is not needed.
>>>
>>> Andre'
>>>
>>>
>>> Here’s a small example for general reference:
>>> Assume I have the following data structure:
>>>
>>> #include <string>
>>> #include <memory>
>>>
>>> class UTF16String {
>>> public:
>>>   UTF16String (const char16_t *data) {
>>>     len = std::char_traits<char16_t>::length(data);
>>>     str_data.reset(new char16_t[len]);
>>>     memcpy(str_data.get(),data,sizeof(char16_t)*(len+1));
>>>   }
>>>
>>> private:
>>>   std::unique_ptr<char16_t[]> str_data;
>>>   size_t len;
>>> };
>>>
>>> int main() {
>>>   UTF16String string {u"Just some data in UTF16 here"};
>>>   return 0;
>>> }
>>>
>>>
>>> This is what it looks like “raw” on OS X:
>>> (UTF16String) string = {
>>>   str_data = {
>>>     __ptr_ = {
>>>       std::__1::__libcpp_compressed_pair_imp<char16_t *,
>>> std::__1::default_delete<char16_t> > = {
>>>         __first_ = 0x00000001001037e0
>>>       }
>>>     }
>>>   }
>>>   len = 28
>>> }
>>>
>>> To define a formatter for it you essentially want to grab two elements:
>>> the data pointer (__first_ = 0x00000001001037e0) and the length (len = 30)
>>> In our example, the length is defined in UTF16-characters rather than
>>> bytes. This is something you want to know when writing a formatter
>>>
>>> So let’s delve right in:
>>> def utf16string_summary(value,*rest):
>>>   str_data =
>>> value.GetChildMemberWithName("str_data").GetChildMemberWithName("__ptr_").GetChildMemberWithName("__first_")
>>>   length_vo = value.GetChildMemberWithName("len")
>>>
>>> Now we have SBValues for the string data and for the length - we want
>>> the “number stored inside” the length:
>>>   length = length_vo.GetValueAsUnsigned(0)
>>>   if length == 0:
>>>     return '""'
>>>
>>> As a special case - if the length is zero, just return an empty string.
>>> I am not going to go in detail over all the possible checks here (hint:
>>> what if str_data’s value is zero?)
>>>
>>> Now let’s grab the bytes - we want length char16_t at the location
>>> pointed to by our str_data:
>>>   data = str_data.GetPointeeData(0,length)
>>>
>>> And now let’s grab a Python string out of those bytes:
>>>   error = lldb.SBError()
>>>   bytes = data.ReadRawData(error,0,2*length)
>>>
>>> The 2*length argument is *carefully* crafted to ensure we get all the
>>> bytes we need - it of course depends on sizeof(char16_t) == 2
>>>
>>> Python is pretty good at string management, all we have to do now is
>>> tell it to turn our string from UTF16 into UTF8:
>>>   return '"%s"' % (bytes.decode('utf-16').encode('utf-8'))
>>>
>>> You’re done. To add the summary automatically to LLDB whenever you
>>> command script import the python file with the formatter:
>>> def __lldb_init_module(debugger,*rest):
>>>   summary =
>>> lldb.SBTypeSummary.CreateWithFunctionName("qstring.utf16string_summary")
>>>   summary.SetOptions(lldb.eTypeOptionHideChildren)
>>>
>>> debugger.GetDefaultCategory().AddTypeSummary(lldb.SBTypeNameSpecifier("UTF16String",False),summary)
>>>
>>> This is what you get with the summary enabled:
>>> (UTF16String) string = "Just some data in UTF16 here”
>>>
>>> Find the C++ and the Python parts of the example attached for reference
>>> - and of course feel free to ping back with any additional questions
>>>
>>>
>>>
>>>
>>>  *- Enrico*
>>> 📩 egranata@.com ☎️ 27683
>>>
>>>
>>>
>>>
>>>
>>
>>
>> --
>> Eran Ifrah
>> Author of codelite, a cross platform open source C/C++ IDE:
>> http://www.codelite.org
>> wxCrafter, a wxWidgets RAD: http://wxcrafter.codelite.org
>>
>>
>>  *- Enrico*
>> 📩 egranata@.com ☎️ 27683
>>
>>
>>
>>
>
>
> --
> Eran Ifrah
> Author of codelite, a cross platform open source C/C++ IDE:
> http://www.codelite.org
> wxCrafter, a wxWidgets RAD: http://wxcrafter.codelite.org
>
>


-- 
Eran Ifrah
Author of codelite, a cross platform open source C/C++ IDE:
http://www.codelite.org
wxCrafter, a wxWidgets RAD: http://wxcrafter.codelite.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140430/251ddd52/attachment.html>


More information about the lldb-dev mailing list