import sys, re, cStringIO, os, dis, types import xam from SimpleHTTPServer import SimpleHTTPRequestHandler, test # # Adapted from SimpleHTTPServer.py. # def show_vinfos(array, d, co=None, path=[]): text = "
    " for i in range(len(array)): vi = array[i] text += "
  1. " if hasattr(co, 'co_code') and path == []: j = i - xam.LOC_LOCALS_PLUS if 0 <= j < len(co.co_varnames): text += "(%s):\t" % co.co_varnames[j] #if name is not None: # text += "%s " % name if vi is None: text += "[NULL]" else: text += "[%x] %s" % (vi.addr, vi.gettext()) if d.has_key(vi.addr): text += " (already seen above)" else: d[vi.addr] = 1 if vi.array: text += show_vinfos(vi.array, d, co, path+[i]) text += '
  2. \n' text += '
\n' return text re_codebuf = re.compile(r'[/]0x([0-9A-Fa-f]+)$') re_proxy = re.compile(r'[/]proxy(\d+)$') def cache_load(filename, cache={}): try: return cache[filename] except KeyError: data = {} try: f = execfile(filename, data) except: data = None cache[filename] = data return data class CodeBufHTTPHandler(SimpleHTTPRequestHandler): def symhtml(self, sym, addr, inbuf=None): text = xam.symtext(sym, addr, inbuf) if isinstance(sym, xam.CodeBuf): if addr == sym.addr: name = '' else: name = '#0x%x' % addr text = "%s" % (sym.addr, name, text) return text def linehtml(self, line, addr): return "%s" % (addr, line) def proxyhtml(self, proxy): return "(snapshot)\n" % codebufs.index(proxy) def htmlpage(self, title, data): return ('%s\n' % title + '

%s

\n' % title # + '
\n' + data + '
\n') def bufferpage(self, codebuf): rev = {} for o, c in codebuf.reverse_lookup: if c is not codebuf: rev[c] = rev.get(c,0) + 1 if rev: data = '

Other code buffers pointing to this one:

\n' else: data = '

No other code buffer points to this one.

\n' data += '
\n' data += '
%s
\n' % codebuf.disassemble(self.symhtml, self.linehtml, self.proxyhtml) data += "
Back to the list of code objects\n" if codebuf.co_name: data = '

Code object %s from file %s, at position %s

%s' % ( codebuf.co_name, codebuf.co_filename, codebuf.get_next_instr(), data) return data def send_head(self): if self.path == '/': title = 'List of all named code objects' data = '\n' else: match = re_codebuf.match(self.path) if match: addr = long(match.group(1), 16) codebuf = xam.codeat(addr) if not codebuf: self.send_error(404, "No code buffer at this address") return None title = '%s code buffer at 0x%x' % (codebuf.mode.capitalize(), codebuf.addr) data = self.bufferpage(codebuf) else: match = re_proxy.match(self.path) if match: title = 'Snapshot' proxy = codebufs[int(match.group(1))] filename = os.path.join(DIRECTORY, proxy.co_filename) moduledata = cache_load(filename) if moduledata is None: co = None else: co = moduledata.get(proxy.co_name) if hasattr(co, 'func_code'): co = co.func_code data = '

PsycoObject structure at this point:

\n' data += show_vinfos(proxy.vlocals, {}, co) data += '

Disassembly of %s:%s:%s:

\n' % ( proxy.co_filename, proxy.co_name, proxy.get_next_instr()) if moduledata is None: txt = "(exception while loading the file '%s')\n" % ( filename) else: if not hasattr(co, 'co_code'): txt = "(no function object '%s' in file '%s')\n" % ( proxy.co_name, filename) else: txt = cStringIO.StringIO() oldstdout = sys.stdout try: sys.stdout = txt dis.disassemble(co, proxy.get_next_instr()) finally: sys.stdout = oldstdout txt = txt.getvalue() data += '
%s
\n' % txt data += "
Back\n" % proxy.addr else: self.send_error(404, "Invalid path") return None f = cStringIO.StringIO(self.htmlpage(title, data)) self.send_response(200) self.send_header("Content-type", "text/html") self.end_headers() return f if __name__ == '__main__': if len(sys.argv) <= 1: print "Usage: python httpxam.py " print " psyco.dump and any .py files containing code objects" print " are loaded from the ." sys.exit(1) DIRECTORY = sys.argv[1] del sys.argv[1] codebufs = xam.readdump(os.path.join(DIRECTORY, 'psyco.dump')) test(CodeBufHTTPHandler)