mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
bf82eb39bb
* Add initial prototying of DeadStoreEliminator * Improve upon DeadStoreEliminator prototype Update `DeadStoreEliminator` prototyping with additional comments and proper function prototype return values. Fix a small warning in `Lifter.h` by adding `llvm::Value` and `llvm::BasicBlock`. * Add initial code for DeadStoreEliminator Provide namespaced `remill::StateSlots` function which visits fields of the module's state struct and returns `StateSlot` objects. Remove `comment` field as the `State` object (an `llvm::StructType`) does not track names in a useful way. * Update state analyzer and fix type errors Update `DeadStoreEliminator.cpp` to properly produce a vector of `StateSlot`s without type errors (i.e. it compiles). Code still needed for other container types besides structs. * Add remill::VisitSequential for arrays and vectors Add state analyzer code for LLVM's `ArrayType` and `VectorType`. Add debugging use of `llvm::Type::dump()`. Consider refactoring as a `StateVisitor` class. * Begin refactor of Visit funcs to StateVisitor * Fix segfault in StateVisitor::visit, code style * Prototype ForwardAliasVisitor for alias analysis Add code for ForwardAliasVisitor subclass of `llvm::InstVisitor`, to be used for performing alias analysis of lifted functions. * Add non-working visit functions for alias analysis * Fix compilation of alias analysis visit funcs * Change ForwardAliasVisitor to RetTy=bool Update ForwardAliasVisitor to use booleans for return types to track when we should add the instruction to the next_wl. Add code to simplify StateSlots for vecs of ints. * Add progress tracking to AliasAnalysis * Correct progress tracker, use BasicBlockFunction() * Change ForwardAliasAnalysis<RetTy = AliasResult> Get some of those sweet sweet enums in there! * Add FAV state pointer field, PHINode impl * Allow non-const add and sub in FAV Allow add and sub instructions with two pointers in the offset map. Add to implementation of visitPHINode. * Update PHINode impl in FAV * Clean up use of StateSlots to create AAMDNodes Add code to create AAMDNodes from StateSlot elements. Change creation of StateSlot vector to have elements for every byte offset of the state structure for fast indexing. * Complete addition of AAMDNodes for load and store Move function defs up for AAMDNode ops. Add AliasMap typedef. Finish generateAAMDNodesFromSlots. * Add GenerateLiveSet func * Initialize live set, add AAMDNodes to stores * Change LiveSet creation to a block visitor class * Add to_remove set to LSBV * Update build script to use os-release for OS detection * Update DSE code to conform to pag's review * Refactor LiveSetBlockVisitor to one LiveSet per block * Update VisitBlock to better check instruction type * Fix VisitBlock CallInst and InvokeInst cases * Stack allocate AAMDInfo in AnalyzeAliases * Add remove pass option for VisitBlock * Add DOT digraph generation * Fix bugs in dot digraph * Fix various bugs in AAMDNodes and LSBV Move AAMDNodes functions later to match their use. Clean up code conventions. Fix small bugs in various spots in the code. * Fix various function prototypes, overflow checks * Merge AliasMap and OffsetMap * Change add/sub insts to be safer Add OpType enum class to replace use of `plus` bool. Add more straightforward bounds checking on AddInst or SubInst values. * Refactor GetUnsignedOffset style * Fix illegal instruction error * Add offset checking for GEP, provide log messages Write a log message for the cases where `GetUnsignedOffset` returns false (indicating an overflow or underflow). * Fix APInt initialization in VisitGEP * Re-add dead store elimination and alias map * Move LSBV into alias analysis, expand callinst Expand definition of cases where a CallInst should be considered to touch the state struct or otherwise revive a slot. * Improve DOT creation, fix errors for callinsts Fix small errors in LiveSetBlockVisitor::CallAccessesState. Clean up DOT digraph generation further. * Clean up code per @pag's comments * Clean up code, add selectinst, fix compile errors Deal with a few small corner cases with FAV Load and Store instructions, add SelectInst visitor. Inline MarkLiveArgs to avoid the complications of C++ generics. * Clean up logging * More changes to please Peter Clean up select and PHI node cases to improve circular dependency handling. * Correct errors in visitSelect * Add load forwarding code * Add code to run FBV * Fix map usage error in FBV * Add call, invoke cases for FBV * Here are the changes whoops * Minor API change * Minor tweaks to DOT digraph printing, as well as attempts to handle the case where the forward analysis pass is incomplete. Still don't have it guarantee completion on everything, but seems 'good enough' for now. * Change log level * Fix compile errors due to messy merge * Pag dead store (#262) * Fix to script calling wrong function. * Makes sure that value names are preserved (#249) * Adds LLVM_VERSION() to accomodate llvm::LLVMContext::setDiscardValueNames() in <3.9 (#250) * Makes sure that value names are preserved * Adds LLVM_VERSION() macros to accomodate * Update README.md * Update README.md * set state and memory as noalias (#254) * Implements some ring 0 instructions in terms of hyper calls and new I/O port intrinsics. (#252) * Random tests. * More decode error info * more playing around * more system instructions. instrinsics for accessing I/O ports. Split our writes to individual control regs for better identification via hyper calls. * CR8 read/write support (#255) * Check argument index of function (#256) * Fix NoAlias Attributes for older LLVM versions * Fix for LLVM 4.0 and 3.9 * Fix typo * Follow remill coding style * Here are the changes whoops * Minor API change * Minor tweaks to DOT digraph printing, as well as attempts to handle the case where the forward analysis pass is incomplete. Still don't have it guarantee completion on everything, but seems 'good enough' for now. * Change log level * Fix compile errors due to messy merge * Improve call/invoke case of FBV * Improve call/invoke case of FBV * Removes a level of indirection in the __remill_basic_block function * Create dedicated stats tracker Plus clean up the FBV visitor a teensy bit more. * Move call/invoke LiveSet gen to static func This commit is to pave the way for future improvements to where this information is calculated (in FAV instead of LSBV). * Add code to FAV for calls and invokes Move call and invoke arg-based livesets to FAV to allow for module-level LSBV code. * Begin change of LSBV to module-level * Minor bug fixes * Remove some dead code * Begin adding more code for call/invoke LSBV * Add entry block checks for LSBV call/invoke * Info about register names, as well as printing them in the digraphs. * Make DOT printing only happen per function, as opposed to printing every function per DOT file. Minor tweaks to interprocedural analysis. * Bug fixes and DOT printing improvements. * Bug fixes and DOT printing improvements. * Also print out DOT digraphs of functions after removing stuff * Tried to make it treat everything before a call to __remill_error as dead but that didn't work out. * Use datalayout and type sizes to handle the number of elements in a sequential type for LLVM 3.8 compatibility, also check for pointer type. * More stats, hopefully fixes a bitcast issue. * Minor bug fixes, and more DOT printing to help diagnose when the offset analysis terminates but there is still stuff in the work list. * Some possible bug fixes * Minor bug fix
245 lines
6.0 KiB
C++
245 lines
6.0 KiB
C++
/*
|
|
* Copyright (c) 2017 Trail of Bits, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <glog/logging.h>
|
|
|
|
#include <algorithm>
|
|
#include <cerrno>
|
|
#include <climits>
|
|
#include <cstdlib>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
|
|
#include "remill/OS/FileSystem.h"
|
|
#include "remill/OS/OS.h"
|
|
|
|
#if REMILL_ON_MACOS
|
|
# ifndef _DARWIN_USE_64_BIT_INODE
|
|
# define _DARWIN_USE_64_BIT_INODE 1
|
|
# endif
|
|
# define stat64 stat
|
|
# define fstat64 fstat
|
|
#endif
|
|
|
|
#if defined(_MAX_PATH) && !defined(PATH_MAX)
|
|
# define PATH_MAX _MAX_PATH
|
|
#endif
|
|
|
|
namespace remill {
|
|
|
|
// Try to create a directory. Returns `true` if the directory was created or
|
|
// exists.
|
|
bool TryCreateDirectory(const std::string &dir_name) {
|
|
mkdir(dir_name.c_str(), 0777); // Ignore errors.
|
|
if (auto d = opendir(dir_name.c_str())) {
|
|
closedir(d);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Iterator over a directory.
|
|
void ForEachFileInDirectory(const std::string &dir_name,
|
|
DirectoryVisitor visitor) {
|
|
std::vector<std::string> paths;
|
|
auto dir = opendir(dir_name.c_str());
|
|
CHECK(dir != nullptr)
|
|
<< "Could not list the " << dir_name << " directory";
|
|
|
|
while (auto ent = readdir(dir)) {
|
|
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
|
|
continue;
|
|
}
|
|
|
|
std::stringstream ss;
|
|
ss << dir_name << "/" << ent->d_name;
|
|
paths.push_back(ss.str());
|
|
}
|
|
closedir(dir);
|
|
|
|
for (const auto &path : paths) {
|
|
if (!visitor(path)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string CurrentWorkingDirectory(void) {
|
|
char result[PATH_MAX] = {};
|
|
auto res = getcwd(result, PATH_MAX);
|
|
CHECK(res)
|
|
<< "Could not determine current working directory: " << strerror(errno);
|
|
return std::string(result);
|
|
}
|
|
|
|
bool FileExists(const std::string &path) {
|
|
if (-1 == access(path.c_str(), F_OK)) {
|
|
return false;
|
|
}
|
|
|
|
struct stat64 file_info = {};
|
|
return stat64(path.c_str(), &file_info) == 0 &&
|
|
(S_ISREG(file_info.st_mode) ||
|
|
S_ISFIFO(file_info.st_mode));
|
|
}
|
|
|
|
uint64_t FileSize(int fd) {
|
|
struct stat64 file_info;
|
|
CHECK(!fstat64(fd, &file_info))
|
|
<< "Cannot stat FD " << fd << ": " << strerror(errno);
|
|
return static_cast<uint64_t>(file_info.st_size);
|
|
}
|
|
|
|
uint64_t FileSize(const std::string &path, int fd) {
|
|
struct stat64 file_info;
|
|
CHECK(!fstat64(fd, &file_info))
|
|
<< "Cannot stat " << path << ": " << strerror(errno);
|
|
return static_cast<uint64_t>(file_info.st_size);
|
|
}
|
|
|
|
uint64_t FileSize(const std::string &path) {
|
|
struct stat64 file_info;
|
|
CHECK(!stat64(path.c_str(), &file_info))
|
|
<< "Cannot stat " << path << ": " << strerror(errno);
|
|
return static_cast<uint64_t>(file_info.st_size);
|
|
}
|
|
|
|
void RemoveFile(const std::string &path) {
|
|
unlink(path.c_str());
|
|
}
|
|
|
|
bool RenameFile(const std::string &from_path, const std::string &to_path) {
|
|
auto ret = rename(from_path.c_str(), to_path.c_str());
|
|
auto err = errno;
|
|
if (-1 == ret) {
|
|
LOG(ERROR)
|
|
<< "Unable to rename " << from_path << " to " << to_path
|
|
<< ": " << strerror(err);
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
enum : size_t {
|
|
kCopyDataSize = 4096ULL
|
|
};
|
|
|
|
static uint8_t gCopyData[kCopyDataSize];
|
|
} // namespace
|
|
|
|
void CopyFile(const std::string &from_path, const std::string &to_path) {
|
|
unlink(to_path.c_str());
|
|
auto from_fd = open(from_path.c_str(), O_RDONLY);
|
|
CHECK(-1 != from_fd)
|
|
<< "Unable to open source file " << from_path
|
|
<< " for copying: " << strerror(errno);
|
|
|
|
auto to_fd = open(to_path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
|
CHECK(-1 != to_fd)
|
|
<< "Unable to open destination file " << to_path
|
|
<< " for copying: " << strerror(errno);
|
|
|
|
auto file_size = FileSize(from_path);
|
|
int errno_copy = 0;
|
|
|
|
do {
|
|
auto num_read = read(
|
|
from_fd, &(gCopyData[0]), std::min<size_t>(kCopyDataSize, file_size));
|
|
if (-1 == num_read) {
|
|
errno_copy = errno;
|
|
break;
|
|
}
|
|
|
|
auto num_written = write(
|
|
to_fd, &(gCopyData[0]), static_cast<size_t>(num_read));
|
|
|
|
if (num_written != num_read) {
|
|
errno_copy = errno;
|
|
break;
|
|
}
|
|
|
|
file_size -= static_cast<size_t>(num_written);
|
|
} while (file_size);
|
|
|
|
close(from_fd);
|
|
close(to_fd);
|
|
|
|
if (errno_copy) {
|
|
unlink(to_path.c_str());
|
|
LOG(FATAL)
|
|
<< "Unable to copy all data read from " << from_path
|
|
<< " to " << to_path << ": " << strerror(errno_copy);
|
|
}
|
|
}
|
|
|
|
void HardLinkOrCopyFile(const std::string &from_path,
|
|
const std::string &to_path) {
|
|
unlink(to_path.c_str());
|
|
if (!link(from_path.c_str(), to_path.c_str())) {
|
|
return;
|
|
}
|
|
|
|
DLOG(WARNING)
|
|
<< "Unable to link " << to_path << " to "
|
|
<< from_path << ": " << strerror(errno);
|
|
|
|
CopyFile(from_path, to_path);
|
|
}
|
|
|
|
void MoveFile(const std::string &from_path, const std::string &to_path) {
|
|
if (!RenameFile(from_path, to_path)) {
|
|
CopyFile(from_path, to_path);
|
|
RemoveFile(from_path);
|
|
}
|
|
}
|
|
|
|
std::string CanonicalPath(const std::string &path) {
|
|
char buff[PATH_MAX + 1] = {};
|
|
#if REMILL_ON_WINDOWS
|
|
auto canon_path_c = _fullpath(buff, path.c_str(), PATH_MAX);
|
|
auto err = ENOENT;
|
|
#else
|
|
auto canon_path_c = realpath(path.c_str(), buff);
|
|
auto err = errno;
|
|
#endif
|
|
if (!canon_path_c) {
|
|
DLOG(WARNING)
|
|
<< "Cannot compute full path of " << path
|
|
<< ": " << strerror(err);
|
|
return path;
|
|
} else {
|
|
std::string canon_path(canon_path_c);
|
|
return canon_path;
|
|
}
|
|
}
|
|
|
|
// Returns the path separator character for this OS.
|
|
const char *PathSeparator(void) {
|
|
#if REMILL_ON_WINDOWS
|
|
return "\\";
|
|
#else
|
|
return "/";
|
|
#endif
|
|
}
|
|
|
|
} // namespace remill
|