d8891fcc |
1 | #define NO_OBSOLETE_FUNCS |
2 | #include <ida.hpp> |
3 | #include <idp.hpp> |
4 | #include <bytes.hpp> |
5 | #include <loader.hpp> |
6 | #include <kernwin.hpp> |
7 | |
8 | #include <name.hpp> |
9 | #include <frame.hpp> |
10 | #include <struct.hpp> |
11 | #include <auto.hpp> |
15c7b2a4 |
12 | #include <intel.hpp> |
d8891fcc |
13 | |
14 | #define IS_START(w, y) !strncmp(w, y, strlen(y)) |
15 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) |
16 | |
15c7b2a4 |
17 | // non-local branch targets |
18 | static ea_t *nonlocal_bt; |
19 | static int nonlocal_bt_alloc; |
20 | static int nonlocal_bt_cnt; |
21 | |
d8891fcc |
22 | //-------------------------------------------------------------------------- |
23 | static int idaapi init(void) |
24 | { |
25 | return PLUGIN_OK; |
26 | } |
27 | |
28 | //-------------------------------------------------------------------------- |
29 | static void idaapi term(void) |
30 | { |
15c7b2a4 |
31 | if (nonlocal_bt != NULL) { |
32 | free(nonlocal_bt); |
33 | nonlocal_bt = NULL; |
34 | } |
35 | nonlocal_bt_alloc = 0; |
d8891fcc |
36 | } |
37 | |
38 | //-------------------------------------------------------------------------- |
39 | |
40 | static const char *reserved_names[] = { |
41 | "name", |
42 | "offset", |
43 | }; |
44 | |
45 | static int is_name_reserved(const char *name) |
46 | { |
47 | int i; |
48 | for (i = 0; i < ARRAY_SIZE(reserved_names); i++) |
49 | if (strcasecmp(name, reserved_names[i]) == 0) |
50 | return 1; |
51 | |
52 | return 0; |
53 | } |
54 | |
15c7b2a4 |
55 | static int nonlocal_bt_cmp(const void *p1, const void *p2) |
56 | { |
57 | const ea_t *e1 = (const ea_t *)p1, *e2 = (const ea_t *)p2; |
58 | return *e1 - *e2; |
59 | } |
60 | |
61 | static void nonlocal_add(ea_t ea) |
62 | { |
63 | if (nonlocal_bt_cnt >= nonlocal_bt_alloc) { |
64 | nonlocal_bt_alloc += nonlocal_bt_alloc * 2 + 64; |
65 | nonlocal_bt = (ea_t *)realloc(nonlocal_bt, |
66 | nonlocal_bt_alloc * sizeof(nonlocal_bt[0])); |
67 | if (nonlocal_bt == NULL) { |
68 | msg("OOM\n"); |
69 | return; |
70 | } |
71 | } |
72 | nonlocal_bt[nonlocal_bt_cnt++] = ea; |
73 | } |
74 | |
d8891fcc |
75 | static void do_def_line(char *buf, size_t buf_size, const char *line) |
76 | { |
15c7b2a4 |
77 | char *endp = NULL; |
78 | ea_t ea, *ea_ret; |
d8891fcc |
79 | int len; |
80 | |
81 | tag_remove(line, buf, buf_size); // remove color codes |
82 | len = strlen(buf); |
83 | if (len < 9) { |
84 | buf[0] = 0; |
85 | return; |
86 | } |
87 | memmove(buf, buf + 9, len - 9 + 1); // rm address |
15c7b2a4 |
88 | |
89 | if (IS_START(buf, "loc_")) { |
90 | ea = strtoul(buf + 4, &endp, 16); |
91 | if (ea != 0 && *endp == ':') { |
92 | ea_ret = (ea_t *)bsearch(&ea, nonlocal_bt, nonlocal_bt_cnt, |
93 | sizeof(nonlocal_bt[0]), nonlocal_bt_cmp); |
94 | if (ea_ret != 0) { |
95 | if (endp[1] != ' ') |
96 | msg("no trailing blank in '%s'\n", buf); |
97 | else |
98 | endp[1] = ':'; |
99 | } |
100 | } |
101 | } |
d8891fcc |
102 | } |
103 | |
104 | static void idaapi run(int /*arg*/) |
105 | { |
15c7b2a4 |
106 | // isEnabled(ea) // address belongs to disassembly |
d8891fcc |
107 | // ea_t ea = get_screen_ea(); |
15c7b2a4 |
108 | // foo = DecodeInstruction(ScreenEA()); |
d8891fcc |
109 | FILE *fout = NULL; |
110 | int fout_line = 0; |
111 | char buf[MAXSTR]; |
15c7b2a4 |
112 | int drop_large = 0; |
d8891fcc |
113 | struc_t *frame; |
114 | func_t *func; |
15c7b2a4 |
115 | ea_t ui_ea_block = 0, ea_size; |
116 | ea_t tmp_ea, target_ea; |
d8891fcc |
117 | ea_t ea; |
118 | int i, o, m, n; |
119 | int ret; |
120 | char *p; |
121 | |
15c7b2a4 |
122 | nonlocal_bt_cnt = 0; |
123 | |
124 | // 1st pass: walk through all funcs |
125 | func = get_func(inf.minEA); |
d8891fcc |
126 | while (func != NULL) |
127 | { |
15c7b2a4 |
128 | func_tail_iterator_t fti(func); |
129 | if (!fti.main()) { |
130 | msg("%x: func_tail_iterator_t main failed\n", ea); |
131 | return; |
132 | } |
133 | const area_t &f_area = fti.chunk(); |
134 | ea = f_area.startEA; |
135 | |
136 | // rename global syms which conflict with frame member names |
d8891fcc |
137 | frame = get_frame(func); |
138 | if (frame != NULL) |
139 | { |
140 | for (m = 0; m < (int)frame->memqty; m++) |
141 | { |
142 | ret = get_member_name(frame->members[m].id, buf, sizeof(buf)); |
143 | if (ret <= 0) { |
144 | msg("%x: member has no name?\n", ea); |
145 | return; |
146 | } |
147 | if (buf[0] == ' ') // what's this? |
148 | continue; |
149 | if (IS_START(buf, "arg_") || IS_START(buf, "var_")) |
150 | continue; |
151 | |
152 | if (is_name_reserved(buf)) { |
153 | msg("%x: renaming '%s'\n", ea, buf); |
154 | qstrncat(buf, "_", sizeof(buf)); |
155 | ret = set_member_name(frame, frame->members[m].soff, buf); |
156 | if (!ret) { |
157 | msg("%x: renaming failed\n", ea); |
158 | return; |
159 | } |
160 | } |
161 | |
162 | tmp_ea = get_name_ea(ea, buf); |
163 | if (tmp_ea == 0 || tmp_ea == ~0) |
164 | continue; |
165 | |
166 | msg("%x: from %x: renaming '%s'\n", tmp_ea, ea, buf); |
167 | qstrncat(buf, "_g", sizeof(buf)); |
168 | set_name(tmp_ea, buf); |
169 | } |
170 | } |
171 | |
172 | func = get_next_func(ea); |
15c7b2a4 |
173 | } |
174 | |
175 | // 2nd pass over whole .text segment |
176 | for (ea = inf.minEA; ea != BADADDR; ea = next_head(ea, inf.maxEA)) |
177 | { |
178 | segment_t *seg = getseg(ea); |
179 | if (!seg || seg->type != SEG_CODE) |
180 | break; |
181 | |
182 | flags_t ea_flags = get_flags_novalue(ea); |
183 | func = get_func(ea); |
184 | if (isCode(ea_flags)) |
185 | { |
186 | if (!decode_insn(ea)) { |
187 | msg("%x: decode_insn() failed\n", ea); |
188 | continue; |
189 | } |
190 | |
191 | // find non-local branches |
192 | if ((cmd.itype == NN_jmp || insn_jcc()) |
193 | && cmd.Operands[0].type == o_near) |
194 | { |
195 | target_ea = cmd.Operands[0].addr; |
196 | if (func == NULL) |
197 | nonlocal_add(target_ea); |
198 | else { |
199 | ret = get_func_chunknum(func, target_ea); |
200 | if (ret != 0) { |
201 | // a jump to another func or chunk |
202 | // check if it lands on func start |
203 | if (!isFunc(get_flags_novalue(target_ea))) |
204 | nonlocal_add(target_ea); |
205 | } |
206 | } |
207 | } |
208 | } |
209 | else { // not code |
210 | if (func == NULL && isOff0(ea_flags)) { |
211 | ea_size = get_item_size(ea); |
212 | for (tmp_ea = 0; tmp_ea < ea_size; tmp_ea += 4) |
213 | nonlocal_add(get_long(ea + tmp_ea)); |
214 | } |
215 | } |
216 | } |
217 | |
218 | if (nonlocal_bt_cnt > 1) { |
219 | qsort(nonlocal_bt, nonlocal_bt_cnt, |
220 | sizeof(nonlocal_bt[0]), nonlocal_bt_cmp); |
d8891fcc |
221 | } |
222 | |
223 | char *fname = askfile_c(1, NULL, "Save asm file"); |
224 | if (fname == NULL) |
225 | return; |
226 | fout = qfopen(fname, "w"); |
227 | if (fout == NULL) { |
228 | msg("couldn't open '%s'\n", fname); |
229 | return; |
230 | } |
231 | |
232 | show_wait_box("Saving.."); |
233 | |
234 | // deal with the beginning |
235 | ea = inf.minEA; |
236 | int flags = 0; // calc_default_idaplace_flags(); |
237 | linearray_t ln(&flags); |
238 | idaplace_t pl; |
239 | pl.ea = ea; |
240 | pl.lnnum = 0; |
241 | ln.set_place(&pl); |
242 | n = ln.get_linecnt(); |
243 | for (i = 0; i < n - 1; i++) { |
244 | do_def_line(buf, sizeof(buf), ln.down()); |
245 | if (strstr(buf, "include")) |
246 | continue; |
247 | |
248 | fout_line++; |
249 | qfprintf(fout, "%s\n", buf); |
250 | p = strstr(buf, ".mmx"); |
251 | if (p != NULL) { |
252 | memcpy(p, ".xmm", 4); |
253 | fout_line++; |
254 | qfprintf(fout, "%s\n", buf); |
255 | } |
256 | } |
257 | |
258 | for (;;) |
259 | { |
15c7b2a4 |
260 | drop_large = 0; |
261 | |
d8891fcc |
262 | if ((ea >> 14) != ui_ea_block) { |
263 | ui_ea_block = ea >> 14; |
264 | showAddr(ea); |
265 | if (wasBreak()) |
266 | break; |
267 | } |
268 | |
269 | segment_t *seg = getseg(ea); |
270 | if (!seg || seg->type != SEG_CODE) |
271 | goto pass; |
272 | if (!decode_insn(ea)) |
273 | goto pass; |
274 | |
275 | // note: decode_insn() picks up things like dd, size is then weird |
276 | //cmd_size = cmd.size; |
277 | |
278 | for (o = 0; o < UA_MAXOP; o++) { |
279 | if (cmd.Operands[o].type == o_void) |
280 | break; |
281 | |
15c7b2a4 |
282 | if (cmd.Operands[o].type == o_mem |
283 | && cmd.Operands[o].specval_shorts.high == 0x21) // correct? |
284 | { |
285 | drop_large = 1; |
286 | } |
287 | #if 0 |
288 | if (cmd.Operands[o].type == o_displ && cmd.Operands[o].reg == 5) { |
289 | member_t *m; |
290 | |
291 | m = get_stkvar(cmd.Operands[o], cmd.Operands[o].addr, NULL); |
292 | if (m == NULL) { |
293 | msg("%x: no stkvar for offs %x\n", |
294 | ea, cmd.Operands[o].addr); |
295 | goto out; |
296 | } |
297 | if (get_struc_name(m->id, buf, sizeof(buf)) <= 0) { |
298 | msg("%x: stkvar with offs %x has no name?\n", |
299 | ea, cmd.Operands[o].addr); |
300 | goto out; |
301 | } |
302 | msg("%x: name '%s'\n", ea, buf); |
303 | } |
304 | #endif |
d8891fcc |
305 | } |
306 | |
307 | pass: |
d8891fcc |
308 | do_def_line(buf, sizeof(buf), ln.down()); |
15c7b2a4 |
309 | if (drop_large) { |
310 | p = strstr(buf, "large "); |
311 | if (p != NULL) |
312 | memmove(p, p + 6, strlen(p + 6) + 1); |
313 | } |
314 | |
315 | fout_line++; |
d8891fcc |
316 | qfprintf(fout, "%s\n", buf); |
317 | |
15c7b2a4 |
318 | // note: next_head skips some undefined stuff |
d8891fcc |
319 | ea = next_not_tail(ea); // correct? |
15c7b2a4 |
320 | if (ea == BADADDR) |
d8891fcc |
321 | break; |
322 | |
323 | pl.ea = ea; |
324 | pl.lnnum = 0; |
325 | ln.set_place(&pl); |
326 | n = ln.get_linecnt(); |
327 | for (i = 0; i < n - 1; i++) |
328 | { |
329 | fout_line++; |
330 | do_def_line(buf, sizeof(buf), ln.down()); |
331 | qfprintf(fout, "%s\n", buf); |
332 | } |
333 | } |
334 | |
335 | if (fout != NULL) |
336 | qfclose(fout); |
15c7b2a4 |
337 | if (fname != NULL) |
338 | qfree(fname); |
d8891fcc |
339 | |
340 | hide_wait_box(); |
341 | msg("%d lines saved.\n", fout_line); |
342 | } |
343 | |
344 | //-------------------------------------------------------------------------- |
345 | |
346 | static const char comment[] = "Generate disassembly lines for one address"; |
347 | static const char help[] = "Generate asm file\n"; |
348 | static const char wanted_name[] = "Save asm"; |
349 | static const char wanted_hotkey[] = "Ctrl-F6"; |
350 | |
351 | //-------------------------------------------------------------------------- |
352 | // |
353 | // PLUGIN DESCRIPTION BLOCK |
354 | // |
355 | //-------------------------------------------------------------------------- |
356 | plugin_t PLUGIN = |
357 | { |
358 | IDP_INTERFACE_VERSION, |
359 | 0, // plugin flags |
360 | init, // initialize |
361 | term, // terminate. this pointer may be NULL. |
362 | run, // invoke plugin |
363 | comment, // long comment about the plugin |
364 | // it could appear in the status line |
365 | // or as a hint |
366 | help, // multiline help about the plugin |
367 | wanted_name, // the preferred short name of the plugin |
368 | wanted_hotkey // the preferred hotkey to run the plugin |
369 | }; |
370 | |
371 | // vim:ts=2:shiftwidth=2:expandtab |