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