bool RDebug::Init() { // The address of '_r_debug' is in the DT_DEBUG entry of the current // executable. init_ = true; size_t dynamic_addr = 0; size_t dynamic_size = 0; String path; // Find the current executable's full path, and its dynamic section // information. if (!FindExecutablePath(&path)) return false; ProcMaps self_maps; if (!FindElfDynamicSection( path.c_str(), &self_maps, &dynamic_addr, &dynamic_size)) { return false; } // Parse the dynamic table and find the DT_DEBUG entry. const ELF::Dyn* dyn_section = reinterpret_cast<const ELF::Dyn*>(dynamic_addr); while (dynamic_size >= sizeof(*dyn_section)) { if (dyn_section->d_tag == DT_DEBUG) { // Found it! LOG("%s: Found DT_DEBUG entry inside %s at %p, pointing to %p\n", __FUNCTION__, path.c_str(), dyn_section, dyn_section->d_un.d_ptr); if (dyn_section->d_un.d_ptr) { r_debug_ = reinterpret_cast<r_debug*>(dyn_section->d_un.d_ptr); LOG("%s: r_debug [r_version=%d r_map=%p r_brk=%p r_ldbase=%p]\n", __FUNCTION__, r_debug_->r_version, r_debug_->r_map, r_debug_->r_brk, r_debug_->r_ldbase); // Only version 1 of the struct is supported. if (r_debug_->r_version != 1) { LOG("%s: r_debug.r_version is %d, 1 expected.\n", __FUNCTION__, r_debug_->r_version); r_debug_ = NULL; } // The linker of recent Android releases maps its link map entries // in read-only pages. Determine if this is the case and record it // for later. The first entry in the list corresponds to the // executable. int prot = self_maps.GetProtectionFlagsForAddress(r_debug_->r_map); readonly_entries_ = (prot & PROT_WRITE) == 0; LOG("%s: r_debug.readonly_entries=%s\n", __FUNCTION__, readonly_entries_ ? "true" : "false"); return true; } } dyn_section++; dynamic_size -= sizeof(*dyn_section); } LOG("%s: There is no non-0 DT_DEBUG entry in this process\n", __FUNCTION__); return false; }
/* * vislib::sys::Path::FindExecutablePath */ vislib::StringW vislib::sys::Path::FindExecutablePath( const vislib::StringW& filename) { #ifdef _WIN32 bool found = false; DWORD bufSize = MAX_PATH; wchar_t *buffer = new wchar_t[bufSize]; // first try: "SearchPath" DWORD rv = ::SearchPathW(NULL, filename.PeekBuffer(), NULL, bufSize, buffer, NULL); if (rv > 0) { found = true; if (rv + 1 > bufSize) { bufSize = rv + 1; delete[] buffer; buffer = new wchar_t[bufSize]; rv = ::SearchPathW(NULL, filename.PeekBuffer(), NULL, bufSize, buffer, NULL); if (rv == 0) { // failed found = false; } } } if (!found) { // second try: "AssocQueryString" // NOTE: // AssocQueryString does not work as specified! It is not possible to ask // for the size of the string buffer holding the value returned. Therefore // this implementation increases the buffersize until the returned strings // no longer grow. DWORD bufLen = MAX_PATH; HRESULT hr; bufSize = MAX_PATH; do { hr = ::AssocQueryStringW(ASSOCF_INIT_BYEXENAME, ASSOCSTR_EXECUTABLE, filename.PeekBuffer(), NULL, buffer, &bufSize); if ((hr != E_POINTER) && (hr != S_OK)) { // error break; } if (bufSize == bufLen) { bufLen += MAX_PATH; bufSize = bufLen; delete[] buffer; buffer = new wchar_t[bufSize]; } else { found = true; } } while (bufSize == bufLen); } if (found) { vislib::StringW retval(buffer); delete[] buffer; return retval; } else { return L""; } #else /* _WIN32 */ // linux is stupid return A2W(FindExecutablePath(W2A(filename))); #endif /* _WIN32 */ }