Skip to content

Commit 1032770

Browse files
Merge branch 'stack_vars_and_phonics' into 'master'
Stack vars See merge request !11
2 parents 141c58c + 7cb5487 commit 1032770

10 files changed

+360
-757
lines changed

atxmega128a4u/scripts/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,14 @@ Python>avr_bss_emu(0x2174,0x223D)
2828

2929
```
3030
Python>runscript('.../rhme3/atxmega128a4u/scripts/avr_dumb_seq_load_xrefs.py')
31+
Python>all_avr_dumb_seq_load_xrefs()
3132
Python>runscript('.../rhme3/atxmega128a4u/scripts/avr_codatafy.py')
3233
Python>dref_all_fixer()
3334
```
3435

36+
6. (optional) create stack variables in a function containing the `idc.here()` with
37+
```
38+
Python>runscript('.../rhme3/atxmega128a4u/scripts/avr_stack_vars.py')
39+
Python>all_y_stack_vars_here()
40+
```
41+

atxmega128a4u/scripts/__init__.py

Whitespace-only changes.

atxmega128a4u/scripts/avr_dumb_seq_load_xrefs.py

+74-64
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
if not logger.handlers:
1010
handler = logging.StreamHandler(stream=sys.stdout)
1111
logger.addHandler(handler)
12-
logger.setLevel(logging.WARNING)
12+
logger.setLevel(logging.INFO)
1313

1414
# just try the dumb thing and make xrefs based on seq load of pairs of immediates.
1515
# doesn't consider RAMP% register values, doesn't consider anything more complicated than:
@@ -21,6 +21,10 @@
2121
import idaapi
2222
import sark
2323

24+
print os.path.dirname(__file__)
25+
sys.path.insert(0, os.path.dirname(__file__))
26+
from avr_utils import *
27+
2428
ram_segment = None
2529
rom_segment = None
2630
for segment in sark.segments():
@@ -29,75 +33,20 @@
2933
elif segment.name == 'ROM' or segment.name == '.text':
3034
rom_segment = segment
3135

32-
rpairs = dict()
33-
34-
for i in range(1,33):
35-
rpairs.update({"r%d" % i: "r%d" % (i-1)})
36-
37-
rpairs.update({
38-
'XL': 'r25',
39-
'YL': 'XH',
40-
'ZL': 'YH',
41-
42-
'XH': 'XL',
43-
'YH': 'YL',
44-
'ZH': 'ZL'
45-
})
46-
47-
prev = None
48-
for line in sark.lines(rom_segment.startEA, rom_segment.endEA):
49-
if prev is None:
50-
prev = line
51-
continue
52-
53-
try:
54-
curr_insn = line.insn
55-
prev_insn = prev.insn
56-
except sark.exceptions.SarkNoInstruction:
57-
logger.debug("skipping @ 0x%x" % line.ea)
58-
prev = line
59-
continue
60-
61-
62-
if (len(prev_insn.operands) != 2 or len(curr_insn.operands) != 2 or
63-
str(prev_insn.operands[0]) == '' or str(prev_insn.operands[1]) == '' or str(curr_insn.operands[0]) == '' or str(curr_insn.operands[1]) == '' or
64-
str(prev_insn.operands[0].type) != 'General_Register' or str(curr_insn.operands[0].type) != 'General_Register' or
65-
str(prev_insn.operands[1].type) != 'Immediate_Value' or str(curr_insn.operands[1].type) != 'Immediate_Value'
66-
):
67-
logger.debug("filtering: %s && %s" % (prev, line))
68-
69-
if curr_insn.mnem == 'ldi' and prev_insn.mnem == 'ldi':
70-
logger.warning("false filtered %s && %s\n\t%s %s %s\n\t%s %s %s" % (prev, line, len(prev_insn.operands), prev_insn.operands[0].type, prev_insn.operands[1].type, len(curr_insn.operands), curr_insn.operands[0].type, curr_insn.operands[1].type))
71-
72-
prev = line
73-
continue
74-
75-
def safe_name(address):
76-
name = sark.Line(address).name
77-
if name[0:4] == 'unk_':
78-
return "0x%x" % address
79-
else:
80-
return "%s" % name
81-
82-
logger.debug("testing @ 0x%x %s == %s" % (line.ea, prev_insn.operands[0].reg, rpairs.get(curr_insn.operands[0].reg)))
83-
if prev_insn.operands[0].reg == rpairs.get(curr_insn.operands[0].reg):
84-
word = int(curr_insn.operands[1].text, 0) * 256 + int(prev_insn.operands[1].text, 0)
85-
address = ram_segment.startEA + word
86-
87-
if address <= ram_segment.endEA:
88-
result = add_dref(line.ea, address, dr_T)
89-
logger.debug("add dref from 0x%x to 0x%x: %s" % (line.ea, address, str(result)))
90-
line.comments.repeat = safe_name(address)
91-
92-
prev = line
36+
def safe_name(address):
37+
name = sark.Line(address).name
38+
if name is None or name == '' or name[0:4] == 'unk_':
39+
return "0x%x" % address
40+
else:
41+
return "%s" % name
9342

