view/code.py

Go to the documentation of this file.
00001 # vim: expandtab
00002 # Copyright (c) 2006 Cristian L. Vlasceanu
00003 #
00004 # Permission is hereby granted, free of charge, to any person
00005 # obtaining a copy of this software and associated documentation
00006 # files (the "Software"), to deal in the Software without
00007 # restriction, including without limitation the rights to use,
00008 # copy, modify, merge, publish, distribute, sublicense, and/or
00009 # sell copies of the Software, and to permit persons to whom
00010 # the Software is furnished to do so, subject to the following
00011 # conditions:
00012 # 
00013 # The above copyright notice and this permission notice shall be
00014 # included in all copies or substantial portions of the Software.
00015 # 
00016 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
00017 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
00018 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
00019 # AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00020 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00021 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
00023 # OR OTHER DEALINGS IN THE SOFTWARE.
00024 # 
00025 # NOTE: The above applies solely to Python source code provided 
00026 # herein, and it DOES NOT COVER the Zero Debugger Engine and plug-ins.
00027 #
00028 from base import Base
00029 import gobject
00030 import gtk
00031 import gtk.gdk
00032 import os
00033 from pixman import PixMan
00034 import zero
00035 
00036 
00037 class Code(Base):
00038     """
00039     Base class for source code and assembly views
00040     """
00041     def __init__(self, w):
00042         Base.__init__(self)
00043         self.__fname = None
00044         self.__pixman = PixMan(w)
00045         self.__currentLine = 0
00046         #cache the breakpoints in this code view:
00047         self.__breakpoints = { }
00048         self.__model = gtk.ListStore(
00049             gobject.TYPE_OBJECT,
00050             gobject.TYPE_STRING,
00051             gobject.TYPE_STRING,
00052             gobject.TYPE_STRING,
00053         )
00054         self.__init_pixbufs(w)
00055         self.__scrolled = gtk.ScrolledWindow()
00056         self.__scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
00057         self.__w = gtk.TreeView(self.__model)
00058         self.__thread = None
00059         self.__addr = 0
00060         self.__scrolled.add(self.__w)
00061         tree = self.__w
00062         tree.connect("button_press_event", self.__on_button_press)
00063         tree.set_headers_visible(False)
00064         tree.get_selection().set_mode(gtk.SELECTION_SINGLE)
00065         # for the arrow at the current program counter:
00066         renderer = gtk.CellRendererPixbuf()
00067         tree.append_column(gtk.TreeViewColumn("", renderer, pixbuf=0))
00068         renderer = gtk.CellRendererText()
00069         tree.append_column(gtk.TreeViewColumn("", renderer, text=1))
00070         tree.append_column(gtk.TreeViewColumn("", renderer, text=2))
00071         tree.append_column(gtk.TreeViewColumn("", renderer, text=3))
00072 
00073     def __init_pixbufs(self, w):
00074         self.__arrow = self.__pixman.get_pixbuf("arrow")
00075         self.__stop = self.__pixman.get_pixbuf("brkpnt")
00076 
00077     def widget(self):
00078         return self.__scrolled
00079 
00080     def filename(self):
00081         return self.__fname
00082 
00083     def set_current_line(self, addr, line):
00084         iter = self.__model.iter_nth_child(None, self.__currentLine)
00085         try:
00086             b = self.__breakpoints[self.__addr]
00087             self.__model.set_value(iter, 0, self.__stop)
00088         except KeyError:
00089             self.__model.set_value(iter, 0, None)
00090         self.__currentLine = line
00091 
00092 
00093     def read(self, thread, addr, sym):
00094         if thread.process():
00095             breakpoints = thread.process().breakpoints()
00096         else:
00097             breakpoints = thread.breakpoints()
00098         #note: template method design pattern
00099         self.read_file(thread, addr, sym, breakpoints)
00100 
00101     def show(self, thread, addr, sym):
00102         assert sym
00103         if sym:
00104             if self.__fname != sym.filename():
00105                 self.read(thread, addr, sym)
00106                 self.__fname = sym.filename()
00107             self.set_current_line(addr, sym.line() - 1)
00108 
00109         iter = self.mark_current_line()
00110         if thread.program_count() == addr:
00111             pixbuf = self.__arrow
00112             try:
00113                 b = self.__breakpoints[addr]
00114                 pixbuf = self.__pixman.compose(self.__stop, pixbuf)
00115             except KeyError:
00116                 pass
00117             self.__model.set_value(iter, 0, pixbuf)
00118         self.__thread = thread
00119         self.__addr = addr
00120         self.__sym = sym
00121 
00122 
00123     def mark_current_line(self):
00124         line = self.__currentLine
00125         iter = self.__model.iter_nth_child(None, line)
00126         tree = self.__w
00127         path = self.__model.get_path(iter)
00128         try:
00129             #available in Pygtk 2.2 and above
00130             tree.set_cursor_on_cell(path)
00131         except:
00132             tree.set_cursor(path, None, False)
00133         return iter
00134 
00135     def clear(self):
00136         self.__model.clear()
00137 
00138     def get_token(self, iter):
00139         "Get the token under cursor in the code view"
00140         return ""
00141 
00142     def __on_button_press(self, w, event):
00143         if event.button == 3:
00144             self.__popup_menu(event)
00145 
00146     def __popup_menu(self, event):
00147         x = int(event.x)
00148         y = int(event.y)
00149         path = self.__w.get_path_at_pos(x, y)[0]
00150         if path:
00151             iter = self.__model.get_iter(path)
00152             if iter:
00153                 #get a tuple of addresses that correspond
00154                 # to the source (or asm) line at event position
00155                 addresses = self.get_addresses(iter)
00156                 #get the word at event position
00157                 token = self.get_token(iter)
00158                 menu = self.__make_contextual_menu(addresses, token)
00159                 if menu:
00160                     menu.popup(None, 
00161                                 None, 
00162                                 None, 
00163                                 event.button, 
00164                                 event.get_time())
00165 
00166     def __make_contextual_menu(self, addrs, token):
00167         menu = gtk.Menu()
00168         if self.__thread:
00169             self.__add_breakpoint_menu_items(menu, self.__thread, addrs)
00170         menu.show_all()
00171         return menu
00172 
00173     def __add_breakpoint_menu_items(self, menu, thread, addresses):
00174         breakpoints_to_enable = []
00175         breakpoints_to_disable = []
00176         breakpoints_to_remove = []
00177         breakpoints_to_set = [] 
00178 
00179         for a in addresses:
00180             allBreakpoints = thread.process().breakpoints(a)
00181             for b in allBreakpoints:
00182                 breakpoints_to_remove.append(b)
00183                 if b.is_enabled():
00184                     breakpoints_to_disable.append(b)
00185                 else:
00186                     breakpoints_to_enable.append(b)
00187             if len(allBreakpoints) == 0:
00188                 breakpoints_to_set.append(a)
00189         if len(breakpoints_to_set):
00190             self.__add_set_breakpoint_item(menu, 
00191                                         "Set Breakpoint", 
00192                                         thread.process(),
00193                                         breakpoints_to_set)
00194             self.__add_set_breakpoint_item(menu, 
00195                                         "Set Thread Breakpoint", 
00196                                         thread,
00197                                         breakpoints_to_set)
00198         
00199         if len(breakpoints_to_remove):
00200             self.__add_remove_breakpoint_item(menu, breakpoints_to_remove)
00201 
00202         # todo: breakpoints_to_enable, to_disable, to_remove
00203 
00204 
00205     def __add_set_breakpoint_item(self, menu, label, thread, breakpoints):
00206         item = gtk.ImageMenuItem("gtk-dialog-error")
00207         item.get_child().set_label(label)
00208         menu.append(item)
00209         if len(breakpoints) > 1:
00210             subMenu = gtk.Menu()
00211             item.set_submenu(subMenu)
00212             for a in breakpoints:
00213                 print "__add_set_breakpoint_item",hex(a)
00214                 subItem = gtk.MenuItem(hex(a))
00215                 subMenu.append(subItem)
00216                 subItem.connect("activate", self.__set_breakpoint, thread, a)
00217         elif len(breakpoints):
00218             a = breakpoints[0]
00219             item.connect("activate", self.__set_breakpoint, thread, a)
00220 
00221 
00222     def __add_remove_breakpoint_item(self, menu, breakpoints):
00223         assert len(breakpoints)
00224         item = gtk.ImageMenuItem("todo")
00225         item.get_child().set_label("Remove Breakpoint")
00226         menu.append(item)
00227         if len(breakpoints) == 1:
00228             b = breakpoints[0]
00229             item.connect("activate", self.__remove_breakpoint, b)
00230         else:
00231             subMenu = gtk.Menu()
00232             item.set_submenu(subMenu)
00233             for b in breakpoints:
00234                 subItem = gtk.MenuItem(hex(b.addr()))
00235                 subMenu.append(subItem)
00236                 subItem.connect("activate", self.__remove_breakpoint, b)
00237 
00238 
00239     def __set_icon_at_line(self, lineNum, pixbuf):
00240         assert lineNum
00241         iter = self.__model.iter_nth_child(None, lineNum - 1)
00242         self.__model.set_value(iter, 0, pixbuf)
00243     
00244     
00245     def set_icon_at_symbol(self, sym, pixbuf):
00246         self.__set_icon_at_line(self.symbol_line(sym), pixbuf)
00247 
00248 
00249     def __set_breakpoint(self, item, thread, addr):
00250         thread.set_breakpoint(addr)
00251         self.__breakpoints[addr] = thread.breakpoints(addr)[0]
00252         sym = thread.symbols().lookup(addr)
00253         if sym:
00254             if sym.filename() == self.filename():
00255                 self.set_icon_at_symbol(sym, self.__stop)
00256 
00257 
00258     def __remove_breakpoint(self, item, brkpnt):
00259         a = brkpnt.addr()
00260         sym = brkpnt.symbol()
00261         brkpnt.remove()
00262         if not len(self.__thread.process().breakpoints(a)):
00263             del self.__breakpoints[a]
00264             if a == self.__thread.program_count():
00265                 self.set_icon_at_symbol(sym, self.__arrow)
00266             else:
00267                 self.set_icon_at_symbol(sym, None)
00268 
00269 
00270     def symbol_line(self, sym):
00271         return sym.line()