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