@@ -46,8 +46,29 @@ ep_rt_aot_walk_managed_stack_for_thread (
4646 ep_rt_thread_handle_t thread,
4747 EventPipeStackContents *stack_contents)
4848{
49- // NativeAOT does not support getting the call stack
50- return false ;
49+ STATIC_CONTRACT_NOTHROW;
50+ EP_ASSERT (thread != NULL );
51+ EP_ASSERT (stack_contents != NULL );
52+
53+ StackFrameIterator frameIterator (thread, thread->GetTransitionFrameForSampling ());
54+
55+ while (frameIterator.IsValid ())
56+ {
57+ frameIterator.CalculateCurrentMethodState ();
58+
59+ // Get the IP.
60+ uintptr_t control_pc = (uintptr_t )frameIterator.GetControlPC ();
61+
62+ if (control_pc != 0 )
63+ {
64+ // Add the IP to the captured stack.
65+ ep_stack_contents_append (stack_contents, control_pc, NULL );
66+ }
67+
68+ frameIterator.Next ();
69+ }
70+
71+ return true ;
5172}
5273
5374bool
@@ -62,6 +83,53 @@ ep_rt_aot_sample_profiler_write_sampling_event_for_threads (
6283 ep_rt_thread_handle_t sampling_thread,
6384 EventPipeEvent *sampling_event)
6485{
86+ STATIC_CONTRACT_NOTHROW;
87+ EP_ASSERT (sampling_thread != NULL );
88+
89+ ThreadStore *thread_store = GetThreadStore ();
90+
91+ // Check to see if we can suspend managed execution.
92+ if (thread_store->GetSuspendingThread () != NULL )
93+ return ;
94+
95+ // Actually suspend managed execution.
96+ thread_store->LockThreadStore ();
97+ thread_store->SuspendAllThreads (false );
98+
99+ EventPipeStackContents stack_contents;
100+ EventPipeStackContents *current_stack_contents;
101+ current_stack_contents = ep_stack_contents_init (&stack_contents);
102+
103+ EP_ASSERT (current_stack_contents != NULL );
104+
105+ // Walk all managed threads and capture stacks.
106+ FOREACH_THREAD (target_thread)
107+ {
108+ ep_stack_contents_reset (current_stack_contents);
109+
110+ // Walk the stack and write it out as an event.
111+ if (ep_rt_aot_walk_managed_stack_for_thread (target_thread, current_stack_contents) && !ep_stack_contents_is_empty (current_stack_contents)) {
112+ // Set the payload.
113+ // TODO: We can actually detect whether we are in managed or external code but does it matter?!
114+ uint32_t payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL;
115+
116+ // Write the sample.
117+ ep_write_sample_profile_event (
118+ sampling_thread,
119+ sampling_event,
120+ target_thread,
121+ current_stack_contents,
122+ (uint8_t *)&payload_data,
123+ sizeof (payload_data));
124+ }
125+ }
126+ END_FOREACH_THREAD
127+
128+ ep_stack_contents_fini (current_stack_contents);
129+
130+ // Resume managed execution.
131+ thread_store->ResumeAllThreads (false );
132+ thread_store->UnlockThreadStore ();
65133}
66134
67135const ep_char8_t *
0 commit comments