forked from OSchip/llvm-project
[lldb/plugins] Add arm64(e) support to ScriptedProcess
This patch adds support for arm64(e) targets to ScriptedProcess, by providing the `DynamicRegisterInfo` to the base `lldb.ScriptedThread` class. This allows create and debugging ScriptedProcess on Apple Silicon hardware as well as Apple mobile devices. It also replace the C++ asserts on `ScriptedThread::GetDynamicRegisterInfo` by some error logging, re-enables `TestScriptedProcess` for arm64 Darwin platforms and adds a new invalid Scripted Thread test. rdar://85892451 Differential Revision: https://reviews.llvm.org/D114923 Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
This commit is contained in:
parent
6fef466779
commit
caea440a11
|
@ -298,14 +298,14 @@ class ScriptedThread:
|
|||
self.register_info['registers'] = [
|
||||
{'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0},
|
||||
{'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3},
|
||||
{'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4', },
|
||||
{'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3', },
|
||||
{'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1', },
|
||||
{'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2', },
|
||||
{'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp', },
|
||||
{'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp', },
|
||||
{'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5', },
|
||||
{'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6', },
|
||||
{'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4'},
|
||||
{'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3'},
|
||||
{'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1'},
|
||||
{'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2'},
|
||||
{'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp'},
|
||||
{'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp'},
|
||||
{'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5'},
|
||||
{'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6'},
|
||||
{'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
|
||||
{'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
|
||||
{'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
|
||||
|
@ -316,8 +316,47 @@ class ScriptedThread:
|
|||
{'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'},
|
||||
{'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0},
|
||||
{'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0},
|
||||
{'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0},
|
||||
{'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0}
|
||||
]
|
||||
elif 'arm64' in arch:
|
||||
self.register_info['sets'] = ['General Purpose Registers']
|
||||
self.register_info['registers'] = [
|
||||
{'name': 'x0', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0, 'generic': 'arg0', 'alt-name': 'arg0'},
|
||||
{'name': 'x1', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg1', 'alt-name': 'arg1'},
|
||||
{'name': 'x2', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg2', 'alt-name': 'arg2'},
|
||||
{'name': 'x3', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3, 'generic': 'arg3', 'alt-name': 'arg3'},
|
||||
{'name': 'x4', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg4', 'alt-name': 'arg4'},
|
||||
{'name': 'x5', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg5', 'alt-name': 'arg5'},
|
||||
{'name': 'x6', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'arg6', 'alt-name': 'arg6'},
|
||||
{'name': 'x7', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'arg7', 'alt-name': 'arg7'},
|
||||
{'name': 'x8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8 },
|
||||
{'name': 'x9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9 },
|
||||
{'name': 'x10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
|
||||
{'name': 'x11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
|
||||
{'name': 'x12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
|
||||
{'name': 'x13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13},
|
||||
{'name': 'x14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14},
|
||||
{'name': 'x15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15},
|
||||
{'name': 'x16', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16},
|
||||
{'name': 'x17', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 17, 'dwarf': 17},
|
||||
{'name': 'x18', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 18, 'dwarf': 18},
|
||||
{'name': 'x19', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 19, 'dwarf': 19},
|
||||
{'name': 'x20', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 20, 'dwarf': 20},
|
||||
{'name': 'x21', 'bitsize': 64, 'offset': 168, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 21, 'dwarf': 21},
|
||||
{'name': 'x22', 'bitsize': 64, 'offset': 176, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 22, 'dwarf': 22},
|
||||
{'name': 'x23', 'bitsize': 64, 'offset': 184, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 23, 'dwarf': 23},
|
||||
{'name': 'x24', 'bitsize': 64, 'offset': 192, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 24, 'dwarf': 24},
|
||||
{'name': 'x25', 'bitsize': 64, 'offset': 200, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 25, 'dwarf': 25},
|
||||
{'name': 'x26', 'bitsize': 64, 'offset': 208, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 26, 'dwarf': 26},
|
||||
{'name': 'x27', 'bitsize': 64, 'offset': 216, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 27, 'dwarf': 27},
|
||||
{'name': 'x28', 'bitsize': 64, 'offset': 224, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 28, 'dwarf': 28},
|
||||
{'name': 'x29', 'bitsize': 64, 'offset': 232, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 29, 'dwarf': 29, 'generic': 'fp', 'alt-name': 'fp'},
|
||||
{'name': 'x30', 'bitsize': 64, 'offset': 240, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 30, 'dwarf': 30, 'generic': 'lr', 'alt-name': 'lr'},
|
||||
{'name': 'sp', 'bitsize': 64, 'offset': 248, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 31, 'dwarf': 31, 'generic': 'sp', 'alt-name': 'sp'},
|
||||
{'name': 'pc', 'bitsize': 64, 'offset': 256, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 32, 'dwarf': 32, 'generic': 'pc', 'alt-name': 'pc'},
|
||||
{'name': 'cpsr', 'bitsize': 32, 'offset': 264, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 33, 'dwarf': 33}
|
||||
]
|
||||
else: raise ValueError('Unknown architecture', arch)
|
||||
return self.register_info
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
@ -311,6 +311,11 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
|
|||
return GetInterface().ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
|
||||
error.AsCString(), error);
|
||||
|
||||
RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext();
|
||||
if (!reg_ctx_sp)
|
||||
return GetInterface().ErrorWithMessage<bool>(
|
||||
LLVM_PRETTY_FUNCTION, "Invalid Register Context", error);
|
||||
|
||||
new_thread_list.AddThread(thread_sp);
|
||||
|
||||
return new_thread_list.GetSize(false) > 0;
|
||||
|
|
|
@ -198,13 +198,17 @@ std::shared_ptr<DynamicRegisterInfo> ScriptedThread::GetDynamicRegisterInfo() {
|
|||
|
||||
if (!m_register_info_sp) {
|
||||
StructuredData::DictionarySP reg_info = GetInterface()->GetRegisterInfo();
|
||||
|
||||
Status error;
|
||||
if (!reg_info)
|
||||
return nullptr;
|
||||
return GetInterface()
|
||||
->ErrorWithMessage<std::shared_ptr<DynamicRegisterInfo>>(
|
||||
LLVM_PRETTY_FUNCTION,
|
||||
"Failed to get scripted thread registers info.", error,
|
||||
LIBLLDB_LOG_THREAD);
|
||||
|
||||
m_register_info_sp = std::make_shared<DynamicRegisterInfo>(
|
||||
*reg_info, m_scripted_process.GetTarget().GetArchitecture());
|
||||
assert(m_register_info_sp->GetNumRegisters() > 0);
|
||||
assert(m_register_info_sp->GetNumRegisterSets() > 0);
|
||||
}
|
||||
|
||||
return m_register_info_sp;
|
||||
|
|
|
@ -41,6 +41,38 @@ class ScriptedProcesTestCase(TestBase):
|
|||
self.expect('script dir(ScriptedProcess)',
|
||||
substrs=["launch"])
|
||||
|
||||
def test_invalid_scripted_register_context(self):
|
||||
"""Test that we can launch an lldb scripted process with an invalid
|
||||
Scripted Thread, with invalid register context."""
|
||||
self.build()
|
||||
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
|
||||
self.assertTrue(target, VALID_TARGET)
|
||||
|
||||
os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
|
||||
def cleanup():
|
||||
del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
scripted_process_example_relpath = 'invalid_scripted_process.py'
|
||||
self.runCmd("command script import " + os.path.join(self.getSourceDir(),
|
||||
scripted_process_example_relpath))
|
||||
|
||||
launch_info = lldb.SBLaunchInfo(None)
|
||||
launch_info.SetProcessPluginName("ScriptedProcess")
|
||||
launch_info.SetScriptedProcessClassName("invalid_scripted_process.InvalidScriptedProcess")
|
||||
error = lldb.SBError()
|
||||
with tempfile.NamedTemporaryFile() as log_file:
|
||||
self.runCmd("log enable lldb thread -f " + log_file.name)
|
||||
process = target.Launch(launch_info, error)
|
||||
|
||||
self.assertTrue(error.Success(), error.GetCString())
|
||||
self.assertTrue(process, PROCESS_IS_VALID)
|
||||
self.assertEqual(process.GetProcessID(), 666)
|
||||
self.assertEqual(process.GetNumThreads(), 0)
|
||||
|
||||
self.assertIn("Failed to get scripted thread registers data.".encode(),
|
||||
log_file.read())
|
||||
|
||||
@skipIf(archs=no_match(['x86_64']))
|
||||
def test_scripted_process_and_scripted_thread(self):
|
||||
"""Test that we can launch an lldb scripted process using the SBAPI,
|
||||
|
@ -103,7 +135,6 @@ class ScriptedProcesTestCase(TestBase):
|
|||
|
||||
@skipUnlessDarwin
|
||||
@skipIfOutOfTreeDebugserver
|
||||
@skipIf(archs=no_match(['x86_64']))
|
||||
@skipIfAsan # rdar://85954489
|
||||
def test_launch_scripted_process_stack_frames(self):
|
||||
"""Test that we can launch an lldb scripted process from the command
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
import os,struct, signal
|
||||
|
||||
from typing import Any, Dict
|
||||
|
||||
import lldb
|
||||
from lldb.plugins.scripted_process import ScriptedProcess
|
||||
from lldb.plugins.scripted_process import ScriptedThread
|
||||
|
||||
class InvalidScriptedProcess(ScriptedProcess):
|
||||
def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData):
|
||||
super().__init__(target, args)
|
||||
|
||||
def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo:
|
||||
return None
|
||||
|
||||
def get_thread_with_id(self, tid: int):
|
||||
return {}
|
||||
|
||||
def get_registers_for_thread(self, tid: int):
|
||||
return {}
|
||||
|
||||
def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData:
|
||||
return None
|
||||
|
||||
def get_loaded_images(self):
|
||||
return self.loaded_images
|
||||
|
||||
def get_process_id(self) -> int:
|
||||
return 666
|
||||
|
||||
def should_stop(self) -> bool:
|
||||
return True
|
||||
|
||||
def is_alive(self) -> bool:
|
||||
return True
|
||||
|
||||
def get_scripted_thread_plugin(self):
|
||||
return InvalidScriptedThread.__module__ + "." + InvalidScriptedThread.__name__
|
||||
|
||||
|
||||
class InvalidScriptedThread(ScriptedThread):
|
||||
def __init__(self, process, args):
|
||||
super().__init__(process, args)
|
||||
|
||||
def get_thread_id(self) -> int:
|
||||
return 0x19
|
||||
|
||||
def get_name(self) -> str:
|
||||
return InvalidScriptedThread.__name__ + ".thread-1"
|
||||
|
||||
def get_state(self) -> int:
|
||||
return lldb.eStateInvalid
|
||||
|
||||
def get_stop_reason(self) -> Dict[str, Any]:
|
||||
return { "type": lldb.eStopReasonSignal, "data": {
|
||||
"signal": signal.SIGINT
|
||||
} }
|
||||
|
||||
def get_stackframes(self):
|
||||
class ScriptedStackFrame:
|
||||
def __init__(idx, cfa, pc, symbol_ctx):
|
||||
self.idx = idx
|
||||
self.cfa = cfa
|
||||
self.pc = pc
|
||||
self.symbol_ctx = symbol_ctx
|
||||
|
||||
|
||||
symbol_ctx = lldb.SBSymbolContext()
|
||||
frame_zero = ScriptedStackFrame(0, 0x42424242, 0x5000000, symbol_ctx)
|
||||
self.frames.append(frame_zero)
|
||||
|
||||
return self.frame_zero[0:0]
|
||||
|
||||
def get_register_context(self) -> str:
|
||||
return None
|
||||
|
||||
def __lldb_init_module(debugger, dict):
|
||||
if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ:
|
||||
debugger.HandleCommand(
|
||||
"process launch -C %s.%s" % (__name__,
|
||||
InvalidScriptedProcess.__name__))
|
||||
else:
|
||||
print("Name of the class that will manage the scripted process: '%s.%s'"
|
||||
% (__name__, InvalidScriptedProcess.__name__))
|
Loading…
Reference in New Issue