GDB (API)
/home/stan/gdb/src/gdb/gdbtk/library/session.tcl
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines