xref: /php-src/sapi/phpdbg/phpdbg.h (revision 6ddab74d)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Felipe Pena <felipe@php.net>                                |
14    | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
15    | Authors: Bob Weinand <bwoebi@php.net>                                |
16    +----------------------------------------------------------------------+
17 */
18 
19 #ifndef PHPDBG_H
20 #define PHPDBG_H
21 
22 #ifdef PHP_WIN32
23 # define PHPDBG_API __declspec(dllexport)
24 #elif defined(__GNUC__) && __GNUC__ >= 4
25 # define PHPDBG_API __attribute__ ((visibility("default")))
26 #else
27 # define PHPDBG_API
28 #endif
29 
30 #include <stdint.h>
31 #include <stddef.h>
32 #include "php.h"
33 #include "php_globals.h"
34 #include "php_variables.h"
35 #include "php_getopt.h"
36 #include "zend_builtin_functions.h"
37 #include "zend_extensions.h"
38 #include "zend_modules.h"
39 #include "zend_globals.h"
40 #include "zend_ini_scanner.h"
41 #include "zend_stream.h"
42 #include "zend_signal.h"
43 #if !defined(_WIN32) && !defined(ZEND_SIGNALS)
44 #	include <signal.h>
45 #elif defined(PHP_WIN32)
46 #	include "win32/signal.h"
47 #endif
48 #include "SAPI.h"
49 #include <fcntl.h>
50 #include <sys/types.h>
51 #if defined(_WIN32) && !defined(__MINGW32__)
52 #	include <windows.h>
53 #	include "config.w32.h"
54 #	undef  strcasecmp
55 #	undef  strncasecmp
56 #	define strcasecmp _stricmp
57 #	define strncasecmp _strnicmp
58 #else
59 #	include <php_config.h>
60 #endif
61 #ifndef O_BINARY
62 #	define O_BINARY 0
63 #endif
64 #include "php_main.h"
65 
66 #ifdef ZTS
67 # include "TSRM.h"
68 #endif
69 
70 #undef zend_hash_str_add
71 #ifdef PHP_WIN32
72 #define zend_hash_str_add(...) \
73 	zend_hash_str_add(__VA_ARGS__)
74 #else
75 #define zend_hash_str_add_tmp(ht, key, len, pData) \
76 	zend_hash_str_add(ht, key, len, pData)
77 #define zend_hash_str_add(...) zend_hash_str_add_tmp(__VA_ARGS__)
78 #endif
79 
80 #ifdef HAVE_PHPDBG_READLINE
81 # ifdef HAVE_LIBREADLINE
82 #	 include <readline/readline.h>
83 #	 include <readline/history.h>
84 # endif
85 # ifdef HAVE_LIBEDIT
86 #	 include <editline/readline.h>
87 # endif
88 #endif
89 
90 /* {{{ strings */
91 #define PHPDBG_NAME "phpdbg"
92 #define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
93 #define PHPDBG_ISSUES "https://github.com/php/php-src/issues"
94 #define PHPDBG_VERSION PHP_VERSION
95 #define PHPDBG_INIT_FILENAME ".phpdbginit"
96 #define PHPDBG_DEFAULT_PROMPT "prompt>"
97 /* }}} */
98 
99 #ifdef ZTS
100 # define PHPDBG_G(v) ZEND_TSRMG(phpdbg_globals_id, zend_phpdbg_globals *, v)
101 #else
102 # define PHPDBG_G(v) (phpdbg_globals.v)
103 #endif
104 
105 #include "phpdbg_sigsafe.h"
106 #include "phpdbg_out.h"
107 #include "phpdbg_lexer.h"
108 #include "phpdbg_cmd.h"
109 #include "phpdbg_utils.h"
110 #include "phpdbg_btree.h"
111 #include "phpdbg_watch.h"
112 #include "phpdbg_bp.h"
113 
114 int phpdbg_do_parse(phpdbg_param_t *stack, char *input);
115 
116 #define PHPDBG_NEXT   2
117 #define PHPDBG_UNTIL  3
118 #define PHPDBG_FINISH 4
119 #define PHPDBG_LEAVE  5
120 
121 /*
122  BEGIN: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
123 */
124 
125 /* {{{ flags */
126 #define PHPDBG_HAS_FILE_BP            (1ULL<<1)
127 #define PHPDBG_HAS_PENDING_FILE_BP    (1ULL<<2)
128 #define PHPDBG_HAS_SYM_BP             (1ULL<<3)
129 #define PHPDBG_HAS_OPLINE_BP          (1ULL<<4)
130 #define PHPDBG_HAS_METHOD_BP          (1ULL<<5)
131 #define PHPDBG_HAS_COND_BP            (1ULL<<6)
132 #define PHPDBG_HAS_OPCODE_BP          (1ULL<<7)
133 #define PHPDBG_HAS_FUNCTION_OPLINE_BP (1ULL<<8)
134 #define PHPDBG_HAS_METHOD_OPLINE_BP   (1ULL<<9)
135 #define PHPDBG_HAS_FILE_OPLINE_BP     (1ULL<<10) /* }}} */
136 
137 /*
138  END: DO NOT CHANGE DO NOT CHANGE DO NOT CHANGE
139 */
140 
141 #define PHPDBG_IN_COND_BP             (1ULL<<11)
142 #define PHPDBG_IN_EVAL                (1ULL<<12)
143 
144 #define PHPDBG_IS_STEPPING            (1ULL<<13)
145 #define PHPDBG_STEP_OPCODE            (1ULL<<14)
146 #define PHPDBG_IS_QUIET               (1ULL<<15)
147 #define PHPDBG_IS_QUITTING            (1ULL<<16)
148 #define PHPDBG_IS_COLOURED            (1ULL<<17)
149 #define PHPDBG_IS_CLEANING            (1ULL<<18)
150 #define PHPDBG_IS_RUNNING             (1ULL<<19)
151 
152 #define PHPDBG_IN_UNTIL               (1ULL<<20)
153 #define PHPDBG_IN_FINISH              (1ULL<<21)
154 #define PHPDBG_IN_LEAVE               (1ULL<<22)
155 
156 #define PHPDBG_IS_REGISTERED          (1ULL<<23)
157 #define PHPDBG_IS_STEPONEVAL          (1ULL<<24)
158 #define PHPDBG_IS_INITIALIZING        (1ULL<<25)
159 #define PHPDBG_IS_SIGNALED            (1ULL<<26)
160 #define PHPDBG_IS_INTERACTIVE         (1ULL<<27)
161 #define PHPDBG_PREVENT_INTERACTIVE    (1ULL<<28)
162 #define PHPDBG_IS_BP_ENABLED          (1ULL<<29)
163 #define PHPDBG_SHOW_REFCOUNTS         (1ULL<<30)
164 #define PHPDBG_IN_SIGNAL_HANDLER      (1ULL<<31)
165 #define PHPDBG_DISCARD_OUTPUT         (1ULL<<32)
166 #define PHPDBG_HAS_PAGINATION         (1ULL<<33)
167 
168 #define PHPDBG_SEEK_MASK              (PHPDBG_IN_UNTIL | PHPDBG_IN_FINISH | PHPDBG_IN_LEAVE)
169 #define PHPDBG_BP_RESOLVE_MASK	      (PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
170 #define PHPDBG_BP_MASK                (PHPDBG_HAS_FILE_BP | PHPDBG_HAS_SYM_BP | PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_OPLINE_BP | PHPDBG_HAS_COND_BP | PHPDBG_HAS_OPCODE_BP | PHPDBG_HAS_FUNCTION_OPLINE_BP | PHPDBG_HAS_METHOD_OPLINE_BP | PHPDBG_HAS_FILE_OPLINE_BP)
171 #define PHPDBG_IS_STOPPING            (PHPDBG_IS_QUITTING | PHPDBG_IS_CLEANING)
172 
173 #define PHPDBG_PRESERVE_FLAGS_MASK    \
174     (PHPDBG_SHOW_REFCOUNTS | \
175      PHPDBG_IS_STEPONEVAL | \
176      PHPDBG_IS_BP_ENABLED | \
177      PHPDBG_STEP_OPCODE | \
178      PHPDBG_IS_QUIET | \
179      PHPDBG_IS_COLOURED | \
180      PHPDBG_HAS_PAGINATION)
181 
182 #ifndef _WIN32
183 #	define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_COLOURED | PHPDBG_IS_BP_ENABLED | PHPDBG_HAS_PAGINATION)
184 #else
185 #	define PHPDBG_DEFAULT_FLAGS (PHPDBG_IS_QUIET | PHPDBG_IS_BP_ENABLED | PHPDBG_HAS_PAGINATION)
186 #endif /* }}} */
187 
188 /* {{{ output descriptors */
189 #define PHPDBG_STDIN 			0
190 #define PHPDBG_STDOUT			1
191 #define PHPDBG_STDERR			2
192 #define PHPDBG_IO_FDS 			3 /* }}} */
193 
194 #define phpdbg_try_access \
195 	{                                                            \
196 		ZEND_DIAGNOSTIC_IGNORED_START("-Wshadow") \
197 		JMP_BUF *__orig_bailout = PHPDBG_G(sigsegv_bailout); \
198 		JMP_BUF __bailout;                                   \
199 		ZEND_DIAGNOSTIC_IGNORED_END \
200                                                                      \
201 		PHPDBG_G(sigsegv_bailout) = &__bailout;              \
202 		if (SETJMP(__bailout) == 0) {
203 #define phpdbg_catch_access \
204 		} else {                                             \
205 			PHPDBG_G(sigsegv_bailout) = __orig_bailout;
206 #define phpdbg_end_try_access() \
207 		}                                                    \
208 			PHPDBG_G(sigsegv_bailout) = __orig_bailout;  \
209 	}
210 
211 
212 void phpdbg_register_file_handles(void);
213 
214 typedef struct _phpdbg_oplog_entry phpdbg_oplog_entry;
215 struct _phpdbg_oplog_entry {
216 	phpdbg_oplog_entry *next;
217 	zend_string *function_name;
218 	zend_class_entry *scope;
219 	zend_string *filename;
220 	zend_op *opcodes;
221 	zend_op *op;
222 };
223 
224 typedef struct _phpdbg_oplog_list phpdbg_oplog_list;
225 struct _phpdbg_oplog_list {
226 	phpdbg_oplog_list *prev;
227 	phpdbg_oplog_entry start; /* Only "next" member used. */
228 };
229 
230 
231 /* {{{ structs */
232 ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
233 	HashTable bp[PHPDBG_BREAK_TABLES];           /* break points */
234 	HashTable registered;                        /* registered */
235 	HashTable seek;                              /* seek oplines */
236 	zend_execute_data *seek_ex;                  /* call frame of oplines to seek to */
237 	zend_object *handled_exception;              /* last handled exception (prevent multiple handling of same exception) */
238 	phpdbg_frame_t frame;                        /* frame */
239 	uint32_t last_line;                          /* last executed line */
240 
241 	char *cur_command;                           /* current command */
242 	phpdbg_lexer_data lexer;                     /* lexer data */
243 	phpdbg_param_t *parser_stack;                /* param stack during lexer / parser phase */
244 
245 #ifndef _WIN32
246 	struct sigaction old_sigsegv_signal;         /* segv signal handler */
247 #endif
248 #ifdef HAVE_USERFAULTFD_WRITEFAULT
249     int watch_userfaultfd;                       /* userfaultfd(2) handler, 0 if unused */
250     pthread_t watch_userfault_thread;            /* thread for watch fault handling */
251 #endif
252 	phpdbg_btree watchpoint_tree;                /* tree with watchpoints */
253 	phpdbg_btree watch_HashTables;               /* tree with original dtors of watchpoints */
254 	HashTable watch_elements;                    /* user defined watch elements */
255 	HashTable watch_collisions;                  /* collision table to check if multiple watches share the same recursive watchpoint */
256 	HashTable watch_recreation;                  /* watch elements pending recreation of their respective watchpoints */
257 	HashTable watch_free;                        /* pointers to watch for being freed */
258 	HashTable *watchlist_mem;                    /* triggered watchpoints */
259 	HashTable *original_watchlist_mem;           /* the original allocation for watchlist_mem, used when watchlist_mem has changed temporarily */
260 	HashTable *watchlist_mem_backup;             /* triggered watchpoints backup table while iterating over it */
261 	bool watchpoint_hit;                    /* a watchpoint was hit */
262 	void (*original_free_function)(void * ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);      /* the original AG(mm_heap)->_free function */
263 	phpdbg_watch_element *watch_tmp;             /* temporary pointer for a watch element */
264 
265 	char *exec;                                  /* file to execute */
266 	size_t exec_len;                             /* size of exec */
267 	zend_op_array *ops;                 	     /* op_array */
268 	zval retval;                                 /* return value */
269 	int bp_count;                                /* breakpoint count */
270 	int vmret;                                   /* return from last opcode handler execution */
271 	bool in_execution;                      /* in execution? */
272 	bool unclean_eval;                      /* do not check for memory leaks when we needed to bail out during eval */
273 
274 	zend_op_array *(*compile_file)(zend_file_handle *file_handle, int type);
275 	zend_op_array *(*init_compile_file)(zend_file_handle *file_handle, int type);
276 	zend_op_array *(*compile_string)(zend_string *source_string, const char *filename, zend_compile_position position);
277 	HashTable file_sources;
278 
279 	zend_arena *oplog_arena;                     /* arena for storing oplog */
280 	phpdbg_oplog_list *oplog_list;               /* list of oplog starts */
281 	phpdbg_oplog_entry *oplog_cur;               /* current oplog entry */
282 
283 	struct {
284 		int fd;
285 	} io[PHPDBG_IO_FDS];                         /* io */
286 	ssize_t (*php_stdiop_write)(php_stream *, const char *, size_t);
287 	struct {
288 		bool active;
289 		int type;
290 		int fd;
291 		char *msg;
292 		int msglen;
293 	} err_buf;                                   /* error buffer */
294 	zend_ulong req_id;                           /* "request id" to keep track of commands */
295 
296 	char *prompt[2];                             /* prompt */
297 	const phpdbg_color_t *colors[PHPDBG_COLORS]; /* colors */
298 	char *buffer;                                /* buffer */
299 	bool last_was_newline;                  /* check if we don't need to output a newline upon next phpdbg_error or phpdbg_notice */
300 
301 	FILE *stdin_file;                            /* FILE pointer to stdin source file */
302 	const php_stream_wrapper *orig_url_wrap_php;
303 
304 	char input_buffer[PHPDBG_MAX_CMD];           /* stdin input buffer */
305 	int input_buflen;                            /* length of stdin input buffer */
306 	phpdbg_signal_safe_mem sigsafe_mem;          /* memory to use in async safe environment (only once!) */
307 
308 	JMP_BUF *sigsegv_bailout;                    /* bailout address for accessibility probing */
309 
310 	uint64_t flags;                              /* phpdbg flags */
311 
312 	char *sapi_name_ptr;                         /* store sapi name to free it if necessary to not leak memory */
313 	zend_ulong lines;                                  /* max number of lines to display */
314 ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */
315 
316 #endif /* PHPDBG_H */
317