Add SBDebugger::GetSetting() public APIs
authorJeffrey Tan <jeffreytan@fb.com>
Thu, 8 Sep 2022 18:00:22 +0000 (11:00 -0700)
committerJeffrey Tan <jeffreytan@fb.com>
Mon, 12 Sep 2022 03:50:03 +0000 (20:50 -0700)
This patch adds new SBDebugger::GetSetting() API which
enables client to access settings as SBStructedData.

Implementation wise, a new ToJSON() virtual function is added to OptionValue
class so that each concrete child class can override and provides its
own JSON representation. This patch aims to define the APIs and implement
a common set of OptionValue child classes, leaving the remaining for
future patches.

This patch is used later by auto deduce source map from source line breakpoint
feature for testing generated source map entries.

Differential Revision: https://reviews.llvm.org/D133038

32 files changed:
lldb/bindings/interface/SBDebugger.i
lldb/include/lldb/API/SBDebugger.h
lldb/include/lldb/Core/UserSettingsController.h
lldb/include/lldb/Interpreter/OptionValue.h
lldb/include/lldb/Interpreter/OptionValueArray.h
lldb/include/lldb/Interpreter/OptionValueBoolean.h
lldb/include/lldb/Interpreter/OptionValueChar.h
lldb/include/lldb/Interpreter/OptionValueDictionary.h
lldb/include/lldb/Interpreter/OptionValueFileSpec.h
lldb/include/lldb/Interpreter/OptionValueFormat.h
lldb/include/lldb/Interpreter/OptionValueFormatEntity.h
lldb/include/lldb/Interpreter/OptionValueLanguage.h
lldb/include/lldb/Interpreter/OptionValuePathMappings.h
lldb/include/lldb/Interpreter/OptionValueProperties.h
lldb/include/lldb/Interpreter/OptionValueRegex.h
lldb/include/lldb/Interpreter/OptionValueSInt64.h
lldb/include/lldb/Interpreter/OptionValueString.h
lldb/include/lldb/Interpreter/OptionValueUInt64.h
lldb/include/lldb/Interpreter/OptionValueUUID.h
lldb/include/lldb/Target/PathMappingList.h
lldb/source/API/SBDebugger.cpp
lldb/source/Core/UserSettingsController.cpp
lldb/source/Interpreter/OptionValueArray.cpp
lldb/source/Interpreter/OptionValueDictionary.cpp
lldb/source/Interpreter/OptionValueFormat.cpp
lldb/source/Interpreter/OptionValueFormatEntity.cpp
lldb/source/Interpreter/OptionValueLanguage.cpp
lldb/source/Interpreter/OptionValuePathMappings.cpp
lldb/source/Interpreter/OptionValueProperties.cpp
lldb/source/Target/PathMappingList.cpp
lldb/test/API/commands/settings/TestSettings.py
lldb/test/API/functionalities/source-map/TestTargetSourceMap.py

index 5d51a6a..e82ce2a 100644 (file)
@@ -225,6 +225,8 @@ public:
         }
     }
 
+    lldb::SBStructuredData GetSetting(const char *setting = nullptr);
+
     SBError
     SetInputString (const char* data);
 
index b9a9b59..d3de61c 100644 (file)
@@ -115,6 +115,21 @@ public:
 
   void Clear();
 
+  /// Getting a specific setting value into SBStructuredData format.
+  /// Client can specify empty string or null to get all settings.
+  ///
+  /// Example usages:
+  /// lldb::SBStructuredData settings = debugger.GetSetting();
+  /// lldb::SBStructuredData settings = debugger.GetSetting(nullptr);
+  /// lldb::SBStructuredData settings = debugger.GetSetting("");
+  /// lldb::SBStructuredData settings = debugger.GetSetting("target.arg0");
+  /// lldb::SBStructuredData settings = debugger.GetSetting("target");
+  ///
+  /// \param[out] setting
+  ///   Property setting path to retrieve values. e.g "target.source-map"
+  ///
+  lldb::SBStructuredData GetSetting(const char *setting = nullptr);
+
   void SetAsync(bool b);
 
   bool GetAsync();
index 35555f0..8afef06 100644 (file)
@@ -57,10 +57,11 @@ public:
 
   virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx,
                                    Stream &strm, llvm::StringRef property_path,
