33#include "zend_generators.h"
44#include <Zend/zend_API.h>
55
6+ static inline bool dd_is_dir_sep (const char c ) {
7+ #ifdef _WIN32
8+ return c == '/' || c == '\\' ;
9+ #else
10+ return c == '/' ;
11+ #endif
12+ }
13+
614void ddtrace_add_code_origin_information (ddtrace_span_data * span , int skip_frames ) {
715 zend_array * meta = ddtrace_property_array (& span -> property_meta );
816
9- zend_execute_data * execute_data = EG (current_execute_data );
1017 zend_long max_frames = get_DD_CODE_ORIGIN_MAX_USER_FRAMES ();
11- int current_frame = 0 ;
12- while ( execute_data && current_frame < max_frames ) {
18+ int current_frame = 0 , collected_frames = 0 ;
19+ for ( zend_execute_data * execute_data = EG ( current_execute_data ); execute_data && collected_frames < max_frames ; execute_data = EX ( prev_execute_data ) ) {
1320 if (UNEXPECTED (!EX (func ))) {
1421 execute_data = zend_generator_check_placeholder_frame (execute_data );
1522 }
16- if (EX (func ) && ZEND_USER_CODE (EX (func )-> type ) && EX (func )-> op_array .filename ) {
17- if (skip_frames > 0 ) {
18- -- skip_frames ;
19- } else {
20- if (current_frame == 0 ) {
21- zval type , * kind = zend_hash_str_find_deref (meta , ZEND_STRL ("span.kind" ));
22- ZVAL_STRING (& type , (kind && Z_TYPE_P (kind ) == IS_STRING ? zend_string_equals_literal (Z_STR_P (kind ), "server" ) || zend_string_equals_literal (Z_STR_P (kind ), "producer" ) : & span -> root -> span == span ) ? "entry" : "exit" );
23- if (!zend_hash_str_add (meta , ZEND_STRL ("_dd.code_origin.type" ), & type )) {
24- zend_string_release (Z_STR (type ));
25- return ; // skip if already present
26- }
27- }
28-
29- zval zv ;
30- zend_string * key ;
23+ if (!EX (func )) {
24+ continue ;
25+ }
3126
32- key = zend_strpprintf ( 0 , "_dd.code_origin.frames.%d.file" , current_frame );
33- ZVAL_STR_COPY ( & zv , EX ( func ) -> op_array . filename ) ;
34- zend_hash_update ( meta , key , & zv ) ;
35- zend_string_release ( key );
27+ if ( skip_frames > 0 ) {
28+ -- skip_frames ;
29+ continue ;
30+ }
3631
37- key = zend_strpprintf ( 0 , "_dd.code_origin.frames.%d.line" , current_frame );
38- ZVAL_LONG ( & zv , current_frame == 0 ? EX ( func ) -> op_array . line_start : EX ( opline ) -> lineno ) ;
39- zend_hash_update ( meta , key , & zv ) ;
40- zend_string_release ( key );
32+ if (! ZEND_USER_CODE ( EX ( func ) -> type ) || ! EX ( func ) -> op_array . filename ) {
33+ ++ current_frame ;
34+ continue ;
35+ }
4136
42- if ( EX ( func ) -> op_array . function_name ) {
43- key = zend_strpprintf ( 0 , "_dd.code_origin.frames.%d.method" , current_frame );
44- ZVAL_STR_COPY ( & zv , EX ( func ) -> op_array . function_name );
45- zend_hash_update ( meta , key , & zv ) ;
46- zend_string_release ( key ) ;
47- }
37+ // Heuristically exclude code outside of the git repository, essentially
38+ const char * vendor = zend_memnistr ( ZSTR_VAL ( EX ( func ) -> op_array . filename ), ZEND_STRL ( "vendor" ), ZSTR_VAL ( EX ( func ) -> op_array . filename ) + ZSTR_LEN ( EX ( func ) -> op_array . filename ) );
39+ if ( vendor && dd_is_dir_sep ( vendor [ -1 ]) && dd_is_dir_sep ( vendor [ 6 ])) {
40+ ++ current_frame ;
41+ continue ;
42+ }
4843
49- if (EX (func )-> op_array .scope ) {
50- key = zend_strpprintf (0 , "_dd.code_origin.frames.%d.type" , current_frame );
51- ZVAL_STR_COPY (& zv , EX (func )-> op_array .scope -> name );
52- zend_hash_update (meta , key , & zv );
53- zend_string_release (key );
54- }
55- ++ current_frame ;
44+ if (collected_frames == 0 ) {
45+ zval type , * kind = zend_hash_str_find_deref (meta , ZEND_STRL ("span.kind" ));
46+ ZVAL_STRING (& type , (kind && Z_TYPE_P (kind ) == IS_STRING ? zend_string_equals_literal (Z_STR_P (kind ), "server" ) || zend_string_equals_literal (Z_STR_P (kind ), "producer" ) : & span -> root -> span == span ) ? "entry" : "exit" );
47+ if (!zend_hash_str_add (meta , ZEND_STRL ("_dd.code_origin.type" ), & type )) {
48+ zend_string_release (Z_STR (type ));
49+ return ; // skip if already present
5650 }
5751 }
58- execute_data = EX (prev_execute_data );
52+
53+ zval zv ;
54+ zend_string * key ;
55+
56+ key = zend_strpprintf (0 , "_dd.code_origin.frames.%d.file" , current_frame );
57+ ZVAL_STR_COPY (& zv , EX (func )-> op_array .filename );
58+ zend_hash_update (meta , key , & zv );
59+ zend_string_release (key );
60+
61+ key = zend_strpprintf (0 , "_dd.code_origin.frames.%d.line" , current_frame );
62+ ZVAL_LONG (& zv , current_frame == 0 ? EX (func )-> op_array .line_start : EX (opline )-> lineno );
63+ zend_hash_update (meta , key , & zv );
64+ zend_string_release (key );
65+
66+ if (EX (func )-> op_array .function_name ) {
67+ key = zend_strpprintf (0 , "_dd.code_origin.frames.%d.method" , current_frame );
68+ ZVAL_STR_COPY (& zv , EX (func )-> op_array .function_name );
69+ zend_hash_update (meta , key , & zv );
70+ zend_string_release (key );
71+ }
72+
73+ if (EX (func )-> op_array .scope ) {
74+ key = zend_strpprintf (0 , "_dd.code_origin.frames.%d.type" , current_frame );
75+ ZVAL_STR_COPY (& zv , EX (func )-> op_array .scope -> name );
76+ zend_hash_update (meta , key , & zv );
77+ zend_string_release (key );
78+ }
79+
80+ ++ collected_frames ;
81+ ++ current_frame ;
5982 }
6083}
6184
62- void ddtrace_maybe_add_code_origin_information (ddtrace_span_data * span ) {
85+ void ddtrace_maybe_add_code_origin_information (ddtrace_span_data * span , int skip_frames ) {
6386 if (get_DD_CODE_ORIGIN_FOR_SPANS_ENABLED ()) {
6487 zval * type = & span -> property_type ;
6588 ZVAL_DEREF (type );
@@ -80,7 +103,7 @@ void ddtrace_maybe_add_code_origin_information(ddtrace_span_data *span) {
80103 }
81104 }
82105
83- ddtrace_add_code_origin_information (span , 0 );
106+ ddtrace_add_code_origin_information (span , skip_frames );
84107 }
85108 }
86109}
0 commit comments