brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · c8dce75 Raw
278 lines · cpp
1//===-- MachVMRegion.cpp ----------------------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  Created by Greg Clayton on 6/26/07.10//11//===----------------------------------------------------------------------===//12 13#include "MachVMRegion.h"14#include "DNBLog.h"15#include <cassert>16#include <mach/mach_vm.h>17#include <mach/vm_statistics.h>18 19// From <mach/vm_statistics.h>, but not on older OSs.20#ifndef VM_MEMORY_SANITIZER21#define VM_MEMORY_SANITIZER 9922#endif23 24MachVMRegion::MachVMRegion(task_t task)25    : m_task(task), m_addr(INVALID_NUB_ADDRESS), m_err(),26      m_start(INVALID_NUB_ADDRESS), m_size(0), m_depth(-1),27      m_curr_protection(0), m_protection_addr(INVALID_NUB_ADDRESS),28      m_protection_size(0) {29  memset(&m_data, 0, sizeof(m_data));30}31 32MachVMRegion::~MachVMRegion() {33  // Restore any original protections and clear our vars34  Clear();35}36 37void MachVMRegion::Clear() {38  RestoreProtections();39  m_addr = INVALID_NUB_ADDRESS;40  m_err.Clear();41  m_start = INVALID_NUB_ADDRESS;42  m_size = 0;43  m_depth = -1;44  memset(&m_data, 0, sizeof(m_data));45  m_curr_protection = 0;46  m_protection_addr = INVALID_NUB_ADDRESS;47  m_protection_size = 0;48}49 50bool MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size,51                                  vm_prot_t prot) {52  if (ContainsAddress(addr)) {53    mach_vm_size_t prot_size = size;54    mach_vm_address_t end_addr = EndAddress();55    if (prot_size > (end_addr - addr))56      prot_size = end_addr - addr;57 58    if (prot_size > 0) {59      if (prot == (m_curr_protection & VM_PROT_ALL)) {60        DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE,61                         "MachVMRegion::%s: protections (%u) already "62                         "sufficient for task 0x%4.4x at address 0x%8.8llx) ",63                         __FUNCTION__, prot, m_task, (uint64_t)addr);64        // Protections are already set as requested...65        return true;66      } else {67        m_err = ::mach_vm_protect(m_task, addr, prot_size, 0, prot);68        if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS))69          m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = "70                            "0x%8.8llx, size = %llu, set_max = %i, prot = %u )",71                            m_task, (uint64_t)addr, (uint64_t)prot_size, 0,72                            prot);73        if (m_err.Fail()) {74          // Try again with the ability to create a copy on write region75          m_err = ::mach_vm_protect(m_task, addr, prot_size, 0,76                                    prot | VM_PROT_COPY);77          if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail())78            m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = "79                              "0x%8.8llx, size = %llu, set_max = %i, prot = %u "80                              ")",81                              m_task, (uint64_t)addr, (uint64_t)prot_size, 0,82                              prot | VM_PROT_COPY);83        }84        if (m_err.Success()) {85          m_curr_protection = prot;86          m_protection_addr = addr;87          m_protection_size = prot_size;88          return true;89        }90      }91    } else {92      DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE,93                       "%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ",94                       __FUNCTION__, m_task, (uint64_t)addr);95    }96  }97  return false;98}99 100bool MachVMRegion::RestoreProtections() {101  if (m_curr_protection != m_data.protection && m_protection_size > 0) {102    m_err = ::mach_vm_protect(m_task, m_protection_addr, m_protection_size, 0,103                              m_data.protection);104    if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail())105      m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, "106                        "size = %llu, set_max = %i, prot = %u )",107                        m_task, (uint64_t)m_protection_addr,108                        (uint64_t)m_protection_size, 0, m_data.protection);109    if (m_err.Success()) {110      m_protection_size = 0;111      m_protection_addr = INVALID_NUB_ADDRESS;112      m_curr_protection = m_data.protection;113      return true;114    }115  } else {116    m_err.Clear();117    return true;118  }119 120  return false;121}122 123#ifdef VM_REGION_FLAG_JIT_ENABLED124#define VM_REGION_HAS_FLAGS 1125#else126#define VM_REGION_HAS_FLAGS 0127#endif128bool MachVMRegion::GetRegionForAddress(nub_addr_t addr) {129  // Restore any original protections and clear our vars130  Clear();131  m_err.Clear();132  m_addr = addr;133  m_start = addr;134  m_depth = 1024;135  mach_msg_type_number_t info_size = kRegionInfoSize;136  static_assert(sizeof(info_size) == 4);137  m_err =138      ::mach_vm_region_recurse(m_task, &m_start, &m_size, &m_depth,139                               (vm_region_recurse_info_t)&m_data, &info_size);140 141  const bool failed = m_err.Fail();142  const bool log_protections = DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS);143 144  if (log_protections || failed)145    m_err.LogThreaded("::mach_vm_region_recurse ( task = 0x%4.4x, address => "146                      "0x%8.8llx, size => %llu, nesting_depth => %d, info => "147                      "%p, infoCnt => %d) addr = 0x%8.8llx ",148                      m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth,149                      &m_data, info_size, (uint64_t)addr);150 151  if (failed)152    return false;153  if (log_protections) {154#if VM_REGION_HAS_FLAGS155    DNBLogThreaded("info = { prot = %u, "156                   "max_prot = %u, "157                   "inheritance = 0x%8.8x, "158                   "offset = 0x%8.8llx, "159                   "user_tag = 0x%8.8x, "160                   "ref_count = %u, "161                   "shadow_depth = %u, "162                   "ext_pager = %u, "163                   "share_mode = %u, "164                   "is_submap = %d, "165                   "behavior = %d, "166                   "object_id = 0x%8.8x, "167                   "user_wired_count = 0x%4.4x, "168                   "flags = %d }",169                   m_data.protection, m_data.max_protection, m_data.inheritance,170                   (uint64_t)m_data.offset, m_data.user_tag, m_data.ref_count,171                   m_data.shadow_depth, m_data.external_pager,172                   m_data.share_mode, m_data.is_submap, m_data.behavior,173                   m_data.object_id, m_data.user_wired_count, m_data.flags);174#else175    // Duplicate log call instead of #if-defing printing of flags to avoid176    // compiler warning: 'embedding a directive within macro arguments has177    // undefined behavior'178    DNBLogThreaded("info = { prot = %u, "179                   "max_prot = %u, "180                   "inheritance = 0x%8.8x, "181                   "offset = 0x%8.8llx, "182                   "user_tag = 0x%8.8x, "183                   "ref_count = %u, "184                   "shadow_depth = %u, "185                   "ext_pager = %u, "186                   "share_mode = %u, "187                   "is_submap = %d, "188                   "behavior = %d, "189                   "object_id = 0x%8.8x, "190                   "user_wired_count = 0x%4.4x }",191                   m_data.protection, m_data.max_protection, m_data.inheritance,192                   (uint64_t)m_data.offset, m_data.user_tag, m_data.ref_count,193                   m_data.shadow_depth, m_data.external_pager,194                   m_data.share_mode, m_data.is_submap, m_data.behavior,195                   m_data.object_id, m_data.user_wired_count);196#endif197  }198  m_curr_protection = m_data.protection;199 200  // We make a request for an address and got no error back, but this201  // doesn't mean that "addr" is in the range. The data in this object will202  // be valid though, so you could see where the next region begins. So we203  // return false, yet leave "m_err" with a successfull return code.204  return !((addr < m_start) || (addr >= (m_start + m_size)));205}206 207uint32_t MachVMRegion::GetDNBPermissions() const {208  if (m_addr == INVALID_NUB_ADDRESS || m_start == INVALID_NUB_ADDRESS ||209      m_size == 0)210    return 0;211  uint32_t dnb_permissions = 0;212 213  if ((m_data.protection & VM_PROT_READ) == VM_PROT_READ)214    dnb_permissions |= eMemoryPermissionsReadable;215  if ((m_data.protection & VM_PROT_WRITE) == VM_PROT_WRITE)216    dnb_permissions |= eMemoryPermissionsWritable;217  if ((m_data.protection & VM_PROT_EXECUTE) == VM_PROT_EXECUTE)218    dnb_permissions |= eMemoryPermissionsExecutable;219  return dnb_permissions;220}221 222#ifndef VM_REGION_FLAG_MTE_ENABLED223#define VM_REGION_FLAG_MTE_ENABLED 0x4224#endif225std::vector<std::string> MachVMRegion::GetFlags() const {226  std::vector<std::string> flags;227#if VM_REGION_HAS_FLAGS228  if (m_data.flags & VM_REGION_FLAG_JIT_ENABLED)229    flags.push_back("jit");230  if (m_data.flags & VM_REGION_FLAG_TPRO_ENABLED)231    flags.push_back("tpro");232  if (m_data.flags & VM_REGION_FLAG_MTE_ENABLED)233    flags.push_back("mt");234#endif235  return flags;236}237 238std::vector<std::string> MachVMRegion::GetMemoryTypes() const {239  std::vector<std::string> types;240  if (m_data.user_tag == VM_MEMORY_STACK) {241    if (m_data.protection == VM_PROT_NONE) {242      types.push_back("stack-guard");243    } else {244      types.push_back("stack");245    }246  }247  if (m_data.user_tag == VM_MEMORY_MALLOC) {248    if (m_data.protection == VM_PROT_NONE)249      types.push_back("malloc-guard");250    else if (m_data.share_mode == SM_EMPTY)251      types.push_back("malloc-reserved");252    else253      types.push_back("malloc-metadata");254  }255  if (m_data.user_tag == VM_MEMORY_MALLOC_NANO ||256      m_data.user_tag == VM_MEMORY_MALLOC_TINY ||257      m_data.user_tag == VM_MEMORY_MALLOC_SMALL ||258      m_data.user_tag == VM_MEMORY_MALLOC_LARGE ||259      m_data.user_tag == VM_MEMORY_MALLOC_LARGE_REUSED ||260      m_data.user_tag == VM_MEMORY_MALLOC_LARGE_REUSABLE ||261      m_data.user_tag == VM_MEMORY_MALLOC_HUGE ||262      m_data.user_tag == VM_MEMORY_REALLOC ||263      m_data.user_tag == VM_MEMORY_SBRK ||264      m_data.user_tag == VM_MEMORY_SANITIZER) {265    types.push_back("heap");266    if (m_data.user_tag == VM_MEMORY_MALLOC_TINY) {267      types.push_back("malloc-tiny");268    }269    if (m_data.user_tag == VM_MEMORY_MALLOC_LARGE) {270      types.push_back("malloc-large");271    }272    if (m_data.user_tag == VM_MEMORY_MALLOC_SMALL) {273      types.push_back("malloc-small");274    }275  }276  return types;277}278