This revision was automatically updated to reflect the committed changes.
Closed by commit rGee11ef6dc0b2: Launch state discoverable in Darwin, use for
SafeToCallFunctions (authored by jasonmolenda).
Changed prior to commit:
https://reviews.llvm.org/D139054?vs=480277&id=482575#toc
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D139054/new/
https://reviews.llvm.org/D139054
Files:
lldb/docs/lldb-gdb-remote.txt
lldb/include/lldb/Target/Process.h
lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
lldb/source/Target/Thread.cpp
lldb/test/API/macosx/early-process-launch/Makefile
lldb/test/API/macosx/early-process-launch/TestEarlyProcessLaunch.py
lldb/test/API/macosx/early-process-launch/main.c
lldb/tools/debugserver/source/DNB.cpp
lldb/tools/debugserver/source/DNB.h
lldb/tools/debugserver/source/MacOSX/MachProcess.h
lldb/tools/debugserver/source/MacOSX/MachProcess.mm
lldb/tools/debugserver/source/RNBRemote.cpp
lldb/tools/debugserver/source/RNBRemote.h
Index: lldb/tools/debugserver/source/RNBRemote.h
===================================================================
--- lldb/tools/debugserver/source/RNBRemote.h
+++ lldb/tools/debugserver/source/RNBRemote.h
@@ -136,6 +136,7 @@
speed_test, // 'qSpeedTest:'
set_detach_on_error, // 'QSetDetachOnError:'
query_transfer, // 'qXfer:'
+ json_query_dyld_process_state, // 'jGetDyldProcessState'
unknown_type
};
@@ -246,6 +247,7 @@
rnb_err_t HandlePacket_qXfer(const char *p);
rnb_err_t HandlePacket_stop_process(const char *p);
rnb_err_t HandlePacket_QSetDetachOnError(const char *p);
+ rnb_err_t HandlePacket_jGetDyldProcessState(const char *p);
rnb_err_t SendStopReplyPacketForThread(nub_thread_t tid);
rnb_err_t SendHexEncodedBytePacket(const char *header, const void *buf,
size_t buf_len, const char *footer);
Index: lldb/tools/debugserver/source/RNBRemote.cpp
===================================================================
--- lldb/tools/debugserver/source/RNBRemote.cpp
+++ lldb/tools/debugserver/source/RNBRemote.cpp
@@ -499,6 +499,10 @@
"Test the maximum speed at which packet can be sent/received."));
t.push_back(Packet(query_transfer, &RNBRemote::HandlePacket_qXfer, NULL,
"qXfer:", "Support the qXfer packet."));
+ t.push_back(Packet(json_query_dyld_process_state,
+ &RNBRemote::HandlePacket_jGetDyldProcessState, NULL,
+ "jGetDyldProcessState",
+ "Query the process state from dyld."));
}
void RNBRemote::FlushSTDIO() {
@@ -5256,6 +5260,22 @@
return SendPacket(strm.str());
}
+rnb_err_t RNBRemote::HandlePacket_jGetDyldProcessState(const char *p) {
+ const nub_process_t pid = m_ctx.ProcessID();
+ if (pid == INVALID_NUB_PROCESS)
+ return SendPacket("E87");
+
+ JSONGenerator::ObjectSP dyld_state_sp = DNBGetDyldProcessState(pid);
+ if (dyld_state_sp) {
+ std::ostringstream strm;
+ dyld_state_sp->DumpBinaryEscaped(strm);
+ dyld_state_sp->Clear();
+ if (strm.str().size() > 0)
+ return SendPacket(strm.str());
+ }
+ return SendPacket("E88");
+}
+
// A helper function that retrieves a single integer value from
// a one-level-deep JSON dictionary of key-value pairs. e.g.
// jThreadExtendedInfo:{"plo_pthread_tsd_base_address_offset":0,"plo_pthread_tsd_base_offset":224,"plo_pthread_tsd_entry_size":8,"thread":144305}]
Index: lldb/tools/debugserver/source/MacOSX/MachProcess.mm
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachProcess.mm
+++ lldb/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -508,7 +508,6 @@
#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
#endif
-
MachProcess::MachProcess()
: m_pid(0), m_cpu_type(0), m_child_stdin(-1), m_child_stdout(-1),
m_child_stderr(-1), m_path(), m_args(), m_task(this),
@@ -516,8 +515,8 @@
m_stdio_mutex(PTHREAD_MUTEX_RECURSIVE), m_stdout_data(),
m_profile_enabled(false), m_profile_interval_usec(0), m_profile_thread(0),
m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE), m_profile_data(),
- m_profile_events(0, eMachProcessProfileCancel),
- m_thread_actions(), m_exception_messages(),
+ m_profile_events(0, eMachProcessProfileCancel), m_thread_actions(),
+ m_exception_messages(),
m_exception_messages_mutex(PTHREAD_MUTEX_RECURSIVE), m_thread_list(),
m_activities(), m_state(eStateUnloaded),
m_state_mutex(PTHREAD_MUTEX_RECURSIVE), m_events(0, kAllEventsMask),
@@ -528,7 +527,8 @@
m_dyld_process_info_create(nullptr),
m_dyld_process_info_for_each_image(nullptr),
m_dyld_process_info_release(nullptr),
- m_dyld_process_info_get_cache(nullptr) {
+ m_dyld_process_info_get_cache(nullptr),
+ m_dyld_process_info_get_state(nullptr) {
m_dyld_process_info_create =
(void *(*)(task_t task, uint64_t timestamp, kern_return_t * kernelError))
dlsym(RTLD_DEFAULT, "_dyld_process_info_create");
@@ -542,6 +542,8 @@
RTLD_DEFAULT, "_dyld_process_info_get_cache");
m_dyld_process_info_get_platform = (uint32_t (*)(void *info))dlsym(
RTLD_DEFAULT, "_dyld_process_info_get_platform");
+ m_dyld_process_info_get_state = (void (*)(void *info, void *stateInfo))dlsym(
+ RTLD_DEFAULT, "_dyld_process_info_get_state");
DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__);
}
@@ -2430,6 +2432,84 @@
return m_task.GetDYLDAllImageInfosAddress(err);
}
+/// From dyld SPI header dyld_process_info.h
+struct dyld_process_state_info {
+ uint64_t timestamp;
+ uint32_t imageCount;
+ uint32_t initialImageCount;
+ // one of dyld_process_state_* values
+ uint8_t dyldState;
+};
+enum {
+ dyld_process_state_not_started = 0x00,
+ dyld_process_state_dyld_initialized = 0x10,
+ dyld_process_state_terminated_before_inits = 0x20,
+ dyld_process_state_libSystem_initialized = 0x30,
+ dyld_process_state_running_initializers = 0x40,
+ dyld_process_state_program_running = 0x50,
+ dyld_process_state_dyld_terminated = 0x60
+};
+
+JSONGenerator::ObjectSP MachProcess::GetDyldProcessState() {
+ JSONGenerator::DictionarySP reply_sp(new JSONGenerator::Dictionary());
+ if (!m_dyld_process_info_get_state) {
+ reply_sp->AddStringItem("error",
+ "_dyld_process_info_get_state unavailable");
+ return reply_sp;
+ }
+ if (!m_dyld_process_info_create) {
+ reply_sp->AddStringItem("error", "_dyld_process_info_create unavailable");
+ return reply_sp;
+ }
+
+ kern_return_t kern_ret;
+ dyld_process_info info =
+ m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret);
+ if (!info || kern_ret != KERN_SUCCESS) {
+ reply_sp->AddStringItem(
+ "error", "Unable to create dyld_process_info for inferior task");
+ return reply_sp;
+ }
+
+ struct dyld_process_state_info state_info;
+ m_dyld_process_info_get_state(info, &state_info);
+ reply_sp->AddIntegerItem("process_state_value", state_info.dyldState);
+ switch (state_info.dyldState) {
+ case dyld_process_state_not_started:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_not_started");
+ break;
+ case dyld_process_state_dyld_initialized:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_dyld_initialized");
+ break;
+ case dyld_process_state_terminated_before_inits:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_terminated_before_inits");
+ break;
+ case dyld_process_state_libSystem_initialized:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_libSystem_initialized");
+ break;
+ case dyld_process_state_running_initializers:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_running_initializers");
+ break;
+ case dyld_process_state_program_running:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_program_running");
+ break;
+ case dyld_process_state_dyld_terminated:
+ reply_sp->AddStringItem("process_state string",
+ "dyld_process_state_dyld_terminated");
+ break;
+ };
+
+ m_dyld_process_info_release(info);
+
+ return reply_sp;
+}
+
size_t MachProcess::GetAvailableSTDERR(char *buf, size_t buf_size) { return 0; }
void *MachProcess::STDIOThread(void *arg) {
Index: lldb/tools/debugserver/source/MacOSX/MachProcess.h
===================================================================
--- lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -362,6 +362,8 @@
DNBProfileDataScanType GetProfileScanType() { return m_profile_scan_type; }
+ JSONGenerator::ObjectSP GetDyldProcessState();
+
private:
enum {
eMachProcessFlagsNone = 0,
@@ -468,6 +470,7 @@
void (*m_dyld_process_info_release)(void *info);
void (*m_dyld_process_info_get_cache)(void *info, void *cacheInfo);
uint32_t (*m_dyld_process_info_get_platform)(void *info);
+ void (*m_dyld_process_info_get_state)(void *info, void *stateInfo);
};
#endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_MACHPROCESS_H
Index: lldb/tools/debugserver/source/DNB.h
===================================================================
--- lldb/tools/debugserver/source/DNB.h
+++ lldb/tools/debugserver/source/DNB.h
@@ -157,6 +157,7 @@
nub_size_t DNBProcessGetStopCount(nub_process_t pid) DNB_EXPORT;
uint32_t DNBProcessGetCPUType(nub_process_t pid) DNB_EXPORT;
size_t DNBGetAllInfos(std::vector<struct kinfo_proc> &proc_infos);
+JSONGenerator::ObjectSP DNBGetDyldProcessState(nub_process_t pid);
// Process executable and arguments
const char *DNBProcessGetExecutablePath(nub_process_t pid);
Index: lldb/tools/debugserver/source/DNB.cpp
===================================================================
--- lldb/tools/debugserver/source/DNB.cpp
+++ lldb/tools/debugserver/source/DNB.cpp
@@ -599,6 +599,14 @@
return proc_infos.size();
}
+JSONGenerator::ObjectSP DNBGetDyldProcessState(nub_process_t pid) {
+ MachProcessSP procSP;
+ if (GetProcessSP(pid, procSP)) {
+ return procSP->GetDyldProcessState();
+ }
+ return {};
+}
+
static size_t
GetAllInfosMatchingName(const char *full_process_name,
std::vector<struct kinfo_proc> &matching_proc_infos) {
Index: lldb/test/API/macosx/early-process-launch/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/early-process-launch/main.c
@@ -0,0 +1,2 @@
+int global = 10;
+int main() { return global; }
Index: lldb/test/API/macosx/early-process-launch/TestEarlyProcessLaunch.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/early-process-launch/TestEarlyProcessLaunch.py
@@ -0,0 +1,57 @@
+"""Test that we don't read objc class tables early in process startup."""
+
+
+import time
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestEarlyProcessLaunch(TestBase):
+
+ NO_DEBUG_INFO_TESTCASE = True
+
+ @skipUnlessDarwin
+ @add_test_categories(['pyapi'])
+ def test_early_process_launch(self):
+ """Test that we don't read objc class tables early in proc startup"""
+ self.build()
+
+ ###
+ ### Hit a breakpoint on the first malloc() call, which
+ ### is before libSystem has finished initializing. At
+ ### this point, we should not read the objc class tables.
+ ### Then continue to main(), which is past libSystem
+ ### initializing. Try again, and they should be read.
+ ###
+ ### Use the types logging to detect the difference.
+
+ target, process, _, bkpt = lldbutil.run_to_name_breakpoint(
+ self, 'malloc')
+
+ target.DisableAllBreakpoints()
+ target.BreakpointCreateByName("main")
+
+ logfile_early = os.path.join(self.getBuildDir(), "types-log-early.txt")
+ self.addTearDownHook(lambda: self.runCmd("log disable lldb types"))
+ self.runCmd("log enable -f %s lldb types" % logfile_early)
+ self.runCmd("p global = 15")
+
+ err = process.Continue()
+ self.assertTrue(err.Success())
+
+ logfile_later = os.path.join(self.getBuildDir(), "types-log-later.txt")
+ self.runCmd("log enable -f %s lldb types" % logfile_later)
+ self.runCmd("p global = 25")
+
+ self.assertTrue(os.path.exists(logfile_early))
+ self.assertTrue(os.path.exists(logfile_later))
+ early_text = open(logfile_early).read()
+ later_text = open(logfile_later).read()
+
+ self.assertIn("ran: no, retry: yes", early_text)
+ self.assertNotIn("ran: no, retry: yes", later_text)
+
+ self.assertNotIn("ran: yes, retry: no", early_text)
+ self.assertIn("ran: yes, retry: no", later_text)
Index: lldb/test/API/macosx/early-process-launch/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/early-process-launch/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/source/Target/Thread.cpp
===================================================================
--- lldb/source/Target/Thread.cpp
+++ lldb/source/Target/Thread.cpp
@@ -1663,6 +1663,10 @@
bool Thread::SafeToCallFunctions() {
Process *process = GetProcess().get();
if (process) {
+ DynamicLoader *loader = GetProcess()->GetDynamicLoader();
+ if (loader && loader->IsFullyInitialized() == false)
+ return false;
+
SystemRuntime *runtime = process->GetSystemRuntime();
if (runtime) {
return runtime->SafeToCallFunctionsOnThisThread(shared_from_this());
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -222,6 +222,8 @@
StructuredData::ObjectSP GetSharedCacheInfo() override;
+ StructuredData::ObjectSP GetDynamicLoaderProcessState() override;
+
std::string HarmonizeThreadIdsForProfileData(
StringExtractorGDBRemote &inputStringExtractor);
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -3829,6 +3829,29 @@
return object_sp;
}
+StructuredData::ObjectSP ProcessGDBRemote::GetDynamicLoaderProcessState() {
+ StructuredData::ObjectSP object_sp;
+ StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
+
+ if (m_gdb_comm.GetDynamicLoaderProcessStateSupported()) {
+ StringExtractorGDBRemote response;
+ response.SetResponseValidatorToJSON();
+ if (m_gdb_comm.SendPacketAndWaitForResponse("jGetDyldProcessState",
+ response) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ StringExtractorGDBRemote::ResponseType response_type =
+ response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse) {
+ if (!response.Empty()) {
+ object_sp =
+ StructuredData::ParseJSON(std::string(response.GetStringRef()));
+ }
+ }
+ }
+ }
+ return object_sp;
+}
+
StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() {
StructuredData::ObjectSP object_sp;
StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -429,6 +429,8 @@
bool GetSharedCacheInfoSupported();
+ bool GetDynamicLoaderProcessStateSupported();
+
bool GetMemoryTaggingSupported();
bool UsesNativeSignals();
@@ -553,6 +555,7 @@
LazyBool m_supports_jThreadExtendedInfo = eLazyBoolCalculate;
LazyBool m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolCalculate;
LazyBool m_supports_jGetSharedCacheInfo = eLazyBoolCalculate;
+ LazyBool m_supports_jGetDyldProcessState = eLazyBoolCalculate;
LazyBool m_supports_QPassSignals = eLazyBoolCalculate;
LazyBool m_supports_error_string_reply = eLazyBoolCalculate;
LazyBool m_supports_multiprocess = eLazyBoolCalculate;
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -613,6 +613,19 @@
return m_supports_jGetSharedCacheInfo;
}
+bool GDBRemoteCommunicationClient::GetDynamicLoaderProcessStateSupported() {
+ if (m_supports_jGetDyldProcessState == eLazyBoolCalculate) {
+ StringExtractorGDBRemote response;
+ m_supports_jGetDyldProcessState = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("jGetDyldProcessState", response) ==
+ PacketResult::Success) {
+ if (!response.IsUnsupportedResponse())
+ m_supports_jGetDyldProcessState = eLazyBoolYes;
+ }
+ }
+ return m_supports_jGetDyldProcessState;
+}
+
bool GDBRemoteCommunicationClient::GetMemoryTaggingSupported() {
if (m_supports_memory_tagging == eLazyBoolCalculate) {
GetRemoteQSupported();
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -286,18 +286,24 @@
struct DescriptorMapUpdateResult {
bool m_update_ran;
+ bool m_retry_update;
uint32_t m_num_found;
- DescriptorMapUpdateResult(bool ran, uint32_t found) {
+ DescriptorMapUpdateResult(bool ran, bool retry, uint32_t found) {
m_update_ran = ran;
+
+ m_retry_update = retry;
+
m_num_found = found;
}
- static DescriptorMapUpdateResult Fail() { return {false, 0}; }
+ static DescriptorMapUpdateResult Fail() { return {false, false, 0}; }
static DescriptorMapUpdateResult Success(uint32_t found) {
- return {true, found};
+ return {true, false, found};
}
+
+ static DescriptorMapUpdateResult Retry() { return {false, true, 0}; }
};
/// Abstraction to read the Objective-C class info.
@@ -395,6 +401,7 @@
uint32_t num_class_infos);
enum class SharedCacheWarningReason {
+ eExpressionUnableToRun,
eExpressionExecutionFailure,
eNotEnoughClassesRead
};
Index: lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
===================================================================
--- lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -1875,6 +1875,9 @@
if (!thread_sp)
return DescriptorMapUpdateResult::Fail();
+ if (!thread_sp->SafeToCallFunctions())
+ return DescriptorMapUpdateResult::Retry();
+
thread_sp->CalculateExecutionContext(exe_ctx);
TypeSystemClang *ast =
ScratchTypeSystemClang::GetForTarget(process->GetTarget());
@@ -2042,7 +2045,7 @@
}
}
- return DescriptorMapUpdateResult(success, num_class_infos);
+ return DescriptorMapUpdateResult(success, false, num_class_infos);
}
uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data,
@@ -2137,6 +2140,9 @@
if (!thread_sp)
return DescriptorMapUpdateResult::Fail();
+ if (!thread_sp->SafeToCallFunctions())
+ return DescriptorMapUpdateResult::Retry();
+
thread_sp->CalculateExecutionContext(exe_ctx);
TypeSystemClang *ast =
ScratchTypeSystemClang::GetForTarget(process->GetTarget());
@@ -2314,7 +2320,7 @@
// Deallocate the memory we allocated for the ClassInfo array
process->DeallocateMemory(class_infos_addr);
- return DescriptorMapUpdateResult(success, num_class_infos);
+ return DescriptorMapUpdateResult(success, false, num_class_infos);
}
lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {
@@ -2414,18 +2420,23 @@
LLDB_LOGF(log,
"attempted to read objc class data - results: "
- "[dynamic_update]: ran: %s, count: %" PRIu32
- " [shared_cache_update]: ran: %s, count: %" PRIu32,
+ "[dynamic_update]: ran: %s, retry: %s, count: %" PRIu32
+ " [shared_cache_update]: ran: %s, retry: %s, count: %" PRIu32,
dynamic_update_result.m_update_ran ? "yes" : "no",
+ dynamic_update_result.m_retry_update ? "yes" : "no",
dynamic_update_result.m_num_found,
shared_cache_update_result.m_update_ran ? "yes" : "no",
+ shared_cache_update_result.m_retry_update ? "yes" : "no",
shared_cache_update_result.m_num_found);
// warn if:
// - we could not run either expression
// - we found fewer than num_classes_to_warn_at classes total
- if ((!shared_cache_update_result.m_update_ran) ||
- (!dynamic_update_result.m_update_ran))
+ if (dynamic_update_result.m_retry_update ||
+ shared_cache_update_result.m_retry_update)
+ WarnIfNoClassesCached(SharedCacheWarningReason::eExpressionUnableToRun);
+ else if ((!shared_cache_update_result.m_update_ran) ||
+ (!dynamic_update_result.m_update_ran))
WarnIfNoClassesCached(
SharedCacheWarningReason::eExpressionExecutionFailure);
else if (dynamic_update_result.m_num_found +
@@ -2504,6 +2515,12 @@
"reduce the quality of type information available.\n",
debugger.GetID(), &m_no_classes_cached_warning);
break;
+ case SharedCacheWarningReason::eExpressionUnableToRun:
+ Debugger::ReportWarning(
+ "could not execute support code to read Objective-C class data because "
+ "it's not yet safe to do so, and will be retried later.\n",
+ debugger.GetID(), nullptr);
+ break;
}
}
Index: lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
===================================================================
--- lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
+++ lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
@@ -79,6 +79,8 @@
void DoClear() override;
+ bool IsFullyInitialized() override;
+
static bool
NotifyBreakpointHit(void *baton,
lldb_private::StoppointCallbackContext *context,
@@ -106,6 +108,7 @@
// exec's when talking to
// debugservers that don't support
// the "reason:exec" annotation.
+ bool m_libsystem_fully_initalized;
};
#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOS_H
Index: lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
===================================================================
--- lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
+++ lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
@@ -79,7 +79,8 @@
: DynamicLoaderDarwin(process), m_image_infos_stop_id(UINT32_MAX),
m_break_id(LLDB_INVALID_BREAK_ID),
m_dyld_handover_break_id(LLDB_INVALID_BREAK_ID), m_mutex(),
- m_maybe_image_infos_address(LLDB_INVALID_ADDRESS) {}
+ m_maybe_image_infos_address(LLDB_INVALID_ADDRESS),
+ m_libsystem_fully_initalized(false) {}
// Destructor
DynamicLoaderMacOS::~DynamicLoaderMacOS() {
@@ -129,6 +130,7 @@
if (did_exec) {
m_libpthread_module_wp.reset();
m_pthread_getspecific_addr.Clear();
+ m_libsystem_fully_initalized = false;
}
return did_exec;
}
@@ -144,6 +146,33 @@
m_break_id = LLDB_INVALID_BREAK_ID;
m_dyld_handover_break_id = LLDB_INVALID_BREAK_ID;
+ m_libsystem_fully_initalized = false;
+}
+
+bool DynamicLoaderMacOS::IsFullyInitialized() {
+ if (m_libsystem_fully_initalized)
+ return true;
+
+ StructuredData::ObjectSP process_state_sp(
+ m_process->GetDynamicLoaderProcessState());
+ if (!process_state_sp)
+ return true;
+ if (process_state_sp->GetAsDictionary()->HasKey("error"))
+ return true;
+ if (!process_state_sp->GetAsDictionary()->HasKey("process_state string"))
+ return true;
+ std::string proc_state = process_state_sp->GetAsDictionary()
+ ->GetValueForKey("process_state string")
+ ->GetAsString()
+ ->GetValue()
+ .str();
+ if (proc_state == "dyld_process_state_not_started" ||
+ proc_state == "dyld_process_state_dyld_initialized" ||
+ proc_state == "dyld_process_state_terminated_before_inits") {
+ return false;
+ }
+ m_libsystem_fully_initalized = true;
+ return true;
}
// Check if we have found DYLD yet
Index: lldb/include/lldb/Target/Process.h
===================================================================
--- lldb/include/lldb/Target/Process.h
+++ lldb/include/lldb/Target/Process.h
@@ -1321,6 +1321,15 @@
return StructuredData::ObjectSP();
}
+ // Get information about the launch state of the process, if possible.
+ //
+ // On Darwin systems, libdyld can report on process state, most importantly
+ // the startup stages where the system library is not yet initialized.
+ virtual lldb_private::StructuredData::ObjectSP
+ GetDynamicLoaderProcessState() {
+ return {};
+ }
+
/// Print a user-visible warning about a module being built with
/// optimization
///
Index: lldb/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/docs/lldb-gdb-remote.txt
+++ lldb/docs/lldb-gdb-remote.txt
@@ -2153,3 +2153,21 @@
The data in this packet is a single a character, which should be '0' if the
inferior process should be killed, or '1' if the server should remove all
breakpoints and detach from the inferior.
+
+//----------------------------------------------------------------------
+// "jGetDyldProcessState"
+//
+// BRIEF
+// This packet fetches the process launch state, as reported by libdyld on
+// Darwin systems, most importantly to indicate when the system libraries
+// have initialized sufficiently to safely call utility functions.
+//
+//
+// LLDB SENDS: jGetDyldProcessState
+// STUB REPLIES: {"process_state_value":48,"process_state string":"dyld_process_state_libSystem_initialized"}
+//
+// PRIORITY TO IMPLEMENT
+// Low. This packet is needed to prevent lldb's utility functions for
+// scanning the Objective-C class list from running very early in
+// process startup.
+//----------------------------------------------------------------------
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits