[Lldb-commits] [lldb] [lldb][libc++] Adds system_clock data formatters. (PR #78609)

Mark de Wever via lldb-commits lldb-commits at lists.llvm.org
Mon Jan 22 11:22:22 PST 2024


https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/78609

>From 31a7604f872116521558dcb9f1b4c2c4f5f9d439 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Thu, 18 Jan 2024 19:21:09 +0100
Subject: [PATCH 1/2] [lldb][libc++] Adds system_clock data formatters.

---
 .../Language/CPlusPlus/CPlusPlusLanguage.cpp  |  25 +++++
 .../Plugins/Language/CPlusPlus/LibCxx.cpp     |  65 +++++++++++-
 .../Plugins/Language/CPlusPlus/LibCxx.h       |   8 ++
 .../chrono/TestDataFormatterLibcxxChrono.py   | 100 ++++++++++++++++++
 .../data-formatter-stl/libcxx/chrono/main.cpp |  52 +++++++++
 5 files changed, 248 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 21c73e6361904e5..f0fe6c9e06d9d47 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1032,6 +1032,31 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
       TypeSummaryImplSP(new StringSummaryFormat(
           eTypeOptionHideChildren | eTypeOptionHideValue, "${var.__rep_} s")));
 
+  // Chrono time point types
+
+  AddCXXSummary(cpp_category_sp,
+                lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider,
+                "libc++ std::chrono::sys_seconds summary provider",
+                "^std::__[[:alnum:]]+::chrono::time_point<"
+                "std::__[[:alnum:]]+::chrono::system_clock, "
+                "std::__[[:alnum:]]+::chrono::duration<long long, "
+                "std::__[[:alnum:]]+::ratio<1, 1> "
+                "> >$",
+                eTypeOptionHideChildren | eTypeOptionHideValue |
+                    eTypeOptionCascade,
+                true);
+  AddCXXSummary(cpp_category_sp,
+                lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider,
+                "libc++ std::chrono::sys_seconds summary provider",
+                "^std::__[[:alnum:]]+::chrono::time_point<"
+                "std::__[[:alnum:]]+::chrono::system_clock, "
+                "std::__[[:alnum:]]+::chrono::duration<int, "
+                "std::__[[:alnum:]]+::ratio<86400, 1> "
+                "> >$",
+                eTypeOptionHideChildren | eTypeOptionHideValue |
+                    eTypeOptionCascade,
+                true);
+
   // Chrono calendar types
 
   cpp_category_sp->AddTypeSummary(
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index d232a38adc029ad..042e22626969987 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -1073,18 +1073,79 @@ bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(
   bool success;
   ValueObjectSP dataobj;
   size_t size;
-  std::tie( success, dataobj, size ) = LibcxxExtractStringViewData(valobj);
+  std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
 
   if (!success) {
     stream << "Summary Unavailable";
     return true;
   }
 
-
   return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
                                         dataobj, size);
 }
 
+bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider(
+    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+  ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");
+  if (!ptr_sp)
+    return false;
+  ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");
+  if (!ptr_sp)
+    return false;
+
+  // The date time in the chrono library is valid in the range
+  // [-32767-01-01T00:00:00Z, 32767-12-31T23:59:59Z]. A 64-bit time_t has a
+  // larger range, the function strftime is not able to format the entire range
+  // of time_t. The exact point has not been investigated; it's limited to
+  // chrono's range.
+  const std::time_t chrono_timestamp_min =
+      -1'096'193'779'200; // -32767-01-01T00:00:00Z
+  const std::time_t chrono_timestamp_max =
+      971'890'963'199; // 32767-12-31T23:59:59Z
+
+  const std::time_t seconds = ptr_sp->GetValueAsSigned(0);
+  if (seconds < chrono_timestamp_min || seconds > chrono_timestamp_max)
+    stream.Printf("timestamp=%ld s", seconds);
+  else {
+    std::array<char, 128> str;
+    std::strftime(str.data(), str.size(), "%FT%H:%M:%SZ", gmtime(&seconds));
+    stream.Printf("date/time=%s timestamp=%ld s", str.data(), seconds);
+  }
+
+  return true;
+}
+
+bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider(
+    ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
+  ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");
+  if (!ptr_sp)
+    return false;
+  ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");
+  if (!ptr_sp)
+    return false;
+
+  // The date time in the chrono library is valid in the range
+  // [-32767-01-01Z, 32767-12-31Z]. A 32-bit time_t has a larger range, the
+  // function strftime is not able to format the entire range of time_t. The
+  // exact point has not been investigated; it's limited to chrono's range.
+  const int chrono_timestamp_min = -12'687'428; // -32767-01-01Z
+  const int chrono_timestamp_max = 11'248'737;  // 32767-12-31Z
+
+  const int days = ptr_sp->GetValueAsSigned(0);
+  if (days < chrono_timestamp_min || days > chrono_timestamp_max)
+    stream.Printf("timestamp=%d days", days);
+
+  else {
+    const std::time_t seconds = std::time_t(86400) * days;
+
+    std::array<char, 128> str;
+    std::strftime(str.data(), str.size(), "%FZ", gmtime(&seconds));
+    stream.Printf("date=%s timestamp=%d days", str.data(), days);
+  }
+
+  return true;
+}
+
 bool lldb_private::formatters::LibcxxChronoMonthSummaryProvider(
     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
   // FIXME: These are the names used in the C++20 ostream operator. Since LLVM
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index 532d185b18543f5..72da6b2426efec8 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -261,6 +261,14 @@ SyntheticChildrenFrontEnd *
 LibcxxStdRangesRefViewSyntheticFrontEndCreator(CXXSyntheticChildren *,
                                                lldb::ValueObjectSP);
 
+bool LibcxxChronoSysSecondsSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &options); // libc++ std::chrono::sys_seconds
+
+bool LibcxxChronoSysDaysSummaryProvider(
+    ValueObject &valobj, Stream &stream,
+    const TypeSummaryOptions &options); // libc++ std::chrono::sys_days
+
 bool LibcxxChronoMonthSummaryProvider(
     ValueObject &valobj, Stream &stream,
     const TypeSummaryOptions &options); // libc++ std::chrono::month
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py
index d4bc140015fbb71..67372572dc4464e 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py
@@ -32,6 +32,106 @@ def test_with_run_command(self):
         self.expect("frame variable m", substrs=["m = 4321 months"])
         self.expect("frame variable y", substrs=["y = 321 years"])
 
