From feabc032f62cc2a2dd4c2626b1c6806a22d5988d Mon Sep 17 00:00:00 2001 From: axel Date: Thu, 2 Feb 2006 01:49:11 +1000 Subject: [PATCH] Generalize the stack tracing code, add support for showing events and command substitutions in stack traces darcs-hash:20060201154911-ac50b-707358ea50231661c05a92b40ca109ec801081e6.gz --- builtin.c | 12 +------- event.c | 69 ++++++++++++++++++++++++++++++++++++++++- event.h | 6 ++++ exec.c | 15 ++------- parser.c | 91 ++++++++++++++++++++++++++++++++++++++----------------- parser.h | 17 +++++++++-- proc.c | 4 +-- reader.c | 1 - signal.c | 2 +- signal.h | 2 +- 10 files changed, 158 insertions(+), 61 deletions(-) diff --git a/builtin.c b/builtin.c index 7b0250445..6496719dc 100644 --- a/builtin.c +++ b/builtin.c @@ -2029,20 +2029,10 @@ static int builtin_source( wchar_t ** argv ) } else { - - /* - Push a new non-shadowwing variable scope to the stack. That - way one can use explicitly local variables in sourced files - that will die on return to the calling file. - */ - int lineno = parser_get_lineno(); - wchar_t *file = parser_current_filename()?wcsdup(parser_current_filename()):0; - reader_push_current_filename( argv[1] ); parser_push_block( SOURCE ); + reader_push_current_filename( argv[1] ); current_block->param1.source_dest = wcsdup( argv[1] ); - current_block->param3.call_lineno = lineno; - current_block->param4.call_filename = file; res = reader_read( fd ); parser_pop_block(); diff --git a/event.c b/event.c index c264c351f..ccbc774fb 100644 --- a/event.c +++ b/event.c @@ -74,6 +74,7 @@ static array_list_t *killme; */ static array_list_t *blocked; +static string_buffer_t *get_desc_buff=0; /** Tests if one event instance matches the definition of a event @@ -186,6 +187,63 @@ static int event_is_blocked( event_t *e ) return 0; } +const wchar_t *event_get_desc( event_t *e ) +{ + if( !get_desc_buff ) + { + get_desc_buff=malloc(sizeof(string_buffer_t) ); + if( !get_desc_buff ) + die_mem(); + sb_init( get_desc_buff ); + } + else + { + sb_clear( get_desc_buff ); + } + + switch( e->type ) + { + + case EVENT_SIGNAL: + sb_printf( get_desc_buff, _(L"signal handler for %ls (%ls)"), sig2wcs(e->param1.signal ), signal_get_desc( e->param1.signal ) ); + break; + + case EVENT_VARIABLE: + sb_printf( get_desc_buff, _(L"handler for variable '%ls'"), e->param1.variable ); + break; + + case EVENT_EXIT: + if( e->param1.pid > 0 ) + { + sb_printf( get_desc_buff, _(L"exit handler for process %d"), e->param1.pid ); + } + else + { + job_t *j = job_get_from_pid( -e->param1.pid ); + if( j ) + sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command ); + else + sb_printf( get_desc_buff, _(L"exit handler for job with process group %d"), -e->param1.pid ); + } + + break; + + case EVENT_JOB_ID: + { + job_t *j = job_get( e->param1.job_id ); + if( j ) + sb_printf( get_desc_buff, _(L"exit handler for job %d, '%ls'"), j->job_id, j->command ); + else + sb_printf( get_desc_buff, _(L"exit handler for job with job id %d"), j->job_id ); + + break; + } + + } + + return (const wchar_t *)get_desc_buff->buff; +} + void event_add_handler( event_t *event ) { @@ -404,8 +462,11 @@ static void event_fire_internal( event_t *event ) they are marked as non-interactive and as a subshell */ is_subshell=1; + parser_push_block( EVENT ); + current_block->param1.event = event; eval( (wchar_t *)b->buff, 0, TOP ); - + parser_pop_block(); + } /* @@ -578,6 +639,12 @@ void event_destroy() free( killme ); killme=0; } + if( get_desc_buff ) + { + sb_destroy( get_desc_buff ); + free( get_desc_buff ); + } + } void event_free( event_t *e ) diff --git a/event.h b/event.h index 1bbfb22e8..9bd3f81bd 100644 --- a/event.h +++ b/event.h @@ -130,4 +130,10 @@ void event_destroy(); */ void event_free( event_t *e ); +/** + Returns a string describing the specified event. The string should + not be freed. +*/ +const wchar_t *event_get_desc( event_t *e ); + #endif diff --git a/exec.c b/exec.c index 5f293eb92..4491ebb54 100644 --- a/exec.c +++ b/exec.c @@ -797,25 +797,17 @@ void exec( job_t *j ) string_buffer_t sb; const wchar_t * def = function_get_definition( p->argv[0] ); -// fwprintf( stderr, L"run function %ls\n", argv[0] ); + //fwprintf( stderr, L"run function %ls\n", argv[0] ); if( def == 0 ) { debug( 0, _( L"Unknown function '%ls'" ), p->argv[0] ); break; } - /* - These two lines must be called before the new block is pushed - */ - int lineno = parser_get_lineno(); - wchar_t *file = parser_current_filename()?wcsdup(parser_current_filename()):0; - parser_push_block( FUNCTION_CALL ); - al_init( ¤t_block->param2.function_vars ); + current_block->param2.function_call_process = p; current_block->param1.function_name = wcsdup( p->argv[0] ); - current_block->param3.call_lineno = lineno; - current_block->param4.call_filename = file; if( builtin_count_args(p->argv)>1 ) { @@ -823,9 +815,6 @@ void exec( job_t *j ) for( i=1, arg=p->argv+1; *arg; i++, arg++ ) { - al_push( ¤t_block->param2.function_vars, - escape(*arg, 1) ); - if( i != 1 ) sb_append( &sb, ARRAY_SEP_STR ); sb_append( &sb, *arg ); diff --git a/parser.c b/parser.c index fc4c48bad..04d0a4ff3 100644 --- a/parser.c +++ b/parser.c @@ -233,6 +233,11 @@ The fish parser. Contains functions for parsing code. */ #define SOURCE_BLOCK _( L"Block created by the . builtin" ) +/** + Source block description +*/ +#define EVENT_BLOCK _( L"event handler block" ) + /** Unknown block description @@ -333,6 +338,9 @@ void parser_push_block( int type ) { block_t *new = calloc( 1, sizeof( block_t )); + new->src_lineno = parser_get_lineno(); + new->src_filename = parser_current_filename()?wcsdup(parser_current_filename()):0; + debug( 3, L"Block push %ls %d\n", parser_get_block_desc(type), block_count( current_block)+1 ); new->outer = current_block; @@ -407,16 +415,11 @@ void parser_pop_block() case FUNCTION_CALL: { free( current_block->param1.function_name ); - free( current_block->param4.call_filename ); - al_foreach( ¤t_block->param2.function_vars, - (void (*)(const void *))&free ); - al_destroy( ¤t_block->param2.function_vars ); break; } case SOURCE: { - free( current_block->param4.call_filename ); free( current_block->param1.source_dest ); break; } @@ -429,6 +432,8 @@ void parser_pop_block() free(eb); } + free( current_block->src_filename ); + block_t *old = current_block; current_block = current_block->outer; free( old ); @@ -471,6 +476,9 @@ const wchar_t *parser_get_block_desc( int block ) case SOURCE: return SOURCE_BLOCK; + case EVENT: + return EVENT_BLOCK; + default: return UNKNOWN_BLOCK; } @@ -1035,40 +1043,60 @@ void parser_stack_trace( block_t *b, string_buffer_t *buff) { if( !b ) return; - - if( b->type == FUNCTION_CALL || b->type==SOURCE) + + if( b->type==EVENT ) + { + sb_printf( buff, _(L"in event handler: %ls\n"), event_get_desc( b->param1.event )); + sb_printf( buff, + L"\n" ); + return; + } + + if( b->type == FUNCTION_CALL || b->type==SOURCE || b->type==SUBST) { int i; - if( b->type==SOURCE) - sb_printf( buff, _(L"in . (source) call of file '%ls',\n"), b->param1.source_dest ); - else - sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_name ); + switch( b->type) + { + case SOURCE: + sb_printf( buff, _(L"in . (source) call of file '%ls',\n"), b->param1.source_dest ); + break; + case FUNCTION_CALL: + sb_printf( buff, _(L"in function '%ls',\n"), b->param1.function_name ); + break; + case SUBST: + sb_printf( buff, _(L"in command substitution\n") ); + break; + } - const wchar_t *file = b->param4.call_filename; + const wchar_t *file = b->src_filename; if( file ) sb_printf( buff, _(L"\tcalled on line %d of file '%ls',\n"), - b->param3.call_lineno, + b->src_lineno, file ); else sb_printf( buff, _(L"\tcalled on standard input,\n") ); - if( al_get_count( &b->param2.function_vars ) ) - { - string_buffer_t tmp; - sb_init( &tmp ); - - for( i=0; iparam2.function_vars ); i++ ) + if( b->type == FUNCTION_CALL ) + { + if( b->param2.function_call_process->argv[1] ) { - sb_append2( &tmp, i?L" ":L"", (wchar_t *)al_get( &b->param2.function_vars, i ), (void *)0 ); + string_buffer_t tmp; + sb_init( &tmp ); + + for( i=1; b->param2.function_call_process->argv[i]; i++ ) + { + sb_append2( &tmp, i>1?L" ":L"", b->param2.function_call_process->argv[i], (void *)0 ); + } + sb_printf( buff, _(L"\twith parameter list '%ls'\n"), (wchar_t *)tmp.buff ); + + sb_destroy( &tmp ); } - sb_printf( buff, _(L"\twith parameter list '%ls'\n"), (wchar_t *)tmp.buff ); - - sb_destroy( &tmp ); } + sb_printf( buff, L"\n" ); } @@ -1096,11 +1124,19 @@ static const wchar_t *is_function() int parser_get_lineno() { int i; - const wchar_t *whole_str = tok_string( current_tokenizer ); + const wchar_t *whole_str; const wchar_t *function_name; int lineno = 1; + if( !current_tokenizer ) + return -1; + + whole_str = tok_string( current_tokenizer ); + + if( !whole_str ) + return -1; + for( i=0; ijob_id, j->command, sig2wcs(WTERMSIG(p->status)), - sig_description( WTERMSIG(p->status) ) ); + signal_get_desc( WTERMSIG(p->status) ) ); else fwprintf( stdout, _( L"%ls: Process %d, \'%ls\' from job %d, \'%ls\' terminated by signal %ls (%ls)" ), @@ -598,7 +598,7 @@ int job_reap( int interactive ) j->job_id, j->command, sig2wcs(WTERMSIG(p->status)), - sig_description( WTERMSIG(p->status) ) ); + signal_get_desc( WTERMSIG(p->status) ) ); tputs(clr_eol,1,&writeb); fwprintf (stdout, L"\n" ); found=1; diff --git a/reader.c b/reader.c index 4fdd693d0..6f8d2439b 100644 --- a/reader.c +++ b/reader.c @@ -2813,7 +2813,6 @@ wchar_t *reader_readline() data->search_buff[0]=0; history_reset(); data->token_history_pos=-1; - } diff --git a/signal.c b/signal.c index 219eb2676..bab6dc4da 100644 --- a/signal.c +++ b/signal.c @@ -342,7 +342,7 @@ const wchar_t *sig2wcs( int sig ) return L"Unknown"; } -const wchar_t *sig_description( int sig ) +const wchar_t *signal_get_desc( int sig ) { int i; for( i=0; lookup[i].desc ; i++ ) diff --git a/signal.h b/signal.h index 22536ec67..5fb4a897b 100644 --- a/signal.h +++ b/signal.h @@ -18,7 +18,7 @@ const wchar_t *sig2wcs( int sig ); /** Returns a description of the specified signal. */ -const wchar_t *sig_description( int sig ); +const wchar_t *signal_get_desc( int sig ); /** Set all signal handlers to SIG_DFL