aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbtk.tcl
blob: 425041e87e6e9fb63b6f015b066f3f738e7ee756 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# GDB GUI setup

set cfile Blank
set wins($cfile) .text
set current_label {}
set screen_height 0
set screen_top 0
set screen_bot 0

proc test {} {
	update_listing {termcap.c foo /etc/termcap 200}
}

proc echo string {puts stdout $string}

proc gdbtk_tcl_fputs {arg} {
	.command.text insert end "$arg"
	.command.text yview -pickplace end
}

proc gdbtk_tcl_flush {} {update idletasks}

proc gdbtk_tcl_query {message} {
	tk_dialog .query "gdb : query" "$message" {} 1 "No" "Yes"
	}

if [info exists env(EDITOR)] then {
	set editor $env(EDITOR)
	} else {
	set editor emacs
}

proc gdbtk_tcl_start_variable_annotation {valaddr ref_type stor_cl cum_expr field type_cast} {
	echo "gdbtk_tcl_start_variable_annotation $valaddr $ref_type $stor_cl $cum_expr $field $type_cast"
}

proc gdbtk_tcl_end_variable_annotation {} {
	echo gdbtk_tcl_end_variable_annotation
}

proc insert_breakpoint_tag {win line} {
	$win configure -state normal
	$win delete $line.0
	$win insert $line.0 "B"
	$win tag add $line $line.0
	$win tag bind $line <1> {
#		echo "tag %W %X %Y %x"
#		echo "tag names [$wins($cfile) tag names]"
	}

	$win configure -state disabled
}

proc delete_breakpoint_tag {win line} {
	$win configure -state normal
	$win delete $line.0
	$win insert $line.0 " "
	$win tag delete $line
	$win configure -state disabled
}

# Callback from GDB to notify us of breakpoint creation.

proc create_breakpoint {bpnum file line} {
	global wins
	global breakpoint_file
	global breakpoint_line

# Record breakpoint locations

	set breakpoint_file($bpnum) $file
	set breakpoint_line($bpnum) $line
	
# If there isn't a window for this file, don't try to update it

	if [info exists wins($file)] {
		insert_breakpoint_tag $wins($file) $line
	}
}

proc delete_breakpoint {bpnum file line} {
	global wins
	global breakpoint_file
	global breakpoint_line

# Save line number for later

	set line $breakpoint_line($bpnum)

# Reset breakpoint annotation info

	unset breakpoint_file($bpnum)
	unset breakpoint_line($bpnum)

# If there isn't a window for this file, don't try to update it

	if [info exists wins($file)] {
		delete_breakpoint_tag $wins($file) $line
	}
}

# This is a callback from C code to notify us of breakpoint changes.  ACTION
# can be one of create, delete, enable, or disable.

proc gdbtk_tcl_breakpoint {action bpnum file line} {
	${action}_breakpoint $bpnum $file $line
}

# Create the popup listing window menu

menu .breakpoint -cursor hand2
.breakpoint add command -label Break
.breakpoint add separator
.breakpoint add command -label "Edit" -command {exec $editor +$selected_line $selected_file &}
.breakpoint add command -label "Set breakpoint" -command {gdb_cmd "break $selected_file:$selected_line"}
#.breakpoint add command -label "Clear breakpoint" -command {echo "Clear"}
#.breakpoint add command -label "Enable breakpoint" -command {echo "Enable"}
#.breakpoint add command -label "Disable breakpoint" -command {echo "Disable"}

# Come here when button is released in the popup menu

bind .breakpoint <Any-ButtonRelease-1> {
	global selected_win

# First, remove the menu, and release the pointer

	.breakpoint unpost
	grab release .breakpoint

# Unhighlight the selected line

	$selected_win tag delete breaktag
#	echo "after deleting $selected_win [$selected_win tag names]"
#	echo "grab [grab current]"

# Actually invoke the menubutton here!

	tk_invokeMenu %W
#	destroy .breakpoint
	grab release $selected_win
}

# Button 1 has been pressed in a listing window.  Pop up a menu.