-                                   uint32_t dump_mask);
+                                   uint32_t dump_mask, bool is_json = false);
 
   virtual void DumpAllPropertyValues(const ExecutionContext *exe_ctx,
-                                     Stream &strm, uint32_t dump_mask);
+                                     Stream &strm, uint32_t dump_mask,
+                                     bool is_json = false);
 
   virtual void DumpAllDescriptions(CommandInterpreter &interpreter,
                                    Stream &strm) const;
index 277a5c9..3c842d1 100644 (file)
@@ -17,6 +17,7 @@
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-private-enumerations.h"
 #include "lldb/lldb-private-interfaces.h"
+#include "llvm/Support/JSON.h"
 
 namespace lldb_private {
 
@@ -82,6 +83,16 @@ public:
   virtual void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                          uint32_t dump_mask) = 0;
 
+  // TODO: make this function pure virtual after implementing it in all
+  // child classes.
+  virtual llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) {
+    // Return nullptr which will create a llvm::json::Value() that is a NULL
+    // value. No setting should ever really have a NULL value in JSON. This
+    // indicates an error occurred and if/when we add a FromJSON() it will know
+    // to fail if someone tries to set it with a NULL JSON value.
+    return nullptr;
+  }
+
   virtual Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign);
index af43887..147e15e 100644 (file)
@@ -29,6 +29,8 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index fd15ccb..01e7c6c 100644 (file)
@@ -29,6 +29,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_current_value;
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 6b8a314..32ec2bb 100644 (file)
@@ -30,6 +30,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_current_value;
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 4c6bcae..1fdccde 100644 (file)
@@ -34,6 +34,8 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 6648bba..b680a89 100644 (file)
@@ -35,6 +35,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_current_value.GetPath();
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 1f2c66b..5be885f 100644 (file)
@@ -31,6 +31,8 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index cb8b2ef..b8ef03a 100644 (file)
@@ -28,6 +28,8 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index c00f71f..f20a2c6 100644 (file)
@@ -33,6 +33,8 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 4bc65ce..82a968a 100644 (file)
@@ -29,6 +29,8 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 14f496b..7c344dc 100644 (file)
@@ -47,11 +47,13 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override;
+
   ConstString GetName() const override { return m_name; }
 
   virtual Status DumpPropertyValue(const ExecutionContext *exe_ctx,
                                    Stream &strm, llvm::StringRef property_path,
-                                   uint32_t dump_mask);
+                                   uint32_t dump_mask, bool is_json = false);
 
   virtual void DumpAllDescriptions(CommandInterpreter &interpreter,
                                    Stream &strm) const;
index 1299874..3c18800 100644 (file)
@@ -28,6 +28,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_regex.GetText();
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 3493eb1..5efae62 100644 (file)
@@ -35,6 +35,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_current_value;
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 820656d..becf35f 100644 (file)
@@ -69,6 +69,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_current_value;
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
@@ -109,7 +113,7 @@ public:
   bool IsCurrentValueEmpty() const { return m_current_value.empty(); }
 
   bool IsDefaultValueEmpty() const { return m_default_value.empty(); }
-  
+
   void SetValidator(ValidatorCallback validator, void *baton = nullptr) {
     m_validator = validator;
     m_validator_baton = baton;
index f212b2a..30c27bf 100644 (file)
@@ -38,6 +38,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_current_value;
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index 0ed490d..e0e4235 100644 (file)
@@ -29,6 +29,10 @@ public:
   void DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
                  uint32_t dump_mask) override;
 
+  llvm::json::Value ToJSON(const ExecutionContext *exe_ctx) override {
+    return m_uuid.GetAsString();
+  }
+
   Status
   SetValueFromString(llvm::StringRef value,
                      VarSetOperationType op = eVarSetOperationAssign) override;
index f1cc779..badbe3e 100644 (file)
@@ -9,10 +9,11 @@
 #ifndef LLDB_TARGET_PATHMAPPINGLIST_H
 #define LLDB_TARGET_PATHMAPPINGLIST_H
 
-#include <map>
-#include <vector>
 #include "lldb/Utility/ConstString.h"
 #include "lldb/Utility/Status.h"
