1 /*
2  * Copyright 2012, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define CONCATENATE(arg1, arg2)   CONCATENATE1(arg1, arg2)
18 #define CONCATENATE1(arg1, arg2)  CONCATENATE2(arg1, arg2)
19 #define CONCATENATE2(arg1, arg2)  arg1##arg2
20 
21 #define INTERRUPTER(sym) \
22     if (real_##sym == NULL) \
23         __init_##sym(); \
24     if (maybe_interrupt()) { \
25         errno = EINTR; \
26         return -1; \
27     }
28 
29 #define CALL_FUNCTION_1(sym, ret, type1) \
30 ret (*real_##sym)(type1) = NULL; \
31 ret sym(type1 arg1) { \
32     INTERRUPTER(sym) \
33     return real_##sym(arg1); \
34 }
35 
36 #define CALL_FUNCTION_2(sym, ret, type1, type2) \
37 ret (*real_##sym)(type1, type2) = NULL; \
38 ret sym(type1 arg1, type2 arg2) { \
39     INTERRUPTER(sym) \
40     return real_##sym(arg1, arg2); \
41 }
42 
43 #define CALL_FUNCTION_3(sym, ret, type1, type2, type3) \
44 ret (*real_##sym)(type1, type2, type3) = NULL; \
45 ret sym(type1 arg1, type2 arg2, type3 arg3) { \
46     INTERRUPTER(sym) \
47     return real_##sym(arg1, arg2, arg3); \
48 }
49 
50 #define CALL_FUNCTION_4(sym, ret, type1, type2, type3, type4) \
51 ret (*real_##sym)(type1, type2, type3, type4) = NULL; \
52 ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
53     INTERRUPTER(sym) \
54     return real_##sym(arg1, arg2, arg3, arg4); \
55 }
56 
57 #define CALL_FUNCTION_5(sym, ret, type1, type2, type3, type4, type5) \
58 ret (*real_##sym)(type1, type2, type3, type4, type5) = NULL; \
59 ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \
60     INTERRUPTER(sym) \
61     return real_##sym(arg1, arg2, arg3, arg4, arg5); \
62 }
63 
64 #define DEFINE_INTERCEPT_N(N, sym, ret, ...) \
65 static void __init_##sym(void); \
66 CONCATENATE(CALL_FUNCTION_, N)(sym, ret, __VA_ARGS__) \
67 static void __init_##sym(void) { \
68     real_##sym = dlsym(RTLD_NEXT, #sym); \
69     if (real_##sym == NULL) { \
70         fprintf(stderr, "Error hooking " #sym ": %s\n", dlerror()); \
71     } \
72 }
73 
74 #define INTERCEPT_NARG(...) INTERCEPT_NARG_N(__VA_ARGS__, INTERCEPT_RSEQ_N())
75 #define INTERCEPT_NARG_N(...) INTERCEPT_ARG_N(__VA_ARGS__)
76 #define INTERCEPT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
77 #define INTERCEPT_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0
78 
79 #define DEFINE_INTERCEPT(sym, ret, ...) DEFINE_INTERCEPT_N(INTERCEPT_NARG(__VA_ARGS__), sym, ret, __VA_ARGS__)
80