diff --git a/lldb/include/lldb/Utility/Args.h b/lldb/include/lldb/Utility/Args.h --- a/lldb/include/lldb/Utility/Args.h +++ b/lldb/include/lldb/Utility/Args.h @@ -14,6 +14,7 @@ #include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/YAMLTraits.h" #include #include #include @@ -34,6 +35,9 @@ struct ArgEntry { private: friend class Args; + friend struct llvm::yaml::MappingTraits; + friend struct llvm::yaml::MappingTraits; + std::unique_ptr ptr; char quote; @@ -283,6 +287,8 @@ char quote_char); private: + friend struct llvm::yaml::MappingTraits; + std::vector m_entries; std::vector m_argv; }; @@ -373,4 +379,28 @@ } // namespace lldb_private +namespace llvm { +namespace yaml { +template <> struct MappingTraits { + class NormalizedArgEntry { + public: + NormalizedArgEntry(IO &) {} + NormalizedArgEntry(IO &, lldb_private::Args::ArgEntry &entry) + : value(entry.ref()), quote(entry.quote) {} + lldb_private::Args::ArgEntry denormalize(IO &) { + return lldb_private::Args::ArgEntry(value, quote); + } + StringRef value; + char quote; + }; + static void mapping(IO &io, lldb_private::Args::ArgEntry &v); +}; +template <> struct MappingTraits { + static void mapping(IO &io, lldb_private::Args &v); +}; +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::Args::ArgEntry) + #endif // LLDB_UTILITY_ARGS_H diff --git a/lldb/source/Utility/Args.cpp b/lldb/source/Utility/Args.cpp --- a/lldb/source/Utility/Args.cpp +++ b/lldb/source/Utility/Args.cpp @@ -684,3 +684,20 @@ m_suffix = std::string(original_args); } } + +void llvm::yaml::MappingTraits::mapping(IO &io, + Args::ArgEntry &v) { + MappingNormalization keys(io, v); + io.mapRequired("value", keys->value); + io.mapRequired("quote", keys->quote); +} + +void llvm::yaml::MappingTraits::mapping(IO &io, Args &v) { + io.mapRequired("entries", v.m_entries); + + // Recompute m_argv vector. + v.m_argv.clear(); + for (auto &entry : v.m_entries) + v.m_argv.push_back(entry.data()); + v.m_argv.push_back(nullptr); +} diff --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp --- a/lldb/source/Utility/ProcessInfo.cpp +++ b/lldb/source/Utility/ProcessInfo.cpp @@ -337,6 +337,7 @@ IO &io, ProcessInstanceInfo &Info) { io.mapRequired("executable", Info.m_executable); io.mapRequired("arg0", Info.m_arg0); + io.mapRequired("args", Info.m_arguments); io.mapRequired("arch", Info.m_arch); io.mapRequired("uid", Info.m_uid); io.mapRequired("gid", Info.m_gid); diff --git a/lldb/test/Shell/Reproducer/TestProcessList.test b/lldb/test/Shell/Reproducer/TestProcessList.test new file mode 100644 --- /dev/null +++ b/lldb/test/Shell/Reproducer/TestProcessList.test @@ -0,0 +1,21 @@ +# UNSUPPORTED: system-freebsd + +# Test that ProcessInfo is correctly serialized by comparing the output of +# 'platform process list -v' during capture and replay. The test assumes that +# there's at least two processes. + +# RUN: %lldb -x -b -o 'platform process list -v' -o 'reproducer generate' --capture --capture-path %t.repro > %t.log +# RUN: %lldb --replay %t.repro >> %t.log +# RUN: cat %t.log | FileCheck %s + +# CHECK: [[PROCS:[0-9]+]] matching processes were found +# CHECK: PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE ARGUMENTS +# CHECK-NEXT: ====== ====== ========== ========== ========== ========== ============================== ============================ +# CHECK-NEXT: [[PID0:[0-9]+]] [[PROC0:.*]] +# CHECK-NEXT: [[PID1:[0-9]+]] [[PROC1:.*]] +# CHECK: Reproducer written to +# CHECK: [[PROCS]] matching processes were found +# CHECK: PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE ARGUMENTS +# CHECK-NEXT: ====== ====== ========== ========== ========== ========== ============================== ============================ +# CHECK-NEXT: [[PID0]] [[PROC0]] +# CHECK-NEXT: [[PID1]] [[PROC1]] diff --git a/lldb/unittests/Utility/ArgsTest.cpp b/lldb/unittests/Utility/ArgsTest.cpp --- a/lldb/unittests/Utility/ArgsTest.cpp +++ b/lldb/unittests/Utility/ArgsTest.cpp @@ -282,3 +282,34 @@ EXPECT_EQ(3u, args.GetArgumentCount()); EXPECT_STREQ(args.GetArgumentAtIndex(2), "b"); } + +TEST(ArgsTest, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + Args args; + args.SetCommandString("this 'has' \"multiple\" args"); + llvm::yaml::Output yout(os); + yout << args; + os.flush(); + + llvm::outs() << buffer; + + // Deserialize. + Args deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(4u, deserialized.GetArgumentCount()); + EXPECT_STREQ(deserialized.GetArgumentAtIndex(0), "this"); + EXPECT_STREQ(deserialized.GetArgumentAtIndex(1), "has"); + EXPECT_STREQ(deserialized.GetArgumentAtIndex(2), "multiple"); + EXPECT_STREQ(deserialized.GetArgumentAtIndex(3), "args"); + + llvm::ArrayRef entries = deserialized.entries(); + EXPECT_EQ(entries[0].GetQuoteChar(), '\0'); + EXPECT_EQ(entries[1].GetQuoteChar(), '\''); + EXPECT_EQ(entries[2].GetQuoteChar(), '"'); + EXPECT_EQ(entries[3].GetQuoteChar(), '\0'); +}