9443
def dref_range_fixer(startEA, endEA):
9544
for line in sark.lines(startEA, endEA):
9645
for xref in line.xrefs_to:
9746
if xref.iscode or xref.frm == idc.BADADDR or str(xref.type) != 'Data_Text': # only try to fix data references from code in ROM of the Data_Text type (as created by the dumb seq xref routine above)
9847
continue
9948
logger.debug("fixing xref (type:%s) to %s from ROM:%x" % (xref.type, safe_name(line.ea), xref.frm))
100-
sark.Line(xref.frm).comments.repeat = safe_name(line.ea)
49+
sark.Line(xref.frm).comments.repeat = str(sark.Line(xref.frm).comments.repeat).replace("0x%x" % line.ea, safe_name(line.ea))
10150
return
10251

10352
def dref_fixer():
@@ -108,7 +57,68 @@ def dref_all_fixer():
10857
dref_range_fixer(ram_segment.startEA, ram_segment.endEA)
10958
return
11059

111-
print("data xrefs (drefs) added for all sequential loads of the bytes 16-bit addresses into RAM.\nIf any lines are renamed in the RAM segment, then the drefs can be fixed by running dref_fixer() on a selection of ram addresses or dref_all_fixer() to perform this operation over all of the RAM segment.")
60+
def avr_dumb_seq_load_xrefs(startEA, endEA):
61+
prev = None
62+
for line in sark.lines(startEA, endEA):
63+
if prev is None:
64+
prev = line
65+
continue
66+
67+
try:
68+
curr_insn = line.insn
69+
prev_insn = prev.insn
70+
except sark.exceptions.SarkNoInstruction:
71+
logger.debug("skipping @ 0x%x" % line.ea)
72+
prev = line
73+
continue
74+
75+
if (len(prev_insn.operands) != 2 or len(curr_insn.operands) != 2 or
76+
str(prev_insn.operands[1]) == '' or str(curr_insn.operands[1]) == ''
77+
):
78+
logger.debug("filtering: %s && %s" % (prev, line))
79+
prev = line
80+
continue
81+
82+
logger.debug("testing %s && %s" % (prev, line))
83+
if (is_latter_of_rxN_sequential_instructions(prev, line, 0) and
84+
str(prev_insn.operands[1].type) == 'Immediate_Value' and str(curr_insn.operands[1].type) == 'Immediate_Value'
85+
):
86+
idc.OpHex(prev.ea, 1)
87+
idc.OpHex(line.ea, 1)
88+
if prev_insn.mnem == 'subi' and curr_insn.mnem == 'sbci':
89+
word = (int(curr_insn.operands[1].text, 0) + 1) * -256 + int(prev_insn.operands[1].text, 0) * -1
90+
address = ram_segment.startEA + word
91+
92+
if (address > ram_segment.startEA + 0x2000 and address < ram_segment.endEA and
93+
str(prev_insn.operands[0]) != 'YL' and str(prev_insn.operands[0].reg) != 'r28' # ignore indexed access into stack
94+
):
95+
result = add_dref(line.ea, address, dr_T)
96+
logger.info("%s adding dref to %s at ROM:%x \"%s\"" % ("Success" if result else "Error", safe_name(address), line.ea, line))
97+
line.comments.repeat = "indexed access into %s" % safe_name(address)
98+
else:
99+
word = int(curr_insn.operands[1].text, 0) * 256 + int(prev_insn.operands[1].text, 0)
100+
address = ram_segment.startEA + word
101+
102+
if address >= ram_segment.startEA and address < ram_segment.endEA:
103+
result = add_dref(line.ea, address, dr_T)
104+
logger.info("%s adding dref to %s at ROM:%x \"%s\"" % ("Success" if result else "Error", safe_name(address), line.ea, line))
105+
if address <= ram_segment.startEA + 32:
106+
line.comments.repeat = "possible %s" % sark.Line(address).comments.repeat # use the ioport name in the comments
107+
else:
108+
line.comments.repeat = safe_name(address)
109+
110+
prev = line
111+
112+
def all_avr_dumb_seq_load_xrefs():
113+
avr_dumb_seq_load_xrefs(rom_segment.startEA, rom_segment.endEA)
114+
return
115+
116+
def all_avr_dumb_seq_load_xrefs_here():
117+
this_function = sark.Function(idc.here())
118+
avr_dumb_seq_load_xrefs(this_function.startEA, this_function.endEA)
119+
return
120+
121+
print("some utility functions are defined. run\nall_avr_dumb_seq_load_xrefs() to define data xrefs (drefs) for all sequential loads of the bytes 16-bit addresses into RAM throughout the whole binary,\nall_avr_dumb_seq_load_xrefs_here() for the current function and\navr_dumb_seq_load_xrefs(startEA, endEA) for a custom range\nIf any lines are renamed in the RAM segment, then the drefs can be fixed by running dref_fixer() on a selection of ram addresses or dref_all_fixer() to perform this operation over all of the RAM segment.")
112122

