1 /* SPDX-License-Identifier: GPL-2.0-only */
5 * Added ORC unwind tables sort support and other updates:
6 * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
7 * Shile Zhang <shile.zhang@linux.alibaba.com>
9 * Copyright 2011 - 2012 Cavium, Inc.
11 * Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
12 * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
14 * Some of this code was taken out of recordmcount.h written by:
16 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
17 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
20 #undef extable_ent_size
21 #undef compare_extable
42 # define extable_ent_size 16
43 # define compare_extable compare_extable_64
44 # define do_sort do_sort_64
45 # define Elf_Addr Elf64_Addr
46 # define Elf_Ehdr Elf64_Ehdr
47 # define Elf_Shdr Elf64_Shdr
48 # define Elf_Rel Elf64_Rel
49 # define Elf_Rela Elf64_Rela
50 # define Elf_Sym Elf64_Sym
51 # define ELF_R_SYM ELF64_R_SYM
52 # define Elf_r_sym Elf64_r_sym
53 # define ELF_R_INFO ELF64_R_INFO
54 # define Elf_r_info Elf64_r_info
55 # define ELF_ST_BIND ELF64_ST_BIND
56 # define ELF_ST_TYPE ELF64_ST_TYPE
57 # define fn_ELF_R_SYM fn_ELF64_R_SYM
58 # define fn_ELF_R_INFO fn_ELF64_R_INFO
59 # define uint_t uint64_t
63 # define extable_ent_size 8
64 # define compare_extable compare_extable_32
65 # define do_sort do_sort_32
66 # define Elf_Addr Elf32_Addr
67 # define Elf_Ehdr Elf32_Ehdr
68 # define Elf_Shdr Elf32_Shdr
69 # define Elf_Rel Elf32_Rel
70 # define Elf_Rela Elf32_Rela
71 # define Elf_Sym Elf32_Sym
72 # define ELF_R_SYM ELF32_R_SYM
73 # define Elf_r_sym Elf32_r_sym
74 # define ELF_R_INFO ELF32_R_INFO
75 # define Elf_r_info Elf32_r_info
76 # define ELF_ST_BIND ELF32_ST_BIND
77 # define ELF_ST_TYPE ELF32_ST_TYPE
78 # define fn_ELF_R_SYM fn_ELF32_R_SYM
79 # define fn_ELF_R_INFO fn_ELF32_R_INFO
80 # define uint_t uint32_t
85 #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
86 /* ORC unwinder only support X86_64 */
89 #include <asm/orc_types.h>
91 #define ERRSTR_MAXSZ 256
93 char g_err
[ERRSTR_MAXSZ
];
95 struct orc_entry
*g_orc_table
;
97 pthread_t orc_sort_thread
;
99 static inline unsigned long orc_ip(const int *ip
)
101 return (unsigned long)ip
+ *ip
;
104 static int orc_sort_cmp(const void *_a
, const void *_b
)
106 struct orc_entry
*orc_a
;
107 const int *a
= g_orc_ip_table
+ *(int *)_a
;
108 const int *b
= g_orc_ip_table
+ *(int *)_b
;
109 unsigned long a_val
= orc_ip(a
);
110 unsigned long b_val
= orc_ip(b
);
118 * The "weak" section terminator entries need to always be on the left
119 * to ensure the lookup code skips them in favor of real entries.
120 * These terminator entries exist to handle any gaps created by
121 * whitelisted .o files which didn't get objtool generation.
123 orc_a
= g_orc_table
+ (a
- g_orc_ip_table
);
124 return orc_a
->sp_reg
== ORC_REG_UNDEFINED
&& !orc_a
->end
? -1 : 1;
127 static void *sort_orctable(void *arg
)
131 int *tmp_orc_ip_table
= NULL
;
132 struct orc_entry
*tmp_orc_table
= NULL
;
133 unsigned int *orc_ip_size
= (unsigned int *)arg
;
134 unsigned int num_entries
= *orc_ip_size
/ sizeof(int);
135 unsigned int orc_size
= num_entries
* sizeof(struct orc_entry
);
137 idxs
= (int *)malloc(*orc_ip_size
);
139 snprintf(g_err
, ERRSTR_MAXSZ
, "malloc idxs: %s",
144 tmp_orc_ip_table
= (int *)malloc(*orc_ip_size
);
145 if (!tmp_orc_ip_table
) {
146 snprintf(g_err
, ERRSTR_MAXSZ
, "malloc tmp_orc_ip_table: %s",
151 tmp_orc_table
= (struct orc_entry
*)malloc(orc_size
);
152 if (!tmp_orc_table
) {
153 snprintf(g_err
, ERRSTR_MAXSZ
, "malloc tmp_orc_table: %s",
158 /* initialize indices array, convert ip_table to absolute address */
159 for (i
= 0; i
< num_entries
; i
++) {
161 tmp_orc_ip_table
[i
] = g_orc_ip_table
[i
] + i
* sizeof(int);
163 memcpy(tmp_orc_table
, g_orc_table
, orc_size
);
165 qsort(idxs
, num_entries
, sizeof(int), orc_sort_cmp
);
167 for (i
= 0; i
< num_entries
; i
++) {
171 /* convert back to relative address */
172 g_orc_ip_table
[i
] = tmp_orc_ip_table
[idxs
[i
]] - i
* sizeof(int);
173 g_orc_table
[i
] = tmp_orc_table
[idxs
[i
]];
177 free(tmp_orc_ip_table
);
183 static int compare_extable(const void *a
, const void *b
)
195 static int do_sort(Elf_Ehdr
*ehdr
,
196 char const *const fname
,
197 table_sort_t custom_sort
)
200 Elf_Shdr
*s
, *shdr
= (Elf_Shdr
*)((char *)ehdr
+ _r(&ehdr
->e_shoff
));
201 Elf_Shdr
*strtab_sec
= NULL
;
202 Elf_Shdr
*symtab_sec
= NULL
;
203 Elf_Shdr
*extab_sec
= NULL
;
205 const Elf_Sym
*symtab
;
206 Elf32_Word
*symtab_shndx
= NULL
;
207 Elf_Sym
*sort_needed_sym
= NULL
;
208 Elf_Shdr
*sort_needed_sec
;
209 Elf_Rel
*relocs
= NULL
;
211 uint32_t *sort_needed_loc
;
212 const char *secstrings
;
219 unsigned int shstrndx
;
220 #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
221 unsigned int orc_ip_size
= 0;
222 unsigned int orc_size
= 0;
223 unsigned int orc_num_entries
= 0;
226 shstrndx
= r2(&ehdr
->e_shstrndx
);
227 if (shstrndx
== SHN_XINDEX
)
228 shstrndx
= r(&shdr
[0].sh_link
);
229 secstrings
= (const char *)ehdr
+ _r(&shdr
[shstrndx
].sh_offset
);
231 shnum
= r2(&ehdr
->e_shnum
);
232 if (shnum
== SHN_UNDEF
)
233 shnum
= _r(&shdr
[0].sh_size
);
235 for (i
= 0, s
= shdr
; s
< shdr
+ shnum
; i
++, s
++) {
236 idx
= r(&s
->sh_name
);
237 if (!strcmp(secstrings
+ idx
, "__ex_table")) {
241 if (!strcmp(secstrings
+ idx
, ".symtab"))
243 if (!strcmp(secstrings
+ idx
, ".strtab"))
246 if ((r(&s
->sh_type
) == SHT_REL
||
247 r(&s
->sh_type
) == SHT_RELA
) &&
248 r(&s
->sh_info
) == extab_index
) {
249 relocs
= (void *)ehdr
+ _r(&s
->sh_offset
);
250 relocs_size
= _r(&s
->sh_size
);
252 if (r(&s
->sh_type
) == SHT_SYMTAB_SHNDX
)
253 symtab_shndx
= (Elf32_Word
*)((const char *)ehdr
+
256 #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
257 /* locate the ORC unwind tables */
258 if (!strcmp(secstrings
+ idx
, ".orc_unwind_ip")) {
259 orc_ip_size
= s
->sh_size
;
260 g_orc_ip_table
= (int *)((void *)ehdr
+
263 if (!strcmp(secstrings
+ idx
, ".orc_unwind")) {
264 orc_size
= s
->sh_size
;
265 g_orc_table
= (struct orc_entry
*)((void *)ehdr
+
271 #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
272 if (!g_orc_ip_table
|| !g_orc_table
) {
274 "incomplete ORC unwind tables in file: %s\n", fname
);
278 orc_num_entries
= orc_ip_size
/ sizeof(int);
279 if (orc_ip_size
% sizeof(int) != 0 ||
280 orc_size
% sizeof(struct orc_entry
) != 0 ||
281 orc_num_entries
!= orc_size
/ sizeof(struct orc_entry
)) {
283 "inconsistent ORC unwind table entries in file: %s\n",
288 /* create thread to sort ORC unwind tables concurrently */
289 if (pthread_create(&orc_sort_thread
, NULL
,
290 sort_orctable
, &orc_ip_size
)) {
292 "pthread_create orc_sort_thread failed '%s': %s\n",
293 strerror(errno
), fname
);
298 fprintf(stderr
, "no __ex_table in file: %s\n", fname
);
303 fprintf(stderr
, "no .symtab in file: %s\n", fname
);
308 fprintf(stderr
, "no .strtab in file: %s\n", fname
);
312 extab_image
= (void *)ehdr
+ _r(&extab_sec
->sh_offset
);
313 strtab
= (const char *)ehdr
+ _r(&strtab_sec
->sh_offset
);
314 symtab
= (const Elf_Sym
*)((const char *)ehdr
+
315 _r(&symtab_sec
->sh_offset
));
318 custom_sort(extab_image
, _r(&extab_sec
->sh_size
));
320 int num_entries
= _r(&extab_sec
->sh_size
) / extable_ent_size
;
321 qsort(extab_image
, num_entries
,
322 extable_ent_size
, compare_extable
);
325 /* If there were relocations, we no longer need them. */
327 memset(relocs
, 0, relocs_size
);
329 /* find the flag main_extable_sort_needed */
330 for (sym
= (void *)ehdr
+ _r(&symtab_sec
->sh_offset
);
331 sym
< sym
+ _r(&symtab_sec
->sh_size
) / sizeof(Elf_Sym
);
333 if (ELF_ST_TYPE(sym
->st_info
) != STT_OBJECT
)
335 if (!strcmp(strtab
+ r(&sym
->st_name
),
336 "main_extable_sort_needed")) {
337 sort_needed_sym
= sym
;
342 if (!sort_needed_sym
) {
344 "no main_extable_sort_needed symbol in file: %s\n",
349 sort_needed_sec
= &shdr
[get_secindex(r2(&sym
->st_shndx
),
350 sort_needed_sym
- symtab
,
352 sort_needed_loc
= (void *)ehdr
+
353 _r(&sort_needed_sec
->sh_offset
) +
354 _r(&sort_needed_sym
->st_value
) -
355 _r(&sort_needed_sec
->sh_addr
);
357 /* extable has been sorted, clear the flag */
358 w(0, sort_needed_loc
);
362 #if defined(SORTTABLE_64) && defined(UNWINDER_ORC_ENABLED)
363 if (orc_sort_thread
) {
365 /* wait for ORC tables sort done */
366 rc
= pthread_join(orc_sort_thread
, &retval
);
369 "pthread_join failed '%s': %s\n",
370 strerror(errno
), fname
);
374 "failed to sort ORC tables '%s': %s\n",
375 (char *)retval
, fname
);