1 /*
2 **
3 ** sk_blocks.c in
4 **
5 ** Author : <sk at devhell dot org>
6 ** Started : Thu May 29 20:39:14 2003
7 ** Updated : Wed Jun 18 00:44:00 2003
8 */
9
10 #include "modflow.h"
11
12 char *call_type_str[] =
13 {
14 "CONT",
15 "JUMP",
16 "CALL",
17 "RET",
18 "UNKN"
19 };
20
21
block_is_called(struct s_iblock * blk)22 int block_is_called(struct s_iblock *blk)
23 {
24 struct s_caller *cur;
25
26 for (cur = blk->caller; cur; cur = cur->next) {
27 if (cur->type == CALLER_CALL)
28 return (1);
29 }
30 return (0);
31 }
32
33 /*
34 void load_blocks()
35 {
36 Elf32_Shdr shdr;
37 elfshsect_t *sect;
38
39
40 }
41 */
42
store_blocks(elfshobj_t * obj,struct s_iblock * blist)43 void store_blocks(elfshobj_t *obj , struct s_iblock *blist)
44 {
45 Elf32_Shdr shdr;
46 elfshsect_t *sect;
47 Elf32_Sym bsym;
48 elfshblk_t curblock;
49 elfshblkref_t blockref;
50 struct s_iblock *cur;
51 struct s_caller *cal;
52 u_int blen;
53 u_int maxlen;
54 int is_func;
55 char buffer[24];
56 char *data;
57
58 maxlen = 0;
59
60 /*
61 for each block, insert a new STT_BLOCK symbol
62 and associated block in data of section
63 */
64
65
66 for (cur = blist; cur; cur = cur->next)
67 {
68 if (!maxlen)
69 data = malloc(sizeof (elfshblk_t));
70 else
71 data = realloc(data, maxlen + sizeof (elfshblk_t));
72
73 /* dump_block(cur); */
74 is_func = 0;
75 blen = sizeof (elfshblk_t);
76 curblock.vaddr = cur->vaddr;
77 curblock.contig = cur->contig;
78 curblock.altern = cur->altern;
79 curblock.size = cur->size;
80 curblock.altype = cur->altype;
81 memcpy(data + maxlen, &curblock, sizeof (elfshblk_t));
82 /*
83 if (!maxlen)
84 else
85 elfsh_append_data_to_section(sect, &curblock, blen);
86 */
87 snprintf(buffer, sizeof (buffer), "block_%08x", cur->vaddr);
88
89 /*
90 for each caller, add a new blcok reference to section
91 */
92
93 for (cal = cur->caller; cal; cal = cal->next)
94 {
95 blockref.vaddr = cal->vaddr;
96 blockref.type = cal->type;
97 if (!is_func && cal->type == CALLER_CALL)
98 {
99 is_func = 1;
100 snprintf(buffer, sizeof (buffer), "function_%08x", cur->vaddr);
101 }
102 data = realloc(data, maxlen + blen + sizeof (elfshblkref_t));
103 memcpy(data + maxlen + blen, &blockref, sizeof (elfshblkref_t));
104 // elfsh_append_data_to_section(sect, &blockref, sizeof (elfshblkref_t));
105 blen += sizeof (elfshblkref_t);
106 }
107
108 /*
109 create symbol
110 */
111 /* printf("maxlen = %i blen = %i\n buffer=%s\n", maxlen, blen, buffer); */
112
113 bsym = elfsh_create_symbol(maxlen, blen, STT_BLOCK, 0, 0, 0);
114 elfsh_insert_symbol(obj->secthash[ELFSH_SECTION_SYMTAB],
115 &bsym, buffer);
116
117 maxlen += blen;
118 }
119
120
121 if (!(sect = elfsh_get_section_by_name(obj, ".control", 0, 0, 0)))
122 {
123 sect = elfsh_create_section(".control");
124 shdr = elfsh_create_shdr(0, SHT_PROGBITS, 0, 0, 0, maxlen,
125 0, 0, 0, 0);
126 }
127
128 elfsh_insert_unmapped_section(obj, sect, shdr, data);
129 sect->altdata = blist;
130 }
131
132 /**
133 *
134 *
135 */
136
block_clean_passed(struct s_iblock * list)137 void block_clean_passed(struct s_iblock *list)
138 {
139 struct s_iblock *cur;
140 for (cur = list; cur; cur = cur->next)
141 cur->passed = 0;
142 }
143
144 /**
145 * create a new block
146 *
147 */
148
block_create(u_int vaddr,u_int size)149 struct s_iblock *block_create(u_int vaddr, u_int size)
150 {
151 struct s_iblock *t;
152
153 t = malloc(sizeof (struct s_iblock));
154 memset(t, 0, sizeof (struct s_iblock));
155 t->vaddr = vaddr;
156 t->size = size;
157 return (t);
158 };
159
160
161
162 /**
163 * add a caller to a block.
164 * sort by vaddr
165 */
166
dump_block(struct s_iblock * b)167 void dump_block(struct s_iblock *b)
168 {
169 printf("[B]=(%08x) [V]=(%08x) sz=(%04u) [N]=(%08x)\n",
170 (int) b, b->vaddr, b->size, (int) b->next);
171 }
172
173
174 /*
175 *
176 *
177 *
178 */
179
display_blocks(elfshobj_t * file,struct s_iblock * blk_list,int level)180 int display_blocks(elfshobj_t *file, struct s_iblock *blk_list,
181 int level)
182 {
183 struct s_iblock *cur;
184 struct s_caller *ccal;
185 u_int offset;
186 char *str;
187 int num;
188
189 char *end_str;
190 u_int end_offset;
191
192 char buf1[30];
193 char buf2[30];
194
195 num = 0;
196 for (cur = blk_list; cur; cur = cur->next)
197 {
198
199 num++;
200 str = elfsh_reverse_metasym(file, cur->vaddr, &offset);
201 end_str = elfsh_reverse_metasym(file, cur->vaddr + cur->size, &end_offset);
202
203 if (str == NULL)
204 *buf1 = 0x00;
205 else
206 snprintf(buf1, sizeof (buf1), "<%s + %i>", str, offset);
207 if (end_str == NULL || !(cur->contig))
208 *buf2 = 0x00;
209 else
210 snprintf(buf2, sizeof (buf2), "<%s + %i>", end_str, end_offset);
211
212 printf("[%08x:%05i:%08x:%08x] %-4s %-30s --> %-30s ",
213 cur->vaddr, cur->size, cur->contig, cur->altern,
214 call_type_str[cur->altype], buf1, buf2);
215
216 if (cur->altern == 0xFFFFFFFF)
217 printf(" [?]");
218 else if (cur->altern != NULL)
219 {
220 str = elfsh_reverse_metasym(file, cur->altern, &offset);
221 printf(" [%s + %i]", (str ? str : ""), offset);
222 }
223
224 printf("\n");
225 if (level > 0)
226 for (ccal = cur->caller; ccal; ccal = ccal->next)
227 {
228 str = elfsh_reverse_metasym(file, ccal->vaddr, &offset);
229 printf("\texecuted from: (%08x) <%s + %i> : %s\n",
230 ccal->vaddr, (str ? str : ""), offset,
231 call_type_str[ccal->type]);
232 }
233 }
234 return (num);
235 }
236
237 /**
238 * add a new block to blocks linked list.
239 * list is sorted by vaddr.
240 * if block is already present, it's not inserted
241 * and function return
242 *
243 */
244
block_add_list(struct s_iblock ** list,struct s_iblock * n)245 void block_add_list(struct s_iblock **list, struct s_iblock *n)
246 {
247 struct s_iblock *cur;
248 struct s_iblock *nxt;
249 // char buffer[12];
250
251 /*
252 printf("[@#$!#$ vaddr = %08x size = %3i] - ", n->vaddr, n->size);
253 snprintf(buffer, sizeof (buffer), "%08x", n->vaddr);
254 if ((cur = hash_get(&block_hash, buffer))) {
255 puts("skipped");
256 return;
257 } else
258 puts("added");
259 */
260 // hash_add(&block_hash, buffer, n);
261 if ((cur = *list))
262 {
263 if (n->vaddr < cur->vaddr)
264 {
265 n->next = *list;
266 *list = n;
267 return;
268 }
269 else
270 {
271 /*
272 we browse linked list until we find that vaddr of block to add
273 is greater or equal to current block vaddr and lesser than next
274 block vaddr.
275 if both vaddr are equal, block is already present in linked list
276 so we simply return. else, we add the new block between current
277 and next block of linked list
278 */
279 while (cur->next)
280 {
281 nxt = cur->next;
282 if ((n->vaddr >= cur->vaddr) && (n->vaddr < nxt->vaddr))
283 {
284 if (n->vaddr != cur->vaddr)
285 break;
286 return;
287 }
288 cur = cur->next;
289 }
290
291 /*
292 new element position found :
293 cur -> new - > cur->next
294 */
295 if (n->vaddr != cur->vaddr)
296 {
297 n->next = cur->next;
298 cur->next = n;
299 }
300 }
301
302 } /* !*list is empty. */
303 else
304 {
305 n->next = *list;
306 *list = n;
307 }
308 }
309
310 /**
311 * add a caller
312 * - vaddr is address of starting block
313 *
314 */
block_add_caller(struct s_iblock * blk,u_int vaddr,int type)315 void block_add_caller(struct s_iblock *blk, u_int vaddr, int type)
316 {
317 struct s_caller *n;
318
319 n = malloc(sizeof (struct s_caller));
320 n->vaddr = vaddr;
321 n->type = type;
322 n->next = blk->caller;
323 blk->caller = n;
324 }
325
326 /**
327 * get a block by vaddr;
328 * if mode is null, return blockonly if vaddr is
329 * equal to block starting address
330 * else return block if vaddr belong to block
331 *
332 */
333
block_get_by_vaddr(struct s_iblock * list,u_int vaddr,int mode)334 struct s_iblock *block_get_by_vaddr(struct s_iblock *list, u_int vaddr,
335 int mode)
336 {
337 struct s_iblock *cur;
338 char buffer[12];
339
340 snprintf(buffer, sizeof (buffer), "%08x", vaddr);
341 if (!(cur = hash_get(&block_hash, buffer)))
342 for (cur = list; cur; cur = cur->next)
343 {
344 if (((cur->vaddr == vaddr)) ||
345 (mode && ((cur->vaddr < vaddr) && (vaddr < (cur->vaddr + cur->size)))))
346 break;
347 else
348 if (vaddr < (cur->vaddr + cur->size))
349 return (0);
350 }
351 return (cur);
352 }
353
354
355 /**
356 * this function add a new element to the kinked list caller
357 * of the current block
358 * this function resolve operand of instruction which may
359 * modifiy execution path.
360 * if resolved to a virtual address, a new block is inserted
361 *
362 * return destination address inserted or -1 if unresolved
363 */
insert_destination_address(elfshobj_t * obj,asm_instr * ins,u_int vaddr,struct s_iblock ** blk_list)364 int insert_destination_address(elfshobj_t *obj,
365 asm_instr *ins, u_int vaddr,
366 struct s_iblock **blk_list)
367 {
368 int ilen;
369 int dest;
370 struct s_iblock *dst;
371 struct s_iblock *dst_end;
372 int new_size;
373
374 dest = 0;
375
376 if ((ins->op1.content & ASM_OP_VALUE) &&
377 !(ins->op1.content & ASM_OP_REFERENCE))
378 {
379 ilen = asm_instr_len(ins);
380 asm_operand_get_immediate(&ins->op1, &dest);
381 dest += ilen + vaddr;
382
383 /*
384 search if destination is inside a block
385 if not, create a new block of size 1
386 located at dst.
387 add block immediatly.
388 */
389 dst_end = *blk_list;
390 dst = block_get_by_vaddr(dst_end, dest, 1);
391 if (!dst)
392 {
393 dst = block_create(dest, 1);
394 dst->altype = CALLER_UNKN;
395 block_add_list(blk_list, dst);
396 }
397
398
399 /*
400 we have to truncate block found unless destination
401 address is block starting address in 2 new blocks:
402 ,--------------------.
403 |31|c0|5b|5e|5f|c9|c3| xor %eax, %eax
404 ^ & pop %ebx, pop %esi, pop %edi, leave, ret
405 | ^-- dest point there.
406 '- size -> 7. cut block at &
407 new_size may not be superior to previous size.
408 dst -> dst_end
409 */
410 else if (dst->vaddr != dest)
411 {
412 new_size = dst->size - (dest - dst->vaddr);
413 dst->size -= new_size;
414 dst_end = block_create(dest, new_size);
415 dst_end->contig = dst->contig;
416 dst_end->altern = dst->altern;
417 dst_end->altype = dst->altype;
418 dst->contig = dest;
419 dst->altype = CALLER_CONT;
420 dst->altern = 0;
421 block_add_list(blk_list, dst_end);
422 dst = dst_end;
423 }
424
425
426 block_add_caller(dst, vaddr,
427 (ins->instr == ASM_CALL ? CALLER_CALL : CALLER_JUMP));
428
429 /*
430 * insert new block into symbol table
431 */
432 /*
433 if (ins->instr == ASM_CALL)
434 {
435 sprintf(buffer, "function_%08x", dest);
436 newsym = elfsh_create_symbol(dest, 0, STT_FUNC, 0, 0, 0);
437 elfsh_insert_symbol(obj->secthash[ELFSH_SECTION_SYMTAB],
438 &newsym, buffer);
439 }
440
441 sprintf(buffer, "%s_%08x", ins->proc->instr_table[ins->instr], vaddr);
442 newsym = elfsh_create_symbol(dest, -1, STT_BLOCK, 0, 0, 0);
443 if ((0 > elfsh_insert_symbol(obj->secthash[ELFSH_SECTION_SYMTAB],
444 &newsym, buffer)))
445 printf("Insertion failed\n");
446 */
447 }
448 else
449 dest = -1;
450 return (dest);
451 }
452
453
454