1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "bs_types.h"
7 #include "bs_tracing.h"
8 #include "bs_symbols.h"
9 #include "bs_oswrap.h"
10 #include "bs_utils.h"
11 
12 /***********************************************************
13  * Functions to resolve symbols names from their addresses *
14  ***********************************************************/
15 
16 #define SymbolNameSize 256
17 typedef struct {
18   void* Offset;
19   char FName[SymbolNameSize];
20 } symbol_entry_t;
21 
22 symbol_entry_t *functions_table = NULL;
23 uint Number_Symbols = 0;
24 
25 #if (_BS_TSYMBOLS_TRACE)
26 /**
27  * Load the Tsymbols file into memory
28  * Note: this is quite unreliable (very OS and toolchain dependent),
29  * but the functionality it provides is quite superfluous (debugging aid)
30  * Therefore it is meant to fail silently
31  */
bs_read_function_names_from_Tsymbols(const char * probable_binary_name)32 void bs_read_function_names_from_Tsymbols(const char *probable_binary_name){
33   if ( probable_binary_name != NULL ) {
34 #define TSymbolsNameSize 256
35     char symbols_fname[TSymbolsNameSize];
36     snprintf(symbols_fname, TSymbolsNameSize, "%s.Tsymbols", probable_binary_name);
37 
38     FILE *symbols_file = fopen(symbols_fname,"rt");
39     if ( symbols_file == NULL ) {
40       return;
41     }
42     uint nbr_symbols = 0;
43     uint read_symbols = 0;
44     uint error = 0;
45     if ( fscanf(symbols_file, "%u\n", &nbr_symbols) != 1 ) {
46       fclose(symbols_file);
47       return;
48     }
49     functions_table = bs_calloc(nbr_symbols, sizeof(symbol_entry_t));
50 
51     while ( !feof(symbols_file) && ( read_symbols < nbr_symbols ) ){
52       int read = fscanf(symbols_file, "%p", &functions_table[read_symbols].Offset);
53       char endofline;
54 
55       if ( (read == 0) || ( read == EOF) ) {
56         error = 1;
57         break;
58       }
59 
60       read = fscanf(symbols_file, "%"STR(SymbolNameSize)"s%c", functions_table[read_symbols].FName, &endofline);
61       functions_table[read_symbols].FName[SymbolNameSize-1] = '\0'; //properly terminate it, in case it was longer than SymbolNameSize
62       if ( (read == 0) || ( read == EOF) ){
63         error = 2;
64         break;
65       }
66       if (endofline != '\n'){
67         bs_skipline(symbols_file); //disregard the rest of the function name
68       }
69       read_symbols++;
70     }
71     if ( error || ( nbr_symbols != read_symbols )) {
72       bs_trace_warning_line("%s seems to be corrupted (%i) (Expected %u entries, read so far %u)\n",symbols_fname, error, nbr_symbols, read_symbols);
73       if (error){
74         free(functions_table);
75         functions_table = NULL;
76       }
77     }
78     Number_Symbols = read_symbols;
79     fclose(symbols_file);
80   }
81 }
82 #endif /* _BS_TSYMBOLS_TRACE */
83 
bs_clear_Tsymbols()84 void bs_clear_Tsymbols(){
85   if ( functions_table != NULL ) {
86     free(functions_table);
87     functions_table = NULL;
88   }
89 }
90 
91 
92 /**
93  * For a given ptr, tell if this could actually be a symbol (or an offset relative to a symbol) == 1
94  * or not == 0
95  */
bs_could_be_symbol(uint32_t ptr)96 int bs_could_be_symbol(uint32_t ptr){
97 #if (_BS_TSYMBOLS_TRACE )
98   if ( functions_table == NULL )
99     return 0;
100   if ( ( ((intptr_t) ptr) < ((intptr_t)functions_table[0].Offset) )
101       || ( ((intptr_t) ptr) > ((intptr_t)functions_table[Number_Symbols-1].Offset) ) ) { //if it is smaller than _init or greater than _end, this is not a symbol
102     return 0;
103   }
104   return 1;
105 #else
106   return 0;
107 #endif
108 }
109 
110 /*
111  * For a given pointer, return the entry in functions_table which contains it (+ the Offset)
112  */
bs_find_symbol_name(void * fptr,uint * EntryNbr,intptr_t * Offset)113 static void bs_find_symbol_name(void *fptr, uint *EntryNbr, intptr_t *Offset){
114   *EntryNbr = 0;
115 
116   {// we search for the last entry smaller than fptr
117     uint Step = ( Number_Symbols + 1 )/ 2;
118     int Trial = Step;
119     uint CloserEntry = 0;
120     int64_t CloserDistance = INT64_MAX;
121 
122     int64_t distance;
123     while ( Step != 0 ){ //A search thru bisection
124       distance = ((intptr_t)fptr) - ((intptr_t)functions_table[Trial].Offset);
125 
126       if ( Step > 1 ) {
127         Step = ( Step + 1 )/ 2;
128       } else {
129         Step = 0;
130       }
131 
132       if ( distance < 0 ) {
133         Trial = BS_MAX(Trial-(int)Step,0);
134       } else if ( distance > 0 ) {
135         if ( distance < CloserDistance ){
136           CloserDistance = distance;
137           CloserEntry = Trial;
138         }
139         Trial = BS_MIN(Trial+Step,Number_Symbols-1);
140       } else if ( distance == 0 ) {
141         CloserDistance = distance;
142         CloserEntry = Trial;
143         break;
144       }
145     }
146 
147     *EntryNbr = CloserEntry;
148   }
149 
150   *Offset = ( (intptr_t) fptr ) - (intptr_t)functions_table[*EntryNbr].Offset;
151 }
152 
153 /*
154  * Print to a string the name of a function/variable given its pointer as in:
155  *  (Symbol_Name+Offset) [Absolute Address in Memory]
156  */
bs_snprint_symbol_name_from_Tsymbols(void * fptr,char * ptr,size_t n)157 void bs_snprint_symbol_name_from_Tsymbols(void *fptr, char* ptr, size_t n){
158   if ( functions_table == NULL ){
159     snprintf(ptr,n, "%p",fptr);
160   } else {
161     uint EntryNbr;
162     intptr_t Offset;
163     bs_find_symbol_name(fptr, &EntryNbr, &Offset);
164     if (Offset == 0) {
165       snprintf(ptr,n, "(%s) [%p]",functions_table[EntryNbr].FName, fptr);
166     } else {
167       snprintf(ptr,n, "(%s + %p) [%p]",functions_table[EntryNbr].FName, (void*)Offset, fptr);
168     }
169   }
170 }
171