# Tracepoint actions dialog for Insight. # Copyright (C) 1997, 1998, 1999, 2001 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License (GPL) as published by # the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. itcl::class ActionDlg { inherit ManagedWin # ------------------------------------------------------------------ # CONSTRUCTOR # ------------------------------------------------------------------ constructor {args} { global _TStepCount _TOtherVariable eval itk_initialize $args set Registers [gdb_reginfo name] if {$Line != ""} { set Locals [gdb_get_locals "$File:$Line"] set Args [gdb_get_args "$File:$Line"] } else { set Locals [gdb_get_locals "*$Address"] set Args [gdb_get_args "*$Address"] } set Variables [concat $Locals $Args] foreach a $Registers { lappend Variables "\$$a" } if {[llength $Args] > 0} { lappend Variables "All Arguments" } if {[llength $Locals] > 0} { lappend Variables "All Locals" } lappend Variables "All Registers" lappend Variables "Collect Stack" build_win # Set a default return status, in case we are destroyed set _TOtherVariable {} # Fill the listboxes with any default data if {"$Data" != {}} { change 1 $Data } } # ------------------------------------------------------------------ # DESTRUCTOR - destroy window containing widget # ------------------------------------------------------------------ destructor { # Remove this window and all hooks # grab release $this # Note that this is okay: the callback (TraceDlg::done, usually) will # ignore stray "cancel" callbacks eval $Callback cancel } # ------------------------------------------------------------------ # METHOD: build_win - build the Trace dialog box (cache this?) # ------------------------------------------------------------------ method build_win {} { global _TStepCount _TOtherVariable set f $itk_interior # The two frames of this dialog set bbox [frame $f.bbox]; # for holding OK,CANCEL buttons set data [frame $f.data]; # for everything else # Setup the button box button $bbox.ok -text OK -command "$this ok" button $bbox.cancel -text CANCEL -command "$this cancel" pack $bbox.ok $bbox.cancel -side left -padx 10 -expand yes # The "Data Collection" Frame set top [frame $data.top] set bot [frame $data.bot] set boxes [frame $top.boxes] set cFrame [frame $boxes.cFrame] set vFrame [frame $boxes.vFrame] set bFrame [frame $boxes.bframe] set oFrame [frame $top.uFrame] pack $cFrame $bFrame $vFrame -side left -expand yes -padx 5 # While stepping if {$WhileStepping} { set step_frame [frame $top.stepf] label $step_frame.whilelbl -text {While Stepping, Steps:} set WhileSteppingEntry [entry $step_frame.steps \ -textvariable _TStepCount \ -width 5] pack $step_frame.whilelbl $WhileSteppingEntry -side left } # The Collect listbox label $cFrame.lbl -text {Collect:} set CollectLB [iwidgets::scrolledlistbox $cFrame.lb -hscrollmode dynamic \ -vscrollmode dynamic \ -selectioncommand [code $this toggle_button_state 0] \ -dblclickcommand [code $this change 0] \ -selectmode extended \ -exportselection false] [$CollectLB component listbox] configure -background gray92 pack $cFrame.lbl $cFrame.lb -side top -expand yes -pady 2 # The Variables listbox label $vFrame.lbl -text {Variables:} set VariablesLB [iwidgets::scrolledlistbox $vFrame.lb -hscrollmode dynamic \ -vscrollmode dynamic \ -selectioncommand [code $this toggle_button_state 1] \ -dblclickcommand [code $this change 1] \ -selectmode extended \ -exportselection false] [$VariablesLB component listbox] configure -background gray92 pack $vFrame.lbl $vFrame.lb -side top -expand yes -pady 2 # The button frame set AddButton [button $bFrame.add -text {<<< Collect} \ -command "$this change 1" -state disabled] set RemoveButton [button $bFrame.del -text {Ignore >>>} \ -command "$this change 0" -state disabled] pack $bFrame.add $bFrame.del -side top -expand yes -pady 5 # The other frame (type-in) label $oFrame.lbl -text {Other:} set OtherEntry [entry $oFrame.ent -textvariable _TOtherVariable] pack $oFrame.lbl $OtherEntry -side left bind $OtherEntry "$this change_other" # Pack these frames if {$WhileStepping} { pack $step_frame -side top } pack $boxes $oFrame -side top -padx 5 -pady 5 pack $top $bot -side top # Fill the list boxes fill_listboxes # Pack the main frames # after idle pack $f.data $bbox -side top -padx 4 -pady 2 \ -expand yes -fill x # !!??? if {$WhileStepping} { $WhileSteppingEntry delete 0 end $WhileSteppingEntry insert 0 $Steps } } method toggle_button_state {add} { # This is invoked whenever a <1> event is generated in # the listbox... if {$add} { set a [$VariablesLB getcurselection] if {"$a" != ""} { $AddButton configure -state normal $RemoveButton configure -state disabled } } else { set a [$CollectLB getcurselection] if {"$a" != ""} { $AddButton configure -state disabled $RemoveButton configure -state normal } } } # ------------------------------------------------------------------ # METHOD: fill_listboxes - fills the two listboxes # ------------------------------------------------------------------ method fill_listboxes {{last {}}} { # Fill the Collect listbox with the variables being collected if {[info exists Collect]} { fill_collect $last } fill_variables $last } # ------------------------------------------------------------------ # METHOD: change - change a selected variable # ------------------------------------------------------------------ method change {add {select {}}} { if {"$select" == {}} { set selections [get_selections $add] set lb [lindex $selections 0] set last [lindex $selections 1] set selection [lindex $selections 2] set noname 1 } else { # This usually (only) occurs when we open this dialog for editing # some existing action. set lb {} set last {} set noname 0 set selection $select } $RemoveButton configure -state disabled $AddButton configure -state disabled # Remove all the selections from one list # and add them to the other list if {$add} { set list1 $Variables set list2 $Collect } else { set list1 $Collect set list2 $Variables } foreach a $selection { if {$noname} { set name [$lb get $a] } else { set name $a } if {"$name" == "All Locals" || "$name" == {$loc}} { set name "All Locals" set lists [all_locals $add] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } elseif {"$name" == "All Registers" || "$name" == {$reg}} { set name "All Registers" set lists [all_regs $add] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } elseif {"$name" == "All Arguments" || "$name" == {$arg}} { set name "All Arguments" set lists [all_args $add] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } else { set i [lsearch -exact $list1 $name] set list1 [lreplace $list1 $i $i] # Check if this is something we want to keep on a list if {[lsearch $Args $name] != -1 || [lsearch $Registers [string trim $name \$]] != -1 || [lsearch $Locals $name] != -1 || $add} { lappend list2 $name } } if {$add} { set Collect $list2 set Variables $list1 } else { set Collect $list1 set Variables $list2 } } # Update boxes (!! SLOW !!) fill_collect $last fill_variables $last } # ------------------------------------------------------------------ # METHOD: fill_collect - fill the collect box # ------------------------------------------------------------------ method fill_collect {{last {}}} { $CollectLB delete 0 end set Collect [sort $Collect] foreach a $Collect { $CollectLB insert end $a } if {"$last" != ""} { $CollectLB see $last } } # ------------------------------------------------------------------ # METHOD: fill_variables - fill the variables box # ------------------------------------------------------------------ method fill_variables {{last {}}} { $VariablesLB delete 0 end set Variables [sort $Variables] foreach a $Variables { $VariablesLB insert end $a } if {"$last" != ""} { $VariablesLB see $last } } # ------------------------------------------------------------------ # METHOD: sort - sort a list of variables, placing regs and # special identifiers (like "All Locals") at end # ------------------------------------------------------------------ method sort {list} { set special_names { "All Arguments" args \ "All Locals" locs \ "All Registers" regs \ "Collect Stack" stack } foreach {name var} $special_names { set i [lsearch $list $name] if {$i != -1} { set $var 1 set list [lreplace $list $i $i] } else { set $var 0 } } # Extract all the locals, regs, args, globals set types_list {Args Locals Registers } foreach type $types_list { set used_$type {} foreach a [set $type] { set i [lsearch $list $a] if {$i != -1} { lappend used_$type $a set list [lreplace $list $i $i] } } set used_$type [lsort [set used_$type]] } set globals [lsort $list] # Sort the remaining list in order: args, locals, globals, regs set list [concat $used_Args $used_Locals $globals $used_Registers] set list2 {} foreach {name var} $special_names { if {[set $var]} { lappend list2 $name } } set list [concat $list2 $list] return $list } # ------------------------------------------------------------------ # METHOD: all_args - add/remove all args # ------------------------------------------------------------------ method all_args {add} { if {$add} { set list1 $Variables set list2 $Collect } else { set list1 $Collect set list2 $Variables } # foreach var $Args { # set i [lsearch $list1 $var] # if {$i != -1} { # set list1 [lreplace $list1 $i $i] # lappend list2 $var # } # } lappend list2 "All Arguments" set i [lsearch $list1 "All Arguments"] if {$i != -1} { set list1 [lreplace $list1 $i $i] } return [list $list1 $list2] } # ------------------------------------------------------------------ # METHOD: all_locals - add/remove all locals # ------------------------------------------------------------------ method all_locals {add} { if {$add} { set list1 $Variables set list2 $Collect } else { set list1 $Collect set list2 $Variables } # foreach var $Locals { # set i [lsearch $list1 $var] # if {$i != -1} { # set list1 [lreplace $list1 $i $i] # lappend list2 $var # } # } lappend list2 "All Locals" set i [lsearch $list1 "All Locals"] if {$i != -1} { set list1 [lreplace $list1 $i $i] } return [list $list1 $list2] } # ------------------------------------------------------------------ # METHOD: all_regs - add/remove all registers # ------------------------------------------------------------------ method all_regs {add} { if {$add} { set list1 $Variables set list2 $Collect } else { set list1 $Collect set list2 $Variables } # foreach var $Registers { # set i [lsearch $list1 "\$$var"] # if {$i != -1} { # set list1 [lreplace $list1 $i $i] # lappend list2 "\$$var" # } # } lappend list2 "All Registers" set i [lsearch $list1 "All Registers"] if {$i != -1} { set list1 [lreplace $list1 $i $i] } return [list $list1 $list2] } # ------------------------------------------------------------------ # METHOD: change_other - add/remove a user defined type # ------------------------------------------------------------------ method change_other {} { set other [$OtherEntry get] if {"$other" != ""} { set added 0 # Check if this is a local/register/arg set i [lsearch $Locals "$other"] if {$i != -1} { set i [lsearch $Collect "$other"] set added 1 if {$i != -1} { # It's a local on the collection list debug "local on collection list" set add 0 set list1 [lreplace $Collect $i $i] set list2 [concat $Variables "$other"] } else { # It's a local on the variables list debug "local on variable list" set add 1 set i [lsearch $Variables "$other"] set list1 [lreplace $Variables $i $i] set list2 [concat $Collect "$other"] } } set i [lsearch $Registers [string trim "$other" \$]] if {$i != -1} { set i [lsearch $Collect "$other"] set added 1 if {$i != -1} { # It's a register on the collection list debug "register on collection list" set add 0 set list1 [lreplace $Collect $i $i] set list2 [concat $Variables "$other"] } else { # It's a register on the variables list debug "register on variable list" set add 1 set i [lsearch $Variables "$other"] set list1 [lreplace $Variables $i $i] set list2 [concat $Collect "$other"] } } set i [lsearch $Args $other] if {$i != -1} { set i [lsearch $Collect "$other"] set added 1 if {$i != -1} { # It's an arg on the collection list debug "arg on collection list" set add 0 set list1 [lreplace $Collect $i $i] set list2 [concat $Variables "$other"] } else { # It's an arg on the variables list debug "arg on variable list" set add 1 set i [lsearch $Variables "$other"] set list1 [lreplace $Variables $i $i] set list2 [concat $Collect "$other"] } } # Check for special tags if {!$added} { if {"[string tolower $other]" == "all locals"} { set i [lsearch $Variables "All Locals"] if {$i != -1} { # It's "All Locals" on the variables list set add 1 set lists [all_locals 1] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } else { # It's "All Locals" on the Collect list set add 0 set lists [all_locals 0] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } } elseif {"[string tolower $other]" == "all registers"} { set i [lsearch $Variables "All Registers"] if {$i != -1} { # It's "All Registers" on the Variables list set add 1 set lists [all_regs 1] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } else { set add 0 set lists [all_regs 0] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } } elseif {"[string tolower $other]" == "all arguments"} { set i [lsearch $Variables "All Arguments"] if {$i != -1} { # It's "All Arguments" on the Variables list set add 1 set lists [all_args 1] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } else { set add 0 set lists [all_args 0] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } } elseif {"[string tolower $other]" == "collect stack"} { set i [lsearch $Variables "Collect Stack"] if {$i != -1} { # It's "All Arguments" on the Variables list set add 1 set lists [all_args 1] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } else { set add 0 set lists [all_args 0] set list1 [lindex $lists 0] set list2 [lindex $lists 1] } } else { # Check if this entry is on the Collect list set i [lsearch $Collect $other] if {$i != -1} { # It's on the list -- remove it set add 0 set list1 [lreplace $Collect $i $i] set list2 $Variables } else { # It's not on the list -- add it set other [string trim $other \ \r\t\n] # accept everything, send to gdb to validate set ok 1 # memranges will be rejected right here if {[string range $other 0 1] == "\$("} { tk_messageBox -type ok -icon error \ -message "Expression syntax not supported" set ok 0 } # do all syntax checking later if {$ok} { #debug "Keeping \"$other\"" # We MUST string out all spaces... if {[regsub -all { } $other {} expression]} { set other $expression } set add 1 set list1 $Variables set list2 [concat $Collect "$other"] } else { #debug "Discarding \"$other\"" } } } } # Clear the entry $OtherEntry delete 0 end if {$add} { set Variables $list1 set Collect $list2 } else { set Variables $list2 set Collect $list1 } fill_listboxes } } # ------------------------------------------------------------------ # METHOD: get_selections - get all the selected variables # pass 0 to get the selections from the collect box # Returns a list of: listbox in which the selections were # obtained, last element selected on the list, and all the # selected elements # ------------------------------------------------------------------ method get_selections {vars} { if {$vars} { set widget $VariablesLB } else { set widget $CollectLB } set elements [$widget curselection] set list {} set i 0 foreach i $elements { lappend list [$widget get $i] } return [list $widget $i $elements] } # ------------------------------------------------------------------ # METHOD: cancel - cancel the dialog and do not set the trace # ------------------------------------------------------------------ method cancel {} { ::delete object $this } method remove_special {list items} { foreach item $items { set i [lsearch $list $item] if {$i != -1} { set list [lreplace $list $i $i] } else { set i [lsearch $list \$$item] if {$i != -1} { set list [lreplace $list $i $i] } } } return $list } # ------------------------------------------------------------------ # METHOD: ok - validate the tracepoint and install it # ------------------------------------------------------------------ method ok {} { global _TStepCount # Add anything in the OtherEntry change_other # Check that we are collecting data if {[llength $Collect] == 0} { # No data! set msg "No data specified for the given action." set answer [tk_messageBox -type ok -title "Tracepoint Error" \ -icon error \ -message $msg] case $answer { cancel { cancel } ok { return } } } set i [lsearch $Collect "All Locals"] if {$i != -1} { set data [lreplace $Collect $i $i] set data [concat $data {$loc}] # Remove all the locals from the list set data [remove_special $data $Locals] } else { set data $Collect } set i [lsearch $data "All Registers"] if {$i != -1} { set data [lreplace $data $i $i] set data [concat $data {$reg}] # Remove all the locals from the list set data [remove_special $data $Registers] } set i [lsearch $data "All Arguments"] if {$i != -1} { set data [lreplace $data $i $i] set data [concat $data {$arg}] # Remove all the locals from the list set data [remove_special $data $Args] } set i [lsearch $data "Collect Stack"] if {$i != -1} { set data [lreplace $data $i $i] set data [concat $data [collect_stack]] } # Remove repeats set d {} foreach i $data { if {![info exists check($i)]} { set check($i) 1 lappend d $i } } if {$WhileStepping} { set steps $_TStepCount } else { set steps 0 } if {"$Data" != {}} { set command "modify" } else { set command "add" } debug "DATA = $data" eval $Callback $command $steps [list $data] ::delete object $this } method collect_stack {} { return $StackCollect } method cmd {line} { $line } # PUBLIC DATA public variable File public variable Line {} public variable WhileStepping 0 public variable Number public variable Callback public variable Data {} public variable Steps {} public variable Address {} # PROTECTED DATA protected variable WhileSteppingEntry protected variable CollectLB protected variable VariablesLB protected variable Variables {} protected variable Collect {} protected variable Locals protected variable Args protected variable Registers protected variable Others {} protected variable AddButton protected variable RemoveButton protected variable OtherEntry protected variable StackCollect {*(char*)$sp@64} }