コード例 #1
0
ファイル: PeHeaderParser.cpp プロジェクト: Redchards/PeParser
void PEHeaderParser::init()
{
	if (getLfanew() == 0)
	{
		throw std::ios_base::failure("Error : bad lfanew value detected. If it is a PE file, it may be corrupted.");
	}

	if (is32bit())
	{
		layout_ = OptionalHeaderLayout<CPUSize::CPU32>::infos.getHolderPtr();
	}
	else
	{
		layout_ = OptionalHeaderLayout<CPUSize::CPU64>::infos.getHolderPtr();
	}
	bool objectFile = false;

	if (!hasPESignature())
	{
		throw std::ios_base::failure("Error : No PE signature detected. If it is a PE file, it may be corrupted.");
	}
	else if (!hasValidMagicNumber())
	{
		throw std::ios_base::failure("Error : Bad magic number value detected. If it is a PE file, it may be corrupted.");
	}

	dllFlags_ = retrieveFieldValue(OptionalHeaderField::DllCharacteristics);
}
コード例 #2
0
static int make_dump_request(debugger_action_t action, pid_t tid) {
  const char* socket_name;
  debugger_msg_t msg;
  size_t msg_len;
  void* msg_ptr;

#if defined(__LP64__)
  debugger32_msg_t msg32;
  if (is32bit(tid)) {
    msg_len = sizeof(debugger32_msg_t);
    memset(&msg32, 0, msg_len);
    msg32.tid = tid;
    msg32.action = action;
    msg_ptr = &msg32;

    socket_name = DEBUGGER32_SOCKET_NAME;
  } else
#endif
  {
    msg_len = sizeof(debugger_msg_t);
    memset(&msg, 0, msg_len);
    msg.tid = tid;
    msg.action = action;
    msg_ptr = &msg;

    socket_name = DEBUGGER_SOCKET_NAME;
  }

  int sock_fd = socket_local_client(socket_name, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
      SOCK_STREAM | SOCK_CLOEXEC);
  if (sock_fd < 0) {
    return -1;
  }

  if (send_request(sock_fd, msg_ptr, msg_len) < 0) {
    TEMP_FAILURE_RETRY(close(sock_fd));
    return -1;
  }

  return sock_fd;
}
コード例 #3
0
ファイル: SharedBitmap.cpp プロジェクト: 3163504123/phantomjs
PassRefPtr<SharedBitmap> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha)
{
    int oldWidth = width();
    int oldHeight = height();
    int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
    int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
    if (!copyWidth || !copyHeight)
        return 0;

    RefPtr<SharedBitmap> newBmp = create(IntSize(copyWidth, copyHeight), useAlpha && is32bit() ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16, false);

    if (!newBmp || !newBmp->bytes())
        return 0;

    DCHolder dcNew(newBmp.get());

    StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight,
        bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);

    return newBmp;
}
コード例 #4
0
ファイル: SharedBitmap.cpp プロジェクト: 3163504123/phantomjs
void SharedBitmap::drawPattern(HDC hdc, const AffineTransform& transform, const FloatRect& tileRectIn, const AffineTransform& patternTransform,
                        const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect, const IntSize& origSourceSize)
{
    if (!m_pixels)
        return;

    if (tileRectIn.width() <= 0 || tileRectIn.height() <= 0)
        return;

    bool useAlpha = op == CompositeSourceOver && hasAlpha() && is32bit();

    int bmpWidth = width();
    int bmpHeight = height();

    FloatRect tileRect(tileRectIn);
    if (bmpWidth != origSourceSize.width()) {
        double rate = static_cast<double>(bmpWidth) / origSourceSize.width();
        double temp = tileRect.width() * rate;
        tileRect.setX(tileRect.x() * rate);
        tileRect.setWidth(temp);
        temp = tileRect.height() * rate;
        tileRect.setY(tileRect.y() * rate);
        tileRect.setHeight(temp);
    }

    OwnPtr<HBITMAP> clippedBmp;

    if (tileRect.x() || tileRect.y() || tileRect.width() != bmpWidth || tileRect.height() != bmpHeight) {
        BitmapInfo patternBmpInfo;
        void* patternPixels;
        clippedBmp = clipBitmap(IntRect(tileRect), useAlpha, patternBmpInfo, patternPixels);
        if (!clippedBmp)
            return;

        bmpWidth = tileRect.width();
        bmpHeight = tileRect.height();
    }

    AffineTransform tf = patternTransform * transform;

    FloatRect trRect = tf.mapRect(destRect);

    RECT clipBox;
    int clipType = GetClipBox(hdc, &clipBox);
    if (clipType == SIMPLEREGION)
        trRect.intersect(FloatRect(clipBox.left, clipBox.top, clipBox.right - clipBox.left, clipBox.bottom - clipBox.top));
    else if (clipType == COMPLEXREGION) {
        OwnPtr<HRGN> clipRgn = adoptPtr(CreateRectRgn(0, 0, 0, 0));
        if (GetClipRgn(hdc, clipRgn.get()) > 0) {
            DWORD regionDataSize = GetRegionData(clipRgn.get(), sizeof(RGNDATA), 0);
            if (regionDataSize) {
                Vector<RGNDATA> regionData(regionDataSize);
                GetRegionData(clipRgn.get(), regionDataSize, regionData.data());
                RECT* rect = reinterpret_cast<RECT*>(regionData[0].Buffer);
                for (DWORD i = 0; i < regionData[0].rdh.nCount; ++i, ++rect)
                    trRect.intersect(FloatRect(rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top));
            }
        }
    }

    if (trRect.width() <= 0 || trRect.height() <= 0)
        return;

    trRect.inflate(1);
    IntRect visibleDstRect = enclosingIntRect(tf.inverse().mapRect(trRect));
    visibleDstRect.intersect(IntRect(destRect));

    if (visibleDstRect.width() <= 0 || visibleDstRect.height() <= 0)
        return;

    trRect = tf.mapRect(visibleDstRect);
    RECT dstRectWin = {
        stableRound(trRect.x()),
        stableRound(trRect.y()),
        stableRound(trRect.maxX()),
        stableRound(trRect.maxY()),
    };
    if (dstRectWin.right <= dstRectWin.left || dstRectWin.bottom <= dstRectWin.top)
        return;

    SIZE bmpSize = { bmpWidth, bmpHeight };

    // Relative to destination, in bitmap pixels
    POINT phaseWin = { stableRound(visibleDstRect.x() - phase.x()), stableRound(visibleDstRect.y() - phase.y()) };
    phaseWin.x = normalizePhase(phaseWin.x, bmpSize.cx);
    phaseWin.y = normalizePhase(phaseWin.y, bmpSize.cy);

    RECT srcRectWin = {
        0,
        0,
        stableRound(visibleDstRect.maxX()) - stableRound(visibleDstRect.x()),
        stableRound(visibleDstRect.maxY()) - stableRound(visibleDstRect.y())
    };
    if (srcRectWin.right <= 0 || srcRectWin.bottom <= 0)
        return;

    BitmapInfo bmpInfo = BitmapInfo::createBottomUp(IntSize(srcRectWin.right, srcRectWin.bottom), useAlpha ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
    void* pixels;
    OwnPtr<HBITMAP> hbmpTemp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));

    if (!hbmpTemp)
        return;

    OwnPtr<HDC> hmemdc = adoptPtr(CreateCompatibleDC(hdc));
    HGDIOBJ oldBmp = SelectObject(hmemdc.get(), hbmpTemp.get());
    if (clippedBmp)
        drawPatternSimple(hmemdc.get(), srcRectWin, clippedBmp.get(), phaseWin);
    else if ((op != CompositeSourceOver || canUseDIBits()) && srcRectWin.right <= bmpSize.cx * 2 && srcRectWin.bottom <= bmpSize.cy * 2)
        drawPatternSimple(hmemdc.get(), srcRectWin, this, bmpSize, phaseWin);
    else if (ensureHandle())
        drawPatternSimple(hmemdc.get(), srcRectWin, getHandle(), phaseWin);
    else {
        void* pixels;
        BitmapInfo bmpInfo;
        OwnPtr<HBITMAP> hbmp = createHandle(&pixels, &bmpInfo, -1, false);
        if (hbmp)
            drawPatternSimple(hmemdc.get(), srcRectWin, hbmp.get(), phaseWin);
        else {
            SelectObject(hmemdc.get(), oldBmp);
            return;
        }
    }

    if (useAlpha && hasAlphaBlendSupport()) {
        static const BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
        bool success = alphaBlendIfSupported(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left, dstRectWin.bottom - dstRectWin.top,
            hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, blend);
        ASSERT_UNUSED(success, success);
    } else if (useAlpha && !hasAlphaBlendSupport() || op == CompositeSourceOver && usesTransparentColor()) {
        TransparentBlt(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left,
            dstRectWin.bottom - dstRectWin.top, hmemdc.get(), 0, 0, srcRectWin.right, srcRectWin.bottom, transparentColor());
    } else {
        DWORD bmpOp = op == CompositeCopy ? SRCCOPY
                    : op == CompositeSourceOver ? SRCCOPY
                    : op == CompositeXOR ? PATINVERT
                    : op == CompositeClear ? WHITENESS
                    : SRCCOPY; // FIXEME: other types?

        StretchDIBits(hdc, dstRectWin.left, dstRectWin.top, dstRectWin.right - dstRectWin.left,
            dstRectWin.bottom - dstRectWin.top, 0, 0, srcRectWin.right, srcRectWin.bottom,
            pixels, &bmpInfo, DIB_RGB_COLORS, bmpOp);
    }
    SelectObject(hmemdc.get(), oldBmp);
}
コード例 #5
0
ファイル: SharedBitmap.cpp プロジェクト: 3163504123/phantomjs
PassOwnPtr<HBITMAP> SharedBitmap::clipBitmap(const IntRect& rect, bool useAlpha, BitmapInfo& bmpInfo, void*& pixels)
{
    if (!bytes())
        return nullptr;

    int oldWidth = width();
    int oldHeight = height();
    int copyWidth = std::min<int>(rect.width(), oldWidth - rect.x());
    int copyHeight = std::min<int>(rect.height(), oldHeight - rect.y());
    if (!copyWidth || !copyHeight)
        return nullptr;

    bmpInfo = BitmapInfo::createBottomUp(IntSize(copyWidth, copyHeight), (useAlpha && is32bit()) ? BitmapInfo::BitCount32 : BitmapInfo::BitCount16);
    OwnPtr<HBITMAP> newBmp = adoptPtr(CreateDIBSection(0, &bmpInfo, DIB_RGB_COLORS, &pixels, 0, 0));

    if (!newBmp)
        return nullptr;

    OwnPtr<HDC> dcNew = adoptPtr(CreateCompatibleDC(0));
    HGDIOBJ tmpNew = SelectObject(dcNew.get(), newBmp.get());

    StretchDIBits(dcNew.get(), 0, 0, copyWidth, copyHeight, rect.x(), rect.y(), copyWidth, copyHeight,
        bytes(), &bitmapInfo(), DIB_RGB_COLORS, SRCCOPY);

    SelectObject(dcNew.get(), tmpNew);
    return newBmp.release();
}
コード例 #6
0
static void monitor_worker_process(int child_pid, const debugger_request_t& request) {
  struct timespec timeout = {.tv_sec = 10, .tv_nsec = 0 };
  if (should_attach_gdb(request)) {
    // If wait_for_gdb is enabled, set the timeout to something large.
    timeout.tv_sec = INT_MAX;
  }

  sigset_t signal_set;
  sigemptyset(&signal_set);
  sigaddset(&signal_set, SIGCHLD);

  bool kill_worker = false;
  bool kill_target = false;
  bool kill_self = false;

  int status;
  siginfo_t siginfo;
  int signal = TEMP_FAILURE_RETRY(sigtimedwait(&signal_set, &siginfo, &timeout));
  if (signal == SIGCHLD) {
    pid_t rc = waitpid(-1, &status, WNOHANG | WUNTRACED);
    if (rc != child_pid) {
      ALOGE("debuggerd: waitpid returned unexpected pid (%d), committing murder-suicide", rc);

      if (WIFEXITED(status)) {
        ALOGW("debuggerd: pid %d exited with status %d", rc, WEXITSTATUS(status));
      } else if (WIFSIGNALED(status)) {
        ALOGW("debuggerd: pid %d received signal %d", rc, WTERMSIG(status));
      } else if (WIFSTOPPED(status)) {
        ALOGW("debuggerd: pid %d stopped by signal %d", rc, WSTOPSIG(status));
      } else if (WIFCONTINUED(status)) {
        ALOGW("debuggerd: pid %d continued", rc);
      }

      kill_worker = true;
      kill_target = true;
      kill_self = true;
    } else if (WIFSIGNALED(status)) {
      ALOGE("debuggerd: worker process %d terminated due to signal %d", child_pid, WTERMSIG(status));
      kill_worker = false;
      kill_target = true;
    } else if (WIFSTOPPED(status)) {
      ALOGE("debuggerd: worker process %d stopped due to signal %d", child_pid, WSTOPSIG(status));
      kill_worker = true;
      kill_target = true;
    }
  } else {
    ALOGE("debuggerd: worker process %d timed out", child_pid);
    kill_worker = true;
    kill_target = true;
  }

  if (kill_worker) {
    // Something bad happened, kill the worker.
    if (kill(child_pid, SIGKILL) != 0) {
      ALOGE("debuggerd: failed to kill worker process %d: %s", child_pid, strerror(errno));
    } else {
      waitpid(child_pid, &status, 0);
    }
  }

  int exit_signal = SIGCONT;
  if (kill_target && request.action == DEBUGGER_ACTION_CRASH) {
    ALOGE("debuggerd: killing target %d", request.pid);
    exit_signal = SIGKILL;
  } else {
    ALOGW("debuggerd: resuming target %d", request.pid);
  }

  if (kill(request.pid, exit_signal) != 0) {
    ALOGE("debuggerd: failed to send signal %d to target: %s", exit_signal, strerror(errno));
  }

  if (kill_self) {
    stop_signal_sender();
    _exit(1);
  }
}