+        self.expect(
+            "frame variable ss_tp",
+            substrs=["ss_tp = date/time=1970-01-01T00:00:00Z timestamp=0 s"],
+        )
+        self.expect(
+            "frame variable ss_tp_d",
+            substrs=["ss_tp_d = date/time=1970-01-01T00:00:00Z timestamp=0 s"],
+        )
+        self.expect(
+            "frame variable ss_tp_d_r",
+            substrs=["ss_tp_d_r = date/time=1970-01-01T00:00:00Z timestamp=0 s"],
+        )
+        self.expect(
+            "frame variable ss_tp_d_r2",
+            substrs=["ss_tp_d_r2 = date/time=1970-01-01T00:00:00Z timestamp=0 s"],
+        )
+
+        self.expect(
+            "frame variable ss_0",
+            substrs=["ss_0 = date/time=1970-01-01T00:00:00Z timestamp=0 s"],
+        )
+
+        self.expect(
+            "frame variable ss_neg_date_time",
+            substrs=[
+                "ss_neg_date_time = date/time=-32767-01-01T00:00:00Z timestamp=-1096193779200 s"
+            ],
+        )
+        self.expect(
+            "frame variable ss_neg_seconds",
+            substrs=["ss_neg_seconds = timestamp=-1096193779201 s"],
+        )
+
+        self.expect(
+            "frame variable ss_pos_date_time",
+            substrs=[
+                "ss_pos_date_time = date/time=32767-12-31T23:59:59Z timestamp=971890963199 s"
+            ],
+        )
+        self.expect(
+            "frame variable ss_pos_seconds",
+            substrs=["ss_pos_seconds = timestamp=971890963200 s"],
+        )
+
+        self.expect(
+            "frame variable ss_min",
+            substrs=["ss_min = timestamp=-9223372036854775808 s"],
+        )
+        self.expect(
+            "frame variable ss_max",
+            substrs=["ss_max = timestamp=9223372036854775807 s"],
+        )
+
+        self.expect(
+            "frame variable sd_tp",
+            substrs=["sd_tp = date=1970-01-01Z timestamp=0 days"],
+        )
+        self.expect(
+            "frame variable sd_tp_d_r",
+            substrs=["sd_tp_d_r = date=1970-01-01Z timestamp=0 days"],
+        )
+        self.expect(
+            "frame variable sd_tp_d_r2",
+            substrs=["sd_tp_d_r2 = date=1970-01-01Z timestamp=0 days"],
+        )
+
+        self.expect(
+            "frame variable sd_0", substrs=["sd_0 = date=1970-01-01Z timestamp=0 days"]
+        )
+        self.expect(
+            "frame variable sd_neg_date",
+            substrs=["sd_neg_date = date=-32767-01-01Z timestamp=-12687428 days"],
+        )
+        self.expect(
+            "frame variable sd_neg_days",
+            substrs=["sd_neg_days = timestamp=-12687429 days"],
+        )
+
+        self.expect(
+            "frame variable sd_pos_date",
+            substrs=["sd_pos_date = date=32767-12-31Z timestamp=11248737 days"],
+        )
+        self.expect(
+            "frame variable sd_pos_days",
+            substrs=["sd_pos_days = timestamp=11248738 days"],
+        )
+
+        self.expect(
+            "frame variable sd_min",
+            substrs=["sd_min = timestamp=-2147483648 days"],
+        )
+        self.expect(
+            "frame variable sd_max",
+            substrs=["sd_max = timestamp=2147483647 days"],
+        )
+
+        # self.expect("frame variable sd_min", substrs=["sd_min = date=1970-01-01Z timestamp=0 days"])
+        # self.expect("frame variable sd_0", substrs=["sd_0 = date=1970-01-01Z timestamp=0 days"])
+        # self.expect("frame variable XXXtp_d_0", substrs=["XXXtp_d_0 = date=1970-01-01Z timestamp=0 days"])
+
         self.expect("frame variable d_0", substrs=["d_0 = day=0"])
         self.expect("frame variable d_1", substrs=["d_1 = day=1"])
         self.expect("frame variable d_31", substrs=["d_31 = day=31"])
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/main.cpp
index 57215aaf343f649..315c88a787d823d 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/main.cpp
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/main.cpp
@@ -15,6 +15,58 @@ int main() {
   std::chrono::months m{4321};
   std::chrono::years y{321};
 
+  // sys_seconds aliasses
+  std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
+      ss_tp{std::chrono::seconds{0}};
+  std::chrono::time_point<std::chrono::system_clock,
+                          std::chrono::duration<long long>>
+      ss_tp_d{std::chrono::seconds{0}};
+  std::chrono::time_point<std::chrono::system_clock,
+                          std::chrono::duration<long long, std::ratio<1>>>
+      ss_tp_d_r{std::chrono::seconds{0}};
+  std::chrono::time_point<std::chrono::system_clock,
+                          std::chrono::duration<long long, std::ratio<1>>>
+      ss_tp_d_r2{std::chrono::seconds{0}};
+
+  // sys_seconds
+  std::chrono::sys_seconds ss_0{std::chrono::seconds{0}};
+  std::chrono::sys_seconds ss_neg_date_time{
+      std::chrono::seconds{-1'096'193'779'200}};
+  std::chrono::sys_seconds ss_neg_seconds{
+      std::chrono::seconds{-1'096'193'779'201}};
+  std::chrono::sys_seconds ss_pos_date_time{
+      std::chrono::seconds{971'890'963'199}};
+  std::chrono::sys_seconds ss_pos_seconds{
+      std::chrono::seconds{971'890'963'200}};
+  std::chrono::sys_seconds ss_min{
+      std::chrono::seconds{std::numeric_limits<long long>::min()}};
+  std::chrono::sys_seconds ss_max{
+      std::chrono::seconds{std::numeric_limits<long long>::max()}};
+
+  // sys_days aliasses
+  std::chrono::time_point<std::chrono::system_clock, std::chrono::days> sd_tp{
+      std::chrono::days{0}};
+  std::chrono::time_point<std::chrono::system_clock,
+                          std::chrono::duration<int, std::ratio<86400>>>
+      sd_tp_d_r{std::chrono::days{0}};
+  std::chrono::time_point<std::chrono::system_clock,
+                          std::chrono::duration<int, std::ratio<86400, 1>>>
+      sd_tp_d_r2{std::chrono::days{0}};
+
+  // sys_days
+  std::chrono::sys_days sd_0{std::chrono::days{0}};
+
+  std::chrono::sys_days sd_neg_date{std::chrono::days{-12'687'428}};
+  std::chrono::sys_days sd_neg_days{std::chrono::days{-12'687'429}};
+
+  std::chrono::sys_days sd_pos_date{std::chrono::days{11'248'737}};
+  std::chrono::sys_days sd_pos_days{std::chrono::days{11'248'738}};
+
+  std::chrono::sys_days sd_min{
+      std::chrono::days{std::numeric_limits<int>::min()}};
+  std::chrono::sys_days sd_max{
+      std::chrono::days{std::numeric_limits<int>::max()}};
+
   std::chrono::day d_0{0};
   std::chrono::day d_1{1};
   std::chrono::day d_31{31};

>From f1b2124e1aee591b69ed2bc6ec30040534a4bf7a Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Mon, 22 Jan 2024 20:22:06 +0100
Subject: [PATCH 2/2] Address review comments.

---
 lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp    | 12 ++++++++++--
 .../libcxx/chrono/TestDataFormatterLibcxxChrono.py   |  4 ----
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index 042e22626969987..060324e2fcfe263 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -1108,7 +1108,11 @@ bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider(
     stream.Printf("timestamp=%ld s", seconds);
   else {
     std::array<char, 128> str;
-    std::strftime(str.data(), str.size(), "%FT%H:%M:%SZ", gmtime(&seconds));
+    std::size_t size =
+        std::strftime(str.data(), str.size(), "%FT%H:%M:%SZ", gmtime(&seconds));
+    if (size == 0)
+      return false;
+
     stream.Printf("date/time=%s timestamp=%ld s", str.data(), seconds);
   }
 
@@ -1139,7 +1143,11 @@ bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider(
     const std::time_t seconds = std::time_t(86400) * days;
 
     std::array<char, 128> str;
-    std::strftime(str.data(), str.size(), "%FZ", gmtime(&seconds));
+    std::size_t size =
+        std::strftime(str.data(), str.size(), "%FZ", gmtime(&seconds));
+    if (size == 0)
+      return false;
+
     stream.Printf("date=%s timestamp=%d days", str.data(), days);
   }
 
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py
index 67372572dc4464e..a90fb828d121a7f 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/chrono/TestDataFormatterLibcxxChrono.py
@@ -128,10 +128,6 @@ def test_with_run_command(self):
             substrs=["sd_max = timestamp=2147483647 days"],
         )
 
-        # self.expect("frame variable sd_min", substrs=["sd_min = date=1970-01-01Z timestamp=0 days"])
-        # self.expect("frame variable sd_0", substrs=["sd_0 = date=1970-01-01Z timestamp=0 days"])
-        # self.expect("frame variable XXXtp_d_0", substrs=["XXXtp_d_0 = date=1970-01-01Z timestamp=0 days"])
-
         self.expect("frame variable d_0", substrs=["d_0 = day=0"])
         self.expect("frame variable d_1", substrs=["d_1 = day=1"])
         self.expect("frame variable d_31", substrs=["d_31 = day=31"])



More information about the lldb-commits mailing list