+#include "llvm/Support/JSON.h"
+#include <map>
+#include <vector>
 
 namespace lldb_private {
 
@@ -41,6 +42,8 @@ public:
   // By default, dump all pairs.
   void Dump(Stream *s, int pair_index = -1);
 
+  llvm::json::Value ToJSON();
+
   bool IsEmpty() const { return m_pairs.empty(); }
 
   size_t GetSize() const { return m_pairs.size(); }
index 0de934b..8a0c7d1 100644 (file)
@@ -436,6 +436,29 @@ SBError SBDebugger::SetErrorFile(SBFile file) {
   return error;
 }
 
+lldb::SBStructuredData SBDebugger::GetSetting(const char *setting) {
+  LLDB_INSTRUMENT_VA(this, setting);
+
+  SBStructuredData data;
+  if (!m_opaque_sp)
+    return data;
+
+  StreamString json_strm;
+  ExecutionContext exe_ctx(
+      m_opaque_sp->GetCommandInterpreter().GetExecutionContext());
+  if (setting && strlen(setting) > 0)
+    m_opaque_sp->DumpPropertyValue(&exe_ctx, json_strm, setting,
+                                   /*dump_mask*/ 0,
+                                   /*is_json*/ true);
+  else
+    m_opaque_sp->DumpAllPropertyValues(&exe_ctx, json_strm, /*dump_mask*/ 0,
+                                       /*is_json*/ true);
+
+  data.m_impl_up->SetObjectSP(
+      StructuredData::ParseJSON(json_strm.GetString().str()));
+  return data;
+}
+
 FILE *SBDebugger::GetInputFileHandle() {
   LLDB_INSTRUMENT_VA(this);
   if (m_opaque_sp) {
index b9f7d5e..9ea4f78 100644 (file)
@@ -53,10 +53,17 @@ Status Properties::SetPropertyValue(const ExecutionContext *exe_ctx,
 }
 
 void Properties::DumpAllPropertyValues(const ExecutionContext *exe_ctx,
-                                       Stream &strm, uint32_t dump_mask) {
+                                       Stream &strm, uint32_t dump_mask,
+                                       bool is_json) {
   OptionValuePropertiesSP properties_sp(GetValueProperties());
-  if (properties_sp)
-    return properties_sp->DumpValue(exe_ctx, strm, dump_mask);
+  if (!properties_sp)
+    return;
+
+  if (is_json) {
+    llvm::json::Value json = properties_sp->ToJSON(exe_ctx);
+    strm.Printf("%s", llvm::formatv("{0:2}", json).str().c_str());
+  } else
+    properties_sp->DumpValue(exe_ctx, strm, dump_mask);
 }
 
 void Properties::DumpAllDescriptions(CommandInterpreter &interpreter,
@@ -71,11 +78,11 @@ void Properties::DumpAllDescriptions(CommandInterpreter &interpreter,
 Status Properties::DumpPropertyValue(const ExecutionContext *exe_ctx,
                                      Stream &strm,
                                      llvm::StringRef property_path,
-                                     uint32_t dump_mask) {
+                                     uint32_t dump_mask, bool is_json) {
   OptionValuePropertiesSP properties_sp(GetValueProperties());
   if (properties_sp) {
     return properties_sp->DumpPropertyValue(exe_ctx, strm, property_path,
-                                            dump_mask);
+                                            dump_mask, is_json);
   }
   Status error;
   error.SetErrorString("empty property list");
index 07cb79e..40357d5 100644 (file)
@@ -75,6 +75,14 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
   }
 }
 
+llvm::json::Value OptionValueArray::ToJSON(const ExecutionContext *exe_ctx) {
+  llvm::json::Array json_array;
+  const uint32_t size = m_values.size();
+  for (uint32_t i = 0; i < size; ++i)
+    json_array.emplace_back(m_values[i]->ToJSON(exe_ctx));
+  return json_array;
+}
+
 Status OptionValueArray::SetValueFromString(llvm::StringRef value,
                                             VarSetOperationType op) {
   Args args(value.str());
index 6baafc9..d185101 100644 (file)
@@ -83,6 +83,15 @@ void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx,
   }
 }
 
+llvm::json::Value
+OptionValueDictionary::ToJSON(const ExecutionContext *exe_ctx) {
+  llvm::json::Object dict;
+  for (const auto &value : m_values) {
+    dict.try_emplace(value.first.GetCString(), value.second->ToJSON(exe_ctx));
+  }
+  return dict;
+}
+
 size_t OptionValueDictionary::GetArgs(Args &args) const {
   args.Clear();
   collection::const_iterator pos, end = m_values.end();
index 76a446d..ab89f67 100644 (file)
@@ -26,6 +26,10 @@ void OptionValueFormat::DumpValue(const ExecutionContext *exe_ctx, Stream &strm,
   }
 }
 
+llvm::json::Value OptionValueFormat::ToJSON(const ExecutionContext *exe_ctx) {
+  return FormatManager::GetFormatAsCString(m_current_value);
+}
+
 Status OptionValueFormat::SetValueFromString(llvm::StringRef value,
                                              VarSetOperationType op) {
   Status error;
index 64fcaf2..98216e1 100644 (file)
@@ -60,6 +60,13 @@ void OptionValueFormatEntity::DumpValue(const ExecutionContext *exe_ctx,
   }
 }
 
+llvm::json::Value
+OptionValueFormatEntity::ToJSON(const ExecutionContext *exe_ctx) {
+  std::string escaped;
+  EscapeBackticks(m_current_format, escaped);
+  return escaped;
+}
+
 Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str,
                                                    VarSetOperationType op) {
   Status error;
index d2fbe24..1be8a55 100644 (file)
@@ -29,6 +29,10 @@ void OptionValueLanguage::DumpValue(const ExecutionContext *exe_ctx,
   }
 }
 
+llvm::json::Value OptionValueLanguage::ToJSON(const ExecutionContext *exe_ctx) {
+  return Language::GetNameForLanguageType(m_current_value);
+}
+
 Status OptionValueLanguage::SetValueFromString(llvm::StringRef value,
                                                VarSetOperationType op) {
   Status error;
index 438c9b7..7cfc445 100644 (file)
@@ -34,6 +34,11 @@ void OptionValuePathMappings::DumpValue(const ExecutionContext *exe_ctx,
   }
 }
 
+llvm::json::Value
+OptionValuePathMappings::ToJSON(const ExecutionContext *exe_ctx) {
+  return m_path_mappings.ToJSON();
+}
+
 Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value,
                                                    VarSetOperationType op) {
   Status error;
index b216557..c2c13ba 100644 (file)
@@ -545,10 +545,26 @@ void OptionValueProperties::DumpValue(const ExecutionContext *exe_ctx,
   }
 }
 
