[Lldb-commits] [lldb] [lldb][ResolveSourceFileCallback] Implement API, Python interface (PR #120834)

via lldb-commits lldb-commits at lists.llvm.org
Sat Dec 21 01:14:00 PST 2024


https://github.com/rchamala updated https://github.com/llvm/llvm-project/pull/120834

>From 126ba755d58aa74c6d0c5727ec08593cfcfb57ee Mon Sep 17 00:00:00 2001
From: Rahul Reddy Chamala <rachamal at fb.com>
Date: Fri, 20 Dec 2024 15:55:36 -0800
Subject: [PATCH] [lldb][ResolveSourceFileCallback] Implement API, Python
 interface

Summary:
RFC https://discourse.llvm.org/t/rfc-python-callback-for-target-get-module/71580

Use SWIG for the resolve source file callback the same as other Python callbacks. TestResolveSourceFileCallback.py verifies the functionalities.

Test Plan:
Added shell tests for validation

```
./llvm-lit -sv TestResolveSourceFileCallback.py
```

Differential Revision: https://phabricator.intern.facebook.com/D67541203
---
 lldb/bindings/python/python-typemaps.swig     |  44 ++++
 lldb/bindings/python/python-wrapper.swig      |  49 ++++-
 lldb/include/lldb/API/SBDefines.h             |   5 +
 lldb/include/lldb/API/SBPlatform.h            |   3 +
 lldb/source/API/SBPlatform.cpp                |  37 ++++
 .../TestResolveSourceFileCallback.py          | 196 ++++++++++++++++++
 lldb/test/API/python_api/sbplatform/test.exe  | Bin 0 -> 21704 bytes
 .../API/python_api/sbplatform/test_new.cpp    |  15 ++
 8 files changed, 347 insertions(+), 2 deletions(-)
 create mode 100644 lldb/test/API/python_api/sbplatform/TestResolveSourceFileCallback.py
 create mode 100755 lldb/test/API/python_api/sbplatform/test.exe
 create mode 100644 lldb/test/API/python_api/sbplatform/test_new.cpp

diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig
index f8c33e15c03e66..84d26986104d31 100644
--- a/lldb/bindings/python/python-typemaps.swig
+++ b/lldb/bindings/python/python-typemaps.swig
@@ -713,3 +713,47 @@ template <> bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
   $1 = $input == Py_None;
   $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
 }
+
+// For lldb::SBPlatformResolveSourceFileCallback
+%typemap(in) (lldb::SBPlatformResolveSourceFileCallback callback, void *callback_baton) {
+  if (!($input == Py_None ||
+       PyCallable_Check(reinterpret_cast<PyObject *>($input)))) {
+        PyErr_SetString(PyExc_TypeError, "Need a callable object or None!");
+        SWIG_fail;
+       }
+
+  if ($input == Py_None) {
+    $1 = nullptr;
+    $2 = nullptr;
+  } else {
+    PythonCallable callable = Retain<PythonCallable>($input);
+    if (!callable.IsValid()) {
+      PyErr_SetString(PyExc_TypeError, "Need a valid callable object");
+      SWIG_fail;
+    }
+
+  llvm::Expected<PythonCallable::ArgInfo> arg_info = callable.GetArgInfo();
+  if (!arg_info) {
+    PyErr_SetString(PyExc_TypeError,
+                      ("Could not get arguments: " +
+                          llvm::toString(arg_info.takeError())).c_str());
+      SWIG_fail;
+  }
+
+  if (arg_info.get().max_positional_args != 3) {
+    PyErr_SetString(PyExc_TypeError, "Expected 3 argument callable object");
+    SWIG_fail;
+  }
+
+    Py_INCREF($input);
+
+    $1 = LLDBSwigPythonCallResolveSourceFileCallback;
+    $2 = $input;
+  }
+}
+
+%typemap(typecheck) (lldb::SBPlatformResolveSourceFileCallback callback,
+                     void *callback_baton) {
+  $1 = $input == Py_None;
+  $1 = $1 || PyCallable_Check(reinterpret_cast<PyObject *>($input));
+}
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig
index b72a462d04643b..fb0b0368914fbf 100644
--- a/lldb/bindings/python/python-wrapper.swig
+++ b/lldb/bindings/python/python-wrapper.swig
@@ -727,7 +727,7 @@ lldb_private::python::SWIGBridge::LLDBSwigPythonHandleOptionArgumentCompletionFo
     dict_sp->AddBooleanItem("no-completion", true);
     return dict_sp;
   }
-    
+
 
   // Convert the return dictionary to a DictionarySP.
   StructuredData::ObjectSP result_obj_sp = result.CreateStructuredObject();
