Skip to content

Commit 04a448d

Browse files
krkjbachorik
authored andcommitted
Patch both rela.plt and rela.dyn for hooks (#1128)
1 parent c9cf391 commit 04a448d

File tree

4 files changed

+119
-63
lines changed

4 files changed

+119
-63
lines changed

ddprof-lib/src/main/cpp/codeCache.cpp

+64-35
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
/*
2-
* Copyright 2016 Andrei Pangin
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.
2+
* Copyright The async-profiler authors
3+
* SPDX-License-Identifier: Apache-2.0
154
*/
165

176
#include "codeCache.h"
@@ -274,48 +263,88 @@ void CodeCache::findSymbolsByPrefix(std::vector<const char *> &prefixes,
274263
}
275264
}
276265

277-
void CodeCache::addImport(void **entry, const char *name) {
278-
switch (name[0]) {
279-
case 'd':
280-
if (strcmp(name, "dlopen") == 0) {
281-
_imports[im_dlopen] = entry;
266+
void CodeCache::saveImport(ImportId id, void** entry) {
267+
for (int ty = 0; ty < NUM_IMPORT_TYPES; ty++) {
268+
if (_imports[id][ty] == nullptr) {
269+
_imports[id][ty] = entry;
270+
return;
271+
}
282272
}
283-
break;
284-
case 'p':
285-
if (strcmp(name, "pthread_create") == 0) {
286-
_imports[im_pthread_create] = entry;
287-
} else if (strcmp(name, "pthread_exit") == 0) {
288-
_imports[im_pthread_exit] = entry;
289-
} else if (strcmp(name, "pthread_setspecific") == 0) {
290-
_imports[im_pthread_setspecific] = entry;
273+
}
274+
275+
void CodeCache::addImport(void **entry, const char *name) {
276+
switch (name[0]) {
277+
case 'c':
278+
if (strcmp(name, "calloc") == 0) {
279+
saveImport(im_calloc, entry);
280+
}
281+
break;
282+
case 'd':
283+
if (strcmp(name, "dlopen") == 0) {
284+
saveImport(im_dlopen, entry);
285+
}
286+
break;
287+
case 'f':
288+
if (strcmp(name, "free") == 0) {
289+
saveImport(im_free, entry);
290+
}
291+
break;
292+
case 'm':
293+
if (strcmp(name, "malloc") == 0) {
294+
saveImport(im_malloc, entry);
295+
}
296+
break;
297+
case 'p':
298+
if (strcmp(name, "pthread_create") == 0) {
299+
saveImport(im_pthread_create, entry);
300+
} else if (strcmp(name, "pthread_exit") == 0) {
301+
saveImport(im_pthread_exit, entry);
302+
} else if (strcmp(name, "pthread_setspecific") == 0) {
303+
saveImport(im_pthread_setspecific, entry);
304+
} else if (strcmp(name, "poll") == 0) {
305+
saveImport(im_poll, entry);
306+
}
307+
break;
308+
case 'r':
309+
if (strcmp(name, "realloc") == 0) {
310+
saveImport(im_realloc, entry);
311+
}
312+
break;
291313
}
292-
break;
293-
}
294314
}
295315

296316
void **CodeCache::findImport(ImportId id) {
297317
if (!_imports_patchable) {
298318
makeImportsPatchable();
299319
_imports_patchable = true;
300320
}
301-
return _imports[id];
321+
return _imports[id][PRIMARY];
302322
}
303323

304324
void CodeCache::patchImport(ImportId id, void *hook_func) {
305-
void **entry = findImport(id);
325+
if (!_imports_patchable) {
326+
makeImportsPatchable();
327+
_imports_patchable = true;
328+
}
329+
330+
for (int ty = 0; ty < NUM_IMPORT_TYPES; ty++) {void **entry = _imports[id][ty];
306331
if (entry != NULL) {
307332
*entry = hook_func;
308-
}
333+
}}
309334
}
310335

311336
void CodeCache::makeImportsPatchable() {
312337
void **min_import = (void **)-1;
313338
void **max_import = NULL;
314339
for (int i = 0; i < NUM_IMPORTS; i++) {
315-
if (_imports[i] != NULL && _imports[i] < min_import)
316-
min_import = _imports[i];
317-
if (_imports[i] != NULL && _imports[i] > max_import)
318-
max_import = _imports[i];
340+
for (int j = 0; j < NUM_IMPORT_TYPES; j++) {
341+
void** entry = _imports[i][j];
342+
if (entry == NULL) continue;
343+
if (entry < min_import)
344+
min_import = entry;
345+
if (entry > max_import)
346+
max_import = entry;
347+
}
319348
}
320349

321350
if (max_import != NULL) {

ddprof-lib/src/main/cpp/codeCache.h

+16-15
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,6 @@
11
/*
2-
* Copyright 2017 Andrei Pangin
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.
2+
* Copyright The async-profiler authors
3+
* SPDX-License-Identifier: Apache-2.0
154
*/
165

176
#ifndef _CODECACHE_H
@@ -35,9 +24,20 @@ enum ImportId {
3524
im_pthread_create,
3625
im_pthread_exit,
3726
im_pthread_setspecific,
27+
im_poll,
28+
im_malloc,
29+
im_calloc,
30+
im_realloc,
31+
im_free,
3832
NUM_IMPORTS
3933
};
4034

35+
enum ImportType {
36+
PRIMARY,
37+
SECONDARY,
38+
NUM_IMPORT_TYPES
39+
};
40+
4141
class NativeFunc {
4242
private:
4343
short _lib_index;
@@ -58,7 +58,7 @@ class NativeFunc {
5858
if (posix_memalign((void**)(&func), sizeof(NativeFunc*), sizeof(NativeFunc)) != 0) {
5959
return -1;
6060
}
61-
return func->_lib_index;
61+
return func->_lib_index;
6262
}
6363

6464
static bool isMarked(const char *name) { return from(name)->_mark != 0; }
@@ -100,7 +100,7 @@ class CodeCache {
100100
unsigned int _plt_offset;
101101
unsigned int _plt_size;
102102

103-
void **_imports[NUM_IMPORTS];
103+
void **_imports[NUM_IMPORTS][NUM_IMPORT_TYPES];
104104
bool _imports_patchable;
105105
bool _debug_symbols;
106106

@@ -113,6 +113,7 @@ class CodeCache {
113113

114114
void expand();
115115
void makeImportsPatchable();
116+
void saveImport(ImportId id, void** entry);
116117

117118
public:
118119
explicit CodeCache(const char *name, short lib_index = -1,

ddprof-lib/src/main/cpp/symbols_linux.cpp

+14-13
Original file line numberDiff line numberDiff line change
@@ -181,33 +181,34 @@ void ElfParser::parseDynamicSection() {
181181
loadSymbolTable(symtab, syment * nsyms, syment, strtab);
182182
}
183183

184-
if (rel != NULL && relsz != 0) {
185-
// If a shared library is built without PLT (-fno-plt), relocation entries for imports
186-
// can be found in .rela.dyn. However, if both sections exist, .rela.plt entries
187-
// should take precedence, that's why we parse .rela.dyn first.
188-
for (size_t offs = relcount * relent; offs < relsz; offs += relent) {
189-
ElfRelocation *r = (ElfRelocation *)(rel + offs);
190-
if (ELF_R_TYPE(r->r_info) == R_GLOB_DAT || ELF_R_TYPE(r->r_info) == R_ABS64) {
184+
if (jmprel != NULL && pltrelsz != 0) {
185+
// Parse .rela.plt table
186+
for (size_t offs = 0; offs < pltrelsz; offs += relent) {
187+
ElfRelocation *r = (ElfRelocation *)(jmprel + offs);
188+
191189
ElfSymbol *sym = (ElfSymbol *)(symtab + ELF_R_SYM(r->r_info) * syment);
192190
if (sym->st_name != 0) {
193191
_cc->addImport((void **)(_base + r->r_offset), strtab + sym->st_name);
194-
}
192+
195193
}
196194
}
197195
}
198196

199-
if (jmprel != NULL && pltrelsz != 0) {
200-
// Parse .rela.plt table
201-
for (size_t offs = 0; offs < pltrelsz; offs += relent) {
202-
ElfRelocation *r = (ElfRelocation *)(jmprel + offs);
197+
if (rel != NULL && relsz != 0) {
198+
// Relocation entries for imports can be found in .rela.dyn, for example
199+
// if a shared library is built without PLT (-fno-plt). However, if both
200+
// entries exist, addImport saves them both.
201+
for (size_t offs = relcount * relent; offs < relsz; offs += relent) {
202+
ElfRelocation *r = (ElfRelocation *)(rel + offs);
203+
if (ELF_R_TYPE(r->r_info) == R_GLOB_DAT || ELF_R_TYPE(r->r_info) == R_ABS64) {
203204
ElfSymbol *sym =
204205
(ElfSymbol *)(symtab + ELF_R_SYM(r->r_info) * syment);
205206
if (sym->st_name != 0) {
206207
_cc->addImport((void **)(_base + r->r_offset),
207208
strtab + sym->st_name);
208209
}
209210
}
210-
}
211+
}}
211212
}
212213
}
213214

test/test/nativemem/malloc_plt_dyn.c

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright The async-profiler authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
9+
const int MALLOC_SIZE = 1999993;
10+
const int MALLOC_DYN_SIZE = 2000003;
11+
12+
// A global pointer referencing malloc as data -> .rela.dyn
13+
static void* (*malloc_dyn)(size_t) = malloc;
14+
15+
int main(void) {
16+
// Direct call -> .rela.plt
17+
void* p = malloc(MALLOC_SIZE);
18+
19+
void* q = malloc_dyn(MALLOC_DYN_SIZE);
20+
21+
free(p);
22+
free(q);
23+
24+
return 0;
25+
}

0 commit comments

Comments
 (0)