GPLv2 release
[centaur.git] / src / libelfu / modelops / detour.c
1 /* This file is part of centaur.
2  *
3  * centaur is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License 2 as
5  * published by the Free Software Foundation.
6
7  * centaur is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11
12  * You should have received a copy of the GNU General Public License
13  * along with centaur.  If not, see <http://www.gnu.org/licenses/>.
14  */
15
16 #include <libelfu/libelfu.h>
17 #include <string.h>
18
19 static void* subFindByAddr(ElfuElf *me, ElfuScn *ms, void *aux1, void *aux2)
20 {
21   GElf_Addr a = *(GElf_Addr*)aux1;
22
23   if (OVERLAPPING(ms->shdr.sh_addr, ms->shdr.sh_size, a, 1)) {
24     return ms;
25   }
26
27   /* Continue */
28   return NULL;
29 }
30
31
32 void elfu_mDetour(ElfuElf *me, GElf_Addr from, GElf_Addr to)
33 {
34   ElfuScn *ms;
35   GElf_Word scnoffset;
36   unsigned char detourcode[] = {0xe9, 0xfc, 0xff, 0xff, 0xff};
37
38   ms = elfu_mScnForall(me, subFindByAddr, &from, NULL);
39
40   if (!ms) {
41     ELFU_WARN("mDetour: Cannot find address %x in any section.\n",
42               (unsigned)from);
43     return;
44   }
45
46   if (ms->shdr.sh_type != SHT_PROGBITS) {
47     ELFU_WARN("mDetour: Cannot detour in non-PROGBITS section %s.\n",
48               elfu_mScnName(me, ms));
49     return;
50   }
51
52   scnoffset = from - ms->shdr.sh_addr;
53
54   if (ms->shdr.sh_size - scnoffset < 5) {
55     ELFU_WARN("mDetour: Not enough space to insert a detour.\n");
56     return;
57   }
58
59   ELFU_DEBUG("mDetour: Detouring at address %x in section %s to %x.\n",
60              (unsigned)from,
61              elfu_mScnName(me, ms),
62              (unsigned)to);
63
64   *(Elf32_Word*)(detourcode + 1) = to - from - 5;
65   memcpy(ms->databuf + scnoffset, detourcode, 5);
66 }