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