static void handle_request(int fd) {
  ALOGV("handle_request(%d)\n", fd);

  android::base::unique_fd closer(fd);
  debugger_request_t request;
  memset(&request, 0, sizeof(request));
  int status = read_request(fd, &request);
  if (status != 0) {
    return;
  }

  ALOGW("debuggerd: handling request: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid,
        request.gid, request.tid);

#if defined(__LP64__)
  // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
  // to the 64 bit debuggerd. If the process is a 32 bit executable,
  // redirect the request to the 32 bit debuggerd.
  if (is32bit(request.tid)) {
    // Only dump backtrace and dump tombstone requests can be redirected.
    if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE ||
        request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
      redirect_to_32(fd, &request);
    } else {
      ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n", request.action);
    }
    return;
  }
#endif

  // Fork a child to handle the rest of the request.
  pid_t fork_pid = fork();
  if (fork_pid == -1) {
    ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
  } else if (fork_pid == 0) {
    worker_process(fd, request);
  } else {
    monitor_worker_process(fork_pid, request);
  }
}
コード例 #7
0
static void handle_request(int fd) {
  ALOGV("handle_request(%d)\n", fd);

  debugger_request_t request;
  memset(&request, 0, sizeof(request));
  int status = read_request(fd, &request);
  if (!status) {
    ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n",
         request.pid, request.uid, request.gid, request.tid);

#if defined(__LP64__)
    // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
    // to the 64 bit debuggerd. If the process is a 32 bit executable,
    // redirect the request to the 32 bit debuggerd.
    if (is32bit(request.tid)) {
      // Only dump backtrace and dump tombstone requests can be redirected.
      if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE
          || request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
        redirect_to_32(fd, &request);
      } else {
        ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n",
              request.action);
      }
      close(fd);
      return;
    }
