<commit_before>//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include <errno.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "lldb/Host/Host.h"
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/Status.h"
#include "llvm/Support/Errno.h"

#include "FreeBSDThread.h"
#include "Plugins/Process/POSIX/CrashReason.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"

using namespace lldb;
using namespace lldb_private;

// We disable the tracing of ptrace calls for integration builds to avoid the
// additional indirection and checks.
#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
// Wrapper for ptrace to catch errors and log calls.

const char *Get_PT_IO_OP(int op) {
  switch (op) {
  case PIOD_READ_D:
    return "READ_D";
  case PIOD_WRITE_D:
    return "WRITE_D";
  case PIOD_READ_I:
    return "READ_I";
  case PIOD_WRITE_I:
    return "WRITE_I";
  default:
    return "Unknown op";
  }
}

// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets
// errno on error because -1 is reserved as a valid result.
extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
                          const char *reqName, const char *file, int line) {
  long int result;

  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));

  if (log) {
    log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d",
                reqName, pid, addr, data, file, line);
    if (req == PT_IO) {
      struct ptrace_io_desc *pi = (struct ptrace_io_desc *)addr;

      log->Printf("PT_IO: op=%s offs=%zx size=%zu", Get_PT_IO_OP(pi->piod_op),
                  (size_t)pi->piod_offs, pi->piod_len);
    }
  }

  // PtraceDisplayBytes(req, data);

  errno = 0;
  result = ptrace(req, pid, (caddr_t)addr, data);

  // PtraceDisplayBytes(req, data);

  if (log && errno != 0) {
    const char *str;
    switch (errno) {
    case ESRCH:
      str = "ESRCH";
      break;
    case EINVAL:
      str = "EINVAL";
      break;
    case EBUSY:
      str = "EBUSY";
      break;
    case EPERM:
      str = "EPERM";
      break;
    default:
      str = "<unknown>";
    }
    log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
  }

  if (log) {
#ifdef __amd64__
    if (req == PT_GETREGS) {
      struct reg *r = (struct reg *)addr;

      log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx",
                  r->r_rip, r->r_rsp, r->r_rbp, r->r_rax);
    }
    if (req == PT_GETDBREGS || req == PT_SETDBREGS) {
      struct dbreg *r = (struct dbreg *)addr;
      char setget = (req == PT_GETDBREGS) ? 'G' : 'S';

      for (int i = 0; i <= 7; i++)
        log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]);
    }
#endif
  }

  return result;
}

// Wrapper for ptrace when logging is not required. Sets errno to 0 prior to
// calling ptrace.
extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) {
  long result = 0;
  errno = 0;
  result = ptrace(req, pid, (caddr_t)addr, data);
  return result;
}

#define PTRACE(req, pid, addr, data)                                           \
  PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
#else
PtraceWrapper((req), (pid), (addr), (data))
#endif

//------------------------------------------------------------------------------
// Static implementations of ProcessMonitor::ReadMemory and
// ProcessMonitor::WriteMemory.  This enables mutual recursion between these
// functions without needed to go thru the thread funnel.

static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf,
                           size_t size, Status &error) {
  struct ptrace_io_desc pi_desc;

  pi_desc.piod_op = PIOD_READ_D;
  pi_desc.piod_offs = (void *)vm_addr;
  pi_desc.piod_addr = buf;
  pi_desc.piod_len = size;

  if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) {
    error.SetErrorToErrno();
    return 0;
  }
  return pi_desc.piod_len;
}

