blob: 20314bfabf90430467398f674374db416c0e6f2f [file] [log] [blame]
# 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 <Return> "$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}
}