1 /*
2 * Copyright (C) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include <cstdio>
16 #include <dlfcn.h>
17 #include <execinfo.h>
18 #include <securec.h>
19
20 #include "bt-test.h"
21
22 #define STRING_MAX_LEN 256
23
24 namespace testbt {
25 typedef const char* (*clibGetVer_t)();
26 typedef int (*clibMaxMin_t)(int, int);
27
28 // close library
closeLib(void * handle)29 void closeLib(void *handle) {
30 printf("\tClosing library\n");
31 dlclose(handle);
32 }
33
34 // open library
openLib(const char * fileName)35 void *openLib(const char *fileName) {
36 printf("\tLoading library %s\n", fileName);
37 void *handle = dlopen(fileName, RTLD_LAZY);
38 if (!handle) {
39 printf("Error loading library!\n");
40 dlerror();
41 }
42
43 return handle;
44 }
45
getSymbol(void * saddr)46 std::string getSymbol(void *saddr) {
47 Dl_info info = { 0 };
48 dladdr(saddr, &info);
49
50 char *str_buffer = static_cast<char *>(malloc(STRING_MAX_LEN * sizeof(char)));
51
52 if (info.dli_sname && info.dli_saddr && info.dli_fbase && info.dli_fname) {
53 int ret = snprintf_s(str_buffer, STRING_MAX_LEN, STRING_MAX_LEN - 1,
54 "<%s+%#lx>[%#lx] -> %s", info.dli_sname,
55 reinterpret_cast<uintptr_t>(saddr) - reinterpret_cast<uintptr_t>(info.dli_saddr),
56 reinterpret_cast<uintptr_t>(saddr) - reinterpret_cast<uintptr_t>(info.dli_fbase), info.dli_fname);
57 if (ret < 0) {
58 free(str_buffer);
59 return "Error: failed to format symbol data\n";
60 }
61
62 std::string str(str_buffer);
63 free(str_buffer);
64 return str;
65 } else {
66 free(str_buffer);
67 }
68
69 return "Error: could not resolve symbol data\n";
70 }
71
72 // test if functions without parameters are loading and working properly
test()73 std::string TestVer::test() {
74 printf("Testing symbol lookup\n");
75 void *handleA = openLib(fileNameA);
76 if (!handleA) {
77 printf("Exiting!\n");
78 return "test failure\n";
79 }
80 void *handleB = openLib(fileNameB);
81 if (!handleB) {
82 printf("Exiting!\n");
83 return "test failure\n";
84 }
85
86 printf("\tLookup symbols %s, %s\n", symbolNameA, symbolNameB);
87 clibGetVer_t getA = reinterpret_cast<clibGetVer_t>(dlsym(handleA, symbolNameA));
88 if (!getA) {
89 printf("Error lookup symbol %s!\n", symbolNameA);
90 printf("Exiting!\n");
91 return "test failure\n";
92 }
93 clibGetVer_t getB = reinterpret_cast<clibGetVer_t>(dlsym(handleB, symbolNameB));
94 if (!getB) {
95 printf("Error lookup symbol %s!\n", symbolNameB);
96 printf("Exiting!\n");
97 return "test failure\n";
98 }
99
100 printf("\tCalling %s, %s\n", symbolNameA, symbolNameB);
101 verA = getA();
102 verB = getB();
103
104 closeLib(handleA);
105 closeLib(handleB);
106
107 printf("Exiting symbol lookup test\n");
108 return "test not failed";
109 }
110
111 // test if functions without parameters symbol can be backteaced properly after
112 // loading
test()113 std::string TestVerBT::test() {
114 printf("Testing symbol backtrace\n");
115 void *handleA = openLib(fileNameA);
116 if (!handleA) {
117 printf("Exiting!\n");
118 return "test failure\n";
119 }
120 void *handleB = openLib(fileNameB);
121 if (!handleB) {
122 printf("Exiting!\n");
123 return "test failure\n";
124 }
125
126 printf("\tLookup symbols %s, %s\n", symbolNameA, symbolNameB);
127 clibGetVer_t getA = reinterpret_cast<clibGetVer_t>(dlsym(handleA, symbolNameA));
128 if (!getA) {
129 printf("Error lookup symbol %s!\n", symbolNameA);
130 printf("Exiting!\n");
131 return "test failure\n";
132 }
133 clibGetVer_t getB = reinterpret_cast<clibGetVer_t>(dlsym(handleB, symbolNameB));
134 if (!getB) {
135 printf("Error lookup symbol %s!\n", symbolNameB);
136 printf("Exiting!\n");
137 return "test failure\n";
138 }
139
140 btA = getSymbol(reinterpret_cast<void *>(getA));
141 btB = getSymbol(reinterpret_cast<void *>(getB));
142 printf("\tFrom dladdr for %s: %s\n", symbolNameA, btA.c_str());
143 printf("\tFrom dladdr for %s: %s\n", symbolNameB, btB.c_str());
144
145 closeLib(handleA);
146 closeLib(handleB);
147
148 printf("Exiting symbol backtrace test\n");
149 return "test not failed";
150 }
151
152 // test if functions with 2 parameters are loading and working properly
test()153 std::string TestMaxMin::test() {
154 printf("Testing symbol lookup\n");
155 void *handleA = openLib(fileNameA);
156 if (!handleA) {
157 printf("Exiting!\n");
158 return "test failure\n";
159 }
160 void *handleB = openLib(fileNameB);
161 if (!handleB) {
162 printf("Exiting!\n");
163 return "test failure\n";
164 }
165
166 printf("\tLookup symbols %s, %s\n", symbolNameA, symbolNameB);
167 clibMaxMin_t getA = reinterpret_cast<clibMaxMin_t>(dlsym(handleA, symbolNameA));
168 if (!getA) {
169 printf("Error lookup symbol %s!\n", symbolNameA);
170 printf("Exiting!\n");
171 return "test failure\n";
172 }
173 clibMaxMin_t getB = reinterpret_cast<clibMaxMin_t>(dlsym(handleB, symbolNameB));
174 if (!getB) {
175 printf("Error lookup symbol %s!\n", symbolNameB);
176 printf("Exiting!\n");
177 return "test failure\n";
178 }
179
180 printf("\tCalling %s, %s\n", symbolNameA, symbolNameB);
181 valA = getA(aa, ab);
182 valB = getB(ba, bb);
183
184 closeLib(handleA);
185 closeLib(handleB);
186
187 printf("Exiting symbol lookup test\n");
188 return "test not failed";
189 }
190
191 // test if functions with 2 parameters symbol can be backteaced properly after
192 // loading
test()193 std::string TestMaxMinBT::test() {
194 printf("Testing symbol backtrace\n");
195 void *handleA = openLib(fileNameA);
196 if (!handleA) {
197 printf("Exiting!\n");
198 return "test failure\n";
199 }
200 void *handleB = openLib(fileNameB);
201 if (!handleB) {
202 printf("Exiting!\n");
203 return "test failure\n";
204 }
205
206 printf("\tLookup symbols %s, %s\n", symbolNameA, symbolNameB);
207 clibMaxMin_t getA = reinterpret_cast<clibMaxMin_t>(dlsym(handleA, symbolNameA));
208 if (!getA) {
209 printf("Error lookup symbol %s!\n", symbolNameA);
210 printf("Exiting!\n");
211 return "test failure\n";
212 }
213 clibMaxMin_t getB = reinterpret_cast<clibMaxMin_t>(dlsym(handleB, symbolNameB));
214 if (!getB) {
215 printf("Error lookup symbol %s!\n", symbolNameB);
216 printf("Exiting!\n");
217 return "test failure\n";
218 }
219
220 btA = getSymbol(reinterpret_cast<void *>(getA));
221 btB = getSymbol(reinterpret_cast<void *>(getB));
222 printf("\tFrom dladdr for %s: %s\n", symbolNameA, btA.c_str());
223 printf("\tFrom dladdr for %s: %s\n", symbolNameB, btB.c_str());
224
225 closeLib(handleA);
226 closeLib(handleB);
227
228 printf("Exiting symbol backtrace test\n");
229 return "test not failed";
230 }
231 } // namespace testbt