static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr,
                            const void *buf, size_t size, Status &error) {
  struct ptrace_io_desc pi_desc;

  pi_desc.piod_op = PIOD_WRITE_D;
  pi_desc.piod_offs = (void *)vm_addr;
  pi_desc.piod_addr = (void *)buf;
  pi_desc.piod_len = size;

  if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) {<commit_msg>[LLDB] FreeBSD suppress compilation warning<commit_after>//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include <errno.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "lldb/Host/Host.h"
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/UnixSignals.h"
#include "lldb/Utility/RegisterValue.h"
#include "lldb/Utility/Scalar.h"
#include "lldb/Utility/Status.h"
#include "llvm/Support/Errno.h"

#include "FreeBSDThread.h"
#include "Plugins/Process/POSIX/CrashReason.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "ProcessFreeBSD.h"
#include "ProcessMonitor.h"

using namespace lldb;
using namespace lldb_private;

// We disable the tracing of ptrace calls for integration builds to avoid the
// additional indirection and checks.
#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
// Wrapper for ptrace to catch errors and log calls.

const char *Get_PT_IO_OP(int op) {
  switch (op) {
  case PIOD_READ_D:
    return "READ_D";
  case PIOD_WRITE_D:
    return "WRITE_D";
  case PIOD_READ_I:
    return "READ_I";
  case PIOD_WRITE_I:
    return "WRITE_I";
  default:
    return "Unknown op";
  }
}

// Wrapper for ptrace to catch errors and log calls. Note that ptrace sets
// errno on error because -1 is reserved as a valid result.
extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
                          const char *reqName, const char *file, int line) {
  long int result;

  Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));

  if (log) {
    log->Printf("ptrace(%s, %" PRIu64 ", %p, %x) called from file %s line %d",
                reqName, pid, addr, data, file, line);
    if (req == PT_IO) {
      struct ptrace_io_desc *pi = (struct ptrace_io_desc *)addr;

      log->Printf("PT_IO: op=%s offs=%zx size=%zu", Get_PT_IO_OP(pi->piod_op),
                  (size_t)pi->piod_offs, pi->piod_len);
    }
  }

  // PtraceDisplayBytes(req, data);

  errno = 0;
  result = ptrace(req, pid, (caddr_t)addr, data);

  // PtraceDisplayBytes(req, data);

  if (log && errno != 0) {
    const char *str;
    switch (errno) {
    case ESRCH:
      str = "ESRCH";
      break;
    case EINVAL:
      str = "EINVAL";
      break;
    case EBUSY:
      str = "EBUSY";
      break;
    case EPERM:
      str = "EPERM";
      break;
    default:
      str = "<unknown>";
    }
    log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
  }

  if (log) {
#ifdef __amd64__
    if (req == PT_GETREGS) {
      struct reg *r = (struct reg *)addr;

      log->Printf("PT_GETREGS: rip=0x%lx rsp=0x%lx rbp=0x%lx rax=0x%lx",
                  r->r_rip, r->r_rsp, r->r_rbp, r->r_rax);
    }
    if (req == PT_GETDBREGS || req == PT_SETDBREGS) {
      struct dbreg *r = (struct dbreg *)addr;
      char setget = (req == PT_GETDBREGS) ? 'G' : 'S';

      for (int i = 0; i <= 7; i++)
        log->Printf("PT_%cETDBREGS: dr[%d]=0x%lx", setget, i, r->dr[i]);
    }
#endif
  }

  return result;
}

// Wrapper for ptrace when logging is not required. Sets errno to 0 prior to
// calling ptrace.
extern long PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data) {
  long result = 0;
  errno = 0;
  result = ptrace(req, pid, (caddr_t)addr, data);
  return result;
}

#define PTRACE(req, pid, addr, data)                                           \
  PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
#else
PtraceWrapper((req), (pid), (addr), (data))
#endif

//------------------------------------------------------------------------------
// Static implementations of ProcessMonitor::ReadMemory and
// ProcessMonitor::WriteMemory.  This enables mutual recursion between these
// functions without needed to go thru the thread funnel.

static size_t DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf,
                           size_t size, Status &error) {
  struct ptrace_io_desc pi_desc;

  pi_desc.piod_op = PIOD_READ_D;
  pi_desc.piod_offs = (void *)vm_addr;
  pi_desc.piod_addr = buf;
  pi_desc.piod_len = size;

  if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) {
    error.SetErrorToErrno();
    return 0;
  }
  return pi_desc.piod_len;
}

static size_t DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr,
                            const void *buf, size_t size, Status &error) {
  struct ptrace_io_desc pi_desc;

  pi_desc.piod_op = PIOD_WRITE_D;
  pi_desc.piod_offs = (void *)vm_addr;
  pi_desc.piod_addr = const_cast<void *>(buf);
  pi_desc.piod_len = size;

  if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0) {
{'fraction_non_alphanumeric': 0.17399014778325123, 'fraction_numerical': 0.0051231527093596055, 'mean_word_length': 2.7142334431028172, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 52, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7551661', 'n_tokens_mistral': 3764, 'n_tokens_neox': 3651, 'n_words': 930}