@@ -753,7 +753,7 @@ bool lldb_private::python::SWIGBridge::LLDBSwigPythonCallParsedCommandObject(
   auto pfunc = self.ResolveName<PythonCallable>("__call__");
 
   if (!pfunc.IsAllocated()) {
-    cmd_retobj.AppendError("Could not find '__call__' method in implementation class"); 
+    cmd_retobj.AppendError("Could not find '__call__' method in implementation class");
     return false;
   }
 
@@ -1095,4 +1095,49 @@ static SBError LLDBSwigPythonCallLocateModuleCallback(
 
   return *sb_error_ptr;
 }
+
+static SBError LLDBSwigPythonCallResolveSourceFileCallback(
+    void *callback_baton,
+     const lldb::ModuleSP &module_sp,
+    const SBFileSpec &original_source_file_spec_sb,
+    SBFileSpec &resolved_source_file_spec_sb) {
+  SWIG_Python_Thread_Block swig_thread_block;
+
+  PyErr_Cleaner py_err_cleaner(true);
+
+  PythonObject module_sb_arg = SWIGBridge::ToSWIGWrapper(module_sp);
+  PythonObject original_source_file_spec_arg = SWIGBridge::ToSWIGWrapper(
+      std::make_unique<SBFileSpec>(original_source_file_spec_sb));
+  PythonObject resolved_source_file_spec_arg = SWIGBridge::ToSWIGWrapper(
+      std::make_unique<SBFileSpec>(resolved_source_file_spec_sb));
+
+  PythonCallable callable =
+      Retain<PythonCallable>(reinterpret_cast<PyObject *>(callback_baton));
+  if (!callable.IsValid()) {
+    return SBError("The callback callable is not valid.");
+  }
+
+  PythonObject result = callable(module_sb_arg, original_source_file_spec_arg,
+                                 resolved_source_file_spec_arg);
+
+  if (!result.IsAllocated())
+    return SBError("No result.");
+  lldb::SBError *sb_error_ptr = nullptr;
+  if (SWIG_ConvertPtr(result.get(), (void **)&sb_error_ptr,
+                      SWIGTYPE_p_lldb__SBError, 0) == -1) {
+    return SBError("Result is not SBError.");
+  }
+
+  if (sb_error_ptr->Success()) {
+    lldb::SBFileSpec *sb_resolved_source_file_spec_ptr = nullptr;
+    if (SWIG_ConvertPtr(resolved_source_file_spec_arg.get(),
+                        (void **)&sb_resolved_source_file_spec_ptr,
+                        SWIGTYPE_p_lldb__SBFileSpec, 0) == -1)
+      return SBError("resolved_source_file_spec is not SBFileSpec.");
+
+    resolved_source_file_spec_sb = *sb_resolved_source_file_spec_ptr;
+  }
+
+  return *sb_error_ptr;
+}
 %}
diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h
index 159a9ba799b181..fa676ed799bbeb 100644
--- a/lldb/include/lldb/API/SBDefines.h
+++ b/lldb/include/lldb/API/SBDefines.h
@@ -146,6 +146,11 @@ typedef void (*SBDebuggerDestroyCallback)(lldb::user_id_t debugger_id,
 typedef lldb::SBError (*SBPlatformLocateModuleCallback)(
     void *baton, const lldb::SBModuleSpec &module_spec,
     lldb::SBFileSpec &module_file_spec, lldb::SBFileSpec &symbol_file_spec);
+
+typedef lldb::SBError (*SBPlatformResolveSourceFileCallback)(
+    void *baton, const lldb::ModuleSP &module_sp,
+    const lldb::SBFileSpec &original_source_file_spec,
+    lldb::SBFileSpec &resolved_source_file_spec);
 }
 
 #endif // LLDB_API_SBDEFINES_H
diff --git a/lldb/include/lldb/API/SBPlatform.h b/lldb/include/lldb/API/SBPlatform.h
index d63d2ed1eaba62..37ab2ef0441cf5 100644
--- a/lldb/include/lldb/API/SBPlatform.h
+++ b/lldb/include/lldb/API/SBPlatform.h
@@ -190,6 +190,9 @@ class LLDB_API SBPlatform {
   SBError SetLocateModuleCallback(lldb::SBPlatformLocateModuleCallback callback,
                                   void *callback_baton);
 
+  SBError SetResolveSourceFileCallback(
+      lldb::SBPlatformResolveSourceFileCallback callback, void *callback_baton);
+
 protected:
   friend class SBDebugger;
   friend class SBTarget;
diff --git a/lldb/source/API/SBPlatform.cpp b/lldb/source/API/SBPlatform.cpp
index 394268b77aa21f..f0fd0a3418fa56 100644
--- a/lldb/source/API/SBPlatform.cpp
+++ b/lldb/source/API/SBPlatform.cpp
@@ -732,3 +732,40 @@ SBError SBPlatform::SetLocateModuleCallback(
       });
   return SBError();
 }