#endif

    // At this point, the thread that made the request is blocked in
    // a read() call.  If the thread has crashed, then this gives us
    // time to PTRACE_ATTACH to it before it has a chance to really fault.
    //
    // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
    // won't necessarily have stopped by the time ptrace() returns.  (We
    // currently assume it does.)  We write to the file descriptor to
    // ensure that it can run as soon as we call PTRACE_CONT below.
    // See details in bionic/libc/linker/debugger.c, in function
    // debugger_signal_handler().
    if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
      ALOGE("ptrace attach failed: %s\n", strerror(errno));
    } else {
      bool detach_failed = false;
      bool tid_unresponsive = false;
      bool attach_gdb = should_attach_gdb(&request);
      if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
        ALOGE("failed responding to client: %s\n", strerror(errno));
      } else {
        char* tombstone_path = NULL;

        if (request.action == DEBUGGER_ACTION_CRASH) {
          close(fd);
          fd = -1;
        }

        int total_sleep_time_usec = 0;
        for (;;) {
          int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
          if (signal == -1) {
            tid_unresponsive = true;
            break;
          }

          switch (signal) {
            case SIGSTOP:
              if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
                ALOGV("stopped -- dumping to tombstone\n");
                tombstone_path = engrave_tombstone(request.pid, request.tid,
                                                   signal, request.original_si_code,
                                                   request.abort_msg_address, true,
                                                   &detach_failed, &total_sleep_time_usec);
              } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
                ALOGV("stopped -- dumping to fd\n");
                dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed,
                               &total_sleep_time_usec);
              } else {
                ALOGV("stopped -- continuing\n");
                status = ptrace(PTRACE_CONT, request.tid, 0, 0);
                if (status) {
                  ALOGE("ptrace continue failed: %s\n", strerror(errno));
                }
                continue; // loop again
              }
              break;

            case SIGABRT:
            case SIGBUS:
            case SIGFPE:
            case SIGILL:
            case SIGSEGV:
