GithubHelp home page GithubHelp logo

Comments (2)

TysonAndre avatar TysonAndre commented on July 19, 2024

This doesn't seem as straightforward as I initially thought.

  • Without patching php-src, the only oplines that will get saved are the oplines that can potentially throw/emit notices (i.e. the ones calling SAVE_OPLINE), which gives a very inaccurate profile of expensive opline.
  • There are many different types of VMs.
  • Often, the current opline will be saved in a register. Overriding the USE_OPLINE macro to save the current opline to a global variable to manually instrument the code seems like the most reliable approach.
  • Time will elapse between reads to the process's memory, so the opline won't correspond to the currently evaluated function. (EDIT: phpspy --pause-process exists and I didn't realize it)

In case anyone finds issue in the future wants to know how I implemented this, the patches I used for phpspy and php-src (8.0-dev) are below. This only targets one of many possible VM configurations (The hybrid VM + using a local variable for the opline)

diff --git a/event_fout.c b/event_fout.c
index 72650a4..124b3bd 100644
--- a/event_fout.c
+++ b/event_fout.c
@@ -45,13 +45,14 @@ int event_handler_fout(struct trace_context_s *context, int event_type) {
                 &udata->rem,
                 &len,
                 1,
-                "%d %.*s%s%.*s %.*s:%d",
+                "%d %.*s%s%.*s %.*s:%d opcode=%u",
                 frame->depth,
                 (int)frame->loc.class_len, frame->loc.class,
                 frame->loc.class_len > 0 ? "::" : "",
                 (int)frame->loc.func_len, frame->loc.func,
                 (int)frame->loc.file_len, frame->loc.file,
-                frame->loc.lineno
+                frame->loc.lineno,
+                (unsigned int)frame->loc.opcode
             ));
             try(rv, event_handler_fout_snprintf(&udata->cur, &udata->rem, &len, 0, "%c", opt_frame_delim));
             break;
