Package vwidget :: Module memview
[hide private]
[frames] | no frames]

Source Code for Module vwidget.memview

  1  """ 
  2  A unified memory analysis view 
  3  """ 
  4   
  5  import os 
  6  import gtk 
  7  import gtk.gdk as gdk 
  8   
  9  import vwidget.views as vw_views 
 10  from vwidget.main import idlethread, idlethreadsync 
 11   
 12  import envi 
 13  import envi.memcanvas as e_canvas 
 14   
 15   
 16  moddir = os.path.dirname(__file__) 
 17   
 18  # All normal key codes are the same as 
 19  # ord('K').  Some are here for special esc/FN etc treatment 
 20  KEYCODE_esc = 0xff1b 
21 22 -class VaTag(vw_views.VRevTextTag):
23
24 - def __init__(self, va):
25 tname = '%.8x' % va 26 vw_views.VRevTextTag.__init__(self, '%.8x' % va) 27 self.va = va
28
29 -class MemoryView(vw_views.VTextView, e_canvas.MemoryCanvas):
30 """ 31 A MemoryCanvas compliant GTK TextView. 32 """ 33
34 - def __init__(self, memobj, syms=None):
35 vw_views.VTextView.__init__(self) 36 self.textview.set_editable(False) 37 e_canvas.MemoryCanvas.__init__(self, memobj, syms=syms) 38 self.iter = self.vwGetAppendIter() 39 self.lastsize = 32 40 41 # Set this to get gui widget updates in a MemoryWindow 42 self.memwin = None 43 44 self.vatag = None 45 self.selectva = None 46 47 # Keep "marked" va locations 48 self.markmap = {} 49 self.beginva = None 50 self.endva = None 51 52 self.valist = [] # our "history" 53 self.histindex = None 54 55 self.colormap = None 56 57 # Anybody who extends this may by default put a file 58 # named memview.conf to describe the default tags 59 fullpath = os.path.join(moddir,"memview.conf") 60 self.vwLoadTags(fullpath) 61 62 self.hotkeys = {} 63 self.textview.connect("key_press_event", self.keyPressed) 64 self.textview.connect("move_cursor", self.cursorMoved) 65 66 self.registerHotKey(KEYCODE_esc, self.goback)
67 68 @idlethread
69 - def setColorMap(self, map):
70 oldmap = None 71 if self.colormap != None: 72 oldmap = self.colormap 73 74 self.colormap = map 75 76 if oldmap: 77 for va in oldmap.keys(): 78 tag = self.getVaTag(va) 79 self.vwSetTagColor(tag, "va") 80 81 if self.colormap: 82 for va,color in self.colormap.items(): 83 tag = self.getVaTag(va) 84 tag.set_property('background', color) 85 tag.set_property('foreground', 'black')
86
87 - def registerHotKey(self, keycode, callback, args=(), kwargs={}):
88 self.hotkeys[keycode] = (callback,args,kwargs)
89
90 - def keyPressed(self, textview, event):
91 hkinfo = self.hotkeys.get(event.keyval) 92 if hkinfo == None: 93 return 94 callback,args,kwargs = hkinfo 95 callback(*args, **kwargs)
96
97 - def cursorMoved(self, textview, stepsize, stepcount, eselect):
98 if stepsize == gtk.MOVEMENT_DISPLAY_LINES: 99 mark = self.textbuf.get_insert() 100 iter = self.textbuf.get_iter_at_mark(mark) 101 lineno = iter.get_line() 102 self.setVaFromLine(lineno+stepcount)
103 104 ############################################################# 105 # The MemoryCanvas API 106
107 - def write(self, msg):
108 self.addText(msg)
109 110 @idlethreadsync
111 - def getTag(self, typename):
112 # Return a type colored tag that doesn't 113 # do highlight on click etc... 114 tag = self.vwGetTag(typename) 115 if tag == None: 116 tag = vw_views.VTextTag(typename) 117 self.vwInitTag(tag, typename) 118 return tag
119 120 @idlethreadsync
121 - def getNameTag(self, tname, typename="name"):
122 """ 123 Get a tag for a unique name 124 (so they all highlight on highlight one) 125 """ 126 tag = self.vwGetTag(tname) 127 if tag == None: 128 tag = vw_views.VRevTextTag(tname) 129 self.vwInitTag(tag, typename, self.vwNamedTagEvent) 130 return tag
131 132 @idlethreadsync
133 - def getVaTag(self, va):
134 tname = "%.8x" % va 135 tag = self.vwGetTag(tname) 136 if tag == None: 137 #tag = gtk.TextTag(tname) 138 tag = VaTag(va) 139 self.vwInitTag(tag, "va", self.vaTagEvent) 140 #tag.va = va 141 return tag
142 143 @idlethread
144 - def addText(self, text, tag=None):
145 if tag == None: 146 tag = self.vwGetTag("default") 147 self.vwInsertText(text, tag=tag, iter=self.iter)
148 149 @idlethread
150 - def addVaText(self, text, va):
151 tag = self.getVaTag(va) 152 self.addText(text, tag=tag)
153 154 ############################################################# 155
156 - def appendHistory(self, va, size=None, rend=None):
157 158 if size == None: 159 size = self.lastsize 160 161 if rend == None: 162 rend = self.currend 163 164 if self.histindex == None: 165 self.histindex = -1 166 self.histindex += 1 167 self.valist = self.valist[:self.histindex] 168 self.valist.append((va,size,rend))
169
170 - def checkRender(self, va, size=None, rend=None):
171 # Check if the given VA is inside the currently rendered 172 # space, and if not, make it there. 173 174 if rend == None: 175 rend = self.currend 176 177 if size == None: 178 size = self.lastsize 179 180 if ( va < self.beginva or 181 va >= self.endva or 182 rend != self.currend ): 183 184 185 self.renderMemory(va, size, rend=rend)
186
187 - def goto(self, va, size=None, rend=None):
188 if size == None: 189 size = self.lastsize 190 self.appendHistory(va, size=size, rend=rend) 191 self.checkRender(va, size, rend=rend) 192 self.__goto(va)
193
194 - def goforward(self):
195 if self.histindex == None: 196 return 197 198 newindex = self.histindex + 1 199 if newindex < len(self.valist): 200 self.histindex = newindex 201 va,size,rend = self.valist[self.histindex] 202 self.checkRender(va,size,rend) 203 self.__goto(va)
204
205 - def goback(self):
206 if self.histindex == None: 207 return 208 if self.histindex > 0: 209 self.histindex -= 1 210 va,size,rend = self.valist[self.histindex] 211 self.checkRender(va,size,rend) 212 self.__goto(va)
213
214 - def godown(self):
215 va,size,rend = self.valist[self.histindex] 216 va = self.endva 217 self.checkRender(va, size, rend) 218 self.__goto(va)
219
220 - def goup(self):
221 va,size,rend = self.valist[self.histindex] 222 va = self.beginva - size 223 self.checkRender(va, size, rend) 224 self.__goto(va)
225
226 - def __goto(self, va):
227 # Scroll and highlight. 228 mark = self.markmap.get(va) 229 while mark == None: 230 va -= 1 231 mark = self.markmap.get(va) 232 self.textview.scroll_to_mark(mark, 0, True, 0, 0.3) 233 234 # Select the specified tag 235 vatag = self.getVaTag(va) 236 self.vaTagSelector(vatag) 237 238 if self.memwin: 239 self.memwin.updateHistoryButtons()
240 #self.memwin.eentry.set_text(hex(va)) 241 242 @idlethreadsync
243 - def renderMemory(self, va, size, rend=None):
244 self.vwClearText() 245 self.iter = self.vwGetAppendIter() 246 247 self.beginva = va 248 self.endva = va + size 249 250 self.render_noclear(va, size, rend=rend)
251 252 @idlethreadsync
253 - def render_noclear(self, va, size, rend=None):
254 # Use this if you've set up your own iter for a partial 255 # re-render and don't want your render call to clear the 256 # current canvas or set the iter. 257 258 if rend == None: 259 rend = self.currend 260 261 self.lastsize = size 262 self.currend = rend # we need this for tag events... store it. 263 264 try: 265 endva = va + size 266 while va < endva: 267 mark = self.textbuf.create_mark(None, self.iter, left_gravity=True) 268 self.markmap[va] = mark 269 va += rend.render(self, va) 270 except Exception, e: 271 self.addText("\nException At %s: %s\n" % (hex(va),e))
272
273 - def refresh(self, va, size):
274 if va < self.beginva or va >= self.endva: 275 return 276 277 endva = va+size 278 279 # Find the beginning mark for the change. 280 mark = self.markmap.get(va) 281 if mark == None: 282 print "WARNING: va 0x%.8x has no mark for refresh!" % va 283 return 284 285 # Get the start iter 286 startiter = self.textbuf.get_iter_at_mark(mark) 287 startline = startiter.get_line() 288 289 # Search for the end iter 290 endmark = None 291 endsearch = endva 292 enditer = None 293 while endsearch < self.endva: 294 endmark = self.markmap.get(endsearch, None) 295 if endmark != None: 296 enditer = self.textbuf.get_iter_at_mark(endmark) 297 break 298 endsearch += 1 299 300 if enditer == None: 301 enditer = self.textbuf.get_end_iter() 302 303 # Delete the old text 304 self.textbuf.delete(startiter, enditer) 305 306 for delva in range(va, endsearch): 307 mark = self.markmap.pop(delva, None) 308 if mark != None: 309 # FIXME make sure parents are using vwClear and deleting marks! 310 self.textbuf.delete_mark(mark) 311 312 # we're all cleaned up, lets re-render the area 313 self.iter = self.textbuf.get_iter_at_line(startline) 314 315 self.render_noclear(va, size) 316 317 # Because the endmark was left gravity, he stayed at the beginning, move him. 318 if endmark != None: 319 self.textbuf.move_mark(endmark, self.iter) 320 321 return
322
323 - def vwClearText(self):
324 vw_views.VTextView.vwClearText(self) 325 # FIXME delete marks from textview! 326 self.markmap = {}
327
328 - def vaTagSelector(self, tag):
329 # Check if it's already selected 330 if self.vatag == tag: 331 return 332 if self.vatag != None: 333 self.vatag.reverse() 334 self.vatag = tag 335 self.vatag.reverse()
336
337 - def vwNamedTagEvent(self, tag, textview, event, iter):
338 self.vwTagEvent(tag, textview, event, iter) 339 self.vwTagSelector(tag, textview, event, iter)
340
341 - def vwTagEvent(self, tag, textview, event, iter):
342 # The first tag on a line is *always* the VA tag 343 # for the line. Update our "position" on clicks 344 if event.type == gdk.BUTTON_PRESS: 345 self.setVaFromIter(iter)
346 347 # A special tag event handler for VA tags.
348 - def vaTagEvent(self, tag, textview, event, iter):
349 350 if event.type == gdk._2BUTTON_PRESS: 351 self.goto(tag.va) 352 353 elif event.type == gdk.BUTTON_PRESS: 354 self.selectva = tag.va 355 self.vaTagSelector(tag)
356
357 - def setVaFromIter(self, iter):
358 lineno = iter.get_line() 359 self.setVaFromLine(lineno)
360
361 - def setVaFromLine(self, lineno):
362 lineiter = self.textbuf.get_iter_at_line(lineno) 363 linetags = lineiter.get_tags() 364 if len(linetags): 365 vatag = linetags[0] 366 va = getattr(vatag, "va", None) 367 if va != None: 368 self.selectva = va 369 self.vaTagSelector(vatag)
370
371 -class ScrolledMemoryView(MemoryView):
372 """ 373 Over-ride some of the MemoryView methods to make this a more 374 continuous scrolling kind of canvas (like a CLI) 375 """ 376 377 @idlethreadsync
378 - def render(self, va, size, rend=None):
379 MemoryView.render(self, va, size, rend=rend) 380 self.addText("\n") 381 self.vwScrollToBottom()
382 383 @idlethread
384 - def addText(self, text, tag=None):
385 MemoryView.addText(self, text, tag=tag) 386 if text.find("\n") != -1: 387 self.vwScrollToBottom()
388
389 - def goto(self, va, size=None, rend=None):
390 if size == None: 391 size = self.lastsize 392 self.renderMemory(va, size, rend=rend)
393
394 - def vwClearText(self):
395 pass
396 397 import vwidget.layout as vw_layout
398 399 -class MemoryWindow(vw_layout.LayoutWindow):
400 - def __init__(self, canvas):
401 self.canvas = canvas 402 vw_layout.LayoutWindow.__init__(self) 403 self.vbox = gtk.VBox() 404 elabel = gtk.Label(" Memory Expression ") 405 slabel = gtk.Label(" Memory Size ") 406 407 self.eentry = gtk.Entry() 408 self.sentry = gtk.Entry() 409 self.sentry.set_text("256") 410 411 self.nextbutton = gtk.Button() 412 i = gtk.image_new_from_stock(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON) 413 self.nextbutton.set_image(i) 414 self.nextbutton.connect("clicked", self.goforward) 415 416 self.backbutton = gtk.Button() 417 i = gtk.image_new_from_stock(gtk.STOCK_GO_BACK, gtk.ICON_SIZE_BUTTON) 418 self.backbutton.set_image(i) 419 self.backbutton.connect("clicked", self.goback) 420 421 self.downbutton = gtk.Button() 422 i = gtk.image_new_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_BUTTON) 423 self.downbutton.set_image(i) 424 self.downbutton.connect("clicked", self.godown) 425 426 self.upbutton = gtk.Button() 427 i = gtk.image_new_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_BUTTON) 428 self.upbutton.set_image(i) 429 self.upbutton.connect("clicked", self.goup) 430 431 hbox = gtk.HBox() 432 433 hbox.pack_start(self.backbutton, expand=False) 434 hbox.pack_start(self.nextbutton, expand=False) 435 hbox.pack_start(self.upbutton, expand=False) 436 hbox.pack_start(self.downbutton, expand=False) 437 hbox.pack_start(elabel, expand=False) 438 hbox.pack_start(self.eentry, expand=True) 439 hbox.pack_start(slabel, expand=False) 440 hbox.pack_start(self.sentry, expand=True) 441 442 self.cbox = gtk.combo_box_new_text() 443 for name in self.canvas.getRendererNames(): 444 self.canvas.addRenderer(name, self.canvas.getRenderer(name)) 445 self.cbox.append_text(name) 446 self.cbox.set_active(0) 447 hbox.pack_start(self.cbox, expand=False) 448 449 self.vbox.pack_start(hbox, expand=False) 450 self.vbox.pack_start(self.canvas, expand=True) 451 self.add(self.vbox) 452 453 self.eentry.connect("activate", self.entryActivated) 454 self.sentry.connect("activate", self.entryActivated) 455 self.cbox.connect("changed", self.updateMemoryView) 456 457 self.canvas.memwin = self 458 self.updateHistoryButtons()
459
460 - def updateHistoryButtons(self):
461 hi = self.canvas.histindex 462 vl = self.canvas.valist 463 self.nextbutton.set_sensitive(False) 464 self.backbutton.set_sensitive(False) 465 if hi == None: 466 return 467 if hi > 0: 468 self.backbutton.set_sensitive(True) 469 if hi < (len(vl)-1): 470 self.nextbutton.set_sensitive(True)
471
472 - def goto(self, va, size=None, rend=None):
473 self.canvas.goto(va, size=size, rend=rend) 474 self.updateHistoryButtons()
475
476 - def godown(self, *args):
477 self.canvas.godown() 478 self.updateHistoryButtons()
479
480 - def goup(self, *args):
481 self.canvas.goup() 482 self.updateHistoryButtons()
483
484 - def goforward(self, *args):
485 self.canvas.goforward() 486 self.updateHistoryButtons()
487
488 - def goback(self, *args):
489 self.canvas.goback() 490 self.updateHistoryButtons()
491
492 - def setExpression(self, expr, size="1024"):
493 self.eentry.set_text(expr) 494 self.sentry.set_text(size) 495 self.updateMemoryView()
496
497 - def entryActivated(self, *args):
498 self.updateMemoryView() 499 self.set_title("Memory: %s" % self.eentry.get_text())
500
501 - def updateMemoryView(self, *args):
502 503 expr, sizestr, rendname = self.getWindowState() 504 505 # If either string is "", return 506 if not expr or not sizestr: 507 return 508 509 try: 510 # FIXME this is a non-api assured assumption 511 va = self.canvas.mem.parseExpression(expr) 512 except Exception, e: 513 self.canvas.addText("Invalid Expression: %s (%s)" % (expr,str(e))) 514 return 515 516 try: 517 size = self.canvas.mem.parseExpression(sizestr) 518 except Exception, e: 519 self.canvas.addText("Invalid Expression: %s (%s)" % (expr,str(e))) 520 return 521 522 rend = self.canvas.getRenderer(rendname) 523 self.goto(va, size=size, rend=rend)
524
525 - def setWindowState(self, state):
526 e,s,r = state 527 self.eentry.set_text(e) 528 self.sentry.set_text(s) 529 try: 530 ridx = self.canvas.getRendererNames().index(r) 531 self.cbox.set_active(ridx) 532 except ValueError, e: 533 pass 534 self.entryActivated()
535
536 - def getWindowState(self):
537 e = self.eentry.get_text() 538 s = self.sentry.get_text() 539 renditer = self.cbox.get_active_iter() 540 r = self.cbox.get_model().get_value(renditer, 0) 541 return (e,s,r)
542