brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.8 KiB · 4558428 Raw
424 lines · cpp
1//===-- cli-wrapper-mpxtable.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// C++ includes10#include <cerrno>11#include <string>12 13#include "cli-wrapper-mpxtable.h"14#include "lldb/API/SBCommandInterpreter.h"15#include "lldb/API/SBCommandReturnObject.h"16#include "lldb/API/SBMemoryRegionInfo.h"17#include "lldb/API/SBProcess.h"18#include "lldb/API/SBTarget.h"19#include "lldb/API/SBThread.h"20 21#include "llvm/ADT/Twine.h"22#include "llvm/TargetParser/Triple.h"23 24static bool GetPtr(char *cptr, uint64_t &ptr, lldb::SBFrame &frame,25                   lldb::SBCommandReturnObject &result) {26  if (!cptr) {27    result.SetError("Bad argument.");28    result.SetStatus(lldb::eReturnStatusFailed);29    return false;30  }31 32  lldb::SBValue ptr_addr = frame.GetValueForVariablePath(cptr);33  if (!ptr_addr.IsValid()) {34    result.SetError("Invalid pointer.");35    result.SetStatus(lldb::eReturnStatusFailed);36    return false;37  }38  ptr = ptr_addr.GetLoadAddress();39  return true;40}41 42enum {43  mpx_base_mask_64 = ~(uint64_t)0xFFFULL,44  mpx_bd_mask_64 = 0xFFFFFFF00000ULL,45  bd_r_shift_64 = 20,46  bd_l_shift_64 = 3,47  bt_r_shift_64 = 3,48  bt_l_shift_64 = 5,49  bt_mask_64 = 0x0000000FFFF8ULL,50 51  mpx_base_mask_32 = 0xFFFFFFFFFFFFF000ULL,52  mpx_bd_mask_32 = 0xFFFFF000ULL,53  bd_r_shift_32 = 12,54  bd_l_shift_32 = 2,55  bt_r_shift_32 = 2,56  bt_l_shift_32 = 4,57  bt_mask_32 = 0x00000FFCULL,58};59 60static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound,61                         uint64_t value, uint64_t meta,62                         lldb::SBCommandReturnObject &result) {63  const lldb::addr_t one_cmpl64 = ~((lldb::addr_t)0);64  const lldb::addr_t one_cmpl32 = ~((uint32_t)0);65 66  if ((lbound == one_cmpl64 || lbound == one_cmpl32) && ubound == 0) {67    result.Printf("Null bounds on map: pointer value = 0x%" PRIu64 "\n", value);68  } else {69    result.Printf("    lbound = 0x%" PRIu64 ",", lbound);70    result.Printf(" ubound = 0x%" PRIu64 , ubound);71    result.Printf(" (pointer value = 0x%" PRIu64 ",", value);72    result.Printf(" metadata = 0x%" PRIu64 ")\n", meta);73  }74}75 76static bool GetBTEntryAddr(uint64_t bndcfgu, uint64_t ptr,77                           lldb::SBTarget &target, llvm::Triple::ArchType arch,78                           size_t &size, lldb::addr_t &bt_entry_addr,79                           lldb::SBCommandReturnObject &result,80                           lldb::SBError &error) {81  lldb::addr_t mpx_base_mask;82  lldb::addr_t mpx_bd_mask;83  lldb::addr_t bd_r_shift;84  lldb::addr_t bd_l_shift;85  lldb::addr_t bt_r_shift;86  lldb::addr_t bt_l_shift;87  lldb::addr_t bt_mask;88 89  if (arch == llvm::Triple::ArchType::x86_64) {90    mpx_base_mask = mpx_base_mask_64;91    mpx_bd_mask = mpx_bd_mask_64;92    bd_r_shift = bd_r_shift_64;93    bd_l_shift = bd_l_shift_64;94    bt_r_shift = bt_r_shift_64;95    bt_l_shift = bt_l_shift_64;96    bt_mask = bt_mask_64;97  } else if (arch == llvm::Triple::ArchType::x86) {98    mpx_base_mask = mpx_base_mask_32;99    mpx_bd_mask = mpx_bd_mask_32;100    bd_r_shift = bd_r_shift_32;101    bd_l_shift = bd_l_shift_32;102    bt_r_shift = bt_r_shift_32;103    bt_l_shift = bt_l_shift_32;104    bt_mask = bt_mask_32;105  } else {106    result.SetError("Invalid arch.");107    result.SetStatus(lldb::eReturnStatusFailed);108    return false;109  }110 111  size = target.GetAddressByteSize();112  lldb::addr_t mpx_bd_base = bndcfgu & mpx_base_mask;113  lldb::addr_t bd_entry_offset = ((ptr & mpx_bd_mask) >> bd_r_shift)114                                 << bd_l_shift;115  lldb::addr_t bd_entry_addr = mpx_bd_base + bd_entry_offset;116 117  std::vector<uint8_t> bd_entry_v(size);118  size_t ret = target.GetProcess().ReadMemory(119      bd_entry_addr, static_cast<void *>(bd_entry_v.data()), size, error);120  if (ret != size || !error.Success()) {121    result.SetError("Failed access to BD entry.");122    return false;123  }124 125  lldb::SBData data;126  data.SetData(error, bd_entry_v.data(), bd_entry_v.size(),127               target.GetByteOrder(), size);128  lldb::addr_t bd_entry = data.GetAddress(error, 0);129 130  if (!error.Success()) {131    result.SetError("Failed access to BD entry.");132    return false;133  }134 135  if ((bd_entry & 0x01) == 0) {136    result.SetError("Invalid bound directory.");137    result.SetStatus(lldb::eReturnStatusFailed);138    return false;139  }140 141  // Clear status bit.142  //143  bd_entry--;144 145  lldb::addr_t bt_addr = bd_entry & ~bt_r_shift;146  lldb::addr_t bt_entry_offset = ((ptr & bt_mask) >> bt_r_shift) << bt_l_shift;147  bt_entry_addr = bt_addr + bt_entry_offset;148 149  return true;150}151 152static bool GetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::SBTarget &target,153                       llvm::Triple::ArchType arch,154                       lldb::SBCommandReturnObject &result,155                       lldb::SBError &error) {156  lldb::addr_t bt_entry_addr;157  size_t size;158  if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,159                      error))160    return false;161 162  // bt_entry_v must have space to store the 4 elements of the BT entry (lower163  // boundary,164  // upper boundary, pointer value and meta data), which all have the same size165  // 'size'.166  //167  std::vector<uint8_t> bt_entry_v(size * 4);168  size_t ret = target.GetProcess().ReadMemory(169      bt_entry_addr, static_cast<void *>(bt_entry_v.data()), size * 4, error);170 171  if ((ret != (size * 4)) || !error.Success()) {172    result.SetError("Unsuccessful. Failed access to BT entry.");173    result.SetStatus(lldb::eReturnStatusFailed);174    return false;175  }176 177  lldb::addr_t lbound;178  lldb::addr_t ubound;179  uint64_t value;180  uint64_t meta;181  lldb::SBData data;182  data.SetData(error, bt_entry_v.data(), bt_entry_v.size(),183               target.GetByteOrder(), size);184  lbound = data.GetAddress(error, size * 0);185  ubound = data.GetAddress(error, size * 1);186  value = data.GetAddress(error, size * 2);187  meta = data.GetAddress(error, size * 3);188  // ubound is stored as one's complement.189  if (arch == llvm::Triple::ArchType::x86) {190    ubound = (~ubound) & 0x00000000FFFFFFFF;191  } else {192    ubound = ~ubound;193  }194 195  if (!error.Success()) {196    result.SetError("Failed access to BT entry.");197    return false;198  }199 200  PrintBTEntry(lbound, ubound, value, meta, result);201 202  result.SetStatus(lldb::eReturnStatusSuccessFinishResult);203  return true;204}205 206static std::vector<uint8_t> uIntToU8(uint64_t input, size_t size) {207  std::vector<uint8_t> output;208  for (size_t i = 0; i < size; i++)209    output.push_back(210        static_cast<uint8_t>((input & (0xFFULL << (i * 8))) >> (i * 8)));211 212  return output;213}214 215static bool SetBTEntry(uint64_t bndcfgu, uint64_t ptr, lldb::addr_t lbound,216                       lldb::addr_t ubound, lldb::SBTarget &target,217                       llvm::Triple::ArchType arch,218                       lldb::SBCommandReturnObject &result,219                       lldb::SBError &error) {220  lldb::addr_t bt_entry_addr;221  size_t size;222 223  if (!GetBTEntryAddr(bndcfgu, ptr, target, arch, size, bt_entry_addr, result,224                      error))225    return false;226 227  // bt_entry_v must have space to store only 2 elements of the BT Entry, the228  // lower boundary and the upper boundary, which both have size 'size'.229  //230  std::vector<uint8_t> bt_entry_v(size * 2);231 232  std::vector<uint8_t> lbound_v = uIntToU8(lbound, size);233  bt_entry_v.insert(bt_entry_v.begin(), lbound_v.begin(), lbound_v.end());234  std::vector<uint8_t> ubound_v = uIntToU8(~ubound, size);235  bt_entry_v.insert(bt_entry_v.begin() + size, ubound_v.begin(),236                    ubound_v.end());237 238  size_t ret = target.GetProcess().WriteMemory(239      bt_entry_addr, (void *)(bt_entry_v.data()), size * 2, error);240  if ((ret != (size * 2)) || !error.Success()) {241    result.SetError("Failed access to BT entry.");242    result.SetStatus(lldb::eReturnStatusFailed);243    return false;244  }245 246  result.SetStatus(lldb::eReturnStatusSuccessFinishResult);247  return true;248}249 250static bool GetInitInfo(lldb::SBDebugger debugger, lldb::SBTarget &target,251                        llvm::Triple::ArchType &arch, uint64_t &bndcfgu,252                        char *arg, uint64_t &ptr,253                        lldb::SBCommandReturnObject &result,254                        lldb::SBError &error) {255  target = debugger.GetSelectedTarget();256  if (!target.IsValid()) {257    result.SetError("Invalid target.");258    result.SetStatus(lldb::eReturnStatusFailed);259    return false;260  }261 262  const std::string triple_s(target.GetTriple());263  const llvm::Triple triple(triple_s);264 265  arch = triple.getArch();266 267  if ((arch != llvm::Triple::ArchType::x86) &&268      (arch != llvm::Triple::ArchType::x86_64)) {269    result.SetError("Platform not supported.");270    result.SetStatus(lldb::eReturnStatusFailed);271    return false;272  }273 274  lldb::SBFrame frame =275      target.GetProcess().GetSelectedThread().GetSelectedFrame();276  if (!frame.IsValid()) {277    result.SetError("No valid process, thread or frame.");278    result.SetStatus(lldb::eReturnStatusFailed);279    return false;280  }281 282  lldb::SBValue bndcfgu_val = frame.FindRegister("bndcfgu");283  if (!bndcfgu_val.IsValid()) {284    result.SetError("Cannot access register BNDCFGU. Does the target support "285                    "Intel(R) Memory Protection Extensions (Intel(R) MPX)?");286    result.SetStatus(lldb::eReturnStatusFailed);287    return false;288  }289 290  lldb::SBData bndcfgu_data = bndcfgu_val.GetData();291  bndcfgu = bndcfgu_data.GetUnsignedInt64(error, 0);292  if (!error.Success()) {293    result.SetError(error, "Invalid read of register BNDCFGU.");294    return false;295  }296 297  if (!GetPtr(arg, ptr, frame, result))298    return false;299 300  return true;301}302 303class MPXTableShow : public lldb::SBCommandPluginInterface {304public:305  bool DoExecute(lldb::SBDebugger debugger, char **command,306                 lldb::SBCommandReturnObject &result) override {307 308    if (command) {309      int arg_c = 0;310      char *arg;311 312      while (*command) {313        if (arg_c >= 1) {314          result.SetError("Too many arguments. See help.");315          result.SetStatus(lldb::eReturnStatusFailed);316          return false;317        }318        arg_c++;319        arg = *command;320        command++;321      }322 323      if (!debugger.IsValid()) {324        result.SetError("Invalid debugger.");325        result.SetStatus(lldb::eReturnStatusFailed);326        return false;327      }328 329      lldb::SBTarget target;330      llvm::Triple::ArchType arch;331      lldb::SBError error;332      uint64_t bndcfgu;333      uint64_t ptr;334 335      if (!GetInitInfo(debugger, target, arch, bndcfgu, arg, ptr, result,336                       error))337        return false;338 339      return GetBTEntry(bndcfgu, ptr, target, arch, result, error);340    }341 342    result.SetError("Too few arguments. See help.");343    result.SetStatus(lldb::eReturnStatusFailed);344    return false;345  }346};347 348class MPXTableSet : public lldb::SBCommandPluginInterface {349public:350  bool DoExecute(lldb::SBDebugger debugger, char **command,351                 lldb::SBCommandReturnObject &result) override {352 353    if (command) {354      int arg_c = 0;355      char *arg[3];356 357      while (*command) {358        arg[arg_c] = *command;359        command++;360        arg_c++;361      }362 363      if (arg_c != 3) {364        result.SetError("Wrong arguments. See help.");365        return false;366      }367 368      if (!debugger.IsValid()) {369        result.SetError("Invalid debugger.");370        return false;371      }372 373      lldb::SBTarget target;374      llvm::Triple::ArchType arch;375      lldb::SBError error;376      uint64_t bndcfgu;377      uint64_t ptr;378 379      if (!GetInitInfo(debugger, target, arch, bndcfgu, arg[0], ptr, result,380                       error))381        return false;382 383      char *endptr;384      errno = 0;385      uint64_t lbound = std::strtoul(arg[1], &endptr, 16);386      if (endptr == arg[1] || errno == ERANGE) {387        result.SetError("Lower Bound: bad argument format.");388        errno = 0;389        return false;390      }391 392      uint64_t ubound = std::strtoul(arg[2], &endptr, 16);393      if (endptr == arg[1] || errno == ERANGE) {394        result.SetError("Upper Bound: bad argument format.");395        errno = 0;396        return false;397      }398 399      return SetBTEntry(bndcfgu, ptr, lbound, ubound, target, arch, result,400                        error);401    }402 403    result.SetError("Too few arguments. See help.");404    return false;405  }406};407 408bool MPXPluginInitialize(lldb::SBDebugger &debugger) {409  lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();410  lldb::SBCommand mpxTable = interpreter.AddMultiwordCommand(411      "mpx-table", "A utility to access the Intel(R) MPX table entries.");412 413  const char *mpx_show_help = "Show the Intel(R) MPX table entry of a pointer."414                              "\nmpx-table show <pointer>";415  mpxTable.AddCommand("show", new MPXTableShow(), mpx_show_help);416 417  const char *mpx_set_help =418      "Set the Intel(R) MPX table entry of a pointer.\n"419      "mpx-table set <pointer> <lower bound> <upper bound>";420  mpxTable.AddCommand("set", new MPXTableSet(), mpx_set_help);421 422  return true;423}424