@@ -175,19 +175,13 @@ static VALUE _native_stop(DDTRACE_UNUSED VALUE _self) {
175175 return Qtrue ;
176176}
177177
178- // Ruby runtime stack callback implementation
179- // This function will be called by libdatadog during crash handling
178+
180179static void ruby_runtime_stack_callback (
181180 void (* emit_frame )(const ddog_crasht_RuntimeStackFrame * ),
182181 void (* emit_stacktrace_string )(const char * )
183182) {
184- // Only using emit_frame - ignore emit_stacktrace_string parameter
185183 (void )emit_stacktrace_string ;
186184
187- // Try to safely walk Ruby stack using direct VM structure access
188- // Avoid Ruby API calls that might hang in crash context
189-
190- // First emit a marker frame to show callback is working
191185 ddog_crasht_RuntimeStackFrame marker_frame = {
192186 .function_name = "ruby_stack_walker_start" ,
193187 .file_name = "crashtracker.c" ,
@@ -196,7 +190,6 @@ static void ruby_runtime_stack_callback(
196190 };
197191 emit_frame (& marker_frame );
198192
199- // Try to get current thread and execution context safely
200193 VALUE current_thread = rb_thread_current ();
201194 if (current_thread == Qnil ) return ;
202195
@@ -222,40 +215,43 @@ static void ruby_runtime_stack_callback(
222215
223216 if (!cfp || !end_cfp ) return ;
224217
225- // Skip dummy frames
226218 end_cfp = RUBY_VM_NEXT_CONTROL_FRAME (end_cfp );
227219 if (end_cfp <= cfp ) return ;
228220
229- // Walk stack frames with extreme caution
230221 int frame_count = 0 ;
231- const int MAX_FRAMES = 10 ; // Keep very low to minimize crash risk
222+ const int MAX_FRAMES = 15 ;
232223
233224 for (; cfp != RUBY_VM_NEXT_CONTROL_FRAME (end_cfp ) && frame_count < MAX_FRAMES ;
234225 cfp = RUBY_VM_NEXT_CONTROL_FRAME (cfp )) {
235226
236227 if (VM_FRAME_RUBYFRAME_P (cfp ) && cfp -> iseq ) {
237- // Instead of calling rb_iseq_* functions, work directly with iseq struct
238228 const rb_iseq_t * iseq = cfp -> iseq ;
239229
240- // Basic frame info without risky API calls
241- char frame_desc [64 ];
242- snprintf (frame_desc , sizeof (frame_desc ), "ruby_frame_%d" , frame_count );
230+ VALUE name = rb_iseq_base_label (iseq );
231+ const char * function_name = (name != Qnil ) ? RSTRING_PTR (name ) : "<unknown>" ;
243232
244- // Try to get basic line info safely using direct struct access
233+ VALUE filename = rb_iseq_path (iseq );
234+ const char * file_name = (filename != Qnil ) ? RSTRING_PTR (filename ) : "<unknown>" ;
235+
236+ // Calculate line number using direct struct access
245237 int line_no = 0 ;
246238 if (iseq && cfp -> pc ) {
247- // Use direct access to iseq body instead of helper functions
248239 if (iseq -> body && iseq -> body -> iseq_encoded && iseq -> body -> iseq_size > 0 ) {
249240 ptrdiff_t pc_offset = cfp -> pc - iseq -> body -> iseq_encoded ;
250241 if (pc_offset >= 0 && pc_offset < iseq -> body -> iseq_size ) {
251- line_no = frame_count + 1 ; // Use frame position as approximation
242+ // Use the Ruby VM line calculation like ddtrace_rb_profile_frames
243+ size_t pos = pc_offset ;
244+ if (pos > 0 ) {
245+ pos -- ; // Use pos-1 because PC points next instruction
246+ }
247+ line_no = rb_iseq_line_no (iseq , pos );
252248 }
253249 }
254250 }
255251
256252 ddog_crasht_RuntimeStackFrame frame = {
257- .function_name = frame_desc ,
258- .file_name = "ruby_source.rb" ,
253+ .function_name = function_name ,
254+ .file_name = file_name ,
259255 .line_number = line_no ,
260256 .column_number = 0
261257 };
@@ -264,15 +260,6 @@ static void ruby_runtime_stack_callback(
264260 frame_count ++ ;
265261 }
266262 }
267-
268- // Emit end marker
269- ddog_crasht_RuntimeStackFrame end_frame = {
270- .function_name = "ruby_stack_walker_end" ,
271- .file_name = "crashtracker.c" ,
272- .line_number = frame_count ,
273- .column_number = 0
274- };
275- emit_frame (& end_frame );
276263}
277264
278265static VALUE _native_register_runtime_stack_callback (DDTRACE_UNUSED VALUE _self , VALUE callback_type ) {
0 commit comments