On Apr 28, 2014, at 3:01 PM, Poenitz Andre <andre.poen...@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 = "">

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

import lldb

def utf16string_summary(value,*rest):
  str_data = value.GetChildMemberWithName("str_data").GetChildMemberWithName("__ptr_").GetChildMemberWithName("__first_")
  length_vo = value.GetChildMemberWithName("len")
  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("UTF16String",False),summary)

Attachment: qstring.cpp
Description: Binary data


- Enrico
📩 egranata@.com ☎️ 27683



_______________________________________________
lldb-dev mailing list
lldb-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to