X-Git-Url: https://ncurses.scripts.mit.edu/?p=ncurses.git;a=blobdiff_plain;f=test%2Ftracemunch;h=4de41963f979fabb76a3c53f17205a80973728a0;hp=d6761cd0421940ffc9cb1d16938f5c67f6929ea0;hb=3ef920d65fb2d4046096131d868ae8d4bba79d46;hpb=3a9b6a3bf0269231bef7de74757a910dedd04e0c diff --git a/test/tracemunch b/test/tracemunch index d6761cd0..4de41963 100755 --- a/test/tracemunch +++ b/test/tracemunch @@ -1,98 +1,594 @@ -#!/usr/bin/perl -# +#!/usr/bin/env perl +# $Id: tracemunch,v 1.28 2020/03/08 12:22:49 tom Exp $ +############################################################################## +# Copyright 2018-2019,2020 Thomas E. Dickey # +# Copyright 1998-2005,2017 Free Software Foundation, Inc. # +# # +# Permission is hereby granted, free of charge, to any person obtaining a # +# copy of this software and associated documentation files (the "Software"), # +# to deal in the Software without restriction, including without limitation # +# the rights to use, copy, modify, merge, publish, distribute, distribute # +# with modifications, sublicense, and/or sell copies of the Software, and to # +# permit persons to whom the Software is furnished to do so, subject to the # +# following conditions: # +# # +# The above copyright notice and this permission notice shall be included in # +# all copies or substantial portions of the Software. # +# # +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # +# THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # +# DEALINGS IN THE SOFTWARE. # +# # +# Except as contained in this notice, the name(s) of the above copyright # +# holders shall not be used in advertising or otherwise to promote the sale, # +# use or other dealings in this Software without prior written # +# authorization. # +############################################################################## # tracemunch -- compactify ncurses trace logs # # The error logs produced by ncurses with tracing enabled can be very tedious # to wade through. This script helps by compacting runs of log lines that # can be conveniently expressed as higher-level operations. -# -# ($Id: tracemunch,v 1.2 1995/10/06 15:02:37 esr Exp $) -$putattr="PutAttrChar\\('(.)' = 0x.., {A_NORMAL}\\) at \\(([0-9]+), ([0-9]+)\\)"; -$waddnstr="waddnstr\\(0x([0-9a-f]+),\"([^\"]+)\",[0-9]+\\) called {A_NORMAL}"; +use strict; +use warnings; + +$| = 1; -sub transaddr -{ - $arg = $_[0]; +our $putattr = + 'PutAttrChar\(\{\{ ' . "'(.)'" + . ' = 0[0-7]+ \}\}\) at \(([0-9]+), ([0-9]+)\)'; +our $waddnstr = + 'waddnstr\(0x([[:xdigit:]]+),"([^\"]+)",[0-9]+\) called \{A_NORMAL\}'; - $arg =~ s/$curscr/curscr/ if ($curscr); - $arg =~ s/$newscr/newscr/ if ($newscr); - $arg =~ s/$stdscr/stdscr/ if ($stdscr); +# If the trace is complete, we can infer addresses using the return value from +# newwin, etc. But if it is incomplete, we can still check for special cases +# such as SCREEN* and WINDOW* parameters. In this table, the type for the +# first parameter is encoded, relying upon an ncurses programming convention: +# 1 = SCREEN* +# 2 = WINDOW* +# 4 = TERMINAL* +our %known_p1 = qw( + TransformLine 1 + _nc_freewin 2 + _nc_initscr 1 + _nc_makenew 1 + _nc_mingw_console_read 1 + _nc_reset_colors 1 + _nc_scroll_optimize 1 + _nc_tinfo 1 + _nc_tinfo_mvcur 1 + _nc_wgetch 2 + adjust_window 2 + assume_default_colors 1 + attr_get 2 + baudrate 1 + beep 1 + border_set 2 + box 2 + box_set 2 + can_change_color 1 + cbreak 1 + clearok 2 + color_content 1 + copywin 2 + curs_set 1 + decrease_size 1 + def_prog_mode 1 + def_shell_mode 1 + define_key 1 + del_curterm 1 + delay_output 1 + delscreen 1 + delwin 2 + derwin 2 + doupdate 1 + dupwin 2 + echo 1 + endwin 1 + erasechar 1 + filter 1 + flash 1 + flushinp 1 + getattrs 2 + getbegx 2 + getbegy 2 + getbkgd 2 + getcurx 2 + getcury 2 + getmaxx 2 + getmaxy 2 + getmouse 1 + getparx 2 + getpary 2 + halfdelay 1 + has_ic 1 + has_il 1 + has_key 1 + idcok 2 + idlok 2 + immedok 2 + increase_size 1 + init_color 1 + init_pair 1 + intrflush 1 + is_cleared 2 + is_idcok 2 + is_idlok 2 + is_immedok 2 + is_keypad 2 + is_leaveok 2 + is_linetouched 2 + is_nodelay 2 + is_notimeout 2 + is_pad 2 + is_scrollok 2 + is_subwin 2 + is_syncok 2 + is_term_resized 1 + is_wintouched 2 + key_defined 1 + keybound 1 + keyok 1 + keypad 2 + killchar 1 + leaveok 2 + longname 1 + meta 2 + mouseinterval 1 + mousemask 1 + mvcur 1 + mvderwin 2 + mvwadd_wch 2 + mvwadd_wchnstr 2 + mvwadd_wchstr 2 + mvwaddch 2 + mvwaddchnstr 2 + mvwaddchstr 2 + mvwaddnstr 2 + mvwaddnwstr 2 + mvwaddstr 2 + mvwaddwstr 2 + mvwchgat 2 + mvwdelch 2 + mvwget_wch 2 + mvwget_wstr 2 + mvwgetch 2 + mvwgetn_wstr 2 + mvwgetnstr 2 + mvwgetstr 2 + mvwhline 2 + mvwhline_set 2 + mvwin 2 + mvwin_wch 2 + mvwin_wchnstr 2 + mvwin_wchstr 2 + mvwinch 2 + mvwinchnstr 2 + mvwinchstr 2 + mvwins_nwstr 2 + mvwins_wch 2 + mvwins_wstr 2 + mvwinsch 2 + mvwinsnstr 2 + mvwinsstr 2 + mvwinstr 2 + mvwinwstr 2 + mvwvline 2 + mvwvline_set 2 + newpad 1 + newterm 1 + newwin 1 + nl 1 + nocbreak 1 + nodelay 2 + noecho 1 + nofilter 1 + nonl 1 + noqiflush 1 + noraw 1 + notimeout 2 + overlap 2 + overlay 2 + overwrite 2 + pair_content 1 + pecho_wchar 2 + pechochar 2 + pnoutrefresh 2 + putwin 2 + qiflush 1 + raw 1 + redrawwin 2 + reset_prog_mode 1 + reset_shell_mode 1 + resetty 1 + resize_term 1 + resizeterm 1 + restartterm 1 + ripoffline 1 + savetty 1 + scr_init 1 + scr_restore 1 + scr_set 1 + scroll 2 + scrollok 2 + set_curterm 4 + set_term 1 + slk_attr 1 + slk_attr_set 1 + slk_attroff 1 + slk_attron 1 + slk_attrset 1 + slk_clear 1 + slk_color 1 + slk_init 1 + slk_label 1 + slk_noutrefresh 1 + slk_refresh 1 + slk_restore 1 + slk_set 1 + slk_touch 1 + start_color 1 + subwin 2 + syncok 2 + termattrs 1 + termname 1 + tgetflag 1 + tgetnum 1 + tigetflag 1 + tigetnum 1 + tigetstr 1 + tinfo 1 + touchline 2 + touchwin 2 + typeahead 1 + unget_wch 1 + ungetch 1 + ungetmouse 1 + untouchwin 2 + use_default_colors 1 + use_env 1 + use_legacy_coding 1 + use_screen 1 + use_tioctl 1 + use_window 2 + vidattr 1 + vidputs 1 + vw_printw 2 + vwprintw 2 + wadd_wch 2 + wadd_wchnstr 2 + wadd_wchstr 2 + waddch 2 + waddchnstr 2 + waddchstr 2 + waddnstr 2 + waddnwstr 2 + waddstr 2 + waddwstr 2 + wattr_get 2 + wattr_off 2 + wattr_on 2 + wattr_set 2 + wattroff 2 + wattron 2 + wattrset 2 + wbkgd 2 + wbkgdset 2 + wborder 2 + wborder_set 2 + wchgat 2 + wclear 2 + wclrtobot 2 + wclrtoeol 2 + wcolor_set 2 + wcursyncup 2 + wdelch 2 + wdeleteln 2 + wechochar 2 + wenclose 2 + werase 2 + wget_wch 2 + wget_wstr 2 + wgetbkgrnd 2 + wgetch 2 + wgetch_events 2 + wgetdelay 2 + wgetn_wstr 2 + wgetnstr 2 + wgetparent 2 + wgetscrreg 2 + wgetstr 2 + whline 2 + whline_set 2 + win_wch 2 + win_wchnstr 2 + win_wchstr 2 + winch 2 + winchnstr 2 + winchstr 2 + winnstr 2 + winnwstr 2 + wins_nwstr 2 + wins_wch 2 + wins_wstr 2 + winsch 2 + winsdelln 2 + winsertln 2 + winsnstr 2 + winsstr 2 + winstr 2 + winwstr 2 + wmouse_trafo 2 + wmove 2 + wnoutrefresh 2 + wprintw 2 + wredrawln 2 + wrefresh 2 + wresize 2 + wscrl 2 + wsetscrreg 2 + wstandend 2 + wstandout 2 + wsyncdown 2 + wsyncup 2 + wtimeout 2 + wtouchln 2 + wvline 2 +); + +our $scr_nums = 0; +our $thr_nums = 0; +our $trm_nums = 0; +our $try_nums = 0; +our $win_nums = 0; +our $curscr = ""; +our $newscr = ""; +our $stdscr = ""; +our %scr_addr; +our %thr_addr; +our %trm_addr; +our %try_addr; +our %win_addr; + +sub has_addr($) { + my $value = shift; + my $result = 0; + $result = 1 if ( $value =~ /\b0x[[:xdigit:]]+\b/i ); + return $result; +} + +sub transaddr($) { + my $arg = shift; + my $n; + + $arg =~ s/\b$curscr\b/curscr/g if ($curscr); + $arg =~ s/\b$newscr\b/newscr/g if ($newscr); + $arg =~ s/\b$stdscr\b/stdscr/g if ($stdscr); + if ( &has_addr($arg) ) { + foreach my $addr ( keys %scr_addr ) { + $n = $scr_addr{$addr}; + $arg =~ s/\b$addr\b/screen$n/g if ( defined $n ); + } + } + if ( &has_addr($arg) ) { + foreach my $addr ( keys %thr_addr ) { + $n = $thr_addr{$addr}; + $arg =~ s/\b$addr\b/thread$n/g if ( defined $n ); + } + } + if ( &has_addr($arg) ) { + foreach my $addr ( keys %trm_addr ) { + $n = $trm_addr{$addr}; + $arg =~ s/\b$addr\b/terminal$n/g if ( defined $n ); + } + } + if ( &has_addr($arg) ) { + foreach my $addr ( keys %try_addr ) { + $n = $try_addr{$addr}; + $arg =~ s/\b$addr\b/tries_$n/g if ( defined $n ); + } + } + if ( &has_addr($arg) ) { + foreach my $addr ( keys %win_addr ) { + $n = $win_addr{$addr}; + $arg =~ s/\b$addr\b/window$n/g if ( defined $n ); + } + } + if ( &has_addr($arg) ) { + if ( $arg =~ /add_wch\((window\d+,)?0x[[:xdigit:]]+\)/i ) { + $arg =~ s/(0x[[:xdigit:]]+)[)]/\&wch)/i; + } + elsif ( + $arg =~ /color_content\((screen\d+,)?\d+(,0x[[:xdigit:]]+){3}/i ) + { + $arg =~ s/(,0x[[:xdigit:]]+){3}[)]/,\&r,\&g,\&b)/i; + } + elsif ( $arg =~ /pair_content\((screen\d+,)?\d+(,0x[[:xdigit:]]+){2}/i ) + { + $arg =~ s/(,0x[[:xdigit:]]+){2}[)]/,\&fg,\&bg)/i; + } + } + if ( &has_addr($arg) and $arg =~ /called\s+\{/ ) { + my $func = $arg; + chomp $func; + $func =~ s/^.*called\s+\{([[:alnum:]_]+)\(.*$/$1/; + if ( defined $known_p1{$func} ) { + my $addr = $arg; + my $type = $known_p1{$func}; + chomp $addr; + $addr =~ s/^[^(]+\((0x[[:xdigit:]]+).*/$1/i; + if ( $addr !~ /^0x[[:xdigit:]]+$/i ) { + printf "OOPS - expected type #$type, skipping\n>>$addr\n"; + } + elsif ( $type == 1 ) { + $scr_addr{$addr} = ++$scr_nums; + $arg = &transaddr($arg); + } + elsif ( $type == 2 ) { + $win_addr{$addr} = ++$win_nums; + $arg = &transaddr($arg); + } + elsif ( $type == 4 ) { + $trm_addr{$addr} = ++$trm_nums; + $arg = &transaddr($arg); + } + } + } return $arg; } -while () -{ -CLASSIFY: { - # Transform window pointer addresses so it's easier to compare logs - $awaiting = "curscr" if ($_ =~ /creating curscr/); - $awaiting = "newscr" if ($_ =~ /creating newscr/); - $awaiting = "stdscr" if ($_ =~ /creating stdscr/); - if ($awaiting && $_ =~ /newwin: returned window is 0x([0-9a-f]+)/) - { - $curscr = "0x$1" if ($awaiting eq "curscr"); - $newscr = "0x$1" if ($awaiting eq "newscr"); - $stdscr = "0x$1" if ($awaiting eq "stdscr"); - $awaiting = ""; - } - - # Compactify runs of PutAttrChar calls (TR_CHARPUT) - if ($_ =~ /$putattr/) - { - $putattr_chars = $1; - $starty = $2; - $startx = $3; - while () - { - if ($_ =~ /$putattr/) { - $putattr_chars .= $1; - } else { - last; - } - } - print "RUN of PutAttrChar()s: \"$putattr_chars\" from ${starty}, ${startx}\n"; - redo CLASSIFY; - } - - # Compactify runs of waddnstr calls (TR_CALLS) - if ($_ =~ /$waddnstr/) - { - $waddnstr_chars = $2; - $winaddr = $1; - while () - { - if ($_ =~ /$waddnstr/ && $1 eq $winaddr) { - $waddnstr_chars .= $2; - } else { - last; - } - } - $winaddstr = &transaddr($winaddr); - print "RUN of waddnstr()s: $winaddr, \"$waddnstr_chars\"\n"; - redo CLASSIFY; - } - - # More transformations can go here - - # Repeated runs of anything - $anyline = &transaddr($_); - $repeatcount = 1; - while () { - if (&transaddr($_) eq $anyline) { - $repeatcount++; - } else { - last; - } - } - if ($repeatcount > 1) { - print "${repeatcount} REPEATS OF $anyline"; - } else { - print $anyline - } - redo CLASSIFY if $_; - - } # :CLASSIFY +sub muncher($) { + my $STDIN = shift; + + while (<$STDIN>) { + my $addr; + my $n; + my $awaiting = ""; + + CLASSIFY: { + + # just in case someone tries a file with cr/lf line-endings: + $_ =~ s/\r\n/\n/g; + $_ =~ s/\r/\n/g; + + my $thread = ""; + if ( $_ =~ /^(0x[[:xdigit:]]+):/ ) { + $thr_addr{$1} = ++$thr_nums unless defined $thr_addr{$1}; + $thread = "thread" . $thr_addr{$1} . ":"; + $_ =~ s/^[^:]*://; + } + + # Transform window pointer addresses so it's easier to compare logs + $awaiting = "curscr" if ( $_ =~ /creating curscr/ ); + $awaiting = "newscr" if ( $_ =~ /creating newscr/ ); + $awaiting = "stdscr" if ( $_ =~ /creating stdscr/ ); + $awaiting = "screen" if ( $_ =~ /^(\+ )*called \{new_prescr\(\)/ ); + if ( $_ =~ /^create :window 0x([[:xdigit:]]+)/ ) { + $addr = "0x$1"; + if ( $awaiting eq "curscr" ) { + $curscr = $addr; + } + elsif ( $awaiting eq "newscr" ) { + $newscr = $addr; + } + elsif ( $awaiting eq "stdscr" ) { + $stdscr = $addr; + } + else { + $win_addr{$addr} = $win_nums++; + } + $awaiting = ""; + } + elsif ( $_ =~ /^(\+ )*called \{set_curterm\((0x[[:xdigit:]]+)\)/ ) { + $trm_addr{$2} = ++$trm_nums unless defined $trm_addr{$2}; + } + elsif ( $_ =~ /^(\+ )*called \{_nc_add_to_try\((0x[[:xdigit:]]+),/ ) + { + $try_addr{$2} = ++$try_nums unless defined $try_addr{$2}; + } + elsif ( $_ =~ /^(\+ )*_nc_alloc_screen_sp 0x([[:xdigit:]]+)/ ) { + $addr = "0x$2"; + $scr_addr{$addr} = ++$scr_nums unless ( $scr_addr{$addr} ); + $awaiting = ""; + } + elsif ( $_ =~ /^(\+ )*return }0x([[:xdigit:]]+)/ ) { + $addr = "0x$2"; + if ( $awaiting eq "screen" ) { + $scr_addr{$addr} = ++$scr_nums unless ( $scr_addr{$addr} ); + } + } + elsif ( $_ =~ /^\.\.\.deleted win=0x([[:xdigit:]]+)/ ) { + $addr = "0x$1"; + $_ = &transaddr($_); + if ( $addr eq $curscr ) { + $curscr = ""; + } + elsif ( $addr eq $newscr ) { + $newscr = ""; + } + elsif ( $addr eq $stdscr ) { + $stdscr = ""; + } + else { + undef $win_addr{$addr}; + } + } + + # Compactify runs of PutAttrChar calls (TR_CHARPUT) + if ( $_ =~ /$putattr/ ) { + my $putattr_chars = $1; + my $starty = $2; + my $startx = $3; + while (<$STDIN>) { + if ( $_ =~ /$putattr/ ) { + $putattr_chars .= $1; + } + else { + last; + } + } + print +"RUN of PutAttrChar()s: \"$putattr_chars\" from ${starty}, ${startx}\n"; + redo CLASSIFY; + } + + # Compactify runs of waddnstr calls (TR_CALLS) + if ( $_ =~ /$waddnstr/ ) { + my $waddnstr_chars = $2; + my $winaddr = $1; + while (<$STDIN>) { + if ( $_ =~ /$waddnstr/ && $1 eq $winaddr ) { + $waddnstr_chars .= $2; + } + else { + last; + } + } + my $winaddstr = &transaddr($winaddr); + print "RUN of waddnstr()s: $winaddr, \"$waddnstr_chars\"\n"; + redo CLASSIFY; + } + + # More transformations can go here + + # Repeated runs of anything + my $anyline = &transaddr($_); + my $repeatcount = 1; + while (<$STDIN>) { + if ( &transaddr($_) eq $anyline ) { + $repeatcount++; + } + else { + last; + } + } + if ( $repeatcount > 1 ) { + print "${repeatcount} REPEATS OF $anyline"; + } + else { + print $thread . $anyline; + } + redo CLASSIFY if $_; + + } # :CLASSIFY + } +} + +if ( $#ARGV >= 0 ) { + while ( $#ARGV >= 0 ) { + my $file = shift @ARGV; + open my $ifh, "<", $file or die $!; + &muncher($ifh); + } +} +else { + &muncher( \*STDIN ); } # tracemunch ends here