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;
}
Esempio n. 2
0
/*
 * 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 */
}