@@ -267,3 +267,113 @@ long elf_find_func_offset_from_file(const char *binary_path, const char *name)
267267 elf_close (& elf_fd );
268268 return ret ;
269269}
270+
271+ struct symbol {
272+ const char * name ;
273+ int bind ;
274+ int idx ;
275+ };
276+
277+ static int symbol_cmp (const void * a , const void * b )
278+ {
279+ const struct symbol * sym_a = a ;
280+ const struct symbol * sym_b = b ;
281+
282+ return strcmp (sym_a -> name , sym_b -> name );
283+ }
284+
285+ /*
286+ * Return offsets in @poffsets for symbols specified in @syms array argument.
287+ * On success returns 0 and offsets are returned in allocated array with @cnt
288+ * size, that needs to be released by the caller.
289+ */
290+ int elf_resolve_syms_offsets (const char * binary_path , int cnt ,
291+ const char * * syms , unsigned long * * poffsets )
292+ {
293+ int sh_types [2 ] = { SHT_DYNSYM , SHT_SYMTAB };
294+ int err = 0 , i , cnt_done = 0 ;
295+ unsigned long * offsets ;
296+ struct symbol * symbols ;
297+ struct elf_fd elf_fd ;
298+
299+ err = elf_open (binary_path , & elf_fd );
300+ if (err )
301+ return err ;
302+
303+ offsets = calloc (cnt , sizeof (* offsets ));
304+ symbols = calloc (cnt , sizeof (* symbols ));
305+
306+ if (!offsets || !symbols ) {
307+ err = - ENOMEM ;
308+ goto out ;
309+ }
310+
311+ for (i = 0 ; i < cnt ; i ++ ) {
312+ symbols [i ].name = syms [i ];
313+ symbols [i ].idx = i ;
314+ }
315+
316+ qsort (symbols , cnt , sizeof (* symbols ), symbol_cmp );
317+
318+ for (i = 0 ; i < ARRAY_SIZE (sh_types ); i ++ ) {
319+ struct elf_sym_iter iter ;
320+ struct elf_sym * sym ;
321+
322+ err = elf_sym_iter_new (& iter , elf_fd .elf , binary_path , sh_types [i ], STT_FUNC );
323+ if (err == - ENOENT )
324+ continue ;
325+ if (err )
326+ goto out ;
327+
328+ while ((sym = elf_sym_iter_next (& iter ))) {
329+ unsigned long sym_offset = elf_sym_offset (sym );
330+ int bind = GELF_ST_BIND (sym -> sym .st_info );
331+ struct symbol * found , tmp = {
332+ .name = sym -> name ,
333+ };
334+ unsigned long * offset ;
335+
336+ found = bsearch (& tmp , symbols , cnt , sizeof (* symbols ), symbol_cmp );
337+ if (!found )
338+ continue ;
339+
340+ offset = & offsets [found -> idx ];
341+ if (* offset > 0 ) {
342+ /* same offset, no problem */
343+ if (* offset == sym_offset )
344+ continue ;
345+ /* handle multiple matches */
346+ if (found -> bind != STB_WEAK && bind != STB_WEAK ) {
347+ /* Only accept one non-weak bind. */
348+ pr_warn ("elf: ambiguous match found '%s@%lu' in '%s' previous offset %lu\n" ,
349+ sym -> name , sym_offset , binary_path , * offset );
350+ err = - ESRCH ;
351+ goto out ;
352+ } else if (bind == STB_WEAK ) {
353+ /* already have a non-weak bind, and
354+ * this is a weak bind, so ignore.
355+ */
356+ continue ;
357+ }
358+ } else {
359+ cnt_done ++ ;
360+ }
361+ * offset = sym_offset ;
362+ found -> bind = bind ;
363+ }
364+ }
365+
366+ if (cnt != cnt_done ) {
367+ err = - ENOENT ;
368+ goto out ;
369+ }
370+
371+ * poffsets = offsets ;
372+
373+ out :
374+ free (symbols );
375+ if (err )
376+ free (offsets );
377+ elf_close (& elf_fd );
378+ return err ;
379+ }
0 commit comments