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