113123
except:
114124
exc_type, exc_value, exc_traceback = sys.exc_info()
+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import idascript
2+
3+
import sys
4+
import os
5+
import traceback
6+
7+
import logging
8+
logger = logging.getLogger(__name__)
9+
if not logger.handlers:
10+
handler = logging.StreamHandler(stream=sys.stdout)
11+
logger.addHandler(handler)
12+
logger.setLevel(logging.INFO)
13+
14+
try:
15+
import idautils
16+
import idaapi
17+
import sark
18+
19+
print os.path.dirname(__file__)
20+
sys.path.insert(0, os.path.dirname(__file__))
21+
from avr_utils import *
22+
23+
def make_stack_variable(func_start, offset, name, size):
24+
func = idaapi.get_func(func_start)
25+
frame = idaapi.get_frame(func)
26+
if frame is None:
27+
if idaapi.add_frame(func, 0, 0, 0) == -1:
28+
raise ValueError("couldn't create frame for function @ 0x%x" % func_start)
29+
frame = idaapi.get_frame(func)
30+
31+
offset += func.frsize
32+
member = idaapi.get_member(frame, offset)
33+
34+
if member:
35+
return 0
36+
else:
37+
# No member at the offset, create a new one
38+
if idaapi.add_struc_member(frame,
39+
name,
40+
offset,
41+
idaapi.wordflag() if size == 2 else idaapi.byteflag(),
42+
None, size) == 0:
43+
return 1
44+
else:
45+
return 0
46+
47+
def is_latter_of_stack_sequential_instructions(prev_line, curr_line, op_num):
48+
other_op_num = 0
49+
if op_num == 0:
50+
other_op_num = 1
51+
52+
if not is_latter_of_rxN_sequential_instructions(prev_line, curr_line, other_op_num):
53+
return False
54+
55+
try:
56+
curr_insn = curr_line.insn
57+
prev_insn = prev_line.insn
58+
except sark.exceptions.SarkNoInstruction:
59+
return False
60+
61+
if (str(prev_insn.operands[op_num]).startswith('Y+') and
62+
prev_insn.operands[op_num].offset == curr_insn.operands[op_num].offset - 1
63+
):
64+
logger.debug("offsets 0x%x && 0x%x are sequential: %s && %s" % (prev_insn.operands[op_num].offset, curr_insn.operands[op_num].offset, prev_line, curr_line))
65+
return True
66+
67+
return False
68+
69+
def doesnt_imply_stack_var(curr_insn):
70+
return str(curr_insn.operands[1].reg) == 'r1'
71+
72+
def operand_to_stack_variable(curr_line, op_num):
73+
logger.debug("setting stack var operand %d of %s" % (op_num, curr_line))
74+
idc.OpStkvar(curr_line.ea, op_num)
75+
return
76+
77+
def create_stack_variable_from_operand(curr_line, op_num):
78+
try:
79+
curr_insn = curr_line.insn
80+
except sark.exceptions.SarkNoInstruction:
81+
return
82+
83+
if doesnt_imply_stack_var(curr_insn):
84+
return
85+
86+
stack_offset = curr_insn.operands[op_num].offset
87+
this_function = sark.Function(curr_line.ea)
88+
89+
next_line = sark.Line(curr_line.ea + len(curr_line.bytes))
90+
size = 2 if is_latter_of_stack_sequential_instructions(curr_line, next_line, op_num) else 1
91+
92+
logger.info("creating %d byte stack variable @ 0x%x based on %s && %s" % (size, stack_offset, curr_line, next_line))
93+
94+
make_stack_variable(this_function.startEA, stack_offset, "var_%x" % stack_offset, size)
95+
return
96+
97+
def all_y_stack_vars_here():
98+
ea = idc.here()
99+
this_function = sark.Function(ea)
100+
101+
prev = None
102+
for line in this_function.lines:
103+
if prev is None:
104+
prev = line
105+
continue
106+
107+
try:
108+
curr_insn = line.insn
109+
prev_insn = prev.insn
110+
except sark.exceptions.SarkNoInstruction:
111+
logger.debug("skipping @ 0x%x" % line.ea)
112+
prev = line
113+
continue
114+
115+
if (len(curr_insn.operands) != 2 or
116+
str(curr_insn.operands[0]) == '' or str(curr_insn.operands[1]) == ''
117+
):
118+
logger.debug("filtering: %s" % (line))
119+
prev = line
120+
continue
121+
122+
logger.debug("testing %s" % (line))
123+
124+
if str(curr_insn.operands[1]).startswith('Y+'):
125+
operand_to_stack_variable(line, 1)
126+
if not is_latter_of_stack_sequential_instructions(prev, line, 1): # avoid marking a stack var for the second part of a sequential load
127+
create_stack_variable_from_operand(line, 1)
128+
129+
if str(curr_insn.operands[0]).startswith('Y+'):
130+
operand_to_stack_variable(line, 0)
131+
if not is_latter_of_stack_sequential_instructions(prev, line, 0): # avoid marking a stack var for the second part of a sequential load
132+
create_stack_variable_from_operand(line, 0)
133+
134+
# TODO also for Y+ in operand 0
135+
prev = line
136+
137+
print("some utility functions are defined:\nall_y_stack_vars_here()")
138+
139+
except:
140+
exc_type, exc_value, exc_traceback = sys.exc_info()
141+
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
142+
143+
idascript.exit()