diff --git a/php_structs_70.h b/php_structs_70.h
index d6848e7..23a00ba 100644
--- a/php_structs_70.h
+++ b/php_structs_70.h
@@ -70,6 +70,7 @@ struct __attribute__((__packed__)) _zend_string_70 {
 struct __attribute__((__packed__)) _zend_op_70 {
     uint8_t                 pad0[24];               /* 0        +24 */
     uint32_t                lineno;                 /* 24       +4 */
+    uint8_t                 opcode;                 /* 28       +1 */
 };
 
 struct __attribute__((__packed__)) _sapi_request_info_70 {
diff --git a/php_structs_71.h b/php_structs_71.h
index 4cbd9ca..f22e90a 100644
--- a/php_structs_71.h
+++ b/php_structs_71.h
@@ -70,6 +70,7 @@ struct __attribute__((__packed__)) _zend_string_71 {
 struct __attribute__((__packed__)) _zend_op_71 {
     uint8_t                 pad0[24];               /* 0        +24 */
     uint32_t                lineno;                 /* 24       +4 */
+    uint8_t                 opcode;                 /* 28       +1 */
 };
 
 struct __attribute__((__packed__)) _sapi_request_info_71 {
diff --git a/php_structs_72.h b/php_structs_72.h
index cb85cf5..16fda1d 100644
--- a/php_structs_72.h
+++ b/php_structs_72.h
@@ -70,6 +70,7 @@ struct __attribute__((__packed__)) _zend_string_72 {
 struct __attribute__((__packed__)) _zend_op_72 {
     uint8_t                 pad0[24];               /* 0        +24 */
     uint32_t                lineno;                 /* 24       +4 */
+    uint8_t                 opcode;                 /* 28       +1 */
 };
 
 struct __attribute__((__packed__)) _sapi_request_info_72 {
diff --git a/php_structs_73.h b/php_structs_73.h
index a4404e0..649b289 100644
--- a/php_structs_73.h
+++ b/php_structs_73.h
@@ -70,6 +70,7 @@ struct __attribute__((__packed__)) _zend_string_73 {
 struct __attribute__((__packed__)) _zend_op_73 {
     uint8_t                 pad0[24];               /* 0        +24 */
     uint32_t                lineno;                 /* 24       +4 */
+    uint8_t                 opcode;                 /* 28       +1 */
 };
 
 struct __attribute__((__packed__)) _sapi_request_info_73 {
diff --git a/php_structs_74.h b/php_structs_74.h
index 7629834..1feee6e 100644
--- a/php_structs_74.h
+++ b/php_structs_74.h
@@ -70,6 +70,7 @@ struct __attribute__((__packed__)) _zend_string_74 {
 struct __attribute__((__packed__)) _zend_op_74 {
     uint8_t                 pad0[24];               /* 0        +24 */
     uint32_t                lineno;                 /* 24       +4 */
+    uint8_t                 opcode;                 /* 28       +1 */
 };
 
 struct __attribute__((__packed__)) _sapi_request_info_74 {
diff --git a/phpspy.c b/phpspy.c
index bcf0f22..5e95d37 100644
--- a/phpspy.c
+++ b/phpspy.c
@@ -522,6 +522,9 @@ static int find_addresses(trace_target_t *target) {
     if (get_symbol_addr(&memo, target->pid, "basic_functions_module", &target->basic_functions_module_addr) != 0) {
         target->basic_functions_module_addr = 0;
     }
+    if (get_symbol_addr(&memo, target->pid, "instrumented_current_opcode", &target->instrumented_current_opcode_addr) != 0) {
+        target->instrumented_current_opcode_addr = 0;
+    }
 
     /* TODO probably don't need zend_string_val_offset */
     #ifdef USE_ZEND
diff --git a/phpspy.h b/phpspy.h
index 69ca13a..e000435 100644
--- a/phpspy.h
+++ b/phpspy.h
@@ -103,6 +103,7 @@ typedef struct trace_loc_s {
     size_t class_len;
     size_t file_len;
     int lineno;
+    int opcode;
 } trace_loc_t;
 
 typedef struct trace_frame_s {
@@ -141,6 +142,7 @@ typedef struct trace_target_s {
     uint64_t core_globals_addr;
     uint64_t alloc_globals_addr;
     uint64_t basic_functions_module_addr;
+    uint64_t instrumented_current_opcode_addr;
 } trace_target_t;
 
 typedef struct trace_context_s {
diff --git a/phpspy_trace.c b/phpspy_trace.c
index 1662a07..006faba 100644
--- a/phpspy_trace.c
+++ b/phpspy_trace.c
@@ -45,6 +45,27 @@ static int do_trace(trace_context_t *context) {
 
         try_copy_proc_mem("execute_data", remote_execute_data, &execute_data, sizeof(execute_data));
         try_copy_proc_mem("zfunc", execute_data.func, &zfunc, sizeof(zfunc));
+        /* XXX the opline contents will change because the process is actively running */
+        if (zfunc.type == 2) {
+            if (depth > 0) {
+                int result = copy_proc_mem(context->target.pid, "opline", execute_data.opline, &zop, sizeof(zop));
+                if (result == 0) {
+                    frame->loc.opcode = zop.opcode;
+                } else {
+                    frame->loc.opcode = 0xff;
+                }
+            } else {
+                uint8_t opcode = 0;
+                int result = copy_proc_mem(context->target.pid, "instrumented_current_opcode", (void*)target->instrumented_current_opcode_addr, &opcode, sizeof(opcode));
+                if (result == 0) {
+                    frame->loc.opcode = opcode;
+                } else {
+                    frame->loc.opcode = 0xff;
+                }
+            }
+        } else {
+            frame->loc.opcode = 0;
+        }
         if (zfunc.common.function_name) {
             try(rv, copy_zstring(context, "function_name", zfunc.common.function_name, frame->loc.func, sizeof(frame->loc.func), &frame->loc.func_len));
         } else {
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 153d8e3bc4..f0cca55239 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -4506,3 +4506,5 @@ ZEND_API zval *zend_get_zval_ptr(const zend_op *opline, int op_type, const znode
        }
        return ret;
 }
+uint8_t instrumented_current_opcode;
+
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 812a7e5bd2..1bdab61485 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -17,6 +17,7 @@
    |          Dmitry Stogov <[email protected]>                              |
    +----------------------------------------------------------------------+
 */
+extern uint8_t instrumented_current_opcode;
 
 #ifdef ZEND_WIN32
 # pragma warning(disable : 4101)
@@ -401,7 +402,7 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H
 #define DCL_OPLINE
 #ifdef ZEND_VM_IP_GLOBAL_REG
 # define OPLINE opline
-# define USE_OPLINE
+# define USE_OPLINE instrumented_current_opcode = OPLINE->opcode;
 # define LOAD_OPLINE() opline = EX(opline)
 # define LOAD_OPLINE_EX()
 # define LOAD_NEXT_OPLINE() opline = EX(opline) + 1
@@ -48060,7 +48061,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDL
 # define ZEND_VM_RETURN()        goto HYBRID_HALT_LABEL
 #endif
 
-
 #if (ZEND_VM_KIND != ZEND_VM_KIND_CALL) && (ZEND_GCC_VERSION >= 4000) && !defined(__clang__)
 # pragma GCC push_options
 # pragma GCC optimize("no-gcse")
@@ -51304,6 +51304,7 @@ ZEND_API void execute_ex(zend_execute_data *ex)
                        int ret;
 #endif
 #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
+        instrumented_current_opcode = OPLINE->opcode;
                HYBRID_SWITCH() {
 #else
 #if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)

from phpspy.

TysonAndre avatar TysonAndre commented on July 19, 2024

Feel free to reopen this if there are plans to do this.

from phpspy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.