1import re 2import parser 3import subprocess 4from addr_utils import phyAddrP 5verbose = False 6from elf_file import elfFile, rawVals 7 8class ChronosEmitter: 9 def __init__(self, dir_name, function_name, imm_fun, emit_as_dummy=None): 10 self.function_name = function_name 11 self.imm_fun = imm_fun 12 self.imm_file_name = '%s/%s.imm' % (dir_name, function_name) 13 self.imm_f = open(self.imm_file_name, 'w') 14 self.debug_f = open('%s/d_%s.imm' % (dir_name, function_name),'w') 15 self.emitted_loop_counts_file = open('%s/%s_emittedLoopCounts' % (dir_name, function_name),'w') 16 self.emit_as_dummy = emit_as_dummy 17 self.elf_fun_to_skip = elfFile().funcs['clean_D_PoU'] 18 self.skip_fun = False 19 20 def emitTopLevelFunction(self): 21 imm_fun = self.imm_fun 22 imm_f = self.imm_f 23 debug_f = self.debug_f 24 25 self.emitEntry() 26 self.emitSyms() 27 self.emitFunction() 28 self.emitLiterals() 29 30 self.imm_f.close() 31 self.debug_f.close() 32 self.emitted_loop_counts_file.close() 33 34 def emitSyms (self): 35 ef = elfFile() 36 for name in sorted(ef.syms.keys(),key=lambda x: ef.syms[x].addr): 37 flag_str = '' 38 sym = ef.syms[name] 39 #objects(O) in objdump is data 40 if 'O' in sym.flags: 41 flag_str += 'd' 42 #functions are text 43 if 'F' in sym.flags: 44 flag_str += 't' 45 self.imm_f.write('s %s 0x%s %s %s\n' % (name, sym.addr, sym.ali_size, flag_str)) 46 47 def emitEntry(self): 48 entry_addr = self.imm_fun.addr 49 s = 'e %#08x\n' % entry_addr 50 self.emitString(s) 51 52 def emitFunction(self): 53 #def emitFunction(imm_fun,imm_f,debug_f=None): 54 imm_fun = self.imm_fun 55 imm_f = self.imm_f 56 debug_f = self.debug_f 57 58 emitted_loop_counts = {} 59 60 i_nodes = imm_fun.imm_nodes 61 imm_loopheads = imm_fun.imm_loopheads 62 #locate the first and last addresses 63 first_addr,last_addr = self.firstAndLastAddr() 64 print 'first - last addrs : %x-%x' % (first_addr,last_addr) 65 size = 4 66 to_emit = {} 67 68 #dict of complex loop "head"s to ( addrs in the loop, its bound) 69 complex_loops = {} 70 #we need to emit instructions in the order of addresses 71 #firstly, put all the lines in a dict 72 for bb_start_addr in imm_fun.bbs: 73 if self.skip_fun and bb_start_addr in self.elf_fun_to_skip.lines: 74 continue 75 for addr in imm_fun.bbs[bb_start_addr]: 76 if addr in imm_loopheads: 77 p_head, f = imm_loopheads[addr] 78 bin_head = phyAddrP(p_head,imm_fun.f_problems[f]) 79 import graph_refine.loop_bounds 80 if imm_fun.loaded_loop_counts and bin_head in imm_fun.bin_loops_by_fs[f]: 81 #The user specified a manual loop-count override 82 loop_count,desc,_ = imm_fun.bin_loops_by_fs[f][bin_head] 83 else: 84 85 print "imm_fun.loaded_loop_counts: %s, bin_loops_by_fs[f].keys: %s, function: %s" % (imm_fun.loaded_loop_counts, str(imm_fun.loops_by_fs[f]), f ) 86 assert False 87 loop_count,desc = graph_refine.loop_bounds.get_bound_super_ctxt(bin_head, []) 88 if graph_refine.loop_bounds.is_complex_loop(addr): 89 body_addrs = graph_refine.loop_bounds.get_loop_addrs(addr) 90 complex_loops[addr] = (body_addrs, loop_count) 91 emitted_loop_counts[bin_head] = (loop_count, desc) 92 print '%x: bound %d/0x%x, %s' % (addr, loop_count, loop_count,desc) 93 else: 94 loop_count = None 95 to_emit[addr] = (addr,addr == bb_start_addr,loop_count) 96 97 for loop_addr in complex_loops.keys(): 98 print "complex loop at 0x%x" % (addr) 99 print "body: %s" % str(map(hex, body_addrs)) 100 #apply the loopcounts to all the instructions in this complex loop 101 body_addrs, loop_bound = complex_loops[loop_addr] 102 for addr in body_addrs: 103 if addr not in to_emit: 104 #dodge the halt case 105 continue 106 addr, is_start_bb, _ = to_emit[addr] 107 to_emit[addr] = (addr,is_start_bb, loop_bound) 108 emitted_loop_counts[addr] = (loop_bound, "complex_body") 109 110 111 #then emit them in order 112 for addr in xrange (first_addr, last_addr + size, size): 113 if addr in to_emit: 114 addr,is_start_bb, loop_count = to_emit[addr] 115 self.emitImm(addr,i_nodes,is_start_bb,loop_count) 116 else: 117 #pad with nop 118 self.emitNop(addr, size) 119 120 for bin_head in emitted_loop_counts: 121 count, desc = emitted_loop_counts[bin_head] 122 self.emitted_loop_counts_file.write("0x%x : count %d, desc: %s\n" % ( bin_head, count, desc)) 123 124 def firstAndLastAddr(self): 125 i_addrs = [] 126 bbs = self.imm_fun.bbs 127 for bb_n in bbs: 128 i_addrs += bbs[bb_n] 129 #print 'chronos_emit i_addrs %s' % i_addrs 130 return min(i_addrs,key=int), max(i_addrs,key = int) 131 132 def emitLiterals (self): 133 ef = elfFile() 134 for addr in sorted(ef.literals,key=int): 135 (size,value) = ef.literals[addr] 136 self.imm_f.write('v %s %s %d\n'% (hex(addr),value,size)) 137 138 def emitLoopcount (self,addr,loop_count): 139 self.imm_f.write('l 0x%x %s\n'% (addr,loop_count)) 140 print 'l 0x%x %s\n'% (addr,loop_count) 141 if self.debug_f: 142 self.debug_f.write('l 0x%x %s\n'% (addr,loop_count)) 143 144 def emitString(self, s): 145 self.imm_f.write(s) 146 if self.debug_f: 147 self.debug_f.write(s) 148 149 def emitNop(self, addr, size): 150 s = 'i %s %d startbb edges end nop _ _' % (hex(addr), size) 151 if rawVals(addr): 152 _, value = rawVals(addr) 153 s += ' %s' % hexSansX(value) 154 s += '\n' 155 self.emitString(s) 156 157 def emitImm(self,addr,nodes,is_startbb,loop_count): 158 ''' 159 Emit a single line of imm instruction 160 ''' 161 162 s = '' 163 node = nodes[addr] 164 #if this is a loop head, emit its loop count 165 if loop_count != None: 166 self.emitLoopcount (addr,loop_count) 167 if verbose: 168 print 'emitting %s: %s' % (addr,node.text) 169 170 #is this the start of a basic block ? 171 if is_startbb: 172 bb = 'startbb' 173 else: 174 bb = 'contbb' 175 176 #all insts are of size 4 177 s += ('i %s 4 %s' % (hex(addr),bb)) 178 179 #output edges 180 s += ' edges' 181 #types of edges : next, call, callret,tailcall,return 182 #call: function call, callret : where to go when call returns ? 183 #return: this edge returns 184 #tailcall: namesake 185 186 187 for e in sorted(node.edges, key = lambda x: x.targ): 188 if type(e.targ) != int: 189 print 'e.targ %s' % e.targ 190 if e.emit: 191 s += ' next '+ hex(e.targ) 192 dummy_call = False 193 if node.call_edge: 194 assert node.call_ret_edge != None 195 if self.skip_fun and node.call_edge.targ in self.elf_fun_to_skip.lines: 196 assert not node.is_tail_call 197 # skip the function call and go directly to the return site 198 s += ' next ' + hex(node.call_ret_edge.targ) 199 dummy_call = True 200 elif node.is_tail_call: 201 s += ' tailcall ' + hex(node.call_edge.targ) 202 else: 203 s += ' call ' + hex(node.call_edge.targ) 204 #print 'call_ret_edge %s ' % node.call_ret_edge.targ 205 s += ' callret ' + hex(node.call_ret_edge.targ) 206 if node.ret_edge: 207 s += ' return' 208 assert not node.call_edge 209 assert not node.call_ret_edge 210 if verbose and node.edges != []: 211 print ' node.edges : ' 212 for x in node.edges: 213 print ' %s ' % x.targ 214 215 s += (' end') 216 txt = node.text 217 #mnenomic condition setcc, input output etc 218 #print '%s: %s' % (addr,txt) 219 value = node.raw_inst 220 if dummy_call: 221 s += ' nop _ _ %s\n' % hexSansX(value) 222 self.emitString(s) 223 return 224 i = parser.decode_instruction(addr, value, txt) 225 s += ' ' + i.mnemonic + ' ' 226 227 if i.condition: 228 s += i.condition + ' ' 229 else: 230 s += '_ ' 231 232 if i.setcc: 233 s += 's ' 234 else: 235 s += '_ ' 236 237 for reg in i.input_registers: 238 s += 'input ' + reg + ' ' 239 for reg in i.output_registers: 240 s += 'output ' + reg + ' ' 241 if hasattr(i, 'shift_val'): 242 s += 'shift #' + i.shift_val + ' ' + i.shift_mode + ' ' 243 if hasattr(i,'shift_reg'): 244 s += 'shift ' + i.shift_reg + ' ' + i.shift_mode + ' ' 245 #finally the raw inst and the text 246 247 s += '%s ' % hexSansX(value) 248 s += '"%s"' % txt 249 s += '\n' 250 251 self.emitString(s) 252 253 254def hexSansX(n): 255 '''translate the input to a hex without the 0x prefix''' 256 s = hex(n) 257 return s[2:] 258 259 260