# Utility module for 'icache.py': interpret tag tables and indirect nodes. # (This module is a bit chatty when confronted with the unexpected.) import regexp import string import ifile # Get the tag table of an open file, as a dictionary. # Seeks around in the file; after reading, the position is undefined. # Return an empty tag table if none is found. # def get_tags(f): # # First see if the last "node" is the end of tag table marker. # f.seek(0, 2) # Seek to EOF end = f.tell() buf = ifile.backup_node(f, end) if not labelmatch(buf, 0, 'end tag table\n'): return {} # No succes # # Next backup to the previous "node" -- the tag table itself. # ###print 'Getting prebuilt tag table...' end = f.tell() - len(buf) buf = ifile.backup_node(f, end) label = 'tag table:\n' if not labelmatch(buf, 0, label): print 'Weird: end tag table marker but no tag table?' print 'Node begins:', `buf[:50]` return {} # # Now read the whole tag table. # end = f.tell() - len(buf) # Do this first! buf = ifile.read_node(f, buf) # # First check for an indirection table. # indirlist = [] if labelmatch(buf, len(label), '(indirect)\n'): indirbuf = ifile.backup_node(f, end) if not labelmatch(indirbuf, 0, 'indirect:\n'): print 'Weird: promised indirection table not found' print 'Node begins:', `indirbuf[:50]` # Carry on. Things probably won't work though. else: indirbuf = ifile.read_node(f, indirbuf) indirlist = parse_indirlist(indirbuf) # # Now parse the tag table. # findtag = regexp.compile('^(.*[nN]ode:[ \t]*(.*))\177([0-9]+)$').match i = 0 tags = {} while 1: match = findtag(buf, i) if not match: break (a,b), (a1,b1), (a2,b2), (a3,b3) = match i = b line = buf[a1:b1] node = string.lower(buf[a2:b2]) offset = eval(buf[a3:b3]) # XXX What if it overflows? if tags.has_key(node): print 'Duplicate key in tag table:', `node` file, offset = map_offset(offset, indirlist) tags[node] = file, offset, line # return tags # Return true if buf[i:] begins with a label, after lower case conversion. # The label argument must be in lower case. # def labelmatch(buf, i, label): return string.lower(buf[i:i+len(label)]) == label # Parse the indirection list. # Return a list of (filename, offset) pairs ready for use. # def parse_indirlist(buf): list = [] findindir = regexp.compile('^(.+):[ \t]*([0-9]+)$').match i = 0 while 1: match = findindir(buf, i) if not match: break (a,b), (a1,b1), (a2,b2) = match file = buf[a1:b1] offset = eval(buf[a2:b2]) # XXX What if this gets overflow? list.append(file, offset) i = b return list # Map an offset through the indirection list. # Return (filename, new_offset). # If the list is empty, return the given offset and an empty file name. # def map_offset(offset, indirlist): if not indirlist: return '', offset # # XXX This could be done more elegant. # filex, offx = indirlist[0] for i in range(len(indirlist)): file1, off1 = indirlist[i] if i+1 >= len(indirlist): file2, off2 = '', 0x7fffffff else: file2, off2 = indirlist[i+1] if off1 <= offset < off2: # Add offx+2 to compensate for extra header. # No idea whether this is always correct. return file1, offset-off1 + offx+2 # # XXX Shouldn't get here. # print 'Oops, map_offset fell through' return '', offset # Not likely to get good results