@@ -207,48 +207,111 @@ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRML
207207{
208208 php_stream_statbuf ssb ;
209209 char realpath [MAXPATHLEN ];
210+ const char * original_path = path ;
211+ zend_bool pending ;
210212
211- if (php_stream_stat_path (path , & ssb ) != FAILURE ) {
212- if (ssb .sb .st_mode & (S_IFREG |S_IFLNK )) {
213- HashTable * broken ;
214- phpdbg_breakfile_t new_break ;
215- size_t path_len = 0L ;
213+ HashTable * broken , * file_breaks = & PHPDBG_G (bp )[PHPDBG_BREAK_FILE ];
214+ phpdbg_breakfile_t new_break ;
215+ size_t path_len = 0L ;
216216
217- if (VCWD_REALPATH (path , realpath )) {
218- path = realpath ;
217+ if (VCWD_REALPATH (path , realpath )) {
218+ path = realpath ;
219+ }
220+ path_len = strlen (path );
221+
222+ if (!zend_hash_str_exists (& PHPDBG_G (file_sources ), path , path_len )) {
223+ if (php_stream_stat_path (path , & ssb ) == FAILURE ) {
224+ if (original_path [0 ] == '/' ) {
225+ phpdbg_error ("breakpoint" , "type=\"nofile\" add=\"fail\" file=\"%s\"" , "Cannot stat %s, it does not exist" , original_path );
226+ return ;
219227 }
228+
229+ file_breaks = & PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ];
230+ path = original_path ;
220231 path_len = strlen (path );
232+ pending = 1 ;
233+ } else if (!(ssb .sb .st_mode & (S_IFREG |S_IFLNK ))) {
234+ phpdbg_error ("breakpoint" , "type=\"notregular\" add=\"fail\" file=\"%s\"" , "Cannot set breakpoint in %s, it is not a regular file" , path );
235+ return ;
236+ }
237+ }
221238
222- if (!(broken = zend_hash_str_find_ptr (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE ], path , path_len ))) {
223- HashTable breaks ;
239+ if (!(broken = zend_hash_str_find_ptr (file_breaks , path , path_len ))) {
240+ HashTable breaks ;
241+ zend_hash_init (& breaks , 8 , NULL , phpdbg_file_breaks_dtor , 0 );
224242
225- zend_hash_init (& breaks , 8 , NULL , phpdbg_file_breaks_dtor , 0 );
243+ broken = zend_hash_str_add_mem (file_breaks , path , path_len , & breaks , sizeof (HashTable ));
244+ }
226245
227- broken = zend_hash_str_update_mem (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE ], path , path_len , & breaks , sizeof (HashTable ));
228- }
246+ if (!zend_hash_index_exists (broken , line_num )) {
247+ PHPDBG_BREAK_INIT (new_break , PHPDBG_BREAK_FILE );
248+ new_break .filename = estrndup (path , path_len );
249+ new_break .line = line_num ;
250+
251+ zend_hash_index_update_mem (broken , line_num , & new_break , sizeof (phpdbg_breakfile_t ));
229252
230- if (! zend_hash_index_exists ( broken , line_num ) ) {
231- PHPDBG_G (flags ) |= PHPDBG_HAS_FILE_BP ;
253+ if (pending ) {
254+ PHPDBG_G (flags ) |= PHPDBG_HAS_PENDING_FILE_BP ;
232255
233- PHPDBG_BREAK_INIT ( new_break , PHPDBG_BREAK_FILE );
234- new_break . filename = estrndup ( path , path_len );
235- new_break . line = line_num ;
256+ phpdbg_notice ( "breakpoint" , "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\" pending=\"pending\"" , "Pending breakpoint #%d added at %s:%ld" , new_break . id , new_break . filename , new_break . line );
257+ } else {
258+ PHPDBG_G ( flags ) |= PHPDBG_HAS_FILE_BP ;
236259
237- zend_hash_index_update_mem (broken , line_num , & new_break , sizeof (phpdbg_breakfile_t ));
260+ phpdbg_notice ("breakpoint" , "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"" , "Breakpoint #%d added at %s:%ld" , new_break .id , new_break .filename , new_break .line );
261+ }
238262
239- phpdbg_notice ("breakpoint" , "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"" , "Breakpoint #%d added at %s:%ld" , new_break .id , new_break .filename , new_break .line );
263+ PHPDBG_BREAK_MAPPING (new_break .id , broken );
264+ } else {
265+ phpdbg_error ("breakpoint" , "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"" , "Breakpoint at %s:%ld exists" , path , line_num );
266+ }
267+ } /* }}} */
240268
241- PHPDBG_BREAK_MAPPING (new_break .id , broken );
242- } else {
243- phpdbg_error ("breakpoint" , "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"" , "Breakpoint at %s:%ld exists" , path , line_num );
269+ PHPDBG_API void phpdbg_resolve_pending_file_break (const char * file TSRMLS_DC ) /* {{{ */
270+ {
271+ HashTable * fileht ;
272+ uint filelen = strlen (file );
273+ zend_string * cur ;
274+
275+ ZEND_HASH_FOREACH_STR_KEY_PTR (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ], cur , fileht ) {
276+ if (cur -> len < filelen && file [filelen - cur -> len - 1 ] == '/' && !memcmp (file + filelen - cur -> len , cur -> val , cur -> len )) {
277+ phpdbg_breakfile_t * brake , new_brake ;
278+ HashTable * master ;
279+ dtor_func_t dtor ;
280+
281+ PHPDBG_G (flags ) |= PHPDBG_HAS_FILE_BP ;
282+
283+ if (!(master = zend_hash_str_find_ptr (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE ], file , filelen ))) {
284+ dtor = PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ].pDestructor ;
285+ PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ].pDestructor = NULL ;
286+ fileht = zend_hash_str_add_mem (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE ], file , filelen , fileht , sizeof (HashTable ));
244287 }
245288
246- } else {
247- phpdbg_error ("breakpoint" , "type=\"notregular\" add=\"fail\" file=\"%s\"" , "Cannot set breakpoint in %s, it is not a regular file" , path );
289+ ZEND_HASH_FOREACH_PTR (fileht , brake ) {
290+ new_brake = * brake ;
291+ new_brake .filename = estrndup (file , filelen );
292+ PHPDBG_BREAK_UNMAPPING (brake -> id );
293+
294+ if (master ) {
295+ zend_hash_index_update_mem (master , brake -> line , & new_brake , sizeof (phpdbg_breakfile_t ));
296+ PHPDBG_BREAK_MAPPING (brake -> id , master );
297+ } else {
298+ efree ((char * ) brake -> filename );
299+ * brake = new_brake ;
300+ PHPDBG_BREAK_MAPPING (brake -> id , fileht );
301+ }
302+ } ZEND_HASH_FOREACH_END ();
303+
304+ zend_hash_del (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ], cur );
305+
306+ if (!master ) {
307+ PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ].pDestructor = dtor ;
308+ }
309+
310+ if (!zend_hash_num_elements (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ])) {
311+ PHPDBG_G (flags ) &= ~PHPDBG_HAS_PENDING_FILE_BP ;
312+ }
248313 }
249- } else {
250- phpdbg_error ("breakpoint" , "type=\"nofile\" add=\"fail\" file=\"%s\"" , "Cannot stat %s, it does not exist" , path );
251- }
314+ } ZEND_HASH_FOREACH_END ();
252315} /* }}} */
253316
254317PHPDBG_API void phpdbg_set_breakpoint_symbol (const char * name , size_t name_len TSRMLS_DC ) /* {{{ */
@@ -1048,6 +1111,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */
10481111PHPDBG_API void phpdbg_clear_breakpoints (TSRMLS_D ) /* {{{ */
10491112{
10501113 zend_hash_clean (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE ]);
1114+ zend_hash_clean (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ]);
10511115 zend_hash_clean (& PHPDBG_G (bp )[PHPDBG_BREAK_SYM ]);
10521116 zend_hash_clean (& PHPDBG_G (bp )[PHPDBG_BREAK_OPLINE ]);
10531117 zend_hash_clean (& PHPDBG_G (bp )[PHPDBG_BREAK_METHOD_OPLINE ]);
@@ -1283,7 +1347,20 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */
12831347 ((phpdbg_breakbase_t * ) brake )-> disabled ? " [disabled]" : "" );
12841348 } ZEND_HASH_FOREACH_END ();
12851349 } ZEND_HASH_FOREACH_END ();
1350+ } if ((PHPDBG_G (flags ) & PHPDBG_HAS_PENDING_FILE_BP )) {
1351+ HashTable * points ;
1352+
1353+ phpdbg_out (SEPARATE "\n" );
1354+ phpdbg_out ("Pending File Breakpoints:\n" );
1355+ ZEND_HASH_FOREACH_PTR (& PHPDBG_G (bp )[PHPDBG_BREAK_FILE_PENDING ], points ) {
1356+ phpdbg_breakfile_t * brake ;
12861357
1358+ ZEND_HASH_FOREACH_PTR (points , brake ) {
1359+ phpdbg_writeln ("file" , "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\" pending=\"pending\"" , "#%d\t\t%s:%lu%s" ,
1360+ brake -> id , brake -> filename , brake -> line ,
1361+ ((phpdbg_breakbase_t * ) brake )-> disabled ? " [disabled]" : "" );
1362+ } ZEND_HASH_FOREACH_END ();
1363+ } ZEND_HASH_FOREACH_END ();
12871364 } break ;
12881365
12891366 case PHPDBG_BREAK_OPLINE : if ((PHPDBG_G (flags ) & PHPDBG_HAS_OPLINE_BP )) {
0 commit comments