+llvm::json::Value
+OptionValueProperties::ToJSON(const ExecutionContext *exe_ctx) {
+  llvm::json::Object json_properties;
+  const size_t num_properties = m_properties.size();
+  for (size_t i = 0; i < num_properties; ++i) {
+    const Property *property = GetPropertyAtIndex(exe_ctx, false, i);
+    if (property) {
+      OptionValue *option_value = property->GetValue().get();
+      assert(option_value);
+      json_properties.try_emplace(property->GetName(),
+                                  option_value->ToJSON(exe_ctx));
+    }
+  }
+  return json_properties;
+}
+
 Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,
                                                 Stream &strm,
                                                 llvm::StringRef property_path,
-                                                uint32_t dump_mask) {
+                                                uint32_t dump_mask, bool is_json) {
   Status error;
   const bool will_modify = false;
   lldb::OptionValueSP value_sp(
@@ -560,7 +576,10 @@ Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx,
       if (dump_mask & ~eDumpOptionName)
         strm.PutChar(' ');
     }
-    value_sp->DumpValue(exe_ctx, strm, dump_mask);
+    if (is_json) {
+      strm.Printf("%s", llvm::formatv("{0:2}", value_sp->ToJSON(exe_ctx)).str().c_str());
+    } else
+      value_sp->DumpValue(exe_ctx, strm, dump_mask);
   }
   return error;
 }
index 4ebb175..468048c 100644 (file)
@@ -131,6 +131,16 @@ void PathMappingList::Dump(Stream *s, int pair_index) {
   }
 }
 
