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 255
17 typedef struct {
18   void* Offset;
19   char FName[SymbolNameSize+1];
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       if ( (read == 0) || ( read == EOF) ){
62         error = 2;
63         break;
64       }
65       if (endofline != '\n'){
66         bs_skipline(symbols_file); //disregard the rest of the function name
67       }
68       read_symbols++;
69     }
70     if ( error || ( nbr_symbols != read_symbols )) {
71       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);
72       if (error){
73         free(functions_table);
74         functions_table = NULL;
75       }
76     }
77     Number_Symbols = read_symbols;
78     fclose(symbols_file);
79   }
80 }
81 #endif /* _BS_TSYMBOLS_TRACE */
82 
bs_clear_Tsymbols()83 void bs_clear_Tsymbols(){
84   if ( functions_table != NULL ) {
85     free(functions_table);
86     functions_table = NULL;
87   }
88 }
89 
90 
91 /**
92  * For a given ptr, tell if this could actually be a symbol (or an offset relative to a symbol) == 1
93  * or not == 0
94  */
bs_could_be_symbol(uint32_t ptr)95 int bs_could_be_symbol(uint32_t ptr){
96 #if (_BS_TSYMBOLS_TRACE )
97   if ( functions_table == NULL )
98     return 0;
99   if ( ( ((intptr_t) ptr) < ((intptr_t)functions_table[0].Offset) )
100       || ( ((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
101     return 0;
102   }
103   return 1;
104 #else
105   return 0;
106 #endif
107 }
108 
109 /*
110  * For a given pointer, return the entry in functions_table which contains it (+ the Offset)
111  */
bs_find_symbol_name(void * fptr,uint * EntryNbr,intptr_t * Offset)112 static void bs_find_symbol_name(void *fptr, uint *EntryNbr, intptr_t *Offset){
113   *EntryNbr = 0;
114 
115   {// we search for the last entry smaller than fptr
116     uint Step = ( Number_Symbols + 1 )/ 2;
117     int Trial = Step;
118     uint CloserEntry = 0;
119     int64_t CloserDistance = INT64_MAX;
120 
121     int64_t distance;
122     while ( Step != 0 ){ //A search thru bisection
123       distance = ((intptr_t)fptr) - ((intptr_t)functions_table[Trial].Offset);
124 
125       if ( Step > 1 ) {
126         Step = ( Step + 1 )/ 2;
127       } else {
128         Step = 0;
129       }
130 
131       if ( distance < 0 ) {
132         Trial = BS_MAX(Trial-(int)Step,0);
133       } else if ( distance > 0 ) {
134         if ( distance < CloserDistance ){
135           CloserDistance = distance;
136           CloserEntry = Trial;
137         }
138         Trial = BS_MIN(Trial+Step,Number_Symbols-1);
139       } else if ( distance == 0 ) {
140         CloserDistance = distance;
141         CloserEntry = Trial;
142         break;
143       }
144     }
145 
146     *EntryNbr = CloserEntry;
147   }
148 
149   *Offset = ( (intptr_t) fptr ) - (intptr_t)functions_table[*EntryNbr].Offset;
150 }
151 
152 /*
153  * Print to a string the name of a function/variable given its pointer as in:
154  *  (Symbol_Name+Offset) [Absolute Address in Memory]
155  */
bs_snprint_symbol_name_from_Tsymbols(void * fptr,char * ptr,size_t n)156 void bs_snprint_symbol_name_from_Tsymbols(void *fptr, char* ptr, size_t n){
157   if ( functions_table == NULL ){
158     snprintf(ptr,n, "%p",fptr);
159   } else {
160     uint EntryNbr;
161     intptr_t Offset;
162     bs_find_symbol_name(fptr, &EntryNbr, &Offset);
163     if (Offset == 0) {
164       snprintf(ptr,n, "(%s) [%p]",functions_table[EntryNbr].FName, fptr);
165     } else {
166       snprintf(ptr,n, "(%s + %p) [%p]",functions_table[EntryNbr].FName, (void*)Offset, fptr);
167     }
168   }
169 }
170