+
+SBError SBPlatform::SetResolveSourceFileCallback(
+    lldb::SBPlatformResolveSourceFileCallback callback, void *callback_baton) {
+  LLDB_INSTRUMENT_VA(this, callback, callback_baton);
+  PlatformSP platform_sp(GetSP());
+  if (!platform_sp) {
+    return SBError("invalid platform");
+  }
+
+  if (!callback) {
+    // Clear the callback.
+    platform_sp->SetResolveSourceFileCallback(nullptr);
+    return SBError();
+  }
+
+  // Platform.h does not accept lldb::SBPlatform ResolveSourceFileCallback
+  // directly because of the SBFileSpec dependency. Use a lambda to
+  // convert FileSpec <--> SBFileSpec for the callback arguments.
+  platform_sp->SetResolveSourceFileCallback(
+      [callback, callback_baton](const lldb::ModuleSP &module_sp,
+                                 const FileSpec &original_source_file_spec,
+                                 FileSpec &resolved_source_file_spec) {
+        SBFileSpec original_source_file_spec_sb(original_source_file_spec);
+        SBFileSpec resolved_source_file_spec_sb;
+
+        SBError error =
+            callback(callback_baton, module_sp, original_source_file_spec_sb,
+                     resolved_source_file_spec_sb);
+
+        if (error.Success()) {
+          resolved_source_file_spec = resolved_source_file_spec_sb.ref();
+        }
+
+        return error.ref().Clone();
+      });
+  return SBError();
+}
diff --git a/lldb/test/API/python_api/sbplatform/TestResolveSourceFileCallback.py b/lldb/test/API/python_api/sbplatform/TestResolveSourceFileCallback.py
new file mode 100644
index 00000000000000..78bf4e47145ca7
--- /dev/null
+++ b/lldb/test/API/python_api/sbplatform/TestResolveSourceFileCallback.py
@@ -0,0 +1,196 @@
+"""
+Test resolve source file callback functionality
+"""
+
+import os
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from pathlib import Path
+
+import lldb
+
+SOURCE_ORIGINAL_FILE = "test.cpp"  # File does not exist
+SOURCE_NEW_FILE = "test_new.cpp"  # File exists
+SOURCE_NEW_NON_EXISTENT_FILE = "non-existent-file"
+EXE_NAME = "test.exe"
+
+
+class ResolveSourceFileCallbackTestCase(TestBase):
+    def setUp(self):
+        TestBase.setUp(self)
+
+        # Set the input directory
+        self.input_dir = (Path(self.getSourceDir())).resolve()
+
+        # Set executable to test.exe and ensure it exists
+        exe_path = (self.input_dir / EXE_NAME).resolve()
+        self.assertTrue(exe_path.exists())
+        exe_path_str = str(exe_path)
+
+        # Create target
+        self.target = self.dbg.CreateTarget(exe_path_str)
+        self.assertTrue(self.target)
+
+        # Create platform
+        self.platform = self.target.GetPlatform()
+
+        # Launch the process once, stop at breakpoint "sum" function and get the frame
+        self.frame = self.get_frame_for_paused_process("sum", exe_path_str)
+
+        # Set the original source file spec
+        source_file_path = os.path.join(self.input_dir, SOURCE_ORIGINAL_FILE)
+        self.original_source_file_spec = lldb.SBFileSpec(source_file_path)
+
+        # Set the new source file spec
+        new_source_file_path = os.path.join(self.input_dir, SOURCE_NEW_FILE)
+        self.new_source_file_spec = lldb.SBFileSpec(new_source_file_path)
+
+    def get_frame_for_paused_process(self, function_name, exe) -> lldb.SBFrame:
+        # Launch the process, stop at breakpoint on function name and get the frame
+
+        # Set breakpoint
+        breakpoint = self.target.BreakpointCreateByName(function_name, exe)
+        self.assertTrue(
+            breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT
+        )
+
+        # Now launch the process, and do not stop at entry point.
+        process = self.target.LaunchSimple(
+            None, None, self.get_process_working_directory()
+        )
+        self.assertTrue(process, PROCESS_IS_VALID)
+
+        # Get the stopped thread
+        thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+        self.assertTrue(
+            thread.IsValid(), "There should be a thread stopped due to breakpoint"
+        )
+
+        # Get the frame
+        frame0 = thread.GetFrameAtIndex(0)
+        self.assertTrue(frame0.IsValid(), "There should be a valid frame")
+
+        return frame0
+
+    def get_source_file_for_frame(self) -> lldb.SBFileSpec:
+        line_entry = self.frame.GetLineEntry()
+        self.assertTrue(line_entry.IsValid(), "There should be a valid line entry")
+
+        return line_entry.GetFileSpec()
+
+    def test_set_non_callable(self):
+        # The callback should be callable.
+        non_callable = "a"
+
+        with self.assertRaises(TypeError, msg="Need a callable object or None!"):
+            self.platform.SetResolveSourceFileCallback(non_callable)
+
+    def test_set_wrong_args(self):
+        # The callback should accept 3 argument.
+        def test_args2(a, b):
+            pass
+
+        with self.assertRaises(TypeError, msg="Expected 3 argument callable object"):
+            self.platform.SetResolveSourceFileCallback(test_args2)
+
+    def test_default(self):
+        # The default behavior is to locate the source file with LLDB implementation
+        # and frame.GetLineEntry should return the original file spec.
+        resolved_source_file_spec = self.get_source_file_for_frame()
+
+        # Check if the source file spec is resolved to the original file spec
+        self.assertEqual(resolved_source_file_spec, self.original_source_file_spec)
+        self.assertFalse(self.original_source_file_spec.Exists())
+
+    def test_set_none(self):
+        # SetResolveSourceFileCallback should succeed to clear the callback with None
+        # and frame.GetLineEntry will return the original file spec.
+        self.assertTrue(self.platform.SetResolveSourceFileCallback(None).Success())
+
+        resolved_source_file_spec = self.get_source_file_for_frame()
+
+        # Check if the source file spec is resolved to the original file spec
+        self.assertEqual(resolved_source_file_spec, self.original_source_file_spec)
+        self.assertFalse(resolved_source_file_spec.Exists())
+
+    def test_return_original_file_on_error(self):
+        # The callback fails, frame.GetLineEntry should return the original file spec.
+
+        # Resolve Source File Callback
+        def test_source_file_callback(
+            module_sp: lldb.SBModule,
+            original_file_spec: lldb.SBFileSpec,
+            resolved_file_spec: lldb.SBFileSpec,
+        ):
+            return lldb.SBError("Resolve Source File Callback failed")
+
+        self.assertTrue(
+            self.platform.SetResolveSourceFileCallback(
+                test_source_file_callback
+            ).Success()
+        )
+
+        resolved_source_file_spec = self.get_source_file_for_frame()
+
+        # Check if the source file spec is resolved to the original file spec
+        self.assertEqual(resolved_source_file_spec, self.original_source_file_spec)
+        self.assertFalse(resolved_source_file_spec.Exists())
+
+    def test_return_orignal_file_with_new_nonexistent_file(self):
+        # The callback should return a valid SBFileSpec but the file does not exist.
+        # frame.GetLineEntry should return the original file spec.
+
+        # Resolve Source File Callback
+        def test_source_file_callback(
+            module_sp: lldb.SBModule,
+            original_file_spec: lldb.SBFileSpec,
+            resolved_file_spec: lldb.SBFileSpec,
+        ):
+            resolved_file_spec.SetDirectory(str(self.input_dir))
+            resolved_file_spec.SetFilename(SOURCE_NEW_NON_EXISTENT_FILE)
+
+            return lldb.SBError()
+
+        # SetResolveSourceFileCallback should succeed and frame.GetLineEntry will return the original file spec
+        self.assertTrue(
+            self.platform.SetResolveSourceFileCallback(
+                test_source_file_callback
+            ).Success()
+        )
+
+        # Get resolved source file spec from frame0
+        resolved_source_file_spec = self.get_source_file_for_frame()
+
+        # Check if the source file spec is resolved to the original file spec
+        self.assertEqual(resolved_source_file_spec, self.original_source_file_spec)
+        self.assertFalse(resolved_source_file_spec.Exists())
+
+    def test_return_new_existent_file(self):
+        # The callback should return a valid SBFileSpec and file exists.
+        # frame.GetLineEntry should return the new file spec.
+
+        # Resolve Source File Callback
+        def test_source_file_callback(
+            module_sp: lldb.SBModule,
+            original_file_spec: lldb.SBFileSpec,
+            resolved_file_spec: lldb.SBFileSpec,
+        ):
+            resolved_file_spec.SetDirectory(str(self.input_dir))
+            resolved_file_spec.SetFilename(SOURCE_NEW_FILE)
+
+            return lldb.SBError()
+
+        # SetResolveSourceFileCallback should succeed and frame.GetLineEntry will return the new file spec from callback
+        self.assertTrue(
+            self.platform.SetResolveSourceFileCallback(
+                test_source_file_callback
+            ).Success()
+        )
+
+        # Get resolved source file spec from frame0
+        resolved_source_file_spec = self.get_source_file_for_frame()
+
+        # Check if the source file spec is resolved to the file set in callback
+        self.assertEqual(resolved_source_file_spec, self.new_source_file_spec)
+        self.assertFalse(self.original_source_file_spec.Exists())
+        self.assertTrue(resolved_source_file_spec.Exists())
diff --git a/lldb/test/API/python_api/sbplatform/test.exe b/lldb/test/API/python_api/sbplatform/test.exe
new file mode 100755
index 0000000000000000000000000000000000000000..ee23081015ce7944535bc76b8a17861d80c74cc0
GIT binary patch
literal 21704
zcmeHP3vgW3c|P~<uC%hOm1OxL+kjWZP#e(d;Rmve at yfPjiTZ^f#H2OX`?xDD?2FyI
z!sZoE4GG3^YBC)P1zOWgCrJlpNSkJ8N)t0qFm#%UnT8Gx?Zio8N*mgkVp`F7P`~fo
zb5^U>%3(5@>2zk#=$`-l-}(Rl{O3RCYR|c^&kk-IG7UrMWQv;wxo}HZLT)a^@NY_1
zVSS=WgvGVu8c_$tiz6&+NZpdAZ<=m}rhX;o0i|9$3zCMX(JLe;gr?d<QtC~muqwLr
z1)s}mDq38gda_FKLiJD66RH7C%k^Y?LD!B5hTVdqmlUjNxgKM4uG1Abw;?PGn(kF`
z*{`V9BTK#WO7FbV(^P1AMRh#sBac26&puBW9C?=p$sh$~E<~l?ex<ix$!oer$!p3s
znD)Hm#DA6cb}7B~pfn at egJD_FbhQf$O?7*>LXUCzq)89+Zq?pw<It_*sHveE=t?D{
zYgc!r;+?5vrg*6HP~Y0lwW~vgY^YaC&@Z;ZIkk1iK4Bgar-`XB%CVTQc-Ftw+8VuY
z{9m4b{Ll9M=#dSHZygH$<czk#HYvkIeLckFS*H*3pET`<;JhlrL$l!QOR$PO+pdP+
zFbgg$Yc!qBSOq7NcPvX-BYU at 7aXW91CJT<8- at AQtDx0zQMxrU(t*c&RA^b6ABppd+
zL at uAqI0*r`;KXCsU(b<POEz69jmDrsu7`Nc#kX!7*|gc}4Xs)&bg?(Ih8;CaV at 1vY
z|2a at SZ@%%^<Ctz9aZ+K$CCLWrJVjxo^BcpGLTK7}y<3Lsxj?}SWw at Tx#3#yd^{<Pt
zXb*=atw+u=sHIv2Y7wYKpca8z1ZokeMW7aeS_FO_5%{3_s{a{2`ksIIxbG)j*ycZc
z+A$~34Illk|BN(0x#p*UC$D)MdGoR`O612__pj$CCnu at j^Y0_aUcY1b*iVO#zI|cW
z-oc*JJ+BR)J=@<3 at dfum{9+>1yzC)qkMd`x*ptI2HarW7;S;_;AXzuzEPyLJScWSN
zljob49iieGMInE;lwWfv$;yw1k6jpk`9C%ezdYd?HeMNi{bOf73|y%U_$SXNnwM>v
z(r5ceHmpRoD7NhzKK9PL_o5fC_!a>%4xBl8CNbq4`%C$sJxal24_rD{oH)Mk((%Cw
z<J^HW#1OfbvxAqoVLLlG!S(*}eG|tAFCF{)V`twz3&Y0-FCHJfc<hz$v;@QAMbwLT
zzxDCtq%6J02-Cide<|V=s-;>4Y7wYKpca8z1ZokeMW7aeS_Enls70U_fm#H9y%FGj
zuksYza7}y;0As0VJ at 3Kto|ON><m4gH6`;F7_k+ek1Mg2xo&voZ^fV|F?|CvA_wE+P
zp%!E5+<N~>+`!^}HQviV_w&igYbmg$zJ*vfj`x7+dtb|0h2s%mK~NEB849%D(%g8D
z|A^SQWc_ukmS0Vnwo*6}@I|&c5NP?Fxw)xsCmK}sUjY3K>NkT5UH_n4PpFn^5vWC=
z7J*s>Y7wYKpca8z1ZokeMW7ae|IZN!;-)Lp1@(Nhes<83=+v`>nF^l!J0>m9XCay9
zx&#}zuq-tx{)lR4vEub}%}W)ppD$jb_&3#a%-pvz>G}^pp3IUz<q4Cx&uD}0@`lOE
zXQ4??t9tHDnZDu@(Wq#<q6-w&g!g1+3Wp`pyIn1>_p5x)l4+4k#1p=-ENQ$?@!Ic$
zN)8W&%B1b#=C16IU&-Shu;g`Iu^pBCgzBGC|34$8=gKQQSgXdH at Yc<n`-3a+g!0N@
zPfut~s5{u(-MhN`#-4S-6}#<ta5&<qiq77ZV&Jy^)w!PDwQI!g+xqjxOeUEb4dU6{
zN?oz(w*E*alZ_ at bRjapty1)C-s(5ernzfN&DAZLrT!`DbLKmLI?utZ{otdm-hhk#S
zuKrbG&*uIfv3aP!?=pfz+xk0uE>pjC05*1w(Ar>sw at B_mHqD1*Ch4F-*^DZ?HWf2X
z7|%aD$yjIJPGw_SsRDDAD?rXKUKinsxOHH;u`1G2dKV+1#-y4|QPpW$O-7%?3om0w
zpVyD5^ShdzBTE0;%g8*S>NKrpN7rduO-B2=^fEqcUr(quZ$S9m^PCoi(0+beax=4w
zb^O0$Na1-o1iphZJhQ85)_)2W=Ie|4L45xD4 at kWA6CiDVpW*LC%RaMy3C#G6y48~N
zg+b<feRzZ&D!v$G>-mqx^Tgsb%TJ=(^W;*N>mEY}#r1#!EHChT1IG8ky#r>U*W2p(
z8x)$?!~VRs0T$mw);5RL!c0TZ+gzWJOp(ld-=Bi<ia9j)A&y2m?h*ArVC at 3WGvHcY
zV&<FEvJzI!AAs at AZFE3{c^#yDP0dvFi+UfqfQRo3wS0)|&AJ}{OTf$&>g!gicALqp
zZTJFp%-hJ^D47=X%aE<>lT5qWga6HS>m(C2=fYZDzhqXJZ;)9pnQn764csJ|KC?h(
zgJi;HC&j{&88+Xi=>f^?GQUn{lVtXr9b~pFd;{d5$={#4q4_ at oGiL4}Gc3K%nfqvM
zL^6)~HP+lBV{pj)ESc@|ZUs4F@`atc9nJf}{Em4YYj*m74D6`6lLl^W{yCUO%;#Bi
zd(#n+ljf6TerwT3sCmNNP6NNa*n{4mG8-6!1Ja$Zns2k_j)q}KzhJ&X#+nlX^P+ix
zrVmQrPMdGBChGS?^}C|}BUIJbFJ1$(=-()IePHezZ0{V!2+NVDS90V5zKZhP$0>7>
zrCTWYF)}I07qX;ao2YvNGWFj<=HEMyQzLLC-Q|G$f}ZoheJ$SOBwlZTpx^sFNC7+z
z(vBB3#GKDJG}d`B-=fs=#Av`{OC+&~_~;GH$2Kuf?q_~yn)zKvnWw(YJk2*{Ja_*S
z^Sp^G#UAHs=EY6S$D_;-9b$g?i_9N<iuuv!m_PI~^M~JJ{`vQqKVsr^_Z<HX<|kG$
z|J`BaqTz4h^jr_UGD2`u_`d{~pPQRNkxsgx_hEnmk3{LTLVeI}aZz?c8CU|@^HP+3
zQlbM8{e>Y>_EDkB(c*ua68%Gs8Z3!A#>^Xo)-7g$=M<x1uwc+N)zo}6btyo<8770H
zC^O+5Ma?s2Gba*bXK;EM<WvSp;oS=J9z*Igv{U-ZJu01X-DA)tYViM+^g(zZKqLR{
z)*mR<vn1+P(*3KDy=t~ng9D|kZbGY<+)!}fTy*ibVasp2#u}0kxyr+#bi3mpfQc{3
zIB{eZ_!j_wPl6oiDepzYA~gJclLPNsZ}=DnHyNA*ZYLN>;WZ#O<a)x1F;%5vOra%@
z(y?#KAo>3oz*#vQoIG+kg!i9e`*GLt7|{fT+-5nD;tscgds)Q+S}Lx%0mP{HQIL;I
zGHsSQ;HSS0!KR34V6FLBswpbwxW%!im}qp1adBm#m==b|_X?zl>EA59vNfJ=jff^!
zI at KB#^WEYYTJVXHHkfV_o<M)&`o?vQBW-<HP<#BMzoP+sM`Jtcy&+ at cVn}rO*ZU}P
z(_#atZ at Fk}yt&a6zz{c!#tuJC)h{eFg<wr-O5?6(!xZXU*U{vHa|~mojdmM5;8Yj9
znA-+hH(`I#v>G1ucNlc2ex%LBQaf<1^t at Sm-r;p!#~IjWcmj=$ZeM7u)u&WDJoKEZ
z^IDB-0&R_+WlNW}8uRK~u;6cl|7dW&>X9Emx^0FwlL^q!!bK&3?4qfD;vd~Q1O7EK
zIILS75;9y8V6-rEN{|Wz#vZPSD^w&@?CDRq{eBtVD`geULM0OzX>%*@<$mi=aQN_Z
z%#DO$7{3TKkznp|(TKvbdahlfIKGJE6pj~hd=JMz;4qD4W;430QyrC>k(rB-d9GpB
z&Fn^IHzV^7A at glVR_9wJ8qCrR^9BCMXB_p-?e^6_RP+Ukz6Sr*zB&F4KI3-NgeU5y
zJ<G}_5|)Ga{dQV;I}*2YPF`5CF}~MVNZxC+sxX$#JJDi73V~YDNWm6)JDnZ3MWSHa
zcL^(zOxc<2lo>k{7kHa+G{|+8l}JTK3ng{dS+Qc?ie*#9bOx^_CQ{jm)6?50MPk{w
z9UFIqlg?!#X<=nkaXMMB9kdAqFDGub61i-FzI|pDPO)SXHULQVbR>V5jXqe#%w3u6
zJsG~}Xx$SVi at N?4Glk at 620J4<may~rEM(F7d-6%gmc5tV4NjAzKp`@2yFHiYL}Ju-
zVj_{ZvpE}mz+Qr3U`Km}l|~<=L_y at -Hn2qtZodBdo*OIoT2=OG!OpZ(%-9=7?TnpI
z#=u7Mv9S&Ad#;`1y}`~=w=?l<kuPh;Qg$SdX39Fk7#B0rMLJLK)F=;)Y#S5^rW{Zm
zM>zl at A-j@Dq>6<x^g#v^LFK!ijtz4va+n=?;YLZ0E~A%>+g3c{M1(c&@C8ymVu()!
zqm7|1aw1sckyKGm8i(VRu(Jt{GiQ%T#8O$zD>)<At}dUGa=w+ufL&w9=mmy75?>>F
zdMqoAw@=|F^@^Ed!H#1X&^lgkEm)<=8;RXj%(<h85R6M)3#ITDEN0j}N!U*~b}A(Y
zkZ#JiT&E_9bjPs^*m34^qKn<`LWB82S3Ux-(vehGDm9+&EJQN#F8dH(t<7jCm(Sj5
z#~jqhqg^!7HLz=>D|gr#!+W`rT(YYW&7~qvBAZVO*v#`)=Pqo}xwE#`uEw4<J{ED@
z_ny0Ydb*OCSgMGrCS?`V6-_#YnMjv&IA>4CrwifDU6`zfRc&3if^}rvPK3sUG!9xe
z4w7 at vQxpqMz8G^X&OXV-lUdLh3?#DxO~<mCL~<0+<&y{hN83H&8A2ZHD)syH<&_?6
zr}X>s({Zo3zp5Qy>3Y|6`MT0|uIYGv>3Z07+%KwKNAh6rs;@sym!Bi_b*$-lW9fR=
zbbKy;Q^VzuEPL?vhhSAaP`Xx8uH+HTLSI*yj^j#4FkBAFvPZO*z6(%Z=@Ik9uB!5F
zLSKKJE<a!B>yFd$1)|z at FOOJQdarxBJQfMza5*H)9?=f>tKo~q@~XJL8amyS2P?s9
z$%Cg{RvfHm|H^9On1xr(f-jo|56*&j%z|G%1IMC3c*XmZl@&JwFi at lCe^3c<BT-F$
z4{%cigub?<#Kk^^zfdvXcn(uuU+32H529d*srb`BrblrYcsi+aK71WG?F3uHC{3lm
zM$r&6=hZ&~ujc=3{dz~*nI|TKVU(t)YIZ)5A~WZ|T&0Pb^Og%YgIBF9<{OuB^QJc^
zxjx`6n75Vl^F`pnD)V_G at K#=tRQ}723 at q&cJ`ZuL+_mhXyxAiB75zO(d2{CffrPX(
z)6t_+J|J>x+<i*qB`H7kf96_+KPBa7{=a$_cq`WZD=Omiys}eT%PKqH1kU(Wp4Vq2
zzIcY6R~23v&mRI0Dx2lx!YugYEV%nq`AdGGado`(2T^>tB$ju2LRczWxKeI8kx>Dl
z;1uz4TTD!Sjl*)%78XPq{A62JJZp`nve8J&iaXhS!HN_QiC8wBOWBSc4|P|Uz?wXh
zv?BR@<gjIDocv)dR<U}v;>C3OFjUGoi<il#iI$c(mNm3{VEdpoxMPc4Nn;&r4Gt at C
zc*|~KZMl8N!1j^NSe0+vxoKdVwR31_&){Bb at 4%*QgO>U at NVxn1AC~Q|6uGFz&ws|^
zYE3P&tau at 7jbY)$Z;-G9aFkyRDf`|?$ripFV#QO~wqSM3m7jaL-pVDR$__yl-!##l
zPwf=gx@%7$FkGER3k3~a?wcr8KA%$c6DcB8IGn~Z7}UwTbWE49Vz%=+5t6q^Ml;0_
zmW0?MIETxiXfcV8+a%)(8rU?_$$1i at _*evM^HBV722HpW8#Y-pjumJ!o0-N~s6%`r
zR8XZ{$`K(Mo{)pZsR+p^hw at oDC?R`HO^mTPbT#K{xHH7n&}A5oq?0kUnuRT7A=!Xy
z3~?19Ow=^yp9rZtO0w&~*&Er at P{eWa$!HOC4n4A?#ZefKVDnO9lbJ-eR27Zp?QzZF
z3qZCmBgDE$7$cf5KfQnDGFJfj7l7X)H?@1hvcT&^O!~g5%ek_;O!_GtyrrP^`;>m4
z(hs7pJo(ERl-J at Y*Wa)7_bdJ774rIbK*J*y`ucbO{#n|u)aSjK|H8dd?f)s&{wbxe
z`(LLTtn at zuoEJ5;{%NIuTIruudhDZtL+kT03{w&ZMYX=Z|GY~%`V|V5CE6%YcZ1=*
zUaha!<r7LDzf3Y||FxW^T(|JvvF7#q-LHQ5x|M#V{|Xi-P+(J9U$67~l>R{_sN1jX
z|L-gPO-fGR|9(R0>o`##tBo1)dlndDqU{U4Uc=IXsd9x|IsQ*Wrd&U$^n*%2NF!xQ
z!CaZh#PKQD4=eq!64=1XvZVDi#QQbn`g*@|q}7#Z(t?Us`v2!jU&mjsmqgH2Sg7<g
z(ec;(U!lPEwZ8ryT6 at ry;9aotRN4M(s4Uml`=nh#SL?ZQWt1!1|2tr~lq=5xit7E8
z{%%^Oyyi9iF?4v}Pn~Y1b at rQ`v^KLnt*7bFAj7$%_4WQte+N$ohV!3E>*;a42#ozN
z>2C~!!|j(YN%Szd405fn=|{lI^-JsN?oXy~Lb+UDuOEX-zjC}NTb}#?=!^DWuP2v(
zLj5Myz7j8)*805RQ=WADnl40vZCC2=RsgR9mnY3?%Ke5O8_MZ@>&YHhYl{|CMk?dM
z``HyDQu2qru0o|>m9n?YqVHYh>Q9vZF}ZxD{%y19Us~tNzgVGA!HW1S`rlaZ>VM58
zrMyy~j~x)J?B{`-T$Qk%7|Mdy*Yv(w^q<-2D%`FGXVGW1{@<fSB$)`i+*einmV at R0
pB7NTI--QNX6)sA}Q(Gkwiz|#*xPv`rb^X5_arKW^C{(cGe*sA9U5Eex

literal 0
HcmV?d00001

diff --git a/lldb/test/API/python_api/sbplatform/test_new.cpp b/lldb/test/API/python_api/sbplatform/test_new.cpp
new file mode 100644
index 00000000000000..e9ffc97618f5d1
--- /dev/null
+++ b/lldb/test/API/python_api/sbplatform/test_new.cpp
@@ -0,0 +1,15 @@
+#include <iostream>
+
+int sum(int a, int b) {
+  return a + b; // Find the line number of function sum here.
+}
+
+int main() {
+
+  int a = 2;
+  int b = 3;
+  int c = sum(a, b);
+
+  std::cout << "c is " << c << std::endl;
+  return 0;
+}



More information about the lldb-commits mailing list