[lldb-dev] Using data formatters to display QString

Eran Ifrah eran.ifrah at gmail.com
Tue Apr 29 13:20:34 PDT 2014


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140429/e6b113f1/attachment.html>


More information about the lldb-dev mailing list