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