No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Debugger.cpp 31KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. #include "il2cpp-config.h"
  2. #if IL2CPP_MONO_DEBUGGER
  3. #include "il2cpp-class-internals.h"
  4. #include "il2cpp-object-internals.h"
  5. #include "il2cpp-metadata.h"
  6. #include "Debugger.h"
  7. #include "os/Thread.h"
  8. #include "os/c-api/Allocator.h"
  9. #include "os/SocketBridge.h"
  10. #include "vm/Assembly.h"
  11. #include "vm/Image.h"
  12. #include "vm/MetadataCache.h"
  13. #include "vm/Method.h"
  14. #include "vm/StackTrace.h"
  15. #include "vm/Thread.h"
  16. #include "utils/Environment.h"
  17. #include "utils/dynamic_array.h"
  18. #include "utils/StringUtils.h"
  19. #include "utils/StringViewUtils.h"
  20. #include "utils/Il2CppHashMap.h"
  21. #include "utils/HashUtils.h"
  22. #include "VmStringUtils.h"
  23. #include <deque>
  24. #include <string>
  25. #include <algorithm>
  26. il2cpp::os::ThreadLocalValue s_ExecutionContexts; // Il2CppThreadUnwindState*
  27. struct MonoDebuggerRuntimeCallbacks
  28. {
  29. void(*il2cpp_debugger_save_thread_context)(Il2CppThreadUnwindState* context, int frameCountAdjust);
  30. void(*il2cpp_debugger_free_thread_context)(Il2CppThreadUnwindState* context);
  31. };
  32. struct DebuggerTransport
  33. {
  34. const char *name;
  35. void(*connect) (const char *address);
  36. int (*wait_for_attach) (void);
  37. void(*close1) (void);
  38. void(*close2) (void);
  39. int (*send) (void *buf, int len);
  40. int(*recv) (void *buf, int len);
  41. };
  42. struct MonoContext;
  43. extern "C"
  44. {
  45. void mono_debugger_agent_parse_options(const char *options);
  46. void mono_debugger_agent_init_minimal();
  47. void mono_debugger_agent_init();
  48. void mono_debugger_run_debugger_thread_func(void* arg);
  49. void debugger_agent_single_step_from_context(MonoContext *ctx, Il2CppSequencePoint* sequencePoint);
  50. void mono_debugger_il2cpp_init();
  51. void unity_debugger_agent_breakpoint(Il2CppSequencePoint* sequencePoint);
  52. void unity_debugger_agent_pausepoint();
  53. void mono_debugger_install_runtime_callbacks(MonoDebuggerRuntimeCallbacks* cbs);
  54. int32_t unity_debugger_agent_is_global_breakpoint_active(void* singleStepRequest);
  55. int32_t unity_debugger_agent_is_single_stepping();
  56. void unity_debugger_agent_handle_exception(Il2CppException *exc);
  57. int32_t il2cpp_mono_methods_match(const MethodInfo* left, const MethodInfo* right);
  58. void debugger_agent_user_break();
  59. int32_t debugger_agent_debug_log_is_enabled();
  60. void debugger_agent_debug_log(int level, Il2CppString *category, Il2CppString *message);
  61. int32_t unity_pause_point_active();
  62. void il2cpp_save_current_thread_context_func_exit();
  63. void mono_debugger_agent_register_transport(DebuggerTransport *trans);
  64. void unity_debugger_agent_thread_startup(uintptr_t tid);
  65. void unity_debugger_agent_thread_end(uintptr_t tid);
  66. void unity_debugger_agent_runtime_shutdown();
  67. static void* il2cpp_malloc(size_t size)
  68. {
  69. return IL2CPP_MALLOC(size);
  70. }
  71. static void il2cpp_mfree(void* memory)
  72. {
  73. IL2CPP_FREE(memory);
  74. }
  75. }
  76. static const Il2CppDebuggerMetadataRegistration *g_metadata;
  77. namespace il2cpp
  78. {
  79. namespace utils
  80. {
  81. typedef dynamic_array<Il2CppSequencePoint*> SequencePointList;
  82. typedef Il2CppHashMap<const MethodInfo*, SequencePointList*, il2cpp::utils::PointerHash<MethodInfo> > MethodToSequencePointsMap;
  83. typedef dynamic_array<Il2CppCatchPoint*> CatchPointList;
  84. typedef Il2CppHashMap<const MethodInfo*, CatchPointList*, il2cpp::utils::PointerHash<MethodInfo> > MethodToCatchPointsMap;
  85. typedef Il2CppHashMap<const MethodInfo*, const MethodInfo*, il2cpp::utils::PointerHash<MethodInfo> > MethodToMethodMap;
  86. typedef dynamic_array<const char*> FileNameList;
  87. typedef Il2CppHashMap<const Il2CppClass*, FileNameList, il2cpp::utils::PointerHash<Il2CppClass> > TypeSourceFileMap;
  88. struct DebuggerContext
  89. {
  90. DebuggerContext() : m_IsDebuggerAttached(false), m_IsDebuggerInitialized(false), m_Il2CppMonoLoaderLock(false), m_Il2CppMonoLoaderLockThreadId(0)
  91. {
  92. }
  93. os::Thread* m_DebuggerThread;
  94. bool m_IsDebuggerAttached;
  95. bool m_IsDebuggerInitialized;
  96. os::Mutex m_Il2CppMonoLoaderLock;
  97. uint64_t m_Il2CppMonoLoaderLockThreadId;
  98. Il2CppMonoInterpCallbacks m_InterpCallbacks;
  99. MethodToSequencePointsMap m_methodToSequencePoints;
  100. MethodToCatchPointsMap m_methodToCatchPoints;
  101. MethodToMethodMap m_uninflatedMethodToInflated;
  102. SequencePointList m_sequencePoints;
  103. TypeSourceFileMap *m_typeSourceFiles;
  104. };
  105. static std::string s_AgentOptions; // Intentionally left out from the DebuggerContext because it is accessed before we have a chance to call void Debugger::AllocateStaticData()
  106. static DebuggerContext* s_DebuggerContext = nullptr;
  107. void Debugger::AllocateStaticData()
  108. {
  109. if (s_DebuggerContext == nullptr)
  110. s_DebuggerContext = new DebuggerContext();
  111. }
  112. void Debugger::FreeStaticData()
  113. {
  114. delete s_DebuggerContext;
  115. s_DebuggerContext = nullptr;
  116. }
  117. static MethodToSequencePointsMap::const_iterator GetMethodSequencePointIterator(const MethodInfo *method);
  118. static void* FrameGetArg(Il2CppSequencePointExecutionContext* frame, int pos)
  119. {
  120. return frame->params[pos];
  121. }
  122. static void* FrameGetLocal(Il2CppSequencePointExecutionContext* frame, int pos)
  123. {
  124. return frame->locals[pos];
  125. }
  126. static void* FrameGetThis(Il2CppSequencePointExecutionContext* frame)
  127. {
  128. return *frame->thisArg;
  129. }
  130. static void InitializeInterpCallbacks()
  131. {
  132. s_DebuggerContext->m_InterpCallbacks.frame_get_arg = FrameGetArg;
  133. s_DebuggerContext->m_InterpCallbacks.frame_get_local = FrameGetLocal;
  134. s_DebuggerContext->m_InterpCallbacks.frame_get_this = FrameGetThis;
  135. }
  136. void Debugger::RegisterMetadata(const Il2CppDebuggerMetadataRegistration *data)
  137. {
  138. g_metadata = data;
  139. }
  140. #if defined(RUNTIME_IL2CPP)
  141. void breakpoint_callback(Il2CppSequencePoint* sequencePoint)
  142. {
  143. unity_debugger_agent_breakpoint(sequencePoint);
  144. }
  145. void pausepoint_callback()
  146. {
  147. unity_debugger_agent_pausepoint();
  148. }
  149. #endif
  150. static void InitializeMonoSoftDebugger(const char* options)
  151. {
  152. #if defined(RUNTIME_IL2CPP)
  153. InitializeInterpCallbacks();
  154. os::SocketBridge::WaitForInitialization();
  155. mono_debugger_il2cpp_init();
  156. mono_debugger_agent_parse_options(options);
  157. mono_debugger_agent_init();
  158. s_DebuggerContext->m_typeSourceFiles = new TypeSourceFileMap();
  159. MonoDebuggerRuntimeCallbacks cbs;
  160. cbs.il2cpp_debugger_save_thread_context = Debugger::SaveThreadContext;
  161. cbs.il2cpp_debugger_free_thread_context = Debugger::FreeThreadContext;
  162. mono_debugger_install_runtime_callbacks(&cbs);
  163. il2cpp::utils::Debugger::RegisterCallbacks(breakpoint_callback, pausepoint_callback);
  164. register_allocator(il2cpp_malloc, il2cpp_mfree);
  165. s_DebuggerContext->m_IsDebuggerInitialized = true;
  166. #else
  167. IL2CPP_ASSERT(0 && "The managed debugger is only supported for the libil2cpp runtime backend.");
  168. #endif
  169. }
  170. void Debugger::SetAgentOptions(const char* options)
  171. {
  172. s_AgentOptions = options;
  173. }
  174. void Debugger::RegisterTransport(const Il2CppDebuggerTransport* transport)
  175. {
  176. #if defined(RUNTIME_IL2CPP)
  177. DebuggerTransport mono_transport;
  178. mono_transport.name = transport->name;
  179. mono_transport.connect = transport->connect;
  180. mono_transport.wait_for_attach = transport->wait_for_attach;
  181. mono_transport.close1 = transport->close1;
  182. mono_transport.close2 = transport->close2;
  183. mono_transport.send = transport->send;
  184. mono_transport.recv = transport->recv;
  185. mono_debugger_agent_register_transport(&mono_transport);
  186. #endif
  187. }
  188. void Debugger::InitializeTypeSourceFileMap()
  189. {
  190. Il2CppClass* lastKlass = NULL;
  191. Il2CppClass *klass = NULL;
  192. FileNameList files;
  193. vm::AssemblyVector* assemblies = vm::Assembly::GetAllAssemblies();
  194. for (vm::AssemblyVector::const_iterator iter = assemblies->begin(); iter != assemblies->end(); ++iter)
  195. {
  196. const Il2CppImage* image = vm::Assembly::GetImage(*iter);
  197. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = image->codeGenModule->debuggerMetadata;
  198. if (debuggerMetadata == NULL)
  199. continue;
  200. for (int i = 0; i < debuggerMetadata->numTypeSourceFileEntries; ++i)
  201. {
  202. Il2CppTypeSourceFilePair& pair = debuggerMetadata->typeSourceFiles[i];
  203. const char *file = debuggerMetadata->sequencePointSourceFiles[pair.sourceFileIndex].file;
  204. klass = il2cpp::vm::MetadataCache::GetTypeInfoFromTypeSourcePair(image, &pair);
  205. if (klass != lastKlass && lastKlass != NULL)
  206. {
  207. s_DebuggerContext->m_typeSourceFiles->add(lastKlass, files);
  208. files.clear();
  209. }
  210. lastKlass = klass;
  211. files.push_back(file);
  212. }
  213. }
  214. if (files.size() > 0)
  215. s_DebuggerContext->m_typeSourceFiles->add(klass, files);
  216. }
  217. void Debugger::Start()
  218. {
  219. if (s_DebuggerContext->m_IsDebuggerInitialized)
  220. {
  221. vm::MetadataCache::InitializeAllMethodMetadata();
  222. InitializeTypeSourceFileMap();
  223. InitializeMethodToSequencePointMap();
  224. InitializeMethodToCatchPointMap();
  225. Debugger::StartDebuggerThread();
  226. }
  227. }
  228. static bool TryInitializeDebugger(const std::string& options)
  229. {
  230. if (StringUtils::StartsWith(STRING_TO_STRINGVIEW(options), "--debugger-agent"))
  231. {
  232. InitializeMonoSoftDebugger(options.c_str() + options.find("=") + 1);
  233. return true;
  234. }
  235. return false;
  236. }
  237. void Debugger::Init()
  238. {
  239. AllocateStaticData();
  240. bool debuggerIsInitialized = false;
  241. if (!s_AgentOptions.empty())
  242. {
  243. debuggerIsInitialized = TryInitializeDebugger(s_AgentOptions);
  244. }
  245. else
  246. {
  247. const std::vector<UTF16String>& args = Environment::GetMainArgs();
  248. for (std::vector<UTF16String>::const_iterator arg = args.begin(); arg != args.end(); ++arg)
  249. {
  250. std::string argument = StringUtils::Utf16ToUtf8(*arg);
  251. debuggerIsInitialized = TryInitializeDebugger(argument);
  252. if (debuggerIsInitialized)
  253. break;
  254. }
  255. }
  256. if (!debuggerIsInitialized)
  257. mono_debugger_agent_init_minimal();
  258. }
  259. static Debugger::OnBreakPointHitCallback s_BreakCallback;
  260. static Debugger::OnPausePointHitCallback s_PauseCallback;
  261. void Debugger::RegisterCallbacks(OnBreakPointHitCallback breakCallback, OnPausePointHitCallback pauseCallback)
  262. {
  263. s_BreakCallback = breakCallback;
  264. s_PauseCallback = pauseCallback;
  265. }
  266. void Debugger::StartDebuggerThread()
  267. {
  268. #if defined(RUNTIME_IL2CPP)
  269. // This thread is allocated here once and never deallocated.
  270. s_DebuggerContext->m_DebuggerThread = new os::Thread();
  271. s_DebuggerContext->m_DebuggerThread->Run(mono_debugger_run_debugger_thread_func, NULL);
  272. #else
  273. IL2CPP_ASSERT(0 && "The managed debugger is only supported for the libil2cpp runtime backend.");
  274. #endif
  275. }
  276. Il2CppThreadUnwindState* Debugger::GetThreadStatePointer()
  277. {
  278. if (!s_DebuggerContext->m_IsDebuggerInitialized)
  279. return NULL;
  280. Il2CppThreadUnwindState* unwindState;
  281. s_ExecutionContexts.GetValue(reinterpret_cast<void**>(&unwindState));
  282. return unwindState;
  283. }
  284. void Debugger::SaveThreadContext(Il2CppThreadUnwindState* context, int frameCountAdjust)
  285. {
  286. if (!s_DebuggerContext->m_IsDebuggerInitialized)
  287. return;
  288. IL2CPP_ASSERT(!IsDebuggerThread(os::Thread::GetCurrentThread()));
  289. }
  290. void Debugger::FreeThreadContext(Il2CppThreadUnwindState* context)
  291. {
  292. if (!s_DebuggerContext->m_IsDebuggerInitialized)
  293. return;
  294. IL2CPP_ASSERT(!IsDebuggerThread(os::Thread::GetCurrentThread()));
  295. }
  296. void Debugger::OnBreakPointHit(Il2CppSequencePoint *sequencePoint)
  297. {
  298. #if defined(RUNTIME_IL2CPP)
  299. if (IsGlobalBreakpointActive() || unity_debugger_agent_is_single_stepping())
  300. {
  301. debugger_agent_single_step_from_context(NULL, sequencePoint);
  302. }
  303. else if (s_BreakCallback)
  304. {
  305. s_BreakCallback(sequencePoint);
  306. }
  307. else
  308. IL2CPP_DEBUG_BREAK();
  309. #else
  310. IL2CPP_ASSERT(0 && "The managed debugger is only supported for the libil2cpp runtime backend.");
  311. #endif
  312. }
  313. void Debugger::OnPausePointHit()
  314. {
  315. #if defined(RUNTIME_IL2CPP)
  316. if (s_PauseCallback)
  317. s_PauseCallback();
  318. #else
  319. IL2CPP_ASSERT(0 && "The managed debugger is only supported for the libil2cpp runtime backend.");
  320. #endif
  321. }
  322. bool Debugger::IsGlobalBreakpointActive()
  323. {
  324. if (!Debugger::GetIsDebuggerAttached())
  325. return false;
  326. #if defined(RUNTIME_IL2CPP)
  327. return unity_debugger_agent_is_global_breakpoint_active(NULL);
  328. #else
  329. IL2CPP_ASSERT(0 && "The managed debugger is only supported for the libil2cpp runtime backend.");
  330. return false;
  331. #endif
  332. }
  333. bool Debugger::GetIsDebuggerAttached()
  334. {
  335. return s_DebuggerContext->m_IsDebuggerAttached;
  336. }
  337. void Debugger::SetIsDebuggerAttached(bool attached)
  338. {
  339. s_DebuggerContext->m_IsDebuggerAttached = attached;
  340. }
  341. bool Debugger::IsDebuggerThread(os::Thread* thread)
  342. {
  343. return thread == s_DebuggerContext->m_DebuggerThread;
  344. }
  345. static void InitializeUnwindState(Il2CppThreadUnwindState* unwindState, uint32_t frameCapacity)
  346. {
  347. unwindState->frameCount = 0;
  348. unwindState->frameCapacity = frameCapacity;
  349. unwindState->executionContexts = (Il2CppSequencePointExecutionContext**)calloc(frameCapacity, sizeof(Il2CppSequencePointExecutionContext*));
  350. }
  351. void Debugger::AllocateThreadLocalData()
  352. {
  353. Il2CppThreadUnwindState* unwindState;
  354. s_ExecutionContexts.GetValue(reinterpret_cast<void**>(&unwindState));
  355. if (unwindState == NULL)
  356. {
  357. unwindState = (Il2CppThreadUnwindState*)calloc(1, sizeof(Il2CppThreadUnwindState));
  358. InitializeUnwindState(unwindState, 512);
  359. s_ExecutionContexts.SetValue(unwindState);
  360. }
  361. }
  362. void Debugger::GrowFrameCapacity(Il2CppThreadUnwindState* unwindState)
  363. {
  364. // Create a new unwind state object to hold the large array of execution context pointers
  365. Il2CppThreadUnwindState newUnwindState;
  366. InitializeUnwindState(&newUnwindState, unwindState->frameCapacity * 2);
  367. // Copy the existing execution context pointers into the new one
  368. memcpy(newUnwindState.executionContexts, unwindState->executionContexts, unwindState->frameCapacity * sizeof(Il2CppSequencePointExecutionContext*));
  369. // Free the existing one
  370. free(unwindState->executionContexts);
  371. // Set the new data into the existing one, so the client can keep its object reference
  372. unwindState->frameCapacity = newUnwindState.frameCapacity;
  373. unwindState->executionContexts = newUnwindState.executionContexts;
  374. }
  375. void Debugger::FreeThreadLocalData()
  376. {
  377. if (s_DebuggerContext->m_IsDebuggerInitialized)
  378. {
  379. Il2CppThreadUnwindState* unwindState;
  380. s_ExecutionContexts.GetValue(reinterpret_cast<void**>(&unwindState));
  381. s_ExecutionContexts.SetValue(NULL);
  382. if (unwindState != NULL)
  383. {
  384. free(unwindState->executionContexts);
  385. free(unwindState);
  386. }
  387. }
  388. }
  389. Il2CppSequencePoint* Debugger::GetSequencePoint(const Il2CppImage* image, size_t id)
  390. {
  391. if (image->codeGenModule->debuggerMetadata->numSequencePoints == 0)
  392. return NULL;
  393. return &image->codeGenModule->debuggerMetadata->sequencePoints[id];
  394. }
  395. struct SeqPointIter
  396. {
  397. SequencePointList::iterator iter, end;
  398. };
  399. Il2CppSequencePoint* Debugger::GetSequencePoints(const MethodInfo* method, void** iter)
  400. {
  401. if (!iter)
  402. return NULL;
  403. SeqPointIter *pIter = NULL;
  404. if (!*iter)
  405. {
  406. MethodToSequencePointsMap::const_iterator entry = GetMethodSequencePointIterator(method);
  407. if (entry == s_DebuggerContext->m_methodToSequencePoints.end())
  408. return NULL;
  409. pIter = new SeqPointIter();
  410. *iter = pIter;
  411. pIter->iter = entry->second->begin();
  412. pIter->end = entry->second->end();
  413. return *(pIter->iter);
  414. }
  415. pIter = (SeqPointIter*)*iter;
  416. pIter->iter++;
  417. if (pIter->iter != pIter->end)
  418. {
  419. return *(pIter->iter);
  420. }
  421. else
  422. {
  423. delete pIter;
  424. *iter = NULL;
  425. }
  426. return NULL;
  427. }
  428. Il2CppSequencePoint* Debugger::GetAllSequencePoints(void* *iter)
  429. {
  430. size_t index = (size_t)(intptr_t)*iter;
  431. if (index >= s_DebuggerContext->m_sequencePoints.size())
  432. return NULL;
  433. Il2CppSequencePoint* retVal = s_DebuggerContext->m_sequencePoints[index];
  434. *iter = (void*)(intptr_t)(index + 1);
  435. return retVal;
  436. }
  437. MethodToSequencePointsMap::const_iterator GetMethodSequencePointIterator(const MethodInfo *method)
  438. {
  439. if (method->is_inflated)
  440. method = method->genericMethod->methodDefinition;
  441. MethodToSequencePointsMap::const_iterator entry = s_DebuggerContext->m_methodToSequencePoints.find(method);
  442. if (entry == s_DebuggerContext->m_methodToSequencePoints.end())
  443. {
  444. //the sequence point map doesn't have uninflated methods, need to map the incoming method to
  445. //an inflated method. il2cpp_mono_methods_match has a case for this.
  446. MethodToMethodMap::const_iterator inflated = s_DebuggerContext->m_uninflatedMethodToInflated.find(method);
  447. if (inflated != s_DebuggerContext->m_uninflatedMethodToInflated.end())
  448. {
  449. method = inflated->second;
  450. }
  451. else
  452. {
  453. for (MethodToSequencePointsMap::iterator mapIter = s_DebuggerContext->m_methodToSequencePoints.begin(); mapIter != s_DebuggerContext->m_methodToSequencePoints.end(); ++mapIter)
  454. {
  455. if (il2cpp_mono_methods_match(method, mapIter->first))
  456. {
  457. s_DebuggerContext->m_uninflatedMethodToInflated.add(method, mapIter->first);
  458. method = mapIter->first;
  459. break;
  460. }
  461. }
  462. }
  463. return s_DebuggerContext->m_methodToSequencePoints.find(method);
  464. }
  465. return entry;
  466. }
  467. Il2CppSequencePoint* Debugger::GetSequencePoint(const Il2CppImage* image, Il2CppCatchPoint* cp)
  468. {
  469. const MethodInfo *method = GetCatchPointMethod(image, cp);
  470. MethodToSequencePointsMap::const_iterator entry = GetMethodSequencePointIterator(method);
  471. if (entry == s_DebuggerContext->m_methodToSequencePoints.end())
  472. return NULL;
  473. SequencePointList::iterator iter = entry->second->begin();
  474. while (iter != entry->second->end())
  475. {
  476. if ((*iter)->ilOffset >= cp->ilOffset)
  477. return *iter;
  478. ++iter;
  479. }
  480. return NULL;
  481. }
  482. struct CatchPointIter
  483. {
  484. CatchPointList::iterator iter, end;
  485. };
  486. Il2CppCatchPoint* Debugger::GetCatchPoints(const MethodInfo* method, void** iter)
  487. {
  488. if (!iter)
  489. return NULL;
  490. CatchPointIter *pIter = NULL;
  491. if (!*iter)
  492. {
  493. MethodToCatchPointsMap::const_iterator entry = s_DebuggerContext->m_methodToCatchPoints.find(method);
  494. if (entry == s_DebuggerContext->m_methodToCatchPoints.end())
  495. return NULL;
  496. pIter = new CatchPointIter();
  497. *iter = pIter;
  498. pIter->iter = entry->second->begin();
  499. pIter->end = entry->second->end();
  500. return *(pIter->iter);
  501. }
  502. pIter = (CatchPointIter*)*iter;
  503. pIter->iter++;
  504. if (pIter->iter != pIter->end)
  505. {
  506. return *(pIter->iter);
  507. }
  508. else
  509. {
  510. delete pIter;
  511. *iter = NULL;
  512. }
  513. return NULL;
  514. }
  515. void Debugger::HandleException(Il2CppException *exc)
  516. {
  517. if (s_DebuggerContext->m_IsDebuggerInitialized)
  518. unity_debugger_agent_handle_exception(exc);
  519. }
  520. bool SequencePointOffsetLess(const Il2CppSequencePoint *s1, const Il2CppSequencePoint *s2)
  521. {
  522. return s1->ilOffset < s2->ilOffset;
  523. }
  524. bool CatchPointOffsetLess(const Il2CppCatchPoint *c1, const Il2CppCatchPoint *c2)
  525. {
  526. return c1->ilOffset < c2->ilOffset;
  527. }
  528. void Debugger::InitializeMethodToSequencePointMap()
  529. {
  530. size_t count = 0;
  531. vm::AssemblyVector* assemblies = vm::Assembly::GetAllAssemblies();
  532. for (vm::AssemblyVector::const_iterator iter = assemblies->begin(); iter != assemblies->end(); ++iter)
  533. {
  534. const Il2CppImage* image = vm::Assembly::GetImage(*iter);
  535. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = image->codeGenModule->debuggerMetadata;
  536. if (debuggerMetadata == NULL)
  537. continue;
  538. for (int i = 0; i < debuggerMetadata->numSequencePoints; ++i)
  539. {
  540. Il2CppSequencePoint& seqPoint = debuggerMetadata->sequencePoints[i];
  541. const MethodInfo *method = GetSequencePointMethod(image, &seqPoint);
  542. if (method != NULL)
  543. {
  544. IL2CPP_ASSERT(!method->is_inflated && "Only open generic methods should have sequence points");
  545. SequencePointList* list;
  546. MethodToSequencePointsMap::iterator existingList = s_DebuggerContext->m_methodToSequencePoints.find(method);
  547. if (existingList == s_DebuggerContext->m_methodToSequencePoints.end())
  548. {
  549. list = new SequencePointList();
  550. s_DebuggerContext->m_methodToSequencePoints.add(method, list);
  551. }
  552. else
  553. {
  554. list = existingList->second;
  555. }
  556. list->push_back(&seqPoint);
  557. count++;
  558. }
  559. }
  560. }
  561. s_DebuggerContext->m_sequencePoints.reserve(count);
  562. for (MethodToSequencePointsMap::iterator methods = s_DebuggerContext->m_methodToSequencePoints.begin(); methods != s_DebuggerContext->m_methodToSequencePoints.end(); ++methods)
  563. {
  564. SequencePointList *seqPoints = methods->second;
  565. std::sort(seqPoints->begin(), seqPoints->end(), SequencePointOffsetLess);
  566. s_DebuggerContext->m_sequencePoints.insert(s_DebuggerContext->m_sequencePoints.end(), seqPoints->begin(), seqPoints->end());
  567. }
  568. }
  569. void Debugger::InitializeMethodToCatchPointMap()
  570. {
  571. vm::AssemblyVector* assemblies = vm::Assembly::GetAllAssemblies();
  572. for (vm::AssemblyVector::const_iterator iter = assemblies->begin(); iter != assemblies->end(); ++iter)
  573. {
  574. const Il2CppImage* image = vm::Assembly::GetImage(*iter);
  575. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = image->codeGenModule->debuggerMetadata;
  576. if (debuggerMetadata == NULL)
  577. continue;
  578. for (int i = 0; i < debuggerMetadata->numCatchPoints; ++i)
  579. {
  580. Il2CppCatchPoint& catchPoint = debuggerMetadata->catchPoints[i];
  581. const MethodInfo *method = GetCatchPointMethod(image, &catchPoint);
  582. if (method != NULL)
  583. {
  584. CatchPointList* list;
  585. MethodToCatchPointsMap::iterator existingList = s_DebuggerContext->m_methodToCatchPoints.find(method);
  586. if (existingList == s_DebuggerContext->m_methodToCatchPoints.end())
  587. {
  588. list = new CatchPointList();
  589. s_DebuggerContext->m_methodToCatchPoints.add(method, list);
  590. }
  591. else
  592. {
  593. list = existingList->second;
  594. }
  595. list->push_back(&catchPoint);
  596. }
  597. }
  598. }
  599. for (MethodToCatchPointsMap::iterator methods = s_DebuggerContext->m_methodToCatchPoints.begin(); methods != s_DebuggerContext->m_methodToCatchPoints.end(); ++methods)
  600. {
  601. CatchPointList *catchPoints = methods->second;
  602. std::sort(catchPoints->begin(), catchPoints->end(), CatchPointOffsetLess);
  603. }
  604. }
  605. const char** Debugger::GetTypeSourceFiles(const Il2CppClass *klass, int& count)
  606. {
  607. TypeSourceFileMap::iterator it = s_DebuggerContext->m_typeSourceFiles->find(klass);
  608. if (it == s_DebuggerContext->m_typeSourceFiles->end())
  609. {
  610. count = 0;
  611. return NULL;
  612. }
  613. count = (int)it->second.size();
  614. return it->second.data();
  615. }
  616. void Debugger::UserBreak()
  617. {
  618. if (s_DebuggerContext->m_IsDebuggerAttached)
  619. debugger_agent_user_break();
  620. }
  621. bool Debugger::IsLoggingEnabled()
  622. {
  623. return debugger_agent_debug_log_is_enabled();
  624. }
  625. void Debugger::Log(int level, Il2CppString *category, Il2CppString *message)
  626. {
  627. if (s_DebuggerContext->m_IsDebuggerAttached)
  628. debugger_agent_debug_log(level, category, message);
  629. }
  630. bool Debugger::IsPausePointActive()
  631. {
  632. return unity_pause_point_active();
  633. }
  634. void Debugger::CheckPausePoint()
  635. {
  636. if (il2cpp::utils::Debugger::IsPausePointActive())
  637. il2cpp::utils::Debugger::OnPausePointHit();
  638. }
  639. const MethodInfo* Debugger::GetSequencePointMethod(const Il2CppImage* image, Il2CppSequencePoint *seqPoint)
  640. {
  641. if (seqPoint == NULL)
  642. return NULL;
  643. return il2cpp::vm::MetadataCache::GetMethodInfoFromSequencePoint(image, seqPoint);
  644. }
  645. const MethodInfo* Debugger::GetCatchPointMethod(const Il2CppImage* image, Il2CppCatchPoint *catchPoint)
  646. {
  647. if (catchPoint == NULL)
  648. return NULL;
  649. return il2cpp::vm::MetadataCache::GetMethodInfoFromCatchPoint(image, catchPoint);
  650. }
  651. const char* Debugger::GetLocalName(const MethodInfo* method, int32_t index)
  652. {
  653. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = method->klass->image->codeGenModule->debuggerMetadata;
  654. return debuggerMetadata->methodExecutionContextInfoStrings[index];
  655. }
  656. const Il2CppMethodScope* Debugger::GetLocalScope(const MethodInfo* method, int32_t index)
  657. {
  658. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = method->klass->image->codeGenModule->debuggerMetadata;
  659. return &debuggerMetadata->methodScopes[index];
  660. }
  661. void Debugger::GetMethodExecutionContextInfo(const MethodInfo* method, uint32_t* executionContextInfoCount, const Il2CppMethodExecutionContextInfo **executionContextInfo, const Il2CppMethodHeaderInfo **headerInfo, const Il2CppMethodScope **scopes)
  662. {
  663. if (il2cpp::vm::Method::IsInflated(method))
  664. method = il2cpp::vm::MetadataCache::GetGenericMethodDefinition(method);
  665. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = method->klass->image->codeGenModule->debuggerMetadata;
  666. Il2CppMethodExecutionContextInfoIndex *index = &debuggerMetadata->methodExecutionContextInfoIndexes[GetTokenRowId(method->token) - 1];
  667. if (index->count != -1)
  668. {
  669. *executionContextInfoCount = index->count;
  670. *executionContextInfo = &debuggerMetadata->methodExecutionContextInfos[index->startIndex];
  671. }
  672. else
  673. {
  674. *executionContextInfoCount = 0;
  675. *executionContextInfo = NULL;
  676. }
  677. *headerInfo = &debuggerMetadata->methodHeaderInfos[GetTokenRowId(method->token) - 1];
  678. *scopes = &debuggerMetadata->methodScopes[(*headerInfo)->startScope];
  679. }
  680. void Debugger::GetStackFrames(void* context)
  681. {
  682. il2cpp::vm::StackFrames* stackFrames = static_cast<il2cpp::vm::StackFrames*>(context);
  683. Il2CppThreadUnwindState* unwindState = GetThreadStatePointer();
  684. if (unwindState == NULL)
  685. return; // There might not be any managed code executing yet.
  686. for (uint32_t i = 0; i < unwindState->frameCount; ++i)
  687. {
  688. const MethodInfo* method = unwindState->executionContexts[i]->method;
  689. if (method != NULL)
  690. {
  691. Il2CppStackFrameInfo frameInfo = { 0 };
  692. frameInfo.method = method;
  693. if (unwindState->executionContexts[i]->currentSequencePoint != NULL)
  694. {
  695. const Il2CppDebuggerMetadataRegistration* debuggerMetadata = method->klass->image->codeGenModule->debuggerMetadata;
  696. if (debuggerMetadata != NULL)
  697. {
  698. int32_t sourceFileIndex = unwindState->executionContexts[i]->currentSequencePoint->sourceFileIndex;
  699. frameInfo.filePath = debuggerMetadata->sequencePointSourceFiles[sourceFileIndex].file;
  700. frameInfo.sourceCodeLineNumber = unwindState->executionContexts[i]->currentSequencePoint->lineStart;
  701. frameInfo.ilOffset = unwindState->executionContexts[i]->currentSequencePoint->ilOffset;
  702. }
  703. }
  704. stackFrames->push_back(frameInfo);
  705. }
  706. }
  707. }
  708. void Debugger::AcquireLoaderLock()
  709. {
  710. s_DebuggerContext->m_Il2CppMonoLoaderLock.Lock();
  711. s_DebuggerContext->m_Il2CppMonoLoaderLockThreadId = os::Thread::CurrentThreadId();
  712. }
  713. void Debugger::ReleaseLoaderLock()
  714. {
  715. s_DebuggerContext->m_Il2CppMonoLoaderLockThreadId = 0;
  716. s_DebuggerContext->m_Il2CppMonoLoaderLock.Unlock();
  717. }
  718. bool Debugger::LoaderLockIsOwnedByThisThread()
  719. {
  720. return s_DebuggerContext->m_Il2CppMonoLoaderLockThreadId == os::Thread::CurrentThreadId();
  721. }
  722. Il2CppMonoInterpCallbacks* Debugger::GetInterpCallbacks()
  723. {
  724. return &s_DebuggerContext->m_InterpCallbacks;
  725. }
  726. void Debugger::RuntimeShutdownEnd()
  727. {
  728. unity_debugger_agent_runtime_shutdown();
  729. }
  730. void Debugger::ThreadStarted(uintptr_t tid)
  731. {
  732. unity_debugger_agent_thread_startup(tid);
  733. }
  734. void Debugger::ThreadStopped(uintptr_t tid)
  735. {
  736. unity_debugger_agent_thread_end(tid);
  737. }
  738. }
  739. }
  740. #else
  741. #include "Debugger.h"
  742. #include "os/Debug.h"
  743. namespace il2cpp
  744. {
  745. namespace utils
  746. {
  747. bool Debugger::GetIsDebuggerAttached()
  748. {
  749. return os::Debug::IsDebuggerPresent();
  750. }
  751. }
  752. }
  753. #endif // IL2CPP_MONO_DEBUGGER