[lldb-dev] Using data formatters to display QString

Enrico Granata egranata at apple.com
Mon Apr 28 17:38:47 PDT 2014


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



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140428/ecda9452/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: qstring.py
Type: text/x-python-script
Size: 752 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140428/ecda9452/attachment.bin>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140428/ecda9452/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: qstring.cpp
Type: application/octet-stream
Size: 411 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140428/ecda9452/attachment.obj>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20140428/ecda9452/attachment-0002.html>


More information about the lldb-dev mailing list