#ifdef SIGSTKFLT
            case SIGSTKFLT:
#endif
            case SIGTRAP:
              ALOGV("stopped -- fatal signal\n");
              // Send a SIGSTOP to the process to make all of
              // the non-signaled threads stop moving.  Without
              // this we get a lot of "ptrace detach failed:
              // No such process".
              kill(request.pid, SIGSTOP);
              // don't dump sibling threads when attaching to GDB because it
              // makes the process less reliable, apparently...
              tombstone_path = engrave_tombstone(request.pid, request.tid,
                                                 signal, request.original_si_code,
                                                 request.abort_msg_address, !attach_gdb,
                                                 &detach_failed, &total_sleep_time_usec);
              break;

            default:
              ALOGE("process stopped due to unexpected signal %d\n", signal);
              break;
          }
          break;
        }

        if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
          if (tombstone_path) {
            write(fd, tombstone_path, strlen(tombstone_path));
          }
          close(fd);
          fd = -1;
        }
        free(tombstone_path);
      }

      if (!tid_unresponsive) {
        ALOGV("detaching");
        if (attach_gdb) {
          // stop the process so we can debug
          kill(request.pid, SIGSTOP);
        }
        if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
          ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
          detach_failed = true;
        } else if (attach_gdb) {
          // if debug.db.uid is set, its value indicates if we should wait
          // for user action for the crashing process.
          // in this case, we log a message and turn the debug LED on
          // waiting for a gdb connection (for instance)
          wait_for_user_action(request);
        }
      }

      // resume stopped process (so it can crash in peace).
      kill(request.pid, SIGCONT);

      // If we didn't successfully detach, we're still the parent, and the
      // actual parent won't receive a death notification via wait(2).  At this point
      // there's not much we can do about that.
      if (detach_failed) {
        ALOGE("debuggerd committing suicide to free the zombie!\n");
        kill(getpid(), SIGKILL);
      }
    }

  }
  if (fd >= 0) {
    close(fd);
  }
}
コード例 #8
0
cString IA32IntelNotation::string(OpcodeFormatStruct* formatStruct) const
{
    // Get the instruction address
    ProcessorAddress ipAddress(gNullPointerProcessorAddress);
    bool shouldUseIp = m_data->getOpcodeAddress(ipAddress);

    // Mark new instruction
    m_dataFormatter.newInstruction(shouldUseIp, ipAddress);

    // Add all the prepost-prefix name
    cString ret;

    // Add all the prepost-prefix name
    for (uint i = 0; i < m_opcode->m_prefixsCount; i++)
        for (uint j = 0; j < ia32dis::IA32_NUMBER_OF_PREFIXS; j++)
            if ((m_opcode->m_prefixs[i] == ia32dis::gIa32PrefixTable[j].m_opcode) &&
                (!ia32dis::gIa32PrefixTable[j].m_isSegmentSelector) &&
                (ia32dis::gIa32PrefixTable[j].m_isOpcodeNameValid))
            {
                ret+= ia32dis::gIa32PrefixTable[j].m_prefixName;
                ret+= " ";
            }

    if (formatStruct != NULL)
        formatStruct->m_opcodeNameStart = ret.length();

    // Add the opcode name
    cString opcodeName = m_opcode->m_opcode->m_opcodeName;
    // Replace name convenstion
    if (opcodeName.find("/") < opcodeName.length())
    {
        // TODO! 64bit
        if (is32bit())
            opcodeName = opcodeName.left(opcodeName.find("/"));
        else
            opcodeName = opcodeName.part(opcodeName.find("/") + 1,
                                         opcodeName.length() - 1);
    }

    uint namePos = opcodeName.find("#");
    while (namePos != opcodeName.length()) {
        switch (opcodeName[namePos + 1])
        {
        case XSTL_CHAR('d'):
            opcodeName = opcodeName.left(namePos) +
                (is32bit() ? "d" : "") +
                opcodeName.part(namePos + 2, opcodeName.length() - 1);
            break;
        case XSTL_CHAR('e'):
            opcodeName = opcodeName.left(namePos) +
                (is32bit() ? "e" : "") +
                opcodeName.part(namePos + 2, opcodeName.length() - 1);
            break;
        case XSTL_CHAR('#'):
            opcodeName = opcodeName.left(namePos) +
                (is32bit() ? "d" : "w") +
                opcodeName.part(namePos + 2, opcodeName.length() - 1);
            break;
        }
        namePos = opcodeName.find("#");
    }

    ret+= m_dataFormatter.reparseOpcode(opcodeName);

    if (formatStruct != NULL)
        formatStruct->m_opcodeOperandsStart = ret.length();

    // Start adding operands
    // Add operands
    if (m_opcode->m_opcode->m_firstOperand == ia32dis::OPND_NO_OPERAND)
    {
        ASSERT(m_opcode->m_opcode->m_secondOperand == ia32dis::OPND_NO_OPERAND);
        ASSERT(m_opcode->m_opcode->m_thridOperand == ia32dis::OPND_NO_OPERAND);
        return m_dataFormatter.endInstruction(ret);
    }

    ret+= m_dataFormatter.reparseFirstOperand(
                    stringOperand(m_opcode->m_opcode->m_firstOperand));

    if (m_opcode->m_opcode->m_secondOperand == ia32dis::OPND_NO_OPERAND)
    {
        ASSERT(m_opcode->m_opcode->m_thridOperand == ia32dis::OPND_NO_OPERAND);
        return m_dataFormatter.endInstruction(ret);
    }

    // Pad with space and first operand
    ret+= m_dataFormatter.getOpcodesSeparator(ret);
    ret+= m_dataFormatter.reparseSecondOperand(
                    stringOperand(m_opcode->m_opcode->m_secondOperand));

    if (m_opcode->m_opcode->m_thridOperand == ia32dis::OPND_NO_OPERAND)
        return m_dataFormatter.endInstruction(ret);

    ret+= m_dataFormatter.getOpcodesSeparator(ret);
    ret+= m_dataFormatter.reparseThirdOperand(
                    stringOperand(m_opcode->m_opcode->m_thridOperand));

    // Build the instruction
    return m_dataFormatter.endInstruction(ret);
}
コード例 #9
0
cString IA32IntelNotation::getModrmString(ia32dis::OperandType type) const
{
    cString ret;
    uint reg = m_opcode->m_modrm.m_bits.m_rm;
    uint mod = m_opcode->m_modrm.m_bits.m_mod;

    ia32dis::ModRMTranslationType* modrmTranslator = NULL;
    ia32dis::RegisterDescription* registersDescriptor = NULL;

    // Load appropriate MOD/RM table. Determined by address size attribute.
    switch (m_opcode->m_addressSize)
    {
    case IntegerEncoding::INTEGER_16BIT:
        // 16 bit
        modrmTranslator = &ia32dis::gIa32ModRM16;
        break;
    case IntegerEncoding::INTEGER_32BIT:
        // 32 bit
        modrmTranslator = &ia32dis::gIa32ModRM32;
        break;
    default:
        // For 64bit and all other unknown value.
        CHECK_FAIL();
    }

    // Load appropriate Register table. Determined by MODR/M mode (Memory
    // reference or direct register access) and MODR/M operand type
    if ((*modrmTranslator)[mod][reg].m_isReference ||
        (type == ia32dis::OPND_MODRM_MEM))
    {
        // MODR/M reference mode. Load MODR/M table based on address size
        // attribute
        switch (m_opcode->m_addressSize)
        {
        case IntegerEncoding::INTEGER_16BIT:
            registersDescriptor = ia32dis::gIa16Registers;
            break;
        case IntegerEncoding::INTEGER_32BIT:
            registersDescriptor = ia32dis::gIa32Registers;
            break;
        // TODO! 64 bit table
        default:
            CHECK_FAIL();
        }
    } else
    {
        // MODR/M Direct register mode (11).
        // NOTE: Check if it truly is either reference (00, 01, 10) or direct
        //       register(11) or not. If not, then redesign is required
        switch (type)
        {
        case ia32dis::OPND_MODRM_dWORDPTR:
            switch (m_opcode->m_operandSize)
            {
            case IntegerEncoding::INTEGER_16BIT:
                registersDescriptor = ia32dis::gIa16Registers;
                break;
            case IntegerEncoding::INTEGER_32BIT:
                registersDescriptor = ia32dis::gIa32Registers;
                break;
            default:
                CHECK_FAIL();
            }
            break;
        case ia32dis::OPND_MODRM_WORDPTR:
            registersDescriptor = ia32dis::gIa16Registers;
            break;
        case ia32dis::OPND_MODRM_BYTEPTR:
            registersDescriptor = ia32dis::gIa8Registers;
            break;
        case ia32dis::OPND_MODRM_MEM: // Handled in the previous case.
        default:
            CHECK_FAIL();
        }
    }

    if ((*modrmTranslator)[mod][reg].m_isReference)
    {
        switch (type)
        {
        case ia32dis::OPND_MODRM_dWORDPTR:
            switch (m_opcode->m_operandSize)
            {
            case IntegerEncoding::INTEGER_16BIT: ret+= "word ptr "; break;
            case IntegerEncoding::INTEGER_32BIT: ret+= "dword ptr ";  break;
            default: break;
            }
            break;
        case ia32dis::OPND_MODRM_WORDPTR:
            ret+= "word ptr "; break;
        case ia32dis::OPND_MODRM_BYTEPTR:
            ret+= "byte ptr "; break;
        default:
            break;
        }

        ret+= getSegmentSelector();
        ret+= "[";
    }

    uint firstReg = (*modrmTranslator)[mod][reg].m_firstRegisterPointer;
    uint secondReg = (*modrmTranslator)[mod][reg].m_secondRegisterPointer;

    if (firstReg != ia32dis::NO_REGISTER)
        ret+= registersDescriptor[firstReg].m_name;

    if (secondReg != ia32dis::NO_REGISTER)
    {
        ret+= "+";
        ret+= registersDescriptor[secondReg].m_name;
    }

    if ((*modrmTranslator)[mod][reg].m_forceSib)
    {
        // Start with the index register
        // TODO: Should this be m_bits.m_base?
        //if (m_opcode->m_sib.m_bits.m_base == ia32dis::IA32_GP32_EBP)
        if (m_opcode->m_sib.m_bits.m_index == ia32dis::IA32_GP32_EBP)
        {
            // mod 0 has no index
            if (mod != 0)
            {
                ret+= registersDescriptor[ia32dis::IA32_GP32_EBP].m_name;
                ret+= "+";
            }
        } else
        {
            //ret+= registersDescriptor[m_opcode->m_sib.m_bits.m_base].m_name;
            ret+= registersDescriptor[m_opcode->m_sib.m_bits.m_index].m_name;
            ret+= "+";
        }
        // Add the scale register
        // TODO: Should this be m_bits.m_index?
        //if (m_opcode->m_sib.m_bits.m_index != ia32dis::IA32_GP32_ESP)
        if (m_opcode->m_sib.m_bits.m_base != ia32dis::IA32_GP32_ESP)
        {
            //ret+= registersDescriptor[m_opcode->m_sib.m_bits.m_index].m_name;
            ret+= registersDescriptor[m_opcode->m_sib.m_bits.m_base].m_name;
            if (m_opcode->m_sib.m_bits.m_scale != 0)
            {
                ret+= "*";
                switch (m_opcode->m_sib.m_bits.m_scale)
                {
                case 1: ret+= "2"; break;
                case 2: ret+= "4"; break;
                case 3: ret+= "8"; break;
                }
            }
        }
    }

    if (m_opcode->m_displacementLength > 0)
    {
        int32 displacement = 0;
        switch (m_opcode->m_displacementLength)
        {
        case 1: displacement = (int8)(m_opcode->m_displacement); break;
        case 2: displacement = (int16)(m_opcode->m_displacement); break;
        case 4: displacement = (int32)(m_opcode->m_displacement); break;
        default:
            CHECK_FAIL();
        }

        if ((*modrmTranslator)[mod][reg].m_displacementRelative)
        {
            /*
             * TODO! How should I treat the displacement? As an address or as a
             *       const?, For now I think I will use it as an address relative+
             *       to 0...
             *
            ret+= m_dataFormatter.translateRelativeAddress(displacement,
                            false,
                            gNullPointerProcessorAddress);
            */

            ret+= m_dataFormatter.translateRelativeDisplacement(displacement);
        } else
        {
            switch (m_opcode->m_displacementLength)
            {
            case 1: ret+= m_dataFormatter.translateUint8(displacement); break;
            case 2: if (is32bit())
                        ret+= m_dataFormatter.translateUint16(displacement);
                    else
                        ret+= m_dataFormatter.translateAbsoluteAddress(
                            ProcessorAddress(ProcessorAddress::PROCESSOR_16,
                                             displacement));
                    break;
            case 4: if (is32bit())
                        ret+= m_dataFormatter.translateAbsoluteAddress(
                            ProcessorAddress(ProcessorAddress::PROCESSOR_32,
                                             displacement));
                    else
                        ret+= m_dataFormatter.translateUint32(displacement);
                    break;
            }
        }
    }

    if ((*modrmTranslator)[mod][reg].m_isReference)
        ret+= "]";

    return ret;
}
コード例 #10
0
static void handle_request(int fd) {
  ALOGV("handle_request(%d)\n", fd);

  ScopedFd closer(fd);
  debugger_request_t request;
  memset(&request, 0, sizeof(request));
  int status = read_request(fd, &request);
  if (status != 0) {
    return;
  }

  ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid, request.gid, request.tid);

