11/*
22 * sorttable.h
33 *
4+ * Added ORC unwind tables sort support and other updates:
5+ * Copyright (C) 1999-2019 Alibaba Group Holding Limited. by:
6+ * Shile Zhang <shile.zhang@linux.alibaba.com>
7+ *
48 * Copyright 2011 - 2012 Cavium, Inc.
59 *
10+ * Some of code was taken out of arch/x86/kernel/unwind_orc.c, written by:
11+ * Copyright (C) 2017 Josh Poimboeuf <jpoimboe@redhat.com>
12+ *
613 * Some of this code was taken out of recordmcount.h written by:
714 *
815 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
7784# define _w w
7885#endif
7986
87+ #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
88+ /* ORC unwinder only support X86_64 */
89+ #include <errno.h>
90+ #include <pthread.h>
91+ #include <asm/orc_types.h>
92+
93+ #define ERRSTR_MAXSZ 256
94+
95+ char g_err [ERRSTR_MAXSZ ];
96+ int * g_orc_ip_table ;
97+ struct orc_entry * g_orc_table ;
98+
99+ pthread_t orc_sort_thread ;
100+
101+ static inline unsigned long orc_ip (const int * ip )
102+ {
103+ return (unsigned long )ip + * ip ;
104+ }
105+
106+ static int orc_sort_cmp (const void * _a , const void * _b )
107+ {
108+ struct orc_entry * orc_a ;
109+ const int * a = g_orc_ip_table + * (int * )_a ;
110+ const int * b = g_orc_ip_table + * (int * )_b ;
111+ unsigned long a_val = orc_ip (a );
112+ unsigned long b_val = orc_ip (b );
113+
114+ if (a_val > b_val )
115+ return 1 ;
116+ if (a_val < b_val )
117+ return -1 ;
118+
119+ /*
120+ * The "weak" section terminator entries need to always be on the left
121+ * to ensure the lookup code skips them in favor of real entries.
122+ * These terminator entries exist to handle any gaps created by
123+ * whitelisted .o files which didn't get objtool generation.
124+ */
125+ orc_a = g_orc_table + (a - g_orc_ip_table );
126+ return orc_a -> sp_reg == ORC_REG_UNDEFINED && !orc_a -> end ? -1 : 1 ;
127+ }
128+
129+ static void * sort_orctable (void * arg )
130+ {
131+ int i ;
132+ int * idxs = NULL ;
133+ int * tmp_orc_ip_table = NULL ;
134+ struct orc_entry * tmp_orc_table = NULL ;
135+ unsigned int * orc_ip_size = (unsigned int * )arg ;
136+ unsigned int num_entries = * orc_ip_size / sizeof (int );
137+ unsigned int orc_size = num_entries * sizeof (struct orc_entry );
138+
139+ idxs = (int * )malloc (* orc_ip_size );
140+ if (!idxs ) {
141+ snprintf (g_err , ERRSTR_MAXSZ , "malloc idxs: %s" ,
142+ strerror (errno ));
143+ pthread_exit (g_err );
144+ }
145+
146+ tmp_orc_ip_table = (int * )malloc (* orc_ip_size );
147+ if (!tmp_orc_ip_table ) {
148+ snprintf (g_err , ERRSTR_MAXSZ , "malloc tmp_orc_ip_table: %s" ,
149+ strerror (errno ));
150+ pthread_exit (g_err );
151+ }
152+
153+ tmp_orc_table = (struct orc_entry * )malloc (orc_size );
154+ if (!tmp_orc_table ) {
155+ snprintf (g_err , ERRSTR_MAXSZ , "malloc tmp_orc_table: %s" ,
156+ strerror (errno ));
157+ pthread_exit (g_err );
158+ }
159+
160+ /* initialize indices array, convert ip_table to absolute address */
161+ for (i = 0 ; i < num_entries ; i ++ ) {
162+ idxs [i ] = i ;
163+ tmp_orc_ip_table [i ] = g_orc_ip_table [i ] + i * sizeof (int );
164+ }
165+ memcpy (tmp_orc_table , g_orc_table , orc_size );
166+
167+ qsort (idxs , num_entries , sizeof (int ), orc_sort_cmp );
168+
169+ for (i = 0 ; i < num_entries ; i ++ ) {
170+ if (idxs [i ] == i )
171+ continue ;
172+
173+ /* convert back to relative address */
174+ g_orc_ip_table [i ] = tmp_orc_ip_table [idxs [i ]] - i * sizeof (int );
175+ g_orc_table [i ] = tmp_orc_table [idxs [i ]];
176+ }
177+
178+ free (idxs );
179+ free (tmp_orc_ip_table );
180+ free (tmp_orc_table );
181+ pthread_exit (NULL );
182+ }
183+ #endif
184+
80185static int compare_extable (const void * a , const void * b )
81186{
82187 Elf_Addr av = _r (a );
@@ -93,6 +198,7 @@ static int do_sort(Elf_Ehdr *ehdr,
93198 char const * const fname ,
94199 table_sort_t custom_sort )
95200{
201+ int rc = -1 ;
96202 Elf_Shdr * s , * shdr = (Elf_Shdr * )((char * )ehdr + _r (& ehdr -> e_shoff ));
97203 Elf_Shdr * strtab_sec = NULL ;
98204 Elf_Shdr * symtab_sec = NULL ;
@@ -113,6 +219,11 @@ static int do_sort(Elf_Ehdr *ehdr,
113219 int idx ;
114220 unsigned int shnum ;
115221 unsigned int shstrndx ;
222+ #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
223+ unsigned int orc_ip_size = 0 ;
224+ unsigned int orc_size = 0 ;
225+ unsigned int orc_num_entries = 0 ;
226+ #endif
116227
117228 shstrndx = r2 (& ehdr -> e_shstrndx );
118229 if (shstrndx == SHN_XINDEX )
@@ -143,21 +254,61 @@ static int do_sort(Elf_Ehdr *ehdr,
143254 if (r (& s -> sh_type ) == SHT_SYMTAB_SHNDX )
144255 symtab_shndx = (Elf32_Word * )((const char * )ehdr +
145256 _r (& s -> sh_offset ));
257+
258+ #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
259+ /* locate the ORC unwind tables */
260+ if (!strcmp (secstrings + idx , ".orc_unwind_ip" )) {
261+ orc_ip_size = s -> sh_size ;
262+ g_orc_ip_table = (int * )((void * )ehdr +
263+ s -> sh_offset );
264+ }
265+ if (!strcmp (secstrings + idx , ".orc_unwind" )) {
266+ orc_size = s -> sh_size ;
267+ g_orc_table = (struct orc_entry * )((void * )ehdr +
268+ s -> sh_offset );
269+ }
270+ #endif
271+ } /* for loop */
272+
273+ #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
274+ if (!g_orc_ip_table || !g_orc_table ) {
275+ fprintf (stderr ,
276+ "incomplete ORC unwind tables in file: %s\n" , fname );
277+ goto out ;
278+ }
279+
280+ orc_num_entries = orc_ip_size / sizeof (int );
281+ if (orc_ip_size % sizeof (int ) != 0 ||
282+ orc_size % sizeof (struct orc_entry ) != 0 ||
283+ orc_num_entries != orc_size / sizeof (struct orc_entry )) {
284+ fprintf (stderr ,
285+ "inconsistent ORC unwind table entries in file: %s\n" ,
286+ fname );
287+ goto out ;
146288 }
147289
290+ /* create thread to sort ORC unwind tables concurrently */
291+ if (pthread_create (& orc_sort_thread , NULL ,
292+ sort_orctable , & orc_ip_size )) {
293+ fprintf (stderr ,
294+ "pthread_create orc_sort_thread failed '%s': %s\n" ,
295+ strerror (errno ), fname );
296+ goto out ;
297+ }
298+ #endif
148299 if (!extab_sec ) {
149300 fprintf (stderr , "no __ex_table in file: %s\n" , fname );
150- return -1 ;
301+ goto out ;
151302 }
152303
153304 if (!symtab_sec ) {
154305 fprintf (stderr , "no .symtab in file: %s\n" , fname );
155- return -1 ;
306+ goto out ;
156307 }
157308
158309 if (!strtab_sec ) {
159310 fprintf (stderr , "no .strtab in file: %s\n" , fname );
160- return -1 ;
311+ goto out ;
161312 }
162313
163314 extab_image = (void * )ehdr + _r (& extab_sec -> sh_offset );
@@ -194,7 +345,7 @@ static int do_sort(Elf_Ehdr *ehdr,
194345 fprintf (stderr ,
195346 "no main_extable_sort_needed symbol in file: %s\n" ,
196347 fname );
197- return -1 ;
348+ goto out ;
198349 }
199350
200351 sort_needed_sec = & shdr [get_secindex (r2 (& sym -> st_shndx ),
@@ -207,6 +358,25 @@ static int do_sort(Elf_Ehdr *ehdr,
207358
208359 /* extable has been sorted, clear the flag */
209360 w (0 , sort_needed_loc );
361+ rc = 0 ;
210362
211- return 0 ;
363+ out :
364+ #if defined(SORTTABLE_64 ) && defined(UNWINDER_ORC_ENABLED )
365+ if (orc_sort_thread ) {
366+ void * retval = NULL ;
367+ /* wait for ORC tables sort done */
368+ rc = pthread_join (orc_sort_thread , & retval );
369+ if (rc )
370+ fprintf (stderr ,
371+ "pthread_join failed '%s': %s\n" ,
372+ strerror (errno ), fname );
373+ else if (retval ) {
374+ rc = -1 ;
375+ fprintf (stderr ,
376+ "failed to sort ORC tables '%s': %s\n" ,
377+ (char * )retval , fname );
378+ }
379+ }
380+ #endif
381+ return rc ;
212382}
0 commit comments