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