[Lldb-commits] [lldb] Summarize std::string's when created from data. (PR #89110)

via lldb-commits lldb-commits at lists.llvm.org
Wed Apr 17 10:41:27 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jacob Lalonde (Jlalond)

<details>
<summary>Changes</summary>

std::string children are normally formatted as their summary [my_string_prop] = "hello world". Sbvalues/ValueObjects created from data do not follow the same summary formatter path and instead hit the value object printer. This change fixes that and adds tests for the future.

Added tests in TestDataFormatterStdString.py and a formatter for a custom struct.

---
Full diff: https://github.com/llvm/llvm-project/pull/89110.diff


4 Files Affected:

- (modified) lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp (+27-4) 
- (added) lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/ConvertToDataFormatter.py (+50) 
- (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/TestDataFormatterStdString.py (+28) 
- (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/main.cpp (+13) 


``````````diff
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
index 86bb575af5ca34..0da01e9ca07fb6 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp
@@ -254,13 +254,13 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider(
   } else
     addr_of_string =
         valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
-  if (addr_of_string != LLDB_INVALID_ADDRESS) {
+  if (addr_of_string != LLDB_INVALID_ADDRESS ||
+        addr_type == eAddressTypeHost) {
     switch (addr_type) {
     case eAddressTypeLoad: {
       ProcessSP process_sp(valobj.GetProcessSP());
       if (!process_sp)
         return false;
-
       StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
       Status error;
       lldb::addr_t addr_of_data =
@@ -287,8 +287,31 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider(
       } else
         return true;
     } break;
-    case eAddressTypeHost:
-      break;
+    case eAddressTypeHost: {
+      // We have the host address of our std::string
+      // But we need to read the pointee data from the debugged process.
+      ProcessSP process_sp(valobj.GetProcessSP());
+      DataExtractor data;
+      Status error;
+      valobj.GetData(data, error);
+      if (error.Fail())
+        return false;
+      // We want to read the address from std::string, which is the first 8 bytes.
+      lldb::offset_t offset = 0;
+      lldb::addr_t addr = data.GetAddress(&offset);
+      if (!addr)
+      {
+        stream.Printf("nullptr");
+        return true;
+      }
+
+      std::string contents;
+      process_sp->ReadCStringFromMemory(addr, contents, error);
+      if (error.Fail())
+        return false;
+      stream.Printf("%s", contents.c_str());
+      return true;
+    } break;
     case eAddressTypeInvalid:
     case eAddressTypeFile:
       break;
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/ConvertToDataFormatter.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/ConvertToDataFormatter.py
new file mode 100644
index 00000000000000..57e42c920f8294
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/ConvertToDataFormatter.py
@@ -0,0 +1,50 @@
+# coding=utf8
+"""
+Helper formmater to verify Std::String by created via SBData
+"""
+
+import lldb
+
+class SyntheticFormatter:
+    def __init__(self, valobj, dict):
+        self.valobj = valobj
+
+    def num_children(self):
+        return 6
+
+    def has_children(self):
+        return True
+
+    def get_child_at_index(self, index):
+        name = None
+        match index:
+            case 0:
+                name = "short_string"
+            case 1:
+                name = "long_string"
+            case 2:
+                name = "short_string_ptr"
+            case 3:
+                name = "long_string_ptr"
+            case 4:
+                name = "short_string_ref"
+            case 5:
+                name = "long_string_ref"
+            case _:
+                return None
+
+        child = self.valobj.GetChildMemberWithName(name)
+        valType = child.GetType()
+        return self.valobj.CreateValueFromData(name,
+                child.GetData(),
+                valType)
+
+
+def __lldb_init_module(debugger, dict):
+    typeName = "string_container"
+    debugger.HandleCommand(
+        'type synthetic add -x "'
+        + typeName
+        + '" --python-class '
+        + f"{__name__}.SyntheticFormatter"
+    )
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/TestDataFormatterStdString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/TestDataFormatterStdString.py
index 0b78fb7dc3911c..2adfe47f9a3cfd 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/TestDataFormatterStdString.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/TestDataFormatterStdString.py
@@ -37,6 +37,8 @@ def test_with_run_command(self):
             substrs=["stopped", "stop reason = breakpoint"],
         )
 
+        self.runCmd("command script import ./ConvertToDataFormatter.py", check=True)
+
         # This is the function to remove the custom formats in order to have a
         # clean slate for the next test case.
         def cleanup():
@@ -60,6 +62,7 @@ def cleanup():
         var_rQ = self.frame().FindVariable("rQ")
         var_pq = self.frame().FindVariable("pq")
         var_pQ = self.frame().FindVariable("pQ")
+        var_str_container = self.frame().FindVariable("sc")
 
         self.assertEqual(var_wempty.GetSummary(), 'L""', "wempty summary wrong")
         self.assertEqual(
@@ -89,6 +92,31 @@ def cleanup():
             "pQ summary wrong",
         )
 
+        self.assertEqual(
+            var_str_container.GetChildAtIndex(0).GetSummary(),
+            '"u22"',
+            "string container child wrong")
+        self.assertEqual(
+            var_str_container.GetChildAtIndex(1).GetSummary(),
+            '"quite a long std::string with lots of info inside it inside a struct"',
+            "string container child wrong")
+        self.assertEqual(
+            var_str_container.GetChildAtIndex(2).GetSummary(),
+            '"u22"',
+            "string container child wrong")
+        self.assertEqual(
+            var_str_container.GetChildAtIndex(3).GetSummary(),
+            '"quite a long std::string with lots of info inside it inside a struct"',
+            "string container child wrong")
+        self.assertEqual(
+            var_str_container.GetChildAtIndex(4).GetSummary(),
+            '"u22"',
+            "string container child wrong")
+        self.assertEqual(
+            var_str_container.GetChildAtIndex(5).GetSummary(),
+            '"quite a long std::string with lots of info inside it inside a struct"',
+            "string container child wrong")
+
         self.runCmd("next")
 
         self.assertEqual(var_S.GetSummary(), 'L"!!!!!"', "new S summary wrong")
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/main.cpp
index eefb96c4573e4e..b169a2e6945568 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libstdcpp/string/main.cpp
@@ -1,5 +1,14 @@
 #include <string>
 
+struct string_container {
+    std::string short_string;
+    std::string long_string;
+    std::string *short_string_ptr = &short_string;
+    std::string *long_string_ptr = &long_string;
+    std::string &short_string_ref = short_string;
+    std::string &long_string_ref = long_string;
+};
+
 int main()
 {
     std::wstring wempty(L"");
@@ -11,6 +20,10 @@ int main()
     std::string Q("quite a long std::strin with lots of info inside it");
     auto &rq = q, &rQ = Q;
     std::string *pq = &q, *pQ = &Q;
+    string_container sc;
+    sc.short_string = "u22";
+    sc.long_string = "quite a long std::string with lots of info inside it inside a struct";
+
     S.assign(L"!!!!!"); // Set break point at this line.
     return 0;
 }

``````````

</details>


https://github.com/llvm/llvm-project/pull/89110


More information about the lldb-commits mailing list