+llvm::json::Value PathMappingList::ToJSON() {
+  llvm::json::Array entries;
+  for (const auto &pair : m_pairs) {
+    llvm::json::Array entry{pair.first.GetStringRef().str(),
+                            pair.second.GetStringRef().str()};
+    entries.emplace_back(std::move(entry));
+  }
+  return entries;
+}
+
 void PathMappingList::Clear(bool notify) {
   if (!m_pairs.empty())
     ++m_mod_id;
index 0ea1e7b..e50a4f3 100644 (file)
@@ -3,7 +3,7 @@ Test lldb settings command.
 """
 
 
-
+import json
 import os
 import re
 import lldb
@@ -274,7 +274,7 @@ class SettingsCommandTestCase(TestBase):
         self.assertEqual(launch_info.GetArgumentAtIndex(0), "A")
         self.assertEqual(launch_info.GetArgumentAtIndex(1), "B")
         self.assertEqual(launch_info.GetArgumentAtIndex(2), "C")
-        
+
         self.expect(
             'target show-launch-environment',
             substrs=["MY_ENV_VAR=YES"])
@@ -787,3 +787,59 @@ class SettingsCommandTestCase(TestBase):
 
         # A known option should fail if its argument is invalid.
         self.expect("settings set auto-confirm bogus", error=True)
+
+    def get_setting_json(self, setting_path = None):
+        settings_data = self.dbg.GetSetting(setting_path)
+        stream = lldb.SBStream()
+        settings_data.GetAsJSON(stream)
+        return json.loads(stream.GetData())
+
+    def verify_setting_value_json(self, setting_path, setting_value):
+        self.runCmd("settings set %s %s" % (setting_path, setting_value))
+        settings_json = self.get_setting_json(setting_path)
+        self.assertEqual(settings_json, setting_value)
+
+    def test_settings_api(self):
+        """
+            Test that ensures SBDebugger::GetSetting() APIs
+            can correctly fetch settings.
+        """
+
+        # Test basic values and embedding special JSON escaping characters.
+        self.runCmd("settings set auto-confirm true")
+        self.runCmd("settings set tab-size 2")
+        arg_value = "hello \"world\""
+        self.runCmd('settings set target.arg0 %s' % arg_value)
+
+        settings_json = self.get_setting_json()
+        self.assertEqual(settings_json["auto-confirm"], True)
+        self.assertEqual(settings_json["tab-size"], 2)
+        self.assertEqual(settings_json["target"]["arg0"], arg_value)
+
+        settings_data = self.get_setting_json("target.arg0")
+        self.assertEqual(settings_data, arg_value)
+
+        # Test OptionValueFileSpec
+        self.verify_setting_value_json("platform.module-cache-directory", self.get_process_working_directory())
+
+        # Test OptionValueArray
+        setting_path = "target.run-args"
+        setting_value = ["value1", "value2", "value3"]
+        self.runCmd("settings set %s %s" % (setting_path, " ".join(setting_value)))
+        settings_json = self.get_setting_json(setting_path)
+        self.assertEqual(settings_json, setting_value)
+
+        # Test OptionValueFormatEntity
+        setting_value = """thread #${thread.index}{, name = \\'${thread.name}\\
+        '}{, queue = ${ansi.fg.green}\\'${thread.queue}\\'${ansi.normal}}{,
+        activity = ${ansi.fg.green}\\'${thread.info.activity.name}\\'${ansi.normal}}
+        {, ${thread.info.trace_messages} messages}{, stop reason = ${ansi.fg.red}$
+        {thread.stop-reason}${ansi.normal}}{\\\\nReturn value: ${thread.return-value}}
+        {\\\\nCompleted expression: ${thread.completed-expression}}\\\\n"""
+        self.verify_setting_value_json("thread-stop-format", setting_value)
+
+        # Test OptionValueRegex
+        self.verify_setting_value_json("target.process.thread.step-avoid-regexp", "^std::")
+
+        # Test OptionValueLanguage
+        self.verify_setting_value_json("repl-lang", "c++")
index 129365a..c1b4565 100644 (file)
@@ -1,12 +1,46 @@
 import lldb
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test.decorators import *
+import json
 import os
 
 
 class TestTargetSourceMap(TestBase):
 
     @no_debug_info_test
+    def test_source_map_via_setting_api(self):
+        """
+            Test that ensures SBDebugger::GetSetting("target.source-map") API
+            can correctly fetch source mapping entries.
+        """
+        # Set the target soure map to map "./" to the current test directory
+        src_dir = self.getSourceDir()
+
+        source_map_setting_path = "target.source-map"
+        initial_source_map = self.dbg.GetSetting(source_map_setting_path)
+        self.assertEquals(initial_source_map.GetSize(), 0,
+            "Initial source map should be empty")
+
+        src_dir = self.getSourceDir()
+        self.runCmd('settings set %s . "%s"' % (source_map_setting_path, src_dir))
+
+        source_map = self.dbg.GetSetting(source_map_setting_path)
+        self.assertEquals(source_map.GetSize(), 1,
+            "source map should be have one appended entry")
+
+        stream = lldb.SBStream()
+        source_map.GetAsJSON(stream)
+        serialized_source_map = json.loads(stream.GetData())
+
+        self.assertEquals(len(serialized_source_map[0]), 2,
+            "source map entry should have two parts")
+        self.assertEquals(serialized_source_map[0][0], ".",
+            "source map entry's first part does not match")
+        self.assertEquals(serialized_source_map[0][1], src_dir,
+            "source map entry's second part does not match")
+
+
+    @no_debug_info_test
     def test_source_map(self):
         """Test target.source-map' functionality."""