phpdbg.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Felipe Pena <felipe@php.net> |
  16. | Authors: Joe Watkins <joe.watkins@live.co.uk> |
  17. | Authors: Bob Weinand <bwoebi@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. #if !defined(ZEND_SIGNALS) || defined(_WIN32)
  21. # include <signal.h>
  22. #endif
  23. #include "phpdbg.h"
  24. #include "phpdbg_prompt.h"
  25. #include "phpdbg_bp.h"
  26. #include "phpdbg_break.h"
  27. #include "phpdbg_list.h"
  28. #include "phpdbg_utils.h"
  29. #include "phpdbg_set.h"
  30. #include "zend_alloc.h"
  31. /* {{{ remote console headers */
  32. #ifndef _WIN32
  33. # include <sys/socket.h>
  34. # include <sys/select.h>
  35. # include <sys/time.h>
  36. # include <sys/types.h>
  37. # include <netinet/in.h>
  38. # include <unistd.h>
  39. # include <arpa/inet.h>
  40. #endif /* }}} */
  41. #if defined(PHP_WIN32) && defined(HAVE_OPENSSL)
  42. # include "openssl/applink.c"
  43. #endif
  44. ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
  45. static zend_bool phpdbg_booted = 0;
  46. #if PHP_VERSION_ID >= 50500
  47. void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC);
  48. #else
  49. void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC);
  50. #endif
  51. static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
  52. {
  53. pg->prompt[0] = NULL;
  54. pg->prompt[1] = NULL;
  55. pg->colors[0] = NULL;
  56. pg->colors[1] = NULL;
  57. pg->colors[2] = NULL;
  58. pg->exec = NULL;
  59. pg->exec_len = 0;
  60. pg->buffer = NULL;
  61. pg->ops = NULL;
  62. pg->vmret = 0;
  63. pg->bp_count = 0;
  64. pg->flags = PHPDBG_DEFAULT_FLAGS;
  65. pg->oplog = NULL;
  66. pg->io[PHPDBG_STDIN] = NULL;
  67. pg->io[PHPDBG_STDOUT] = NULL;
  68. pg->io[PHPDBG_STDERR] = NULL;
  69. pg->frame.num = 0;
  70. } /* }}} */
  71. static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
  72. {
  73. ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
  74. #if PHP_VERSION_ID >= 50500
  75. zend_execute_old = zend_execute_ex;
  76. zend_execute_ex = phpdbg_execute_ex;
  77. #else
  78. zend_execute_old = zend_execute;
  79. zend_execute = phpdbg_execute_ex;
  80. #endif
  81. REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
  82. REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT);
  83. REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
  84. REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
  85. REGISTER_LONG_CONSTANT("PHPDBG_FUNC", STR_PARAM, CONST_CS|CONST_PERSISTENT);
  86. REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT);
  87. REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT);
  88. REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR", PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT);
  89. return SUCCESS;
  90. } /* }}} */
  91. static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */
  92. {
  93. zend_hash_destroy((HashTable*)brake);
  94. } /* }}} */
  95. static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */
  96. {
  97. efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol);
  98. } /* }}} */
  99. static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */
  100. {
  101. efree((char*)((phpdbg_breakop_t*)brake)->name);
  102. } /* }}} */
  103. static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */
  104. {
  105. zend_hash_destroy((HashTable*)brake);
  106. } /* }}} */
  107. static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */
  108. {
  109. phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data;
  110. if (brake) {
  111. if (brake->ops) {
  112. TSRMLS_FETCH();
  113. destroy_op_array(
  114. brake->ops TSRMLS_CC);
  115. efree(brake->ops);
  116. }
  117. efree((char*)brake->code);
  118. }
  119. } /* }}} */
  120. static void php_phpdbg_destroy_registered(void *data) /* {{{ */
  121. {
  122. zend_function *function = (zend_function*) data;
  123. TSRMLS_FETCH();
  124. destroy_zend_function(
  125. function TSRMLS_CC);
  126. } /* }}} */
  127. static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
  128. {
  129. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
  130. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
  131. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
  132. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
  133. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
  134. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
  135. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
  136. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
  137. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
  138. zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
  139. zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
  140. zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
  141. return SUCCESS;
  142. } /* }}} */
  143. static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
  144. {
  145. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
  146. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
  147. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
  148. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
  149. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
  150. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
  151. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
  152. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
  153. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
  154. zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
  155. zend_hash_destroy(&PHPDBG_G(seek));
  156. zend_hash_destroy(&PHPDBG_G(registered));
  157. zend_hash_destroy(&PHPDBG_G(watchpoints));
  158. zend_llist_destroy(&PHPDBG_G(watchlist_mem));
  159. if (PHPDBG_G(buffer)) {
  160. efree(PHPDBG_G(buffer));
  161. PHPDBG_G(buffer) = NULL;
  162. }
  163. if (PHPDBG_G(exec)) {
  164. efree(PHPDBG_G(exec));
  165. PHPDBG_G(exec) = NULL;
  166. }
  167. if (PHPDBG_G(prompt)[0]) {
  168. free(PHPDBG_G(prompt)[0]);
  169. }
  170. if (PHPDBG_G(prompt)[1]) {
  171. free(PHPDBG_G(prompt)[1]);
  172. }
  173. PHPDBG_G(prompt)[0] = NULL;
  174. PHPDBG_G(prompt)[1] = NULL;
  175. if (PHPDBG_G(oplog)) {
  176. fclose(
  177. PHPDBG_G(oplog));
  178. PHPDBG_G(oplog) = NULL;
  179. }
  180. if (PHPDBG_G(ops)) {
  181. destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
  182. efree(PHPDBG_G(ops));
  183. PHPDBG_G(ops) = NULL;
  184. }
  185. return SUCCESS;
  186. } /* }}} */
  187. /* {{{ proto mixed phpdbg_exec(string context)
  188. Attempt to set the execution context for phpdbg
  189. If the execution context was set previously it is returned
  190. If the execution context was not set previously boolean true is returned
  191. If the request to set the context fails, boolean false is returned, and an E_WARNING raised */
  192. static PHP_FUNCTION(phpdbg_exec)
  193. {
  194. char *exec = NULL;
  195. int exec_len = 0;
  196. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {
  197. return;
  198. }
  199. {
  200. struct stat sb;
  201. zend_bool result = 1;
  202. if (VCWD_STAT(exec, &sb) != FAILURE) {
  203. if (sb.st_mode & (S_IFREG|S_IFLNK)) {
  204. if (PHPDBG_G(exec)) {
  205. ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1);
  206. efree(PHPDBG_G(exec));
  207. result = 0;
  208. }
  209. PHPDBG_G(exec) = estrndup(exec, exec_len);
  210. PHPDBG_G(exec_len) = exec_len;
  211. if (result)
  212. ZVAL_BOOL(return_value, 1);
  213. } else {
  214. zend_error(
  215. E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec);
  216. ZVAL_BOOL(return_value, 0);
  217. }
  218. } else {
  219. zend_error(
  220. E_WARNING, "Failed to set execution context (%s) the file does not exist", exec);
  221. ZVAL_BOOL(return_value, 0);
  222. }
  223. }
  224. } /* }}} */
  225. /* {{{ proto void phpdbg_break_next()
  226. instructs phpdbg to insert a breakpoint at the next opcode */
  227. static PHP_FUNCTION(phpdbg_break_next)
  228. {
  229. if (zend_parse_parameters_none() != SUCCESS) {
  230. return;
  231. } else if (EG(current_execute_data) && EG(active_op_array)) {
  232. zend_ulong opline_num = (EG(current_execute_data)->opline -
  233. EG(active_op_array)->opcodes);
  234. phpdbg_set_breakpoint_opline_ex(
  235. &EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC);
  236. }
  237. } /* }}} */
  238. /* {{{ proto void phpdbg_break_file(string file, integer line) */
  239. static PHP_FUNCTION(phpdbg_break_file)
  240. {
  241. char *file = NULL;
  242. int flen = 0;
  243. long line;
  244. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &file, &flen, &line) == FAILURE) {
  245. return;
  246. }
  247. phpdbg_set_breakpoint_file(file, line TSRMLS_CC);
  248. } /* }}} */
  249. /* {{{ proto void phpdbg_break_method(string class, string method) */
  250. static PHP_FUNCTION(phpdbg_break_method)
  251. {
  252. char *class = NULL,
  253. *method = NULL;
  254. int clen = 0,
  255. mlen = 0;
  256. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class, &clen, &method, &mlen) == FAILURE) {
  257. return;
  258. }
  259. phpdbg_set_breakpoint_method(class, method TSRMLS_CC);
  260. } /* }}} */
  261. /* {{{ proto void phpdbg_break_function(string function) */
  262. static PHP_FUNCTION(phpdbg_break_function)
  263. {
  264. char *function = NULL;
  265. int function_len;
  266. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &function, &function_len) == FAILURE) {
  267. return;
  268. }
  269. phpdbg_set_breakpoint_symbol(function, function_len TSRMLS_CC);
  270. } /* }}} */
  271. /* {{{ proto void phpdbg_clear(void)
  272. instructs phpdbg to clear breakpoints */
  273. static PHP_FUNCTION(phpdbg_clear)
  274. {
  275. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
  276. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
  277. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
  278. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
  279. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
  280. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
  281. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
  282. zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
  283. } /* }}} */
  284. /* {{{ proto void phpdbg_color(integer element, string color) */
  285. static PHP_FUNCTION(phpdbg_color)
  286. {
  287. long element = 0L;
  288. char *color = NULL;
  289. int color_len = 0;
  290. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {
  291. return;
  292. }
  293. switch (element) {
  294. case PHPDBG_COLOR_NOTICE:
  295. case PHPDBG_COLOR_ERROR:
  296. case PHPDBG_COLOR_PROMPT:
  297. phpdbg_set_color_ex(element, color, color_len TSRMLS_CC);
  298. break;
  299. default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant");
  300. }
  301. } /* }}} */
  302. /* {{{ proto void phpdbg_prompt(string prompt) */
  303. static PHP_FUNCTION(phpdbg_prompt)
  304. {
  305. char *prompt = NULL;
  306. int prompt_len = 0;
  307. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {
  308. return;
  309. }
  310. phpdbg_set_prompt(prompt TSRMLS_CC);
  311. } /* }}} */
  312. ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)
  313. ZEND_END_ARG_INFO()
  314. ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2)
  315. ZEND_ARG_INFO(0, file)
  316. ZEND_ARG_INFO(0, line)
  317. ZEND_END_ARG_INFO()
  318. ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2)
  319. ZEND_ARG_INFO(0, class)
  320. ZEND_ARG_INFO(0, method)
  321. ZEND_END_ARG_INFO()
  322. ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1)
  323. ZEND_ARG_INFO(0, function)
  324. ZEND_END_ARG_INFO()
  325. ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
  326. ZEND_ARG_INFO(0, element)
  327. ZEND_ARG_INFO(0, color)
  328. ZEND_END_ARG_INFO()
  329. ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0)
  330. ZEND_ARG_INFO(0, string)
  331. ZEND_END_ARG_INFO()
  332. ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0)
  333. ZEND_ARG_INFO(0, context)
  334. ZEND_END_ARG_INFO()
  335. ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
  336. ZEND_END_ARG_INFO()
  337. zend_function_entry phpdbg_user_functions[] = {
  338. PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
  339. PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo)
  340. PHP_FE(phpdbg_break_file, phpdbg_break_file_arginfo)
  341. PHP_FE(phpdbg_break_method, phpdbg_break_method_arginfo)
  342. PHP_FE(phpdbg_break_function, phpdbg_break_function_arginfo)
  343. PHP_FE(phpdbg_exec, phpdbg_exec_arginfo)
  344. PHP_FE(phpdbg_color, phpdbg_color_arginfo)
  345. PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
  346. #ifdef PHP_FE_END
  347. PHP_FE_END
  348. #else
  349. {NULL,NULL,NULL}
  350. #endif
  351. };
  352. static zend_module_entry sapi_phpdbg_module_entry = {
  353. STANDARD_MODULE_HEADER,
  354. PHPDBG_NAME,
  355. phpdbg_user_functions,
  356. PHP_MINIT(phpdbg),
  357. NULL,
  358. PHP_RINIT(phpdbg),
  359. PHP_RSHUTDOWN(phpdbg),
  360. NULL,
  361. PHPDBG_VERSION,
  362. STANDARD_MODULE_PROPERTIES
  363. };
  364. static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */
  365. {
  366. if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
  367. return FAILURE;
  368. }
  369. phpdbg_booted=1;
  370. return SUCCESS;
  371. } /* }}} */
  372. static char* php_sapi_phpdbg_read_cookies(TSRMLS_D) /* {{{ */
  373. {
  374. return NULL;
  375. } /* }}} */
  376. static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */
  377. {
  378. return 0;
  379. }
  380. /* }}} */
  381. static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */
  382. {
  383. /* We do nothing here, this function is needed to prevent that the fallback
  384. * header handling is called. */
  385. return SAPI_HEADER_SENT_SUCCESSFULLY;
  386. }
  387. /* }}} */
  388. static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */
  389. {
  390. }
  391. /* }}} */
  392. static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
  393. {
  394. /*
  395. * We must not request TSRM before being boot
  396. */
  397. if (phpdbg_booted) {
  398. phpdbg_error("%s", message);
  399. switch (PG(last_error_type)) {
  400. case E_ERROR:
  401. case E_CORE_ERROR:
  402. case E_COMPILE_ERROR:
  403. case E_USER_ERROR:
  404. case E_PARSE:
  405. case E_RECOVERABLE_ERROR:
  406. if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
  407. phpdbg_list_file(
  408. zend_get_executed_filename(TSRMLS_C),
  409. 3,
  410. zend_get_executed_lineno(TSRMLS_C)-1,
  411. zend_get_executed_lineno(TSRMLS_C)
  412. TSRMLS_CC
  413. );
  414. }
  415. do {
  416. switch (phpdbg_interactive(TSRMLS_C)) {
  417. case PHPDBG_LEAVE:
  418. case PHPDBG_FINISH:
  419. case PHPDBG_UNTIL:
  420. case PHPDBG_NEXT:
  421. return;
  422. }
  423. } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
  424. }
  425. } else fprintf(stdout, "%s\n", message);
  426. }
  427. /* }}} */
  428. static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */
  429. {
  430. fflush(stdout);
  431. if(SG(request_info).argv0) {
  432. free(SG(request_info).argv0);
  433. SG(request_info).argv0 = NULL;
  434. }
  435. return SUCCESS;
  436. }
  437. /* }}} */
  438. static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */
  439. {
  440. unsigned int len;
  441. char *docroot = "";
  442. /* In phpdbg mode, we consider the environment to be a part of the server variables
  443. */
  444. php_import_environment_variables(track_vars_array TSRMLS_CC);
  445. if (PHPDBG_G(exec)) {
  446. len = PHPDBG_G(exec_len);
  447. if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF",
  448. &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
  449. php_register_variable("PHP_SELF", PHPDBG_G(exec),
  450. track_vars_array TSRMLS_CC);
  451. }
  452. if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME",
  453. &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
  454. php_register_variable("SCRIPT_NAME", PHPDBG_G(exec),
  455. track_vars_array TSRMLS_CC);
  456. }
  457. if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME",
  458. &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
  459. php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec),
  460. track_vars_array TSRMLS_CC);
  461. }
  462. if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED",
  463. &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
  464. php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec),
  465. track_vars_array TSRMLS_CC);
  466. }
  467. }
  468. /* any old docroot will doo */
  469. len = 0U;
  470. if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT",
  471. &docroot, len, &len TSRMLS_CC)) {
  472. php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC);
  473. }
  474. }
  475. /* }}} */
  476. static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */
  477. {
  478. return phpdbg_write("%s", message);
  479. } /* }}} */
  480. #if PHP_VERSION_ID >= 50700
  481. static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */
  482. {
  483. #else
  484. static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
  485. {
  486. TSRMLS_FETCH();
  487. #endif
  488. fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
  489. } /* }}} */
  490. /* copied from sapi/cli/php_cli.c cli_register_file_handles */
  491. static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */
  492. {
  493. zval *zin, *zout, *zerr;
  494. php_stream *s_in, *s_out, *s_err;
  495. php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
  496. zend_constant ic, oc, ec;
  497. MAKE_STD_ZVAL(zin);
  498. MAKE_STD_ZVAL(zout);
  499. MAKE_STD_ZVAL(zerr);
  500. s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in);
  501. s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
  502. s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
  503. if (s_in==NULL || s_out==NULL || s_err==NULL) {
  504. FREE_ZVAL(zin);
  505. FREE_ZVAL(zout);
  506. FREE_ZVAL(zerr);
  507. if (s_in) php_stream_close(s_in);
  508. if (s_out) php_stream_close(s_out);
  509. if (s_err) php_stream_close(s_err);
  510. return;
  511. }
  512. #if PHP_DEBUG
  513. /* do not close stdout and stderr */
  514. s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
  515. s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
  516. #endif
  517. php_stream_to_zval(s_in, zin);
  518. php_stream_to_zval(s_out, zout);
  519. php_stream_to_zval(s_err, zerr);
  520. ic.value = *zin;
  521. ic.flags = CONST_CS;
  522. ic.name = zend_strndup(ZEND_STRL("STDIN"));
  523. ic.name_len = sizeof("STDIN");
  524. ic.module_number = 0;
  525. zend_register_constant(&ic TSRMLS_CC);
  526. oc.value = *zout;
  527. oc.flags = CONST_CS;
  528. oc.name = zend_strndup(ZEND_STRL("STDOUT"));
  529. oc.name_len = sizeof("STDOUT");
  530. oc.module_number = 0;
  531. zend_register_constant(&oc TSRMLS_CC);
  532. ec.value = *zerr;
  533. ec.flags = CONST_CS;
  534. ec.name = zend_strndup(ZEND_STRL("STDERR"));
  535. ec.name_len = sizeof("STDERR");
  536. ec.module_number = 0;
  537. zend_register_constant(&ec TSRMLS_CC);
  538. FREE_ZVAL(zin);
  539. FREE_ZVAL(zout);
  540. FREE_ZVAL(zerr);
  541. }
  542. /* }}} */
  543. /* {{{ sapi_module_struct phpdbg_sapi_module
  544. */
  545. static sapi_module_struct phpdbg_sapi_module = {
  546. "phpdbg", /* name */
  547. "phpdbg", /* pretty name */
  548. php_sapi_phpdbg_module_startup, /* startup */
  549. php_module_shutdown_wrapper, /* shutdown */
  550. NULL, /* activate */
  551. php_sapi_phpdbg_deactivate, /* deactivate */
  552. php_sapi_phpdbg_ub_write, /* unbuffered write */
  553. php_sapi_phpdbg_flush, /* flush */
  554. NULL, /* get uid */
  555. NULL, /* getenv */
  556. php_error, /* error handler */
  557. php_sapi_phpdbg_header_handler, /* header handler */
  558. php_sapi_phpdbg_send_headers, /* send headers handler */
  559. php_sapi_phpdbg_send_header, /* send header handler */
  560. NULL, /* read POST data */
  561. php_sapi_phpdbg_read_cookies, /* read Cookies */
  562. php_sapi_phpdbg_register_vars, /* register server variables */
  563. php_sapi_phpdbg_log_message, /* Log message */
  564. NULL, /* Get request time */
  565. NULL, /* Child terminate */
  566. STANDARD_SAPI_MODULE_PROPERTIES
  567. };
  568. /* }}} */
  569. const opt_struct OPTIONS[] = { /* {{{ */
  570. {'c', 1, "ini path override"},
  571. {'d', 1, "define ini entry on command line"},
  572. {'n', 0, "no php.ini"},
  573. {'z', 1, "load zend_extension"},
  574. /* phpdbg options */
  575. {'q', 0, "no banner"},
  576. {'v', 0, "disable quietness"},
  577. {'s', 0, "enable stepping"},
  578. {'b', 0, "boring colours"},
  579. {'i', 1, "specify init"},
  580. {'I', 0, "ignore init"},
  581. {'O', 1, "opline log"},
  582. {'r', 0, "run"},
  583. {'E', 0, "step-through-eval"},
  584. {'S', 1, "sapi-name"},
  585. #ifndef _WIN32
  586. {'l', 1, "listen"},
  587. {'a', 1, "address-or-any"},
  588. #endif
  589. {'V', 0, "version"},
  590. {'-', 0, NULL}
  591. }; /* }}} */
  592. const char phpdbg_ini_hardcoded[] =
  593. "html_errors=Off\n"
  594. "register_argc_argv=On\n"
  595. "implicit_flush=On\n"
  596. "display_errors=Off\n"
  597. "log_errors=On\n"
  598. "max_execution_time=0\n"
  599. "max_input_time=-1\n"
  600. "error_log=\n"
  601. "output_buffering=off\0";
  602. /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
  603. #define INI_DEFAULT(name, value) \
  604. Z_SET_REFCOUNT(tmp, 0); \
  605. Z_UNSET_ISREF(tmp); \
  606. ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \
  607. zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL);
  608. void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
  609. {
  610. zval tmp;
  611. INI_DEFAULT("report_zend_debug", "0");
  612. } /* }}} */
  613. static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
  614. {
  615. /* print blurb */
  616. if (!cleaning) {
  617. phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
  618. PHPDBG_VERSION);
  619. phpdbg_writeln("To get help using phpdbg type \"help\" and press enter");
  620. phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
  621. } else {
  622. phpdbg_notice("Clean Execution Environment");
  623. phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
  624. phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
  625. phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
  626. phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files)));
  627. }
  628. } /* }}} */
  629. static inline void phpdbg_sigint_handler(int signo) /* {{{ */
  630. {
  631. TSRMLS_FETCH();
  632. if (EG(in_execution)) {
  633. /* set signalled only when not interactive */
  634. if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
  635. PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
  636. }
  637. } else {
  638. /* we quit remote consoles on recv SIGINT */
  639. if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
  640. PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
  641. zend_bailout();
  642. }
  643. }
  644. } /* }}} */
  645. #ifndef _WIN32
  646. int phpdbg_open_socket(const char *interface, short port) /* {{{ */
  647. {
  648. int fd = socket(AF_INET, SOCK_STREAM, 0);
  649. switch (fd) {
  650. case -1:
  651. return -1;
  652. default: {
  653. int reuse = 1;
  654. switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
  655. case -1:
  656. close(fd);
  657. return -2;
  658. default: {
  659. struct sockaddr_in address;
  660. memset(&address, 0, sizeof(address));
  661. address.sin_port = htons(port);
  662. address.sin_family = AF_INET;
  663. if ((*interface == '*')) {
  664. address.sin_addr.s_addr = htonl(INADDR_ANY);
  665. } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
  666. close(fd);
  667. return -3;
  668. }
  669. switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
  670. case -1:
  671. close(fd);
  672. return -4;
  673. default: {
  674. listen(fd, 5);
  675. }
  676. }
  677. }
  678. }
  679. }
  680. }
  681. return fd;
  682. } /* }}} */
  683. static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */
  684. {
  685. if ((*socket)[0] >= 0) {
  686. shutdown(
  687. (*socket)[0], SHUT_RDWR);
  688. close((*socket)[0]);
  689. }
  690. if (streams[0]) {
  691. fclose(streams[0]);
  692. }
  693. if ((*socket)[1] >= 0) {
  694. shutdown(
  695. (*socket)[1], SHUT_RDWR);
  696. close((*socket)[1]);
  697. }
  698. if (streams[1]) {
  699. fclose(streams[1]);
  700. }
  701. } /* }}} */
  702. /* don't inline this, want to debug it easily, will inline when done */
  703. int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */
  704. {
  705. if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
  706. ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
  707. ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
  708. }
  709. streams[0] = NULL;
  710. streams[1] = NULL;
  711. if ((*listen)[0] < 0 || (*listen)[1] < 0) {
  712. if ((*listen)[0] < 0) {
  713. phpdbg_rlog(stderr,
  714. "console failed to initialize (stdin) on %s:%d", address, port[0]);
  715. }
  716. if ((*listen)[1] < 0) {
  717. phpdbg_rlog(stderr,
  718. "console failed to initialize (stdout) on %s:%d", address, port[1]);
  719. }
  720. if ((*listen)[0] >= 0) {
  721. close((*listen)[0]);
  722. }
  723. if ((*listen)[1] >= 0) {
  724. close((*listen)[1]);
  725. }
  726. return FAILURE;
  727. }
  728. phpdbg_close_sockets(socket, streams);
  729. phpdbg_rlog(stderr,
  730. "accepting connections on %s:%d/%d", address, port[0], port[1]);
  731. {
  732. struct sockaddr_in address;
  733. socklen_t size = sizeof(address);
  734. char buffer[20] = {0};
  735. {
  736. memset(&address, 0, size);
  737. (*socket)[0] = accept(
  738. (*listen)[0], (struct sockaddr *) &address, &size);
  739. inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
  740. phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
  741. }
  742. {
  743. memset(&address, 0, size);
  744. (*socket)[1] = accept(
  745. (*listen)[1], (struct sockaddr *) &address, &size);
  746. inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
  747. phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
  748. }
  749. }
  750. dup2((*socket)[0], fileno(stdin));
  751. dup2((*socket)[1], fileno(stdout));
  752. setbuf(stdout, NULL);
  753. streams[0] = fdopen((*socket)[0], "r");
  754. streams[1] = fdopen((*socket)[1], "w");
  755. return SUCCESS;
  756. } /* }}} */
  757. void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
  758. {
  759. int is_handled = FAILURE;
  760. TSRMLS_FETCH();
  761. switch (sig) {
  762. case SIGBUS:
  763. case SIGSEGV:
  764. is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC);
  765. if (is_handled == FAILURE) {
  766. #ifdef ZEND_SIGNALS
  767. zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC);
  768. #else
  769. sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
  770. #endif
  771. }
  772. break;
  773. }
  774. } /* }}} */
  775. #endif
  776. static inline zend_mm_heap *phpdbg_mm_get_heap() /* {{{ */
  777. {
  778. zend_mm_heap *mm_heap;
  779. TSRMLS_FETCH();
  780. mm_heap = zend_mm_set_heap(NULL TSRMLS_CC);
  781. zend_mm_set_heap(mm_heap TSRMLS_CC);
  782. return mm_heap;
  783. } /* }}} */
  784. void *phpdbg_malloc_wrapper(size_t size) /* {{{ */
  785. {
  786. return zend_mm_alloc(phpdbg_mm_get_heap(), size);
  787. } /* }}} */
  788. void phpdbg_free_wrapper(void *p) /* {{{ */
  789. {
  790. zend_mm_free(phpdbg_mm_get_heap(), p);
  791. } /* }}} */
  792. void *phpdbg_realloc_wrapper(void *ptr, size_t size) /* {{{ */
  793. {
  794. return zend_mm_realloc(phpdbg_mm_get_heap(), ptr, size);
  795. } /* }}} */
  796. int main(int argc, char **argv) /* {{{ */
  797. {
  798. sapi_module_struct *phpdbg = &phpdbg_sapi_module;
  799. char *sapi_name;
  800. char *ini_entries;
  801. int ini_entries_len;
  802. char **zend_extensions = NULL;
  803. zend_ulong zend_extensions_len = 0L;
  804. zend_bool ini_ignore;
  805. char *ini_override;
  806. char *exec;
  807. size_t exec_len;
  808. char *init_file;
  809. size_t init_file_len;
  810. zend_bool init_file_default;
  811. char *oplog_file;
  812. size_t oplog_file_len;
  813. zend_ulong flags;
  814. char *php_optarg;
  815. int php_optind, opt, show_banner = 1;
  816. long cleaning = 0;
  817. zend_bool remote = 0;
  818. int run = 0;
  819. int step = 0;
  820. #ifdef _WIN32
  821. char *bp_tmp_file = NULL;
  822. #else
  823. char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX";
  824. #endif
  825. #ifndef _WIN32
  826. char *address;
  827. int listen[2];
  828. int server[2];
  829. int socket[2];
  830. FILE* streams[2] = {NULL, NULL};
  831. #endif
  832. #ifdef ZTS
  833. void ***tsrm_ls;
  834. #endif
  835. #ifndef _WIN32
  836. struct sigaction signal_struct;
  837. signal_struct.sa_sigaction = phpdbg_signal_handler;
  838. signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
  839. address = strdup("127.0.0.1");
  840. socket[0] = -1;
  841. socket[1] = -1;
  842. listen[0] = -1;
  843. listen[1] = -1;
  844. server[0] = -1;
  845. server[1] = -1;
  846. streams[0] = NULL;
  847. streams[1] = NULL;
  848. #endif
  849. #ifdef PHP_WIN32
  850. _fmode = _O_BINARY; /* sets default for file streams to binary */
  851. setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
  852. setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
  853. setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
  854. #endif
  855. #ifdef ZTS
  856. tsrm_startup(1, 1, 0, NULL);
  857. tsrm_ls = ts_resource(0);
  858. #endif
  859. phpdbg_main:
  860. if (!cleaning) {
  861. #ifdef _WIN32
  862. bp_tmp_file = malloc(L_tmpnam);
  863. if (bp_tmp_file) {
  864. if (!tmpnam(bp_tmp_file)) {
  865. free(bp_tmp_file);
  866. bp_tmp_file = NULL;
  867. }
  868. }
  869. if (!bp_tmp_file) {
  870. phpdbg_error("Unable to create temporary file");
  871. return 1;
  872. }
  873. #else
  874. if (!mkstemp(bp_tmp_file)) {
  875. memset(bp_tmp_file, 0, sizeof(bp_tmp_file));
  876. }
  877. #endif
  878. }
  879. ini_entries = NULL;
  880. ini_entries_len = 0;
  881. ini_ignore = 0;
  882. ini_override = NULL;
  883. zend_extensions = NULL;
  884. zend_extensions_len = 0L;
  885. exec = NULL;
  886. exec_len = 0;
  887. init_file = NULL;
  888. init_file_len = 0;
  889. init_file_default = 1;
  890. oplog_file = NULL;
  891. oplog_file_len = 0;
  892. flags = PHPDBG_DEFAULT_FLAGS;
  893. php_optarg = NULL;
  894. php_optind = 1;
  895. opt = 0;
  896. run = 0;
  897. step = 0;
  898. sapi_name = NULL;
  899. while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
  900. switch (opt) {
  901. case 'r':
  902. run++;
  903. break;
  904. case 'n':
  905. ini_ignore = 1;
  906. break;
  907. case 'c':
  908. if (ini_override) {
  909. free(ini_override);
  910. }
  911. ini_override = strdup(php_optarg);
  912. break;
  913. case 'd': {
  914. int len = strlen(php_optarg);
  915. char *val;
  916. if ((val = strchr(php_optarg, '='))) {
  917. val++;
  918. if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
  919. ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
  920. memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
  921. ini_entries_len += (val - php_optarg);
  922. memcpy(ini_entries + ini_entries_len, "\"", 1);
  923. ini_entries_len++;
  924. memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
  925. ini_entries_len += len - (val - php_optarg);
  926. memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
  927. ini_entries_len += sizeof("\n\0\"") - 2;
  928. } else {
  929. ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
  930. memcpy(ini_entries + ini_entries_len, php_optarg, len);
  931. memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
  932. ini_entries_len += len + sizeof("\n\0") - 2;
  933. }
  934. } else {
  935. ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
  936. memcpy(ini_entries + ini_entries_len, php_optarg, len);
  937. memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
  938. ini_entries_len += len + sizeof("=1\n\0") - 2;
  939. }
  940. } break;
  941. case 'z':
  942. zend_extensions_len++;
  943. if (zend_extensions) {
  944. zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
  945. } else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
  946. zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
  947. break;
  948. /* begin phpdbg options */
  949. case 'S': { /* set SAPI name */
  950. if (sapi_name) {
  951. free(sapi_name);
  952. }
  953. sapi_name = strdup(php_optarg);
  954. } break;
  955. case 'I': { /* ignore .phpdbginit */
  956. init_file_default = 0;
  957. } break;
  958. case 'i': { /* set init file */
  959. if (init_file) {
  960. free(init_file);
  961. }
  962. init_file_len = strlen(php_optarg);
  963. if (init_file_len) {
  964. init_file = strdup(php_optarg);
  965. }
  966. } break;
  967. case 'O': { /* set oplog output */
  968. oplog_file_len = strlen(php_optarg);
  969. if (oplog_file_len) {
  970. oplog_file = strdup(php_optarg);
  971. }
  972. } break;
  973. case 'v': /* set quietness off */
  974. flags &= ~PHPDBG_IS_QUIET;
  975. break;
  976. case 's': /* set stepping on */
  977. step = 1;
  978. break;
  979. case 'E': /* stepping through eval on */
  980. flags |= PHPDBG_IS_STEPONEVAL;
  981. break;
  982. case 'b': /* set colours off */
  983. flags &= ~PHPDBG_IS_COLOURED;
  984. break;
  985. case 'q': /* hide banner */
  986. show_banner = 0;
  987. break;
  988. #ifndef _WIN32
  989. /* if you pass a listen port, we will accept input on listen port */
  990. /* and write output to listen port * 2 */
  991. case 'l': { /* set listen ports */
  992. if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
  993. if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
  994. /* default to hardcoded ports */
  995. listen[0] = 4000;
  996. listen[1] = 8000;
  997. } else {
  998. listen[1] = (listen[0] * 2);
  999. }
  1000. }
  1001. } break;
  1002. case 'a': { /* set bind address */
  1003. free(address);
  1004. if (!php_optarg) {
  1005. address = strdup("*");
  1006. } else address = strdup(php_optarg);
  1007. } break;
  1008. #endif
  1009. case 'V': {
  1010. sapi_startup(phpdbg);
  1011. phpdbg->startup(phpdbg);
  1012. printf(
  1013. "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2016 The PHP Group\n%s",
  1014. PHPDBG_VERSION,
  1015. __DATE__,
  1016. __TIME__,
  1017. PHP_VERSION,
  1018. get_zend_version()
  1019. );
  1020. sapi_deactivate(TSRMLS_C);
  1021. sapi_shutdown();
  1022. return 0;
  1023. } break;
  1024. }
  1025. }
  1026. /* set exec if present on command line */
  1027. if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS))
  1028. {
  1029. exec_len = strlen(argv[php_optind]);
  1030. if (exec_len) {
  1031. if (exec) {
  1032. free(exec);
  1033. }
  1034. exec = strdup(argv[php_optind]);
  1035. }
  1036. php_optind++;
  1037. }
  1038. #ifndef _WIN32
  1039. /* setup remote server if necessary */
  1040. if (!cleaning &&
  1041. (listen[0] > 0 && listen[1] > 0)) {
  1042. if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
  1043. remote = 0;
  1044. exit(0);
  1045. }
  1046. /* set remote flag to stop service shutting down upon quit */
  1047. remote = 1;
  1048. }
  1049. #endif
  1050. if (sapi_name) {
  1051. phpdbg->name = sapi_name;
  1052. }
  1053. phpdbg->ini_defaults = phpdbg_ini_defaults;
  1054. phpdbg->phpinfo_as_text = 1;
  1055. phpdbg->php_ini_ignore_cwd = 1;
  1056. sapi_startup(phpdbg);
  1057. phpdbg->executable_location = argv[0];
  1058. phpdbg->phpinfo_as_text = 1;
  1059. phpdbg->php_ini_ignore = ini_ignore;
  1060. phpdbg->php_ini_path_override = ini_override;
  1061. if (ini_entries) {
  1062. ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
  1063. memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
  1064. memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
  1065. } else {
  1066. ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
  1067. memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
  1068. }
  1069. ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
  1070. if (zend_extensions_len) {
  1071. zend_ulong zend_extension = 0L;
  1072. while (zend_extension < zend_extensions_len) {
  1073. const char *ze = zend_extensions[zend_extension];
  1074. size_t ze_len = strlen(ze);
  1075. ini_entries = realloc(
  1076. ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
  1077. memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
  1078. ini_entries_len += (sizeof("zend_extension=")-1);
  1079. memcpy(&ini_entries[ini_entries_len], ze, ze_len);
  1080. ini_entries_len += ze_len;
  1081. memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
  1082. free(zend_extensions[zend_extension]);
  1083. zend_extension++;
  1084. }
  1085. free(zend_extensions);
  1086. }
  1087. phpdbg->ini_entries = ini_entries;
  1088. if (phpdbg->startup(phpdbg) == SUCCESS) {
  1089. #ifdef _WIN32
  1090. EXCEPTION_POINTERS *xp;
  1091. __try {
  1092. #endif
  1093. zend_mm_heap *mm_heap = phpdbg_mm_get_heap();
  1094. if (mm_heap->use_zend_alloc) {
  1095. mm_heap->_malloc = phpdbg_malloc_wrapper;
  1096. mm_heap->_realloc = phpdbg_realloc_wrapper;
  1097. mm_heap->_free = phpdbg_free_wrapper;
  1098. mm_heap->use_zend_alloc = 0;
  1099. }
  1100. zend_activate(TSRMLS_C);
  1101. PHPDBG_G(original_free_function) = mm_heap->_free;
  1102. mm_heap->_free = phpdbg_watch_efree;
  1103. phpdbg_setup_watchpoints(TSRMLS_C);
  1104. #if defined(ZEND_SIGNALS) && !defined(_WIN32)
  1105. zend_try {
  1106. zend_signal_activate(TSRMLS_C);
  1107. } zend_end_try();
  1108. #endif
  1109. #if defined(ZEND_SIGNALS) && !defined(_WIN32)
  1110. zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try();
  1111. zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try();
  1112. #elif !defined(_WIN32)
  1113. sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
  1114. sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
  1115. #endif
  1116. if (php_request_startup(TSRMLS_C) == SUCCESS) {
  1117. int i;
  1118. SG(request_info).argc = argc - php_optind + 1;
  1119. SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));
  1120. for (i = SG(request_info).argc; --i;) {
  1121. SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
  1122. }
  1123. SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup("");
  1124. php_hash_environment(TSRMLS_C);
  1125. }
  1126. /* make sure to turn off buffer for ev command */
  1127. php_output_activate(TSRMLS_C);
  1128. php_output_deactivate(TSRMLS_C);
  1129. /* do not install sigint handlers for remote consoles */
  1130. /* sending SIGINT then provides a decent way of shutting down the server */
  1131. #ifndef _WIN32
  1132. if (listen[0] < 0) {
  1133. #endif
  1134. #if defined(ZEND_SIGNALS) && !defined(_WIN32)
  1135. zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try();
  1136. #else
  1137. signal(SIGINT, phpdbg_sigint_handler);
  1138. #endif
  1139. #ifndef _WIN32
  1140. }
  1141. #endif
  1142. PG(modules_activated) = 0;
  1143. /* set flags from command line */
  1144. PHPDBG_G(flags) = flags;
  1145. #ifndef _WIN32
  1146. /* setup io here */
  1147. if (streams[0] && streams[1]) {
  1148. PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
  1149. signal(SIGPIPE, SIG_IGN);
  1150. }
  1151. #endif
  1152. PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
  1153. PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
  1154. PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
  1155. if (exec) { /* set execution context */
  1156. PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
  1157. PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
  1158. free(exec);
  1159. }
  1160. if (oplog_file) { /* open oplog */
  1161. PHPDBG_G(oplog) = fopen(oplog_file, "w+");
  1162. if (!PHPDBG_G(oplog)) {
  1163. phpdbg_error(
  1164. "Failed to open oplog %s", oplog_file);
  1165. }
  1166. free(oplog_file);
  1167. }
  1168. /* set default colors */
  1169. phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold") TSRMLS_CC);
  1170. phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold") TSRMLS_CC);
  1171. phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC);
  1172. /* set default prompt */
  1173. phpdbg_set_prompt(PROMPT TSRMLS_CC);
  1174. /* Make stdin, stdout and stderr accessible from PHP scripts */
  1175. phpdbg_register_file_handles(TSRMLS_C);
  1176. if (show_banner) {
  1177. /* print blurb */
  1178. phpdbg_welcome((cleaning > 0) TSRMLS_CC);
  1179. }
  1180. /* auto compile */
  1181. if (PHPDBG_G(exec)) {
  1182. phpdbg_compile(TSRMLS_C);
  1183. }
  1184. /* initialize from file */
  1185. PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
  1186. zend_try {
  1187. phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC);
  1188. phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC);
  1189. } zend_end_try();
  1190. PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
  1191. /* quit if init says so */
  1192. if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
  1193. goto phpdbg_out;
  1194. }
  1195. /* step from here, not through init */
  1196. if (step) {
  1197. PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
  1198. }
  1199. if (run) {
  1200. /* no need to try{}, run does it ... */
  1201. PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC);
  1202. if (run > 1) {
  1203. /* if -r is on the command line more than once just quit */
  1204. goto phpdbg_out;
  1205. }
  1206. }
  1207. /* #ifndef for making compiler shutting up */
  1208. #ifndef _WIN32
  1209. phpdbg_interact:
  1210. #endif
  1211. /* phpdbg main() */
  1212. do {
  1213. zend_try {
  1214. phpdbg_interactive(TSRMLS_C);
  1215. } zend_catch {
  1216. if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
  1217. FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
  1218. phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC);
  1219. fclose(bp_tmp_fp);
  1220. cleaning = 1;
  1221. } else {
  1222. cleaning = 0;
  1223. }
  1224. #ifndef _WIN32
  1225. if (!cleaning) {
  1226. /* remote client disconnected */
  1227. if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
  1228. if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
  1229. /* renegociate connections */
  1230. phpdbg_open_sockets(
  1231. address, listen, &server, &socket, streams);
  1232. /* set streams */
  1233. if (streams[0] && streams[1]) {
  1234. PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
  1235. }
  1236. /* this must be forced */
  1237. CG(unclean_shutdown) = 0;
  1238. } else {
  1239. /* local consoles cannot disconnect, ignore EOF */
  1240. PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
  1241. }
  1242. }
  1243. }
  1244. #endif
  1245. } zend_end_try();
  1246. } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
  1247. /* this must be forced */
  1248. CG(unclean_shutdown) = 0;
  1249. /* this is just helpful */
  1250. PG(report_memleaks) = 0;
  1251. #ifndef _WIN32
  1252. phpdbg_out:
  1253. if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
  1254. PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
  1255. goto phpdbg_interact;
  1256. }
  1257. #endif
  1258. #ifdef _WIN32
  1259. } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
  1260. phpdbg_error("Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");
  1261. }
  1262. phpdbg_out:
  1263. #endif
  1264. {
  1265. int i;
  1266. /* free argv */
  1267. for (i = SG(request_info).argc; --i;) {
  1268. efree(SG(request_info).argv[i]);
  1269. }
  1270. efree(SG(request_info).argv);
  1271. }
  1272. #ifndef ZTS
  1273. /* force cleanup of auto and core globals */
  1274. zend_hash_clean(CG(auto_globals));
  1275. memset(
  1276. &core_globals, 0, sizeof(php_core_globals));
  1277. #endif
  1278. if (ini_entries) {
  1279. free(ini_entries);
  1280. }
  1281. if (ini_override) {
  1282. free(ini_override);
  1283. }
  1284. /* this must be forced */
  1285. CG(unclean_shutdown) = 0;
  1286. /* this is just helpful */
  1287. PG(report_memleaks) = 0;
  1288. php_request_shutdown((void*)0);
  1289. zend_try {
  1290. php_module_shutdown(TSRMLS_C);
  1291. } zend_end_try();
  1292. sapi_shutdown();
  1293. }
  1294. if (cleaning || remote) {
  1295. goto phpdbg_main;
  1296. }
  1297. #ifdef ZTS
  1298. /* bugggy */
  1299. /* tsrm_shutdown(); */
  1300. #endif
  1301. #ifndef _WIN32
  1302. if (address) {
  1303. free(address);
  1304. }
  1305. #endif
  1306. if (sapi_name) {
  1307. free(sapi_name);
  1308. }
  1309. #ifdef _WIN32
  1310. free(bp_tmp_file);
  1311. #else
  1312. unlink(bp_tmp_file);
  1313. #endif
  1314. return 0;
  1315. } /* }}} */