Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/dyninstAPI/src/linux-x86.C
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

341 lines
12 KiB
C++

/*
* See the dyninst/COPYRIGHT file for copyright information.
*
* We provide the Paradyn Tools (below described as "Paradyn")
* on an AS IS basis, and do not warrant its validity or performance.
* We reserve the right to update, modify, or discontinue this
* software at any time. We shall have no obligation to supply such
* updates or modifications or any other form of support to you.
*
* By your use of Paradyn, you understand and agree that we (or any
* other person or entity with proprietary rights in Paradyn) are
* under no obligation to provide either maintenance services,
* update services, notices of latent defects, or correction of
* defects for Paradyn.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
// $Id: linux-x86.C,v 1.142 2008/08/01 17:55:12 roundy Exp $
#include <fstream>
#include <string>
#include <fcntl.h>
#include <sys/user.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <math.h> // for floor()
#include <unistd.h> // for sysconf()
//#include <elf.h>
//#include <libelf.h>
#include "dyninstAPI/src/baseTramp.h"
#include "dyninstAPI/src/image.h"
#include "dyninstAPI/src/function.h"
#include "dyninstAPI/src/instPoint.h"
#include "common/src/headers.h"
#include "dyninstAPI/src/os.h"
#include "common/src/stats.h"
#include "dyninstAPI/src/debug.h"
#include "dyninstAPI/src/util.h" // getCurrWallTime
#include "common/src/pathName.h"
#include "dyninstAPI/src/inst-x86.h"
#include "dyninstAPI/src/emit-x86.h"
#include "registers/x86_regs.h"
#include "registers/x86_64_regs.h"
#include "dyninstAPI/src/mapped_object.h"
#include "dyninstAPI/src/linux.h"
#include "dyninstAPI/src/registerSpace.h"
#include <sstream>
#include "dyninstAPI/src/ast.h"
#include "dyninstAPI/src/binaryEdit.h"
#include "dyninstAPI/src/dynThread.h"
#include "dyninstAPI/src/dynProcess.h"
#include "common/src/linuxKludges.h"
#include "instructionAPI/h/InstructionDecoder.h"
#include "instructionAPI/h/Instruction.h"
using namespace Dyninst;
using namespace Dyninst::SymtabAPI;
using namespace Dyninst::ProcControlAPI;
Address PCProcess::getLibcStartMainParam(PCThread *trappingThread) {
Address mainaddr = 0;
unsigned addrWidth = getAddressWidth();
RegisterPool regs;
trappingThread->getRegisters(regs);
Address targetAddr = 0;
if( getArch() == Arch_x86_64 ) {
if( addrWidth == 4 ) {
targetAddr = regs[x86_64::rsp] + addrWidth;
}else{
targetAddr = regs[x86_64::rdi];
}
}else{
targetAddr = regs[x86::esp] + addrWidth;
}
if( !readDataSpace((const void *)targetAddr, addrWidth, (void *)&mainaddr, false) ) {
proccontrol_printf("%s[%d]: failed to read address of main out of libc\n",
FILE__, __LINE__);
}
return mainaddr;
}
Address PCProcess::getTOCoffsetInfo(Address) {
assert(!"This function is unimplemented");
return 0;
}
Address PCProcess::getTOCoffsetInfo(func_instance *) {
assert(!"This function is unimplemented");
return 0;
}
bool PCProcess::getOPDFunctionAddr(Address &) {
return true;
}
AstNodePtr PCProcess::createUnprotectStackAST() {
// Since we are punching our way down to an internal function, we
// may run into problems due to stack execute protection. Basically,
// glibc knows that it needs to be able to execute on the stack in
// in order to load libraries with dl_open(). It has code in
// _dl_map_object_from_fd (the workhorse of dynamic library loading)
// that unprotects a global, exported variable (__stack_prot), sets
// the execute flag, and reprotects it. This only happens, however,
// when the higher-level dl_open() functions (which we skip) are called,
// as they append an undocumented flag to the library open mode. Otherwise,
// assignment to the variable happens without protection, which will
// cause a fault.
//
// Instead of chasing the value of the undocumented flag, we will
// unprotect the __stack_prot variable ourselves (if we can find it).
startup_printf("%s[%d]: creating AST to call mprotect to unprotect libc stack protection variable\n",
FILE__, __LINE__);
// find variable __stack_prot
// mprotect READ/WRITE __stack_prot
std::vector<int_variable *> vars;
std::vector<func_instance *> funcs;
Address var_addr;
int size;
int pagesize;
Address page_start;
bool ret;
ret = findVarsByAll("__stack_prot", vars);
if(!ret || vars.size() == 0) {
return AstNodePtr();
} else if(vars.size() > 1) {
startup_printf("%s[%d]: Warning: found more than one __stack_prot variable\n",
FILE__, __LINE__);
}
pagesize = getpagesize();
var_addr = vars[0]->getAddress();
page_start = var_addr & ~(pagesize -1);
size = var_addr - page_start +sizeof(int);
ret = findFuncsByAll("mprotect",funcs);
if(!ret || funcs.size() == 0) {
startup_printf("%s[%d]: Couldn't find mprotect\n",
FILE__, __LINE__);
return AstNodePtr();
}
// mprotect: int mprotect(const void *addr, size_t len, int prot);
func_instance *mprot = funcs[0];
std::vector<AstNodePtr> args;
args.push_back(AstNode::operandNode(AstNode::operandType::Constant, (void *)page_start));
args.push_back(AstNode::operandNode(AstNode::operandType::Constant, (void *)(intptr_t)size));
// prot = READ|WRITE|EXECUTE
args.push_back(AstNode::operandNode(AstNode::operandType::Constant, (void *)7));
return AstNode::funcCallNode(mprot, args);
}
// For now, this isn't defined
#if 0
/* Find libc and add it as a shared object
* Search for __libc_start_main
* Save old code at beginning of __libc_start_main
* Insert trap
* Signal thread to continue
*/
bool PCProcess::instrumentLibcStartMain()
{
unsigned int maps_size =0;
map_entries *maps = getVMMaps(getPid(), maps_size);
unsigned int libcIdx=0;
while (libcIdx < maps_size &&
! (strstr(maps[libcIdx].path,"/libc")
&& strstr(maps[libcIdx].path,".so"))) {
libcIdx++;
}
assert(libcIdx != maps_size);
//TODO: address code and data are not always 0,0: need to fix this
fileDescriptor libcFD = fileDescriptor(maps[libcIdx].path,0,0,true);
mapped_object *libc = mapped_object::createMappedObject(libcFD, this);
addASharedObject(libc);
// find __libc_startmain
const std::vector<func_instance*> *funcs;
funcs = libc->findFuncVectorByPretty("__libc_start_main");
if(funcs->size() == 0 || (*funcs)[0] == NULL) {
logLine( "Couldn't find __libc_start_main\n");
return false;
} else if (funcs->size() > 1) {
startup_printf("[%s:%u] - Found %d functions called __libc_start_main, weird\n",
FILE__, __LINE__, funcs->size());
}
if (!(*funcs)[0]->isInstrumentable()) {
logLine( "__libc_start_main is not instrumentable\n");
return false;
}
Address addr = (*funcs)[0]->addr();
startup_printf("%s[%d]: Instrumenting libc.so:__libc_start_main() at 0x%x\n",
FILE__, __LINE__, (int)addr);
// save original code at beginning of function
if (!readDataSpace((void *)addr, sizeof(savedCodeBuffer),savedCodeBuffer,true)) {
fprintf(stderr, "%s[%d]: readDataSpace\n", __FILE__, __LINE__);
fprintf(stderr, "%s[%d][%s]: failing instrumentLibcStartMain\n",
__FILE__, __LINE__, getThreadStr(getExecThreadID()));
fprintf(stderr, "Failed to read at address 0x%lx\n", addr);
return false;
}
startup_printf("%s[%d]: Saved %d bytes from entry of __libc_start_main\n",
FILE__, __LINE__, sizeof(savedCodeBuffer));
// insert trap
codeGen gen(1);
insnCodeGen::generateTrap(gen);
if (!writeDataSpace((void *)addr, gen.used(), gen.start_ptr())) {
fprintf(stderr, "%s[%d][%s]: failing instrumentLibcStartMain\n",
__FILE__, __LINE__, getThreadStr(getExecThreadID()));
return false;
}
libcstartmain_brk_addr = addr;
// TODO continueProc(); // signal process to continue
return true;
}// end instrumentLibcStartMain
#endif
bool PCProcess::bindPLTEntry(const SymtabAPI::relocationEntry &entry, Address base_addr,
func_instance *, Address target_addr) {
// We just want to overwrite the GOT entry with our target address.
Address got_entry = entry.rel_addr() + base_addr;
return writeDataSpace((void *)got_entry, sizeof(Address), &target_addr);
}
bool AddressSpace::getDyninstRTLibName() {
startup_printf("dyninstRT_name: %s\n", dyninstRT_name.c_str());
if (dyninstRT_name.length() == 0) {
// Get env variable
if (getenv("DYNINSTAPI_RT_LIB") != NULL) {
dyninstRT_name = getenv("DYNINSTAPI_RT_LIB");
}
else {
std::string msg;
PCProcess *proc;
if ((proc = dynamic_cast<PCProcess *>(this)) != NULL) {
msg = std::string("Environment variable ") +
std::string("DYNINSTAPI_RT_LIB") +
std::string(" has not been defined for process ") +
utos(proc->getPid());
}
else {
msg = std::string("Environment variable ") +
std::string("DYNINSTAPI_RT_LIB") +
std::string(" has not been defined");
}
showErrorCallback(101, msg);
return false;
}
}
// Automatically choose 32-bit library if necessary.
const char *modifier = "";
const char *name = dyninstRT_name.c_str();
const char *split = P_strrchr(name, '/');
if ( !split ) split = name;
split = P_strchr(split, '.');
if ( !split || P_strlen(split) <= 1 ) {
// We should probably print some error here.
// Then, of course, the user will find out soon enough.
startup_printf("Invalid Dyninst RT lib name: %s\n",
dyninstRT_name.c_str());
return false;
}
if (getAddressWidth() == 4 &&
(sizeof(void *) == 8)) {
// Need _m32...
if (P_strstr(name, "_m32") == NULL) {
modifier = "_m32";
}
}
const char *suffix = split;
if( getAOut()->isStaticExec() ) {
suffix = ".a";
}else{
if( P_strncmp(suffix, ".a", 2) == 0 ) {
// Add symlinks in makefiles as follows:
// (lib).so => lib.so.(major)
// lib.so.major => lib.so.major.minor
// lib.so.major.minor => lib.so.major.minor.maintenance
suffix = ".so";
}
}
dyninstRT_name = std::string(name, split - name) +
std::string(modifier) +
std::string(suffix);
startup_printf("Dyninst RT Library name set to '%s'\n",
dyninstRT_name.c_str());
// Check to see if the library given exists.
if (access(dyninstRT_name.c_str(), R_OK)) {
std::string msg = std::string("Runtime library ") + dyninstRT_name
+ std::string(" does not exist or cannot be accessed!");
showErrorCallback(101, msg);
return false;
}
return true;
}