tizen 2.3 release
[framework/system/swap-probe.git] / helper / da_call_original.S
1 /*
2  *  DA probe
3  *
4  * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  *
8  * Vitaliy Cherepanov <v.cherepanov@samsung.com>
9  *
10  * This library is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU Lesser General Public License as published by the
12  * Free Software Foundation; either version 2.1 of the License, or (at your option)
13  * any later version.
14  *
15  * This library is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18  * License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this library; if not, write to the Free Software Foundation, Inc., 51
22  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23  *
24  * Contributors:
25  * - Samsung RnD Institute Russia
26  *
27  */
28
29 /*
30  * function
31  *  <some ret type> _da_call_original(void *funcp, char *args[], int args_count);
32  *
33  *  arguments:
34  *      funcp       - function pointer address to call
35  *      args        - params array for function
36  *      args_count  - params count
37  *  return values:
38  *      depends on original function (funcp)
39  *
40  *  use this function to call original function with variable arguments count
41  *  in ld-preloaded probes
42  *
43  *  example:
44  *      #include <dlfcn.h>
45  *      #include <dlsym.h>
46  *
47  *      typedef int (*execl_type)(const char *path, const char *arg, ...);
48  *      static execl_type execl_real;
49  *      //....
50  *      //_da_call_original function prototype
51  *      int call_original(void *funcp, char *args[], int args_count);
52  *      //...
53  *      execl_real = (execl_type)dlsym(RTLD_NEXT , "execl");
54  *      //...
55  *      //probe execl
56  *      int execl(const char *path, const char *arg, ...)
57  *      {
58  *              int res = 0;
59  *              va_list ap;
60  *              int args_count = 0, i;
61  *
62  *              //additional argumets list terminates with NULL pointer on execl call
63  *              //calculate arguments count with terminate NULL
64  *              va_start(ap, arg);
65  *              do
66  *                      args_count++;
67  *              while (va_arg(ap, char *) != 0);
68  *              va_end(ap);
69  *
70  *              //add 2 for <path> and <arg> params
71  *              args_count += 2;
72  *
73  *              //create and fill args arras
74  *              char *all_args[args_count];
75  *
76  *              va_start(ap, arg);
77  *
78  *              all_args[0] = (char *)path;
79  *              all_args[1] = (char *)arg;
80  *              for (i = 2; i < args_count; i++)
81  *                      all_args[i] = va_arg(ap, char *);
82  *              //do something
83  *              //.....
84  *              //call original function
85  *              res = _da_call_original(&execl_real, all_args, args_count);
86  *              //do something
87  *              //......
88  *              return res;
89  *
90  *      }
91  *
92  *  this function is written in asm because there is no other way to prepare
93  *  variable count of arguments for original function call
94  */
95
96 #define stack_size 0x40
97
98 #if defined(__x86_64__)
99     /* x86 64-bit ----------------------------------------------- */
100
101 .text
102 .global _da_call_original
103 .type _da_call_original, @function
104 _da_call_original:
105         mov     $-1, %rax
106         ret
107 #elif defined(__i386)
108
109 .text
110 .global _da_call_original
111 .type _da_call_original, @function
112 _da_call_original:
113         #save stack position
114         push %ebp
115         mov  %esp, %ebp
116
117         #create local stack
118         sub  $stack_size, %esp
119
120         #store registers
121         push %ebx
122         push %ecx
123         push %edx
124
125         #load args array pointer
126         movl 0xc(%ebp),%ecx
127         #load args_count
128         movl 0x10(%ebp), %ebx
129
130         #calculate stack size for original function call
131         #stack size = (args_count) * 4
132         shl  $2, %ebx
133         #create stack for original function call
134         sub  %ebx, %esp
135
136         #push all arguments to stack
137         #for (i = 0; i < args_count; i++) {
138         movl $0, %eax
139         jmp  for_i_cmp
140         for_i:
141                 #args[i] -> stack
142                 mov  (%ecx), %edx
143                 mov  %edx, (%esp)
144                 #stack++
145                 add  $4, %esp
146                 add  $4, %ecx
147                 add  $4, %eax
148         for_i_cmp:
149         cmpl %ebx, %eax
150         jl   for_i
151         #}
152
153         #shift stack back
154         sub  %ebx, %esp
155
156         #call original function (funcp)
157         movl 8(%ebp), %eax
158         call *(%eax)
159         #now function result in %eax
160
161         #restore stack after call function
162         add  %ebx, %esp
163
164         #restore registers
165         pop  %edx
166         pop  %ecx
167         pop  %ebx
168
169         #restore local stack
170         add  $stack_size, %esp
171         #return
172         pop  %ebp
173         ret
174
175 #elif defined(__arm__)
176 .text
177 .global _da_call_original
178 .type _da_call_original, %function
179
180 _da_call_original:
181         push {fp, lr, r5, r6, r7, r8}
182         #create local stack
183         add  fp, sp, #4
184         sub  sp, sp, #stack_size
185         #store params to stack
186         str  r0, [fp, #-12]
187         str  r1, [fp, #-16]
188         str  r2, [fp, #-20]
189
190         #load args array pointer
191         ldr  r5, [fp, #-16]
192         #load args_count
193         ldr  r6, [fp, #-20]
194
195         #calculate stack size for original function call
196         #stack size = (args_count) * 4
197         lsl  r6, r6, #2
198         #create stack for original function call
199         sub  sp, sp, r6
200         #first 4 params pass throw r0-r3
201         #so move stack to 4 words
202         sub  sp, sp, #16
203
204         #for (i = 4; i < arg; i++) {
205         mov  r7, #16
206         b    for_i_cmp
207         for_i:
208                 #args[i] -> stack[i]
209                 ldr  r8, [r5, r7]
210                 str  r8, [sp, r7]
211                 add  r7, r7, #4
212         for_i_cmp:
213         cmp  r7, r6
214         blt  for_i
215         #}
216
217         #move stack pointer back to 4 words
218         add  sp, sp, #16
219         #load first 4 args
220         ldr  r0, [r5, #0 ]
221         ldr  r1, [r5, #4 ]
222         ldr  r2, [r5, #8 ]
223         ldr  r3, [r5, #12]
224
225         #call original function (funcp)
226         ldr  r5, [fp, #-12]
227         ldr  r5, [r5]
228         blx  r5
229         #now function result in r0
230
231         #restore stack after original fincion call
232         add  sp, sp, r6
233
234         #local stack restore
235         add  sp, sp, #stack_size
236         #return
237         pop  {fp, pc, r5, r6, r7, r8}
238 #endif