atxmega128a4u/scripts/avr_utils.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import sys
2+
import logging
3+
utils_logger = logging.getLogger(__name__)
4+
if not utils_logger.handlers:
5+
handler = logging.StreamHandler(stream=sys.stdout)
6+
utils_logger.addHandler(handler)
7+
utils_logger.setLevel(logging.INFO)
8+
9+
def avr_get_register_pairs():
10+
rpairs = dict()
11+
12+
for i in range(1, 33, 2):
13+
rpairs.update({"r%d" % i: "r%d" % (i-1)})
14+
15+
rpairs.update({
16+
'XH': 'XL',
17+
'YH': 'YL',
18+
'ZH': 'ZL'
19+
})
20+
21+
return rpairs
22+
23+
def is_latter_of_rxN_sequential_instructions(prev_line, curr_line, op_num):
24+
if prev_line is None:
25+
return False
26+
27+
try:
28+
curr_insn = curr_line.insn
29+
prev_insn = prev_line.insn
30+
except sark.exceptions.SarkNoInstruction:
31+
return False
32+
33+
if (len(prev_insn.operands) != 2 or len(curr_insn.operands) != 2 or
34+
str(prev_insn.operands[0]) == '' or str(prev_insn.operands[1]) == '' or str(curr_insn.operands[0]) == '' or str(curr_insn.operands[1]) == '' or
35+
str(prev_insn.operands[op_num].type) != 'General_Register' or str(curr_insn.operands[op_num].type) != 'General_Register'
36+
):
37+
return False
38+
39+
if prev_insn.operands[op_num].reg == avr_get_register_pairs().get(curr_insn.operands[op_num].reg):
40+
utils_logger.debug("registers %s and %s are sequential: %s && %s" % (prev_insn.operands[op_num].reg, curr_insn.operands[op_num].reg, prev_line, curr_line))
41+
return True
42+
43+
return False

0 commit comments

Comments
 (0)