@@ -175,28 +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 
191-   ddog_crasht_RuntimeStackFrame  marker_frame  =  {
192-     .function_name  =  "ruby_stack_walker_start" ,
193-     .file_name  =  "crashtracker.c" ,
194-     .line_number  =  1 ,
195-     .column_number  =  0 
196-   };
197-   emit_frame (& marker_frame );
198- 
199-   // Try to get current thread and execution context safely 
200185  VALUE  current_thread  =  rb_thread_current ();
201186  if  (current_thread  ==  Qnil ) return ;
202187
@@ -213,7 +198,6 @@ static void ruby_runtime_stack_callback(
213198  const  rb_execution_context_t  * ec  =  th -> ec ;
214199  if  (!ec ) return ;
215200
216-   // Safety checks 
217201  if  (th -> status  ==  THREAD_KILLED ) return ;
218202  if  (!ec -> vm_stack  ||  ec -> vm_stack_size  ==  0 ) return ;
219203
@@ -222,40 +206,47 @@ static void ruby_runtime_stack_callback(
222206
223207  if  (!cfp  ||  !end_cfp ) return ;
224208
225-   // Skip dummy frames 
226209  end_cfp  =  RUBY_VM_NEXT_CONTROL_FRAME (end_cfp );
227210  if  (end_cfp  <= cfp ) return ;
228211
229-   // Walk stack frames with extreme caution 
212+   const  rb_control_frame_t  * top_sentinel  =  RUBY_VM_NEXT_CONTROL_FRAME (cfp );
213+ 
214+   cfp  =  RUBY_VM_NEXT_CONTROL_FRAME (end_cfp );
215+ 
230216  int  frame_count  =  0 ;
231-   const  int  MAX_FRAMES  =  10 ; // Keep very low to minimize crash risk 
232217
233-   for  (; cfp  !=  RUBY_VM_NEXT_CONTROL_FRAME (end_cfp ) &&  frame_count  <  MAX_FRAMES ;
234-        cfp  =  RUBY_VM_NEXT_CONTROL_FRAME (cfp )) {
218+   for  (; cfp  !=  top_sentinel ; cfp  =  RUBY_VM_NEXT_CONTROL_FRAME (cfp )) {
219+     if  (cfp -> iseq  &&  !cfp -> pc ) {
220+       continue ;
221+     }
235222
236223    if  (VM_FRAME_RUBYFRAME_P (cfp ) &&  cfp -> iseq ) {
237-       // Instead of calling rb_iseq_* functions, work directly with iseq struct 
238224      const  rb_iseq_t  * iseq  =  cfp -> iseq ;
239225
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 );
226+       VALUE  name  =  rb_iseq_base_label (iseq );
227+       const  char  * function_name  =  (name  !=  Qnil ) ? RSTRING_PTR (name ) : "<unknown>" ;
228+ 
229+       VALUE  filename  =  rb_iseq_path (iseq );
230+       const  char  * file_name  =  (filename  !=  Qnil ) ? RSTRING_PTR (filename ) : "<unknown>" ;
243231
244-       // Try to get basic line info safely using direct struct access 
245232      int  line_no  =  0 ;
246233      if  (iseq  &&  cfp -> pc ) {
247-         // Use direct access to iseq body instead of helper functions 
248234        if  (iseq -> body  &&  iseq -> body -> iseq_encoded  &&  iseq -> body -> iseq_size  >  0 ) {
249235          ptrdiff_t  pc_offset  =  cfp -> pc  -  iseq -> body -> iseq_encoded ;
250236          if  (pc_offset  >= 0  &&  pc_offset  <  iseq -> body -> iseq_size ) {
251-             line_no  =  frame_count  +  1 ; // Use frame position as approximation 
237+             // Use the Ruby VM line calculation like ddtrace_rb_profile_frames 
238+             size_t  pos  =  pc_offset ;
239+             if  (pos  >  0 ) {
240+               pos -- ; // Use pos-1 because PC points next instruction 
241+             }
242+             line_no  =  rb_iseq_line_no (iseq , pos );
252243          }
253244        }
254245      }
255246
256247      ddog_crasht_RuntimeStackFrame  frame  =  {
257-         .function_name  =  frame_desc ,
258-         .file_name  =  "ruby_source.rb" ,
248+         .function_name  =  function_name ,
249+         .file_name  =  file_name ,
259250        .line_number  =  line_no ,
260251        .column_number  =  0 
261252      };
@@ -264,21 +255,11 @@ static void ruby_runtime_stack_callback(
264255      frame_count ++ ;
265256    }
266257  }
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 );
276258}
277259
278260static  VALUE  _native_register_runtime_stack_callback (DDTRACE_UNUSED  VALUE  _self , VALUE  callback_type ) {
279261  ENFORCE_TYPE (callback_type , T_SYMBOL );
280262
281-   // Verify we're using the frame type (should always be :frame) 
282263  VALUE  frame_symbol  =  ID2SYM (rb_intern ("frame" ));
283264  if  (callback_type  !=  frame_symbol ) {
284265    rb_raise (rb_eArgError , "Invalid callback_type. Only :frame is supported" );
0 commit comments