1 /* 2 * Copyright 2005, Ingo Weinhold, bonefish@users.sf.net. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "SymbolLookup.h" 7 8 #include <new> 9 10 #include <string.h> 11 #include <runtime_loader.h> 12 13 14 using std::nothrow; 15 using namespace BPrivate; 16 17 // PrepareAddress 18 const void * 19 Area::PrepareAddress(const void *address) 20 { 21 TRACE(("Area::PrepareAddress(%p): area: %ld\n", address, fRemoteID)); 22 23 // clone the area, if not done already 24 if (fLocalID < 0) { 25 fLocalID = clone_area("cloned area", &fLocalAddress, B_ANY_ADDRESS, 26 B_READ_AREA, fRemoteID); 27 if (fLocalID < 0) { 28 TRACE(("Area::PrepareAddress(): Failed to clone area %ld: %s\n", 29 fRemoteID, strerror(fLocalID))); 30 throw Exception(fLocalID); 31 } 32 } 33 34 // translate the address 35 const void *result = (const void*)((addr_t)address - (addr_t)fRemoteAddress 36 + (addr_t)fLocalAddress); 37 38 TRACE(("Area::PrepareAddress(%p) done: %p\n", address, result)); 39 40 return result; 41 } 42 43 44 // #pragma mark - 45 46 // constructor 47 RemoteMemoryAccessor::RemoteMemoryAccessor(team_id team) 48 : fTeam(team), 49 fAreas() 50 { 51 } 52 53 // destructor 54 RemoteMemoryAccessor::~RemoteMemoryAccessor() 55 { 56 // delete the areas 57 while (Area *area = fAreas.Head()) { 58 fAreas.Remove(area); 59 delete area; 60 } 61 } 62 63 // Init 64 status_t 65 RemoteMemoryAccessor::Init() 66 { 67 // get a list of the team's areas 68 area_info areaInfo; 69 int32 cookie = 0; 70 status_t error; 71 while ((error = get_next_area_info(fTeam, &cookie, &areaInfo)) == B_OK) { 72 73 TRACE(("area %ld: address: %p, size: %ld, name: %s\n", areaInfo.area, 74 areaInfo.address, areaInfo.size, areaInfo.name)); 75 76 Area *area = new(nothrow) Area(areaInfo.area, areaInfo.address, 77 areaInfo.size); 78 if (!area) 79 return B_NO_MEMORY; 80 81 fAreas.Add(area); 82 } 83 84 if (fAreas.IsEmpty()) 85 return error; 86 87 return B_OK; 88 } 89 90 // PrepareAddress 91 const void * 92 RemoteMemoryAccessor::PrepareAddress(const void *remoteAddress, int32 size) 93 { 94 TRACE(("RemoteMemoryAccessor::PrepareAddress(%p, %ld)\n", remoteAddress, 95 size)); 96 97 if (!remoteAddress) { 98 TRACE(("RemoteMemoryAccessor::PrepareAddress(): Got null address!\n")); 99 throw Exception(B_BAD_VALUE); 100 } 101 102 return _FindArea(remoteAddress, size).PrepareAddress(remoteAddress); 103 } 104 105 // _FindArea 106 Area & 107 RemoteMemoryAccessor::_FindArea(const void *address, int32 size) 108 { 109 TRACE(("RemoteMemoryAccessor::_FindArea(%p, %ld)\n", address, size)); 110 111 for (AreaList::Iterator it = fAreas.GetIterator(); it.HasNext();) { 112 Area *area = it.Next(); 113 if (area->ContainsAddress(address, size)) 114 return *area; 115 } 116 117 TRACE(("RemoteMemoryAccessor::_FindArea(): No area found for address %p\n", 118 address)); 119 throw Exception(B_ENTRY_NOT_FOUND); 120 } 121 122 123 // #pragma mark - 124 125 // constructor 126 SymbolLookup::SymbolLookup(team_id team) 127 : RemoteMemoryAccessor(team), 128 fDebugArea(NULL) 129 { 130 } 131 132 // destructor 133 SymbolLookup::~SymbolLookup() 134 { 135 } 136 137 // Init 138 status_t 139 SymbolLookup::Init() 140 { 141 TRACE(("SymbolLookup::Init()\n")); 142 143 status_t error = RemoteMemoryAccessor::Init(); 144 if (error != B_OK) 145 return error; 146 147 TRACE(("SymbolLookup::Init(): searching debug area...\n")); 148 149 // find the runtime loader debug area 150 runtime_loader_debug_area *remoteDebugArea = NULL; 151 int32 cookie = 0; 152 area_info areaInfo; 153 while (get_next_area_info(fTeam, &cookie, &areaInfo) == B_OK) { 154 if (strcmp(areaInfo.name, RUNTIME_LOADER_DEBUG_AREA_NAME) == 0) { 155 remoteDebugArea = (runtime_loader_debug_area*)areaInfo.address; 156 break; 157 } 158 } 159 160 if (!remoteDebugArea) { 161 TRACE(("SymbolLookup::Init(): Couldn't find debug area!\n")); 162 return B_ERROR; 163 } 164 165 TRACE(("SymbolLookup::Init(): found debug area, translating address...\n")); 166 167 // translate the address 168 try { 169 fDebugArea = &Read(*remoteDebugArea); 170 171 TRACE(("SymbolLookup::Init(): translated debug area is at: %p, " 172 "loaded_images: %p\n", fDebugArea, fDebugArea->loaded_images)); 173 174 } catch (Exception exception) { 175 return exception.Error(); 176 } 177 178 return B_OK; 179 } 180 181 // LookupSymbolAddress 182 status_t 183 SymbolLookup::LookupSymbolAddress(addr_t address, addr_t *_baseAddress, 184 const char **_symbolName, const char **_imageName, bool *_exactMatch) 185 { 186 // Note, that this function doesn't find all symbols that we would like 187 // to find. E.g. static functions do not appear in the symbol table 188 // as function symbols, but as sections without name and size. The .symtab 189 // section together with the .strtab section, which apparently differ from 190 // the tables referred to by the .dynamic section, also contain proper names 191 // and sizes for those symbols. Therefore, to get completely satisfying 192 // results, we would need to read those tables from the shared object. 193 194 TRACE(("SymbolLookup::LookupSymbolAddress(%p)\n", (void*)address)); 195 196 // get the image for the address 197 const image_t *image = _FindImageAtAddress(address); 198 if (!image) 199 return B_ENTRY_NOT_FOUND; 200 201 TRACE(("SymbolLookup::LookupSymbolAddress(): found image: ID: %ld, text: " 202 "address: %p, size: %ld\n", 203 image->id, (void*)image->regions[0].vmstart, image->regions[0].size)); 204 205 // search the image for the symbol 206 const struct Elf32_Sym *symbolFound = NULL; 207 addr_t deltaFound = INT_MAX; 208 bool exactMatch = false; 209 const char *symbolName = NULL; // remote 210 211 int32 hashTabSize = Read(image->symhash[0]); 212 const uint32 *hashBuckets = image->symhash + 2; // remote 213 const uint32 *hashChains = image->symhash + 2 + hashTabSize; // remote 214 const elf_region_t *textRegion = image->regions; // local 215 216 for (int32 i = 0; i < hashTabSize; i++) { 217 for (int32 j = Read(hashBuckets[i]); 218 j != STN_UNDEF; 219 j = Read(hashChains[j])) { 220 221 const struct Elf32_Sym *symbol = &Read(image->syms[j]); 222 223 // The symbol table contains not only symbols referring to functions 224 // and data symbols within the shared object, but also referenced 225 // symbols of other shared objects, as well as section and file 226 // references. We ignore everything but function and data symbols 227 // that have an st_value != 0 (0 seems to be an indication for a 228 // symbol defined elsewhere -- couldn't verify that in the specs 229 // though). 230 if ((ELF32_ST_TYPE(symbol->st_info) != STT_FUNC 231 && ELF32_ST_TYPE(symbol->st_info) != STT_OBJECT) 232 || symbol->st_value == 0 233 || symbol->st_value + symbol->st_size + textRegion->delta 234 > textRegion->vmstart + textRegion->size) { 235 continue; 236 } 237 238 // skip symbols starting after the given address 239 addr_t symbolAddress = symbol->st_value + textRegion->delta; 240 241 if (symbolAddress > address) 242 continue; 243 addr_t symbolDelta = address - symbolAddress; 244 245 if (!symbolFound || symbolDelta < deltaFound) { 246 deltaFound = symbolDelta; 247 symbolFound = symbol; 248 symbolName = SYMNAME(image, symbol); 249 250 if (symbolDelta >= 0 && symbolDelta < symbol->st_size) { 251 // exact match 252 exactMatch = true; 253 break; 254 } 255 } 256 } 257 } 258 259 TRACE(("SymbolLookup::LookupSymbolAddress(): done: symbol: %p, image name: " 260 "%s, exact match: %d\n", symbolFound, image->name, exactMatch)); 261 262 if (_baseAddress) { 263 if (symbolFound) 264 *_baseAddress = symbolFound->st_value + textRegion->delta; 265 else 266 *_baseAddress = textRegion->vmstart; 267 } 268 269 if (_imageName) 270 *_imageName = image->name; 271 272 if (_symbolName) 273 *_symbolName = symbolName; // remote address 274 275 if (_exactMatch) 276 *_exactMatch = exactMatch; 277 278 return B_OK; 279 } 280 281 // _FindImageAtAddress 282 const image_t * 283 SymbolLookup::_FindImageAtAddress(addr_t address) 284 { 285 TRACE(("SymbolLookup::_FindImageAtAddress(%p)\n", (void*)address)); 286 287 // iterate through the images 288 for (const image_t *image = &Read(*Read(fDebugArea->loaded_images->head)); 289 image; 290 image = &Read(*image->next)) { 291 if (image->regions[0].vmstart <= address 292 && address < image->regions[0].vmstart + image->regions[0].size) { 293 return image; 294 } 295 } 296 297 return NULL; 298 } 299 300