[Lldb-commits] [lldb] f9a663f - Revert "[lldb] Add an example of interactive scripted process debugging (NFC)"
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Mon Mar 6 13:18:17 PST 2023
Author: Med Ismail Bennani
Date: 2023-03-06T13:17:46-08:00
New Revision: f9a663f9692f5e5342be0cbb27abc74cdf417434
URL: https://github.com/llvm/llvm-project/commit/f9a663f9692f5e5342be0cbb27abc74cdf417434
DIFF: https://github.com/llvm/llvm-project/commit/f9a663f9692f5e5342be0cbb27abc74cdf417434.diff
LOG: Revert "[lldb] Add an example of interactive scripted process debugging (NFC)"
This reverts commit 70b9822ef3b0774609c72d380504c9abfa717f81.
Added:
Modified:
Removed:
lldb/test/API/functionalities/interactive_scripted_process/Makefile
lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
lldb/test/API/functionalities/interactive_scripted_process/main.cpp
################################################################################
diff --git a/lldb/test/API/functionalities/interactive_scripted_process/Makefile b/lldb/test/API/functionalities/interactive_scripted_process/Makefile
deleted file mode 100644
index f2bee8980e62e..0000000000000
--- a/lldb/test/API/functionalities/interactive_scripted_process/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-CXXFLAGS=--std=c++17 -g
-
-all: main
-
-clean:
- rm -rf main *.dSYM
diff --git a/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py b/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
deleted file mode 100644
index 7d354ea2780e0..0000000000000
--- a/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py
+++ /dev/null
@@ -1,349 +0,0 @@
-# Usage:
-# ./bin/lldb $LLVM/lldb/test/API/functionalities/interactive_scripted_process/main \
-# -o "br set -p 'Break here'" -o "run" \
-# -o "command script import
-# $LLVM/lldb/test/API/functionalities/interactive_scripted_process/interactive_scripted_process.py" \
-# -o "br set -p 'also break here'" -o 'continue'
-
-import os,json,struct,signal
-
-from threading import Thread
-from typing import Any, Dict
-
-import lldb
-from lldb.plugins.scripted_process import ScriptedProcess
-from lldb.plugins.scripted_process import ScriptedThread
-
-class PassthruScriptedProcess(ScriptedProcess):
- driving_target = None
- driving_process = None
-
- def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
- super().__init__(exe_ctx, args)
-
- self.driving_target = None
- self.driving_process = None
-
- self.driving_target_idx = args.GetValueForKey("driving_target_idx")
- if (self.driving_target_idx and self.driving_target_idx.IsValid()):
- if self.driving_target_idx.GetType() == lldb.eStructuredDataTypeInteger:
- idx = self.driving_target_idx.GetIntegerValue(42)
- if self.driving_target_idx.GetType() == lldb.eStructuredDataTypeString:
- idx = int(self.driving_target_idx.GetStringValue(100))
- self.driving_target = self.target.GetDebugger().GetTargetAtIndex(idx)
- self.driving_process = self.driving_target.GetProcess()
- for driving_thread in self.driving_process:
- structured_data = lldb.SBStructuredData()
- structured_data.SetFromJSON(json.dumps({
- "driving_target_idx" : idx,
- "thread_idx" : driving_thread.GetIndexID()
- }))
-
- self.threads[driving_thread.GetThreadID()] = PassthruScriptedThread(self, structured_data)
-
- for module in self.driving_target.modules:
- path = module.file.fullpath
- load_addr = module.GetObjectFileHeaderAddress().GetLoadAddress(self.driving_target)
- self.loaded_images.append({"path": path, "load_addr": load_addr})
-
- def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
- mem_region = lldb.SBMemoryRegionInfo()
- error = self.driving_process.GetMemoryRegionInfo(addr, mem_region)
- if error.Fail():
- return None
- return mem_region
-
- def read_memory_at_address(self, addr: int, size: int, error: lldb.SBError) -> lldb.SBData:
- data = lldb.SBData()
- bytes_read = self.driving_process.ReadMemory(addr, size, error)
-
- if error.Fail():
- return data
-
- data.SetDataWithOwnership(error, bytes_read,
- self.driving_target.GetByteOrder(),
- self.driving_target.GetAddressByteSize())
-
- return data
-
- def write_memory_at_address(self, addr, data, error):
- return self.driving_process.WriteMemory(addr,
- bytearray(data.uint8.all()),
- error)
-
- def get_loaded_images(self):
- return self.loaded_images
-
- def get_process_id(self) -> int:
- return 42
-
- def is_alive(self) -> bool:
- return True
-
- def get_scripted_thread_plugin(self):
- return PassthruScriptedThread.__module__ + "." + PassthruScriptedThread.__name__
-
-class MultiplexedScriptedProcess(PassthruScriptedProcess):
- def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
- super().__init__(exe_ctx, args)
- self.multiplexer = None
- if isinstance(self.driving_process, lldb.SBProcess) and self.driving_process:
- parity = args.GetValueForKey("parity")
- #TODO: Change to Walrus operator (:=) with oneline if assignment
- # Requires python 3.8
- val = extract_value_from_structured_data(parity, 0)
- if val is not None:
- self.parity = val
-
- # Turn PassThruScriptedThread into MultiplexedScriptedThread
- for thread in self.threads.values():
- thread.__class__ = MultiplexedScriptedThread
-
- def get_process_id(self):
- return self.parity + 420
-
- def launch(self):
- self.first_launch = True
- return lldb.SBError()
-
- def resume(self, should_stop):
- if self.first_launch:
- self.first_launch = False
- return super().resume()
- else:
- if not self.multiplexer:
- error = lldb.SBError()
- error.SetErrorString("Multiplexer is not set.")
- return error
- return self.multiplexer.resume(pid=self.get_process_id())
-
- def get_threads_info(self):
- if not self.multiplexer:
- return super().get_threads_info()
- return self.multiplexer.get_threads_info(pid=self.get_process_id())
-
- def get_scripted_thread_plugin(self):
- return MultiplexedScriptedThread.__module__ + "." + MultiplexedScriptedThread.__name__
-
-class PassthruScriptedThread(ScriptedThread):
- def __init__(self, process, args):
- super().__init__(process, args)
- driving_target_idx = args.GetValueForKey("driving_target_idx")
- thread_idx = args.GetValueForKey("thread_idx")
-
- #TODO: Change to Walrus operator (:=) with oneline if assignment
- # Requires python 3.8
- val = extract_value_from_structured_data(thread_idx, 0)
- if val is not None:
- self.idx = val
-
- self.driving_target = None
- self.driving_process = None
- self.driving_thread = None
-
- #TODO: Change to Walrus operator (:=) with oneline if assignment
- # Requires python 3.8
- val = extract_value_from_structured_data(driving_target_idx, 42)
- if val is not None:
- self.driving_target = self.target.GetDebugger().GetTargetAtIndex(val)
- self.driving_process = self.driving_target.GetProcess()
- self.driving_thread = self.driving_process.GetThreadByIndexID(self.idx)
-
- if self.driving_thread:
- self.id = self.driving_thread.GetThreadID()
-
- def get_thread_id(self) -> int:
- return self.id
-
- def get_name(self) -> str:
- return PassthruScriptedThread.__name__ + ".thread-" + str(self.idx)
-
- def get_stop_reason(self) -> Dict[str, Any]:
- stop_reason = { "type": lldb.eStopReasonInvalid, "data": { }}
-
- if self.driving_thread and self.driving_thread.IsValid() \
- and self.get_thread_id() == self.driving_thread.GetThreadID():
- stop_reason["type"] = lldb.eStopReasonNone
-
- if self.driving_thread.GetStopReason() != lldb.eStopReasonNone:
- if 'arm64' in self.scripted_process.arch:
- stop_reason["type"] = lldb.eStopReasonException
- stop_reason["data"]["desc"] = self.driving_thread.GetStopDescription(100)
- elif self.scripted_process.arch == 'x86_64':
- stop_reason["type"] = lldb.eStopReasonSignal
- stop_reason["data"]["signal"] = signal.SIGTRAP
- else:
- stop_reason["type"] = self.driving_thread.GetStopReason()
-
- return stop_reason
-
- def get_register_context(self) -> str:
- if not self.driving_thread or self.driving_thread.GetNumFrames() == 0:
- return None
- frame = self.driving_thread.GetFrameAtIndex(0)
-
- GPRs = None
- registerSet = frame.registers # Returns an SBValueList.
- for regs in registerSet:
- if 'general purpose' in regs.name.lower():
- GPRs = regs
- break
-
- if not GPRs:
- return None
-
- for reg in GPRs:
- self.register_ctx[reg.name] = int(reg.value, base=16)
-
- return struct.pack("{}Q".format(len(self.register_ctx)), *self.register_ctx.values())
-
-class MultiplexedScriptedThread(PassthruScriptedThread):
- def get_name(self) -> str:
- parity = "Odd" if self.scripted_process.parity % 2 else "Even"
- return parity + MultiplexedScriptedThread.__name__ + ".thread-" + str(self.idx)
-
-class MultiplexerScriptedProcess(PassthruScriptedProcess):
- listener = None
- multiplexed_processes = None
-
- def wait_for_driving_process_to_stop(self, originator_pid, stop_event_mask):
- event = lldb.SBEvent()
-
- done = False
- while not done:
- if self.listener.WaitForEvent(5, event):
- event_mask = event.GetType();
- if event.BroadcasterMatchesRef(self.driving_process.GetBroadcaster()):
- if event_mask & lldb.SBProcess.eBroadcastBitStateChanged:
- done = True;
- continue
-
- self.listener.StopListeningForEvents(self.driving_process.GetBroadcaster(),
- stop_event_mask)
-
- # Stop multiplexer process
- mux_process = self.target.GetProcess()
- mux_process.ForceScriptedState(lldb.eStateRunning);
- mux_process.ForceScriptedState(lldb.eStateStopped);
-
- child_process = self.multiplexed_processes[originator_pid]
- child_process.ForceScriptedState(lldb.eStateRunning);
- child_process.ForceScriptedState(lldb.eStateStopped);
-
- def __init__(self, exe_ctx: lldb.SBExecutionContext, args : lldb.SBStructuredData):
- super().__init__(exe_ctx, args)
- if isinstance(self.driving_process, lldb.SBProcess) and self.driving_process:
- self.listener = lldb.SBListener("lldb.listener.multiplexer-scripted-process")
- self.multiplexed_processes = {}
-
- def resume(self, should_stop=True, pid=None):
- if not pid or pid not in self.multiplexed_processes.keys():
- return super().resume()
-
- stop_event_mask = lldb.SBProcess.eBroadcastBitInterrupt | lldb.SBProcess.eBroadcastBitStateChanged
- self.listener.StartListeningForEvents(self.driving_process.GetBroadcaster(),
- stop_event_mask)
-
- listener_thread = Thread(target=self.wait_for_driving_process_to_stop,
- args=[pid, stop_event_mask])
- listener_thread.start()
-
- # Resume the driving process
- self.driving_process.Continue()
-
- # Update the scripted process state.
- return lldb.SBError()
-
- def get_threads_info(self, pid=None):
- # if not pid or pid not in self.multiplexed_processes.keys():
- if not pid:
- return super().get_threads_info()
- parity = pid % 2
- return dict(filter(lambda pair: pair[0] % 2 == parity, self.threads.items()))
-
-def multiplex(mux_process, muxed_process):
- muxed_process.GetScriptedImplementation().multiplexer = mux_process.GetScriptedImplementation()
- mux_process.GetScriptedImplementation().multiplexed_processes[muxed_process.GetProcessID()] = muxed_process
-
-def launch_scripted_process(target, class_name, dictionary):
- structured_data = lldb.SBStructuredData()
- structured_data.SetFromJSON(json.dumps(dictionary))
-
- launch_info = lldb.SBLaunchInfo(None)
- launch_info.SetProcessPluginName("ScriptedProcess")
- launch_info.SetScriptedProcessClassName(class_name)
- launch_info.SetScriptedProcessDictionary(structured_data)
-
- error = lldb.SBError()
- return target.Launch(launch_info, error)
-
-def duplicate_target(driving_target):
- error = lldb.SBError()
- exe = driving_target.executable.fullpath
- triple = driving_target.triple
- debugger = driving_target.GetDebugger()
- return debugger.CreateTargetWithFileAndTargetTriple(exe, triple)
-
-def extract_value_from_structured_data(data, default_val):
- if data and data.IsValid():
- if data.GetType() == lldb.eStructuredDataTypeInteger:
- return data.GetIntegerValue(default_val)
- if data.GetType() == lldb.eStructuredDataTypeString:
- return int(data.GetStringValue(100))
- return None
-
-def __lldb_init_module(debugger, dict):
- def error_out(message):
- print(message)
- return
-
- if not debugger.GetNumTargets() > 0:
- return error_out("Interactive scripted processes requires one non scripted process.")
-
- debugger.SetAsync(True)
-
- driving_target = debugger.GetSelectedTarget()
- if not driving_target:
- return error_out("Driving target is invalid")
-
- driving_process = driving_target.GetProcess()
- if not driving_process:
- return error_out("Driving process is invalid")
-
- # Check that the driving process is stopped somewhere.
- if not driving_process.state == lldb.eStateStopped:
- return error_out("Driving process isn't stopped")
-
- # Create a seconde target for the multiplexer scripted process
- mux_target = duplicate_target(driving_target)
- if not mux_target:
- return error_out("Couldn't duplicate driving target to launch multiplexer scripted process")
-
- class_name = __name__ + "." + MultiplexerScriptedProcess.__name__
- dictionary = {'driving_target_idx': debugger.GetIndexOfTarget(driving_target)}
- mux_process = launch_scripted_process(mux_target, class_name, dictionary)
- if not mux_process:
- return error_out("Couldn't launch multiplexer scripted process")
-
- # Create a target for the multiplexed even scripted process
- even_target = duplicate_target(driving_target)
- if not even_target:
- return error_out("Couldn't duplicate driving target to launch multiplexed even scripted process")
-
- class_name = __name__ + "." + MultiplexedScriptedProcess.__name__
- dictionary['parity'] = 0
- even_process = launch_scripted_process(even_target, class_name, dictionary)
- if not even_process:
- return error_out("Couldn't launch multiplexed even scripted process")
- multiplex(mux_process, even_process)
-
- # Create a target for the multiplexed odd scripted process
- odd_target = duplicate_target(driving_target)
- if not odd_target:
- return error_out("Couldn't duplicate driving target to launch multiplexed odd scripted process")
-
- dictionary['parity'] = 1
- odd_process = launch_scripted_process(odd_target, class_name, dictionary)
- if not odd_process:
- return error_out("Couldn't launch multiplexed odd scripted process")
- multiplex(mux_process, odd_process)
diff --git a/lldb/test/API/functionalities/interactive_scripted_process/main.cpp b/lldb/test/API/functionalities/interactive_scripted_process/main.cpp
deleted file mode 100644
index 397a154c9c5e2..0000000000000
--- a/lldb/test/API/functionalities/interactive_scripted_process/main.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <iostream>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <vector>
-
-void spawn_thread(int index) {
- std::string name = "I'm thread " + std::to_string(index) + " !";
- bool done = false;
- std::string state = "Started execution!";
- while (true) {
- if (done) // also break here
- break;
- }
-
- state = "Stopped execution!";
-}
-
-int main() {
- size_t num_threads = 10;
- std::vector<std::thread> threads;
-
- for (size_t i = 0; i < num_threads; i++) {
- threads.push_back(std::thread(spawn_thread, i));
- }
-
- std::cout << "Spawned " << threads.size() << " threads!"; // Break here
-
- for (auto &t : threads) {
- if (t.joinable())
- t.join();
- }
-
- return 0;
-}
More information about the lldb-commits
mailing list