proc breakpoint_menu {win x y xrel yrel} {
	global wins
	global win_to_file
	global file_to_debug_file
	global highlight
	global selected_line
	global selected_file
	global selected_win

	grab $win

#	echo "bpm grab current [grab current]"

# Map TK window name back to file name.

	set file $win_to_file($win)

	set pos [$win index @$xrel,$yrel]

# Record selected file and line for menu button actions

	set selected_file $file_to_debug_file($file)
	set selected_line [lindex [split $pos .] 0]
	set selected_win $win

# Highlight the selected line

	eval $win tag config breaktag $highlight
	$win tag add breaktag "$pos linestart" "$pos linestart + 1l"

# Post the menu near the pointer, (and grab it)

	.breakpoint post [expr $x-[winfo width .breakpoint]/2] [expr $y-10]
	grab .breakpoint
#	echo "after grab [grab current]"
}

proc do_nothing {} {}

proc create_file_win {filename} {
	global breakpoint_file
	global breakpoint_line

	regsub -all {\.|/} $filename {} temp
	set win .text$temp
	text $win -height 25 -width 80 -relief raised -borderwidth 2 -yscrollcommand textscrollproc -setgrid true -cursor hand2
	bind $win <Enter> {focus %W}
#	bind $win <1> {breakpoint_menu %W %X %Y %x %y}
	bind $win <B1-Motion> do_nothing
	bind $win n {gdb_cmd next ; update_ptr}
	bind $win s {gdb_cmd step ; update_ptr}
	bind $win c {gdb_cmd continue ; update_ptr}
	bind $win f {gdb_cmd finish ; update_ptr}
	bind $win u {gdb_cmd up ; update_ptr}
	bind $win d {gdb_cmd down ; update_ptr}
	set fh [open $filename]
	$win delete 0.0 end
	$win insert 0.0 [read $fh]
	close $fh
	set numlines [$win index end]
	set numlines [lindex [split $numlines .] 0]
	for {set i 1} {$i <= $numlines} {incr i} {
		$win insert $i.0 [format "   %4d " $i]
		}

	$win tag add wholebuf 0.0 end
	$win tag bind wholebuf <1> {breakpoint_menu %W %X %Y %x %y}
	foreach bpnum [array names breakpoint_file] {
		if {$breakpoint_file($bpnum) == $filename} {
			insert_breakpoint_tag $win $breakpoint_line($bpnum)
			}
		}

	$win configure -state disabled
	return $win
}

proc update_listing {linespec} {
	global pointers
	global screen_height
	global screen_top
	global screen_bot
	global wins cfile
	global current_label
	global win_to_file
	global file_to_debug_file

	set line [lindex $linespec 3]
	set filename [lindex $linespec 2]
	set funcname [lindex $linespec 1]
	set debug_file [lindex $linespec 0]

	if {$filename == ""} {set filename Blank}

	if {$filename != $cfile} then {
		pack forget $wins($cfile)
		set cfile $filename
		if ![info exists wins($cfile)] then {
			set wins($cfile) [create_file_win $cfile]
			set win_to_file($wins($cfile)) $cfile
			set file_to_debug_file($cfile) $debug_file
			set pointers($cfile) 1.1
			}

		pack $wins($cfile) -side left -expand yes -in .listing -fill both -after .label
		$wins($cfile) yview [expr $line - $screen_height / 2]
		}

	if {$current_label != "$filename.$funcname"} then {
		set tail [expr [string last / $filename] + 1]
		.label configure -text "[string range $filename $tail end] : ${funcname}()"
		set current_label $filename.$funcname
		}

	if [info exists pointers($cfile)] then {
		$wins($cfile) configure -state normal
		set pointer_pos $pointers($cfile)
		$wins($cfile) configure -state normal
		$wins($cfile) delete $pointer_pos
		$wins($cfile) insert $pointer_pos " "

		set pointer_pos [$wins($cfile) index $line.1]
		set pointers($cfile) $pointer_pos

		$wins($cfile) delete $pointer_pos
		$wins($cfile) insert $pointer_pos "\xbb"

		if {$line < $screen_top + 1
		    || $line > $screen_bot} then {
			$wins($cfile) yview [expr $line - $screen_height / 2]
			}

		$wins($cfile) configure -state disabled
		}
}

