GDB (API)
|
00001 # Local preferences functions for Insight. 00002 # Copyright (C) 2000, 2001, 2002, 2004, 2008 Red Hat, Inc. 00003 # 00004 # This program is free software; you can redistribute it and/or modify it 00005 # under the terms of the GNU General Public License (GPL) as published by 00006 # the Free Software Foundation; either version 2 of the License, or (at 00007 # your option) any later version. 00008 # 00009 # This program is distributed in the hope that it will be useful, 00010 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 # GNU General Public License for more details. 00013 00014 namespace eval Session { 00015 namespace export save load notice_file_change delete list_names 00016 00017 # An internal function for canonicalizing path names. This probably 00018 # should use `realpath', but that is more work. So for now we neglect 00019 # the possibility of symlinks. 00020 proc _exe_name {path} { 00021 00022 # Get real directory. 00023 if {[string compare $::gdbtk_platform(os) "cygwin"] == 0} { 00024 set path [ide_cygwin_path to_win32 $path] 00025 } 00026 set save [pwd] 00027 cd [file dirname $path] 00028 set dir [pwd] 00029 cd $save 00030 return [file join $dir [file tail $path]] 00031 } 00032 00033 # An internal function used when saving sessions. Returns a string 00034 # that can be used to recreate all pertinent breakpoint state. 00035 proc _serialize_bps {} { 00036 set result {} 00037 00038 # HACK. When debugging gdb with itself in the build 00039 # directory, there is a ".gdbinit" file that will set 00040 # breakpoints on internal_error() and info_command(). 00041 # If we then save and set them, they will accumulate. 00042 # Possible fixes are to modify GDB so we can tell which 00043 # breakpoints were set from .gdbinit, or modify 00044 # _recreate_bps to record which breakpoints were 00045 # set before it was called. For now, we simply detect the 00046 # most common case and fix it. 00047 set basename [string tolower [file tail $::gdb_exe_name]] 00048 if {[string match "gdb*" $basename] 00049 || [string match "insight*" $basename]} { 00050 set debugging_gdb 1 00051 } else { 00052 set debugging_gdb 0 00053 } 00054 00055 foreach bp_num [gdb_get_breakpoint_list] { 00056 lassign [gdb_get_breakpoint_info $bp_num] file function line_number \ 00057 address type enabled disposition ignore_count command_list \ 00058 condition thread hit_count user_specification 00059 00060 # These breakpoints are set when debugging GDB with itself. 00061 # Ignore them so they don't accumulate. They get set again 00062 # by .gdbinit anyway. 00063 if {$debugging_gdb} { 00064 if {$function == "internal_error" || $function == "info_command"} { 00065 continue 00066 } 00067 } 00068 00069 switch -glob -- $type { 00070 "breakpoint" - 00071 "hw breakpoint" { 00072 if {$disposition == "delete"} { 00073 set cmd tbreak 00074 } else { 00075 set cmd break 00076 } 00077 00078 append cmd " " 00079 if {$user_specification != ""} { 00080 append cmd "$user_specification" 00081 } elseif {$file != ""} { 00082 # BpWin::bp_store uses file tail here, but I think that is 00083 # wrong. 00084 append cmd "$file:$line_number" 00085 } else { 00086 append cmd "*$address" 00087 } 00088 } 00089 "watchpoint" - 00090 "hw watchpoint" { 00091 set cmd watch 00092 if {$user_specification != ""} { 00093 append cmd " $user_specification" 00094 } else { 00095 # There's nothing sensible to do. 00096 continue 00097 } 00098 } 00099 00100 "catch*" { 00101 # FIXME: Don't know what to do. 00102 continue 00103 } 00104 00105 default { 00106 # Can't serialize anything other than those listed above. 00107 continue 00108 } 00109 } 00110 00111 lappend result [list $cmd $enabled $condition $command_list] 00112 } 00113 00114 return $result 00115 } 00116 00117 # An internal function used when loading sessions. It takes a 00118 # breakpoint string and recreates all the breakpoints. 00119 proc _recreate_bps {specs} { 00120 foreach spec $specs { 00121 lassign $spec create enabled condition commands 00122 00123 # Create the breakpoint 00124 if {[catch {gdb_cmd $create} txt]} { 00125 dbug W $txt 00126 } 00127 00128 # Below we use `\$bpnum'. This means we don't have to figure out 00129 # the number of the breakpoint when doing further manipulations. 00130 00131 if {! $enabled} { 00132 gdb_cmd "disable \$bpnum" 00133 } 00134 00135 if {$condition != ""} { 00136 gdb_cmd "cond \$bpnum $condition" 00137 } 00138 00139 if {[llength $commands]} { 00140 lappend commands end 00141 eval gdb_run_readline_command_no_output [list "commands \$bpnum"] \ 00142 $commands 00143 } 00144 } 00145 } 00146 00147 # 00148 # This procedure decides what makes up a gdb `session'. Roughly a 00149 # session is whatever the user found useful when debugging a certain 00150 # executable. 00151 # 00152 # Eventually we should expand this procedure to know how to save 00153 # window placement and contents. That requires more work. 00154 # 00155 proc save {} { 00156 global gdb_exe_name gdb_target_name 00157 global gdb_current_directory gdb_source_path 00158 00159 # gdb sessions are named after the executable. 00160 set name [_exe_name $gdb_exe_name] 00161 set key gdb/session/$name 00162 00163 # We fill a hash and then use that to set the actual preferences. 00164 00165 # Always set the exe. name in case we later decide to change the 00166 # interpretation of the session key. Use the full path to the 00167 # executable. 00168 set values(executable) $name 00169 00170 # Some simple state the user wants. 00171 set values(args) [gdb_get_inferior_args] 00172 set values(dirs) $gdb_source_path 00173 set values(pwd) $gdb_current_directory 00174 set values(target) $gdb_target_name 00175 set values(hostname) [pref getd gdb/load/$gdb_target_name-hostname] 00176 set values(port) [pref getd gdb/load/$gdb_target_name-portname] 00177 set values(target_cmd) $::gdb_target_cmd 00178 set values(bg) $::gdb_bg_num 00179 00180 # these prefs need to be made session-dependent 00181 set values(run_attach) [pref get gdb/src/run_attach] 00182 set values(run_load) [pref get gdb/src/run_load] 00183 set values(run_run) [pref get gdb/src/run_run] 00184 set values(run_cont) [pref get gdb/src/run_cont] 00185 00186 # Breakpoints. 00187 set values(breakpoints) [_serialize_bps] 00188 00189 # Recompute list of recent sessions. Trim to no more than 20 sessions. 00190 set recent [concat [list $name] \ 00191 [lremove [pref getd gdb/recent-projects] $name]] 00192 if {[llength $recent] > 20} { 00193 set recent [lreplace $recent 20 end] 00194 } 00195 pref setd gdb/recent-projects $recent 00196 00197 foreach k [array names values] { 00198 pref setd $key/$k $values($k) 00199 } 00200 pref setd $key/all-keys [array names values] 00201 } 00202 00203 # 00204 # Load a session saved with Session::save. NAME is the pretty name of 00205 # the session, as returned by Session::list_names. 00206 # 00207 proc load {name} { 00208 # gdb sessions are named after the executable. 00209 set key gdb/session/$name 00210 00211 # Fetch all keys for this session into an array. 00212 foreach k [pref getd $key/all-keys] { 00213 set values($k) [pref getd $key/$k] 00214 } 00215 00216 if {[info exists values(executable)]} { 00217 gdb_clear_file 00218 set_exe_name $values(executable) 00219 set_exe 00220 } 00221 } 00222 00223 # 00224 # This is called from file_changed_hook. It does all the work of 00225 # loading a session, if one exists with the same name as the current 00226 # executable. 00227 # 00228 proc notice_file_change {} { 00229 global gdb_exe_name gdb_target_name 00230 00231 debug "noticed file change event for $gdb_exe_name" 00232 00233 # gdb sessions are named after the executable. 00234 set name [_exe_name $gdb_exe_name] 00235 set key gdb/session/$name 00236 00237 # Fetch all keys for this session into an array. 00238 foreach k [pref getd $key/all-keys] { 00239 set values($k) [pref getd $key/$k] 00240 } 00241 00242 # reset these back to their defaults 00243 pref set gdb/src/run_attach 0 00244 pref set gdb/src/run_load 0 00245 pref set gdb/src/run_run 1 00246 pref set gdb/src/run_cont 0 00247 00248 if {! [info exists values(executable)] || $values(executable) != $name} { 00249 # No such session. 00250 return 00251 } 00252 00253 debug "reloading session for $name" 00254 00255 if {[info exists values(dirs)]} { 00256 # FIXME: short-circuit confirmation. 00257 gdb_cmd "directory" 00258 gdb_cmd "directory $values(dirs)" 00259 } 00260 00261 if {[info exists values(pwd)]} { 00262 catch {gdb_cmd "cd $values(pwd)"} 00263 } 00264 00265 if {[info exists values(args)]} { 00266 gdb_set_inferior_args $values(args) 00267 } 00268 00269 if {[info exists values(breakpoints)]} { 00270 _recreate_bps $values(breakpoints) 00271 } 00272 00273 if {[info exists values(target)]} { 00274 #debug "Restoring Target: $values(target)" 00275 set gdb_target_name $values(target) 00276 00277 if {[info exists values(hostname)]} { 00278 pref setd gdb/load/$gdb_target_name-hostname $values(hostname) 00279 #debug "Restoring Hostname: $values(hostname)" 00280 } 00281 00282 if {[info exists values(port)]} { 00283 pref setd gdb/load/$gdb_target_name-portname $values(port) 00284 #debug "Restoring Port: $values(port)" 00285 } 00286 00287 #debug "Restoring Target_Cmd: $values(target_cmd)" 00288 set ::gdb_target_cmd $values(target_cmd) 00289 set_baud 00290 } 00291 00292 if {[info exists values(run_attach)]} { 00293 pref set gdb/src/run_attach $values(run_attach) 00294 pref set gdb/src/run_load $values(run_load) 00295 pref set gdb/src/run_run $values(run_run) 00296 pref set gdb/src/run_cont $values(run_cont) 00297 } 00298 00299 if {[info exists values(bg)] && [pref get gdb/use_color_schemes]} { 00300 set_bg_colors $values(bg) 00301 } 00302 } 00303 00304 # 00305 # Delete a session. NAME is the internal name of the session. 00306 # 00307 proc delete {name} { 00308 # FIXME: we can't yet fully define this because the libgui 00309 # preference code doesn't supply a delete method. 00310 set recent [lremove [pref getd gdb/recent-projects] $name] 00311 pref setd gdb/recent-projects $recent 00312 } 00313 00314 # 00315 # Return a list of all known sessions. This returns the `pretty name' 00316 # of the session -- something suitable for a menu. 00317 # 00318 proc list_names {} { 00319 set newlist {} 00320 set result {} 00321 foreach name [pref getd gdb/recent-projects] { 00322 set exe [pref getd gdb/session/$name/executable] 00323 # Take this opportunity to prune the list. 00324 if {[file exists $exe]} then { 00325 lappend newlist $name 00326 lappend result $exe 00327 } else { 00328 # FIXME: if we could delete keys we would delete all keys 00329 # associated with NAME now. 00330 } 00331 } 00332 pref setd gdb/recent-projects $newlist 00333 return $result 00334 } 00335 }