#if defined(__LP64__)
  // On 64 bit systems, requests to dump 32 bit and 64 bit tids come
  // to the 64 bit debuggerd. If the process is a 32 bit executable,
  // redirect the request to the 32 bit debuggerd.
  if (is32bit(request.tid)) {
    // Only dump backtrace and dump tombstone requests can be redirected.
    if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE ||
        request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
      redirect_to_32(fd, &request);
    } else {
      ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n", request.action);
    }
    return;
  }
#endif

  // Fork a child to handle the rest of the request.
  pid_t fork_pid = fork();
  if (fork_pid == -1) {
    ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
    return;
  } else if (fork_pid != 0) {
    waitpid(fork_pid, nullptr, 0);
    return;
  }

  // Open the tombstone file if we need it.
  std::string tombstone_path;
  int tombstone_fd = -1;
  switch (request.action) {
    case DEBUGGER_ACTION_DUMP_TOMBSTONE:
    case DEBUGGER_ACTION_CRASH:
      tombstone_fd = open_tombstone(&tombstone_path);
      if (tombstone_fd == -1) {
        ALOGE("debuggerd: failed to open tombstone file: %s\n", strerror(errno));
        exit(1);
      }
      break;

    case DEBUGGER_ACTION_DUMP_BACKTRACE:
      break;

    default:
      ALOGE("debuggerd: unexpected request action: %d", request.action);
      exit(1);
  }

  // At this point, the thread that made the request is blocked in
  // a read() call.  If the thread has crashed, then this gives us
  // time to PTRACE_ATTACH to it before it has a chance to really fault.
  //
  // The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
  // won't necessarily have stopped by the time ptrace() returns.  (We
  // currently assume it does.)  We write to the file descriptor to
  // ensure that it can run as soon as we call PTRACE_CONT below.
  // See details in bionic/libc/linker/debugger.c, in function
  // debugger_signal_handler().

  // Attach to the target process.
  if (ptrace(PTRACE_ATTACH, request.tid, 0, 0) != 0) {
    ALOGE("debuggerd: ptrace attach failed: %s", strerror(errno));
    exit(1);
  }

  // Don't attach to the sibling threads if we want to attach gdb.
  // Supposedly, it makes the process less reliable.
  bool attach_gdb = should_attach_gdb(&request);
  int signal_in_fd = -1;
  int signal_out_fd = -1;
  pid_t signal_pid = 0;
  if (attach_gdb) {
    // Open all of the input devices we need to listen for VOLUMEDOWN before dropping privileges.
    if (init_getevent() != 0) {
      ALOGE("debuggerd: failed to initialize input device, not waiting for gdb");
      attach_gdb = false;
    }

    // Fork a process that stays root, and listens on a pipe to pause and resume the target.
    if (!fork_signal_sender(&signal_in_fd, &signal_out_fd, &signal_pid, request.pid)) {
      attach_gdb = false;
    }
  }

  auto notify_signal_sender = [=]() {
    char buf[1];
    if (TEMP_FAILURE_RETRY(write(signal_in_fd, "", 1)) != 1) {
      ALOGE("debuggerd: failed to notify signal process: %s", strerror(errno));
    } else if (TEMP_FAILURE_RETRY(read(signal_out_fd, buf, 1)) != 1) {
      ALOGE("debuggerd: failed to read response from signal process: %s", strerror(errno));
    }
  };

  std::set<pid_t> siblings;
  if (!attach_gdb) {
    ptrace_siblings(request.pid, request.tid, siblings);
  }

  // Generate the backtrace map before dropping privileges.
  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));

  bool succeeded = false;

  // Now that we've done everything that requires privileges, we can drop them.
  if (drop_privileges()) {
    succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings);
    if (succeeded) {
      if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
        if (!tombstone_path.empty()) {
          write(fd, tombstone_path.c_str(), tombstone_path.length());
        }
      }
    }

    if (attach_gdb) {
      // Tell the signal process to send SIGSTOP to the target.
      notify_signal_sender();
    }
  }

  if (ptrace(PTRACE_DETACH, request.tid, 0, 0) != 0) {
    ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
  }

  for (pid_t sibling : siblings) {
    ptrace(PTRACE_DETACH, sibling, 0, 0);
  }

  // Wait for gdb, if requested.
  if (attach_gdb && succeeded) {
    wait_for_user_action(request);

    // Tell the signal process to send SIGCONT to the target.
    notify_signal_sender();

    uninit_getevent();
    waitpid(signal_pid, nullptr, 0);
  }

  exit(!succeeded);
}