proc update_ptr {} {update_listing [gdb_loc]}

# Setup listing window

frame .listing

wm minsize . 1 1

label .label -text "*No file*" -borderwidth 2 -relief raised
text $wins($cfile) -height 25 -width 80 -relief raised -borderwidth 2 -yscrollcommand textscrollproc -setgrid true -cursor hand2
scrollbar .scroll -orient vertical -command {$wins($cfile) yview}

if {[tk colormodel .text] == "color"} {
	set highlight "-background red2 -borderwidth 2 -relief sunk"
} else {
	set fg [lindex [.text config -foreground] 4]
	set bg [lindex [.text config -background] 4]
	set highlight "-foreground $bg -background $fg -borderwidth 0"
}

proc textscrollproc {args} {global screen_height screen_top screen_bot
			    eval ".scroll set $args"
			    set screen_height [lindex $args 1]
			    set screen_top [lindex $args 2]
			    set screen_bot [lindex $args 3]}

$wins($cfile) insert 0.0 "  This page intentionally left blank."
$wins($cfile) configure -state disabled

pack .label -side bottom -fill x -in .listing
pack $wins($cfile) -side left -expand yes -in .listing -fill both
pack .scroll -side left -fill y -in .listing

button .start -text Start -command \
	{gdb_cmd {break main}
	 gdb_cmd {enable delete $bpnum}
	 gdb_cmd run
	 update_ptr }
button .step -text Step -command {gdb_cmd step ; update_ptr}
button .next -text Next -command {gdb_cmd next ; update_ptr}
button .continue -text Continue -command {gdb_cmd continue ; update_ptr}
button .finish -text Finish -command {gdb_cmd finish ; update_ptr}
#button .test -text Test -command {echo [info var]}
button .exit -text Exit -command {gdb_cmd quit}
button .up -text Up -command {gdb_cmd up ; update_ptr}
button .down -text Down -command {gdb_cmd down ; update_ptr}
button .bottom -text "Bottom" -command {gdb_cmd {frame 0} ; update_ptr}

proc files_command {} {
	toplevel .files_window

	wm minsize .files_window 1 1
#	wm overrideredirect .files_window true
	listbox .files_window.list -geometry 30x20 -setgrid true
	button .files_window.close -text Close -command {destroy .files_window}
	tk_listboxSingleSelect .files_window.list
	eval .files_window.list insert 0 [lsort [gdb_listfiles]]
	pack .files_window.list -side top -fill both -expand yes
	pack .files_window.close -side bottom -fill x -expand no -anchor s
	bind .files_window.list <Any-ButtonRelease-1> {
		set file [%W get [%W curselection]]
		gdb_cmd "list $file:1,0"
		update_listing [gdb_loc $file:1]
		destroy .files_window}
}

button .files -text Files -command files_command

pack .listing -side bottom -fill both -expand yes
#pack .test -side bottom -fill x
pack .start .step .next .continue .finish .up .down .bottom .files .exit -side left
toplevel .command

# Setup command window

label .command.label -text "* Command Buffer *" -borderwidth 2 -relief raised
text .command.text -height 25 -width 80 -relief raised -borderwidth 2 -setgrid true -cursor hand2

pack .command.label -side top -fill x
pack .command.text -side top -expand yes -fill both

set command_line {}

gdb_cmd {set language c}
gdb_cmd {set height 0}
gdb_cmd {set width 0}

bind .command.text <Any-Key> {
	global command_line

	%W insert end %A
	%W yview -pickplace end
	append command_line %A
	}
bind .command.text <Key-Return> {
	global command_line

	%W insert end \n
	%W yview -pickplace end
	gdb_cmd $command_line
	set command_line {}
	update_ptr
	%W insert end "(gdb) "
	%W yview -pickplace end
	}
bind .command.text <Enter> {focus %W}
bind .command.text <Delete> {delete_char %W}
bind .command.text <BackSpace> {delete_char %W}
proc delete_char {win} {
	global command_line

	tk_textBackspace $win
	$win yview -pickplace insert
	set tmp [expr [string length $command_line] - 2]
	set command_line [string range $command_line 0 $tmp]
}

wm minsize .command 1 1