IFC @231845
Sponsored by: Cisco Systems, Inc.
This commit is contained in:
commit
9dba179d5e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/multi-fibv6/head/; revision=231846
2
Makefile
2
Makefile
@ -24,7 +24,7 @@
|
||||
# check-old-dirs - List obsolete directories.
|
||||
# check-old-files - List obsolete files.
|
||||
# check-old-libs - List obsolete libraries.
|
||||
# delete-old - Delete obsolete directories/files/libraries.
|
||||
# delete-old - Delete obsolete directories/files.
|
||||
# delete-old-dirs - Delete obsolete directories.
|
||||
# delete-old-files - Delete obsolete files.
|
||||
# delete-old-libs - Delete obsolete libraries.
|
||||
|
7
UPDATING
7
UPDATING
@ -22,6 +22,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 10.x IS SLOW:
|
||||
machines to maximize performance. (To disable malloc debugging, run
|
||||
ln -s aj /etc/malloc.conf.)
|
||||
|
||||
20120211:
|
||||
The getifaddrs upgrade path broken with 20111215 has been restored.
|
||||
If you have upgraded in between 20111215 and 20120209 you need to
|
||||
recompile libc again with your kernel. You still need to recompile
|
||||
world to be able to configure CARP but this restriction already
|
||||
comes from 20111215.
|
||||
|
||||
20120114:
|
||||
The set_rcvar() function has been removed from /etc/rc.subr. All
|
||||
base and ports rc.d scripts have been updated, so if you have a
|
||||
|
@ -921,6 +921,15 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
|
||||
if (pipe(pip) < 0)
|
||||
error("Pipe call failed: %s", strerror(errno));
|
||||
}
|
||||
if (cmdentry.cmdtype == CMDNORMAL &&
|
||||
cmd->ncmd.redirect == NULL &&
|
||||
varlist.list == NULL &&
|
||||
(mode == FORK_FG || mode == FORK_NOJOB) &&
|
||||
!disvforkset() && !iflag && !mflag) {
|
||||
vforkexecshell(jp, argv, environment(), path,
|
||||
cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
|
||||
goto parent;
|
||||
}
|
||||
if (forkshell(jp, cmd, mode) != 0)
|
||||
goto parent; /* at end of routine */
|
||||
if (flags & EV_BACKCMD) {
|
||||
|
@ -231,7 +231,9 @@ hashcmd(int argc __unused, char **argv __unused)
|
||||
int verbose;
|
||||
struct cmdentry entry;
|
||||
char *name;
|
||||
int errors;
|
||||
|
||||
errors = 0;
|
||||
verbose = 0;
|
||||
while ((c = nextopt("rv")) != '\0') {
|
||||
if (c == 'r') {
|
||||
@ -254,19 +256,21 @@ hashcmd(int argc __unused, char **argv __unused)
|
||||
&& cmdp->cmdtype == CMDNORMAL)
|
||||
delete_cmd_entry();
|
||||
find_command(name, &entry, DO_ERR, pathval());
|
||||
if (verbose) {
|
||||
if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
|
||||
cmdp = cmdlookup(name, 0);
|
||||
if (cmdp != NULL)
|
||||
printentry(cmdp, verbose);
|
||||
else
|
||||
outfmt(out2, "%s: not found\n", name);
|
||||
if (entry.cmdtype == CMDUNKNOWN)
|
||||
errors = 1;
|
||||
else if (verbose) {
|
||||
cmdp = cmdlookup(name, 0);
|
||||
if (cmdp != NULL)
|
||||
printentry(cmdp, verbose);
|
||||
else {
|
||||
outfmt(out2, "%s: not found\n", name);
|
||||
errors = 1;
|
||||
}
|
||||
flushall();
|
||||
}
|
||||
argptr++;
|
||||
}
|
||||
return 0;
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
|
||||
#undef CEOF /* syntax.h redefines this */
|
||||
#endif
|
||||
#include "redir.h"
|
||||
#include "exec.h"
|
||||
#include "show.h"
|
||||
#include "main.h"
|
||||
#include "parser.h"
|
||||
@ -885,6 +886,54 @@ forkshell(struct job *jp, union node *n, int mode)
|
||||
}
|
||||
|
||||
|
||||
pid_t
|
||||
vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
|
||||
{
|
||||
pid_t pid;
|
||||
struct jmploc jmploc;
|
||||
struct jmploc *savehandler;
|
||||
|
||||
TRACE(("vforkexecshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
|
||||
mode));
|
||||
INTOFF;
|
||||
flushall();
|
||||
savehandler = handler;
|
||||
pid = vfork();
|
||||
if (pid == -1) {
|
||||
TRACE(("Vfork failed, errno=%d\n", errno));
|
||||
INTON;
|
||||
error("Cannot fork: %s", strerror(errno));
|
||||
}
|
||||
if (pid == 0) {
|
||||
TRACE(("Child shell %d\n", (int)getpid()));
|
||||
if (setjmp(jmploc.loc))
|
||||
_exit(exception == EXEXEC ? exerrno : 2);
|
||||
if (pip != NULL) {
|
||||
close(pip[0]);
|
||||
if (pip[1] != 1) {
|
||||
dup2(pip[1], 1);
|
||||
close(pip[1]);
|
||||
}
|
||||
}
|
||||
handler = &jmploc;
|
||||
shellexec(argv, envp, path, idx);
|
||||
}
|
||||
handler = savehandler;
|
||||
if (jp) {
|
||||
struct procstat *ps = &jp->ps[jp->nprocs++];
|
||||
ps->pid = pid;
|
||||
ps->status = -1;
|
||||
ps->cmd = nullstr;
|
||||
jp->foreground = 1;
|
||||
#if JOBS
|
||||
setcurjob(jp);
|
||||
#endif
|
||||
}
|
||||
INTON;
|
||||
TRACE(("In parent shell: child = %d\n", (int)pid));
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wait for job to finish.
|
||||
|
@ -91,6 +91,7 @@ void setjobctl(int);
|
||||
void showjobs(int, int);
|
||||
struct job *makejob(union node *, int);
|
||||
pid_t forkshell(struct job *, union node *, int);
|
||||
pid_t vforkexecshell(struct job *, char **, char **, const char *, int, int []);
|
||||
int waitforjob(struct job *, int *);
|
||||
int stoppedjobs(void);
|
||||
int backgndpidset(void);
|
||||
|
@ -94,6 +94,7 @@ struct var vps2;
|
||||
struct var vps4;
|
||||
struct var vvers;
|
||||
static struct var voptind;
|
||||
struct var vdisvfork;
|
||||
|
||||
int forcelocal;
|
||||
|
||||
@ -125,6 +126,8 @@ static const struct varinit varinit[] = {
|
||||
#endif
|
||||
{ &voptind, 0, "OPTIND=1",
|
||||
getoptsreset },
|
||||
{ &vdisvfork, VUNSET, "SH_DISABLE_VFORK=",
|
||||
NULL },
|
||||
{ NULL, 0, NULL,
|
||||
NULL }
|
||||
};
|
||||
@ -600,7 +603,7 @@ showvarscmd(int argc __unused, char **argv __unused)
|
||||
}
|
||||
}
|
||||
|
||||
INTON;
|
||||
INTOFF;
|
||||
vars = ckmalloc(n * sizeof(*vars));
|
||||
i = 0;
|
||||
for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
|
||||
@ -625,7 +628,7 @@ showvarscmd(int argc __unused, char **argv __unused)
|
||||
out1c('\n');
|
||||
}
|
||||
ckfree(vars);
|
||||
INTOFF;
|
||||
INTON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ extern struct var vppid;
|
||||
extern struct var vps1;
|
||||
extern struct var vps2;
|
||||
extern struct var vps4;
|
||||
extern struct var vdisvfork;
|
||||
#ifndef NO_HISTORY
|
||||
extern struct var vhistsize;
|
||||
extern struct var vterm;
|
||||
@ -109,6 +110,7 @@ extern int initial_localeisutf8;
|
||||
#endif
|
||||
|
||||
#define mpathset() ((vmpath.flags & VUNSET) == 0)
|
||||
#define disvforkset() ((vdisvfork.flags & VUNSET) == 0)
|
||||
|
||||
void initvar(void);
|
||||
void setvar(const char *, const char *, int);
|
||||
|
@ -590,7 +590,7 @@ zfs_do_clone(int argc, char **argv)
|
||||
zfs_handle_t *zhp = NULL;
|
||||
boolean_t parents = B_FALSE;
|
||||
nvlist_t *props;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int c;
|
||||
|
||||
if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
|
||||
@ -1052,7 +1052,7 @@ destroy_print_cb(zfs_handle_t *zhp, void *arg)
|
||||
static int
|
||||
destroy_print_snapshots(zfs_handle_t *fs_zhp, destroy_cbdata_t *cb)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
assert(cb->cb_firstsnap == NULL);
|
||||
assert(cb->cb_prevsnap == NULL);
|
||||
err = zfs_iter_snapshots_sorted(fs_zhp, destroy_print_cb, cb);
|
||||
@ -1130,7 +1130,7 @@ destroy_clones(destroy_cbdata_t *cb)
|
||||
ZFS_TYPE_SNAPSHOT);
|
||||
if (zhp != NULL) {
|
||||
boolean_t defer = cb->cb_defer_destroy;
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* We can't defer destroy non-snapshots, so set it to
|
||||
@ -1207,7 +1207,7 @@ zfs_do_destroy(int argc, char **argv)
|
||||
|
||||
at = strchr(argv[0], '@');
|
||||
if (at != NULL) {
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
/* Build the list of snaps to destroy in cb_nvl. */
|
||||
if (nvlist_alloc(&cb.cb_nvl, NV_UNIQUE_NAME, 0) != 0)
|
||||
@ -1474,7 +1474,7 @@ zfs_do_get(int argc, char **argv)
|
||||
zprop_get_cbdata_t cb = { 0 };
|
||||
int i, c, flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
|
||||
char *value, *fields;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int limit = 0;
|
||||
zprop_list_t fake_name = { 0 };
|
||||
|
||||
@ -1711,7 +1711,7 @@ zfs_do_inherit(int argc, char **argv)
|
||||
zfs_prop_t prop;
|
||||
inherit_cbdata_t cb = { 0 };
|
||||
char *propname;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int flags = 0;
|
||||
boolean_t received = B_FALSE;
|
||||
|
||||
@ -1917,7 +1917,7 @@ zfs_do_upgrade(int argc, char **argv)
|
||||
{
|
||||
boolean_t all = B_FALSE;
|
||||
boolean_t showversions = B_FALSE;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
upgrade_cbdata_t cb = { 0 };
|
||||
char c;
|
||||
int flags = ZFS_ITER_ARGS_CAN_BE_PATHS;
|
||||
@ -2206,7 +2206,7 @@ userspace_cb(void *arg, const char *domain, uid_t rid, uint64_t space)
|
||||
uid_t id;
|
||||
uint64_t classes;
|
||||
#ifdef sun
|
||||
int err;
|
||||
int err = 0;
|
||||
directory_error_t e;
|
||||
#endif
|
||||
|
||||
@ -2562,7 +2562,7 @@ zfs_do_userspace(int argc, char **argv)
|
||||
boolean_t prtnum = B_FALSE;
|
||||
boolean_t parseable = B_FALSE;
|
||||
boolean_t sid2posix = B_FALSE;
|
||||
int error;
|
||||
int error = 0;
|
||||
int c;
|
||||
zfs_sort_column_t *default_sortcol = NULL;
|
||||
zfs_sort_column_t *sortcol = NULL;
|
||||
@ -2925,7 +2925,7 @@ zfs_do_list(int argc, char **argv)
|
||||
list_cbdata_t cb = { 0 };
|
||||
char *value;
|
||||
int limit = 0;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
zfs_sort_column_t *sortcol = NULL;
|
||||
int flags = ZFS_ITER_PROP_LISTSNAPS | ZFS_ITER_ARGS_CAN_BE_PATHS;
|
||||
|
||||
@ -3062,7 +3062,9 @@ zfs_do_rename(int argc, char **argv)
|
||||
{
|
||||
zfs_handle_t *zhp;
|
||||
renameflags_t flags = { 0 };
|
||||
int c, ret, types;
|
||||
int c;
|
||||
int ret = 0;
|
||||
int types;
|
||||
boolean_t parents = B_FALSE;
|
||||
|
||||
/* check options */
|
||||
@ -3155,7 +3157,7 @@ static int
|
||||
zfs_do_promote(int argc, char **argv)
|
||||
{
|
||||
zfs_handle_t *zhp;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/* check options */
|
||||
if (argc > 1 && argv[1][0] == '-') {
|
||||
@ -3276,7 +3278,7 @@ rollback_check(zfs_handle_t *zhp, void *data)
|
||||
static int
|
||||
zfs_do_rollback(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int c;
|
||||
boolean_t force = B_FALSE;
|
||||
rollback_cbdata_t cb = { 0 };
|
||||
@ -3394,7 +3396,7 @@ static int
|
||||
zfs_do_set(int argc, char **argv)
|
||||
{
|
||||
set_cbdata_t cb;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
/* check for options */
|
||||
if (argc > 1 && argv[1][0] == '-') {
|
||||
@ -3448,7 +3450,7 @@ static int
|
||||
zfs_do_snapshot(int argc, char **argv)
|
||||
{
|
||||
boolean_t recursive = B_FALSE;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
char c;
|
||||
nvlist_t *props;
|
||||
|
||||
@ -5286,7 +5288,7 @@ zfs_do_holds(int argc, char **argv)
|
||||
holds_cbdata_t cb = { 0 };
|
||||
|
||||
int limit = 0;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int flags = 0;
|
||||
|
||||
/* check options */
|
||||
@ -5863,7 +5865,7 @@ static int
|
||||
unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
|
||||
{
|
||||
zfs_handle_t *zhp;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
struct stat64 statbuf;
|
||||
struct extmnttab entry;
|
||||
const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
|
||||
@ -6331,7 +6333,7 @@ manual_mount(int argc, char **argv)
|
||||
zfs_handle_t *zhp;
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
char mntopts[MNT_LINE_MAX] = { '\0' };
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int c;
|
||||
int flags = 0;
|
||||
char *dataset, *path;
|
||||
@ -6481,7 +6483,7 @@ zfs_do_diff(int argc, char **argv)
|
||||
char *tosnap = NULL;
|
||||
char *fromsnap = NULL;
|
||||
char *atp, *copy;
|
||||
int err;
|
||||
int err = 0;
|
||||
int c;
|
||||
|
||||
while ((c = getopt(argc, argv, "FHt")) != -1) {
|
||||
@ -6551,7 +6553,7 @@ zfs_do_diff(int argc, char **argv)
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
int i;
|
||||
char *progname;
|
||||
char *cmdname;
|
||||
|
@ -2696,6 +2696,17 @@ find_a_file (const struct path_prefix *pprefix, const char *name, int mode,
|
||||
return xstrdup (DEFAULT_LINKER);
|
||||
#endif
|
||||
|
||||
#ifdef FREEBSD_NATIVE
|
||||
if (! strcmp(name, "include"))
|
||||
{
|
||||
#ifdef CROSS_INCLUDE_DIR
|
||||
return xstrdup(CROSS_INCLUDE_DIR);
|
||||
#else
|
||||
return xstrdup(STANDARD_INCLUDE_DIR);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Determine the filename to execute (special case for absolute paths). */
|
||||
|
||||
if (IS_ABSOLUTE_PATH (name))
|
||||
|
247
contrib/llvm/tools/bugpoint/BugDriver.cpp
Normal file
247
contrib/llvm/tools/bugpoint/BugDriver.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
//===- BugDriver.cpp - Top-Level BugPoint class implementation ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class contains all of the shared state and information that is used by
|
||||
// the BugPoint tool to track down errors in optimizations. This class is the
|
||||
// main driver class that invokes all sub-functionality.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "ToolRunner.h"
|
||||
#include "llvm/Linker.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
Triple TargetTriple;
|
||||
}
|
||||
|
||||
// Anonymous namespace to define command line options for debugging.
|
||||
//
|
||||
namespace {
|
||||
// Output - The user can specify a file containing the expected output of the
|
||||
// program. If this filename is set, it is used as the reference diff source,
|
||||
// otherwise the raw input run through an interpreter is used as the reference
|
||||
// source.
|
||||
//
|
||||
cl::opt<std::string>
|
||||
OutputFile("output", cl::desc("Specify a reference program output "
|
||||
"(for miscompilation detection)"));
|
||||
}
|
||||
|
||||
/// setNewProgram - If we reduce or update the program somehow, call this method
|
||||
/// to update bugdriver with it. This deletes the old module and sets the
|
||||
/// specified one as the current program.
|
||||
void BugDriver::setNewProgram(Module *M) {
|
||||
delete Program;
|
||||
Program = M;
|
||||
}
|
||||
|
||||
|
||||
/// getPassesString - Turn a list of passes into a string which indicates the
|
||||
/// command line options that must be passed to add the passes.
|
||||
///
|
||||
std::string llvm::getPassesString(const std::vector<std::string> &Passes) {
|
||||
std::string Result;
|
||||
for (unsigned i = 0, e = Passes.size(); i != e; ++i) {
|
||||
if (i) Result += " ";
|
||||
Result += "-";
|
||||
Result += Passes[i];
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
BugDriver::BugDriver(const char *toolname, bool find_bugs,
|
||||
unsigned timeout, unsigned memlimit, bool use_valgrind,
|
||||
LLVMContext& ctxt)
|
||||
: Context(ctxt), ToolName(toolname), ReferenceOutputFile(OutputFile),
|
||||
Program(0), Interpreter(0), SafeInterpreter(0), gcc(0),
|
||||
run_find_bugs(find_bugs), Timeout(timeout),
|
||||
MemoryLimit(memlimit), UseValgrind(use_valgrind) {}
|
||||
|
||||
BugDriver::~BugDriver() {
|
||||
delete Program;
|
||||
}
|
||||
|
||||
|
||||
/// ParseInputFile - Given a bitcode or assembly input filename, parse and
|
||||
/// return it, or return null if not possible.
|
||||
///
|
||||
Module *llvm::ParseInputFile(const std::string &Filename,
|
||||
LLVMContext& Ctxt) {
|
||||
SMDiagnostic Err;
|
||||
Module *Result = ParseIRFile(Filename, Err, Ctxt);
|
||||
if (!Result)
|
||||
Err.Print("bugpoint", errs());
|
||||
|
||||
// If we don't have an override triple, use the first one to configure
|
||||
// bugpoint, or use the host triple if none provided.
|
||||
if (Result) {
|
||||
if (TargetTriple.getTriple().empty()) {
|
||||
Triple TheTriple(Result->getTargetTriple());
|
||||
|
||||
if (TheTriple.getTriple().empty())
|
||||
TheTriple.setTriple(sys::getHostTriple());
|
||||
|
||||
TargetTriple.setTriple(TheTriple.getTriple());
|
||||
}
|
||||
|
||||
Result->setTargetTriple(TargetTriple.getTriple()); // override the triple
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
// This method takes the specified list of LLVM input files, attempts to load
|
||||
// them, either as assembly or bitcode, then link them together. It returns
|
||||
// true on failure (if, for example, an input bitcode file could not be
|
||||
// parsed), and false on success.
|
||||
//
|
||||
bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
|
||||
assert(Program == 0 && "Cannot call addSources multiple times!");
|
||||
assert(!Filenames.empty() && "Must specify at least on input filename!");
|
||||
|
||||
// Load the first input file.
|
||||
Program = ParseInputFile(Filenames[0], Context);
|
||||
if (Program == 0) return true;
|
||||
|
||||
outs() << "Read input file : '" << Filenames[0] << "'\n";
|
||||
|
||||
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
|
||||
std::auto_ptr<Module> M(ParseInputFile(Filenames[i], Context));
|
||||
if (M.get() == 0) return true;
|
||||
|
||||
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
|
||||
std::string ErrorMessage;
|
||||
if (Linker::LinkModules(Program, M.get(), Linker::DestroySource,
|
||||
&ErrorMessage)) {
|
||||
errs() << ToolName << ": error linking in '" << Filenames[i] << "': "
|
||||
<< ErrorMessage << '\n';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
outs() << "*** All input ok\n";
|
||||
|
||||
// All input files read successfully!
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// run - The top level method that is invoked after all of the instance
|
||||
/// variables are set up from command line arguments.
|
||||
///
|
||||
bool BugDriver::run(std::string &ErrMsg) {
|
||||
if (run_find_bugs) {
|
||||
// Rearrange the passes and apply them to the program. Repeat this process
|
||||
// until the user kills the program or we find a bug.
|
||||
return runManyPasses(PassesToRun, ErrMsg);
|
||||
}
|
||||
|
||||
// If we're not running as a child, the first thing that we must do is
|
||||
// determine what the problem is. Does the optimization series crash the
|
||||
// compiler, or does it produce illegal code? We make the top-level
|
||||
// decision by trying to run all of the passes on the the input program,
|
||||
// which should generate a bitcode file. If it does generate a bitcode
|
||||
// file, then we know the compiler didn't crash, so try to diagnose a
|
||||
// miscompilation.
|
||||
if (!PassesToRun.empty()) {
|
||||
outs() << "Running selected passes on program to test for crash: ";
|
||||
if (runPasses(Program, PassesToRun))
|
||||
return debugOptimizerCrash();
|
||||
}
|
||||
|
||||
// Set up the execution environment, selecting a method to run LLVM bitcode.
|
||||
if (initializeExecutionEnvironment()) return true;
|
||||
|
||||
// Test to see if we have a code generator crash.
|
||||
outs() << "Running the code generator to test for a crash: ";
|
||||
std::string Error;
|
||||
compileProgram(Program, &Error);
|
||||
if (!Error.empty()) {
|
||||
outs() << Error;
|
||||
return debugCodeGeneratorCrash(ErrMsg);
|
||||
}
|
||||
outs() << '\n';
|
||||
|
||||
// Run the raw input to see where we are coming from. If a reference output
|
||||
// was specified, make sure that the raw output matches it. If not, it's a
|
||||
// problem in the front-end or the code generator.
|
||||
//
|
||||
bool CreatedOutput = false;
|
||||
if (ReferenceOutputFile.empty()) {
|
||||
outs() << "Generating reference output from raw program: ";
|
||||
if (!createReferenceFile(Program)) {
|
||||
return debugCodeGeneratorCrash(ErrMsg);
|
||||
}
|
||||
CreatedOutput = true;
|
||||
}
|
||||
|
||||
// Make sure the reference output file gets deleted on exit from this
|
||||
// function, if appropriate.
|
||||
sys::Path ROF(ReferenceOutputFile);
|
||||
FileRemover RemoverInstance(ROF.str(), CreatedOutput && !SaveTemps);
|
||||
|
||||
// Diff the output of the raw program against the reference output. If it
|
||||
// matches, then we assume there is a miscompilation bug and try to
|
||||
// diagnose it.
|
||||
outs() << "*** Checking the code generator...\n";
|
||||
bool Diff = diffProgram(Program, "", "", false, &Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << Error;
|
||||
return debugCodeGeneratorCrash(ErrMsg);
|
||||
}
|
||||
if (!Diff) {
|
||||
outs() << "\n*** Output matches: Debugging miscompilation!\n";
|
||||
debugMiscompilation(&Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << Error;
|
||||
return debugCodeGeneratorCrash(ErrMsg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
outs() << "\n*** Input program does not match reference diff!\n";
|
||||
outs() << "Debugging code generator problem!\n";
|
||||
bool Failure = debugCodeGenerator(&Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << Error;
|
||||
return debugCodeGeneratorCrash(ErrMsg);
|
||||
}
|
||||
return Failure;
|
||||
}
|
||||
|
||||
void llvm::PrintFunctionList(const std::vector<Function*> &Funcs) {
|
||||
unsigned NumPrint = Funcs.size();
|
||||
if (NumPrint > 10) NumPrint = 10;
|
||||
for (unsigned i = 0; i != NumPrint; ++i)
|
||||
outs() << " " << Funcs[i]->getName();
|
||||
if (NumPrint < Funcs.size())
|
||||
outs() << "... <" << Funcs.size() << " total>";
|
||||
outs().flush();
|
||||
}
|
||||
|
||||
void llvm::PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs) {
|
||||
unsigned NumPrint = GVs.size();
|
||||
if (NumPrint > 10) NumPrint = 10;
|
||||
for (unsigned i = 0; i != NumPrint; ++i)
|
||||
outs() << " " << GVs[i]->getName();
|
||||
if (NumPrint < GVs.size())
|
||||
outs() << "... <" << GVs.size() << " total>";
|
||||
outs().flush();
|
||||
}
|
330
contrib/llvm/tools/bugpoint/BugDriver.h
Normal file
330
contrib/llvm/tools/bugpoint/BugDriver.h
Normal file
@ -0,0 +1,330 @@
|
||||
//===- BugDriver.h - Top-Level BugPoint class -------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class contains all of the shared state and information that is used by
|
||||
// the BugPoint tool to track down errors in optimizations. This class is the
|
||||
// main driver class that invokes all sub-functionality.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BUGDRIVER_H
|
||||
#define BUGDRIVER_H
|
||||
|
||||
#include "llvm/ADT/ValueMap.h"
|
||||
#include "llvm/Transforms/Utils/ValueMapper.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Value;
|
||||
class PassInfo;
|
||||
class Module;
|
||||
class GlobalVariable;
|
||||
class Function;
|
||||
class BasicBlock;
|
||||
class AbstractInterpreter;
|
||||
class Instruction;
|
||||
class LLVMContext;
|
||||
|
||||
class DebugCrashes;
|
||||
|
||||
class GCC;
|
||||
|
||||
extern bool DisableSimplifyCFG;
|
||||
|
||||
/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
|
||||
///
|
||||
extern bool BugpointIsInterrupted;
|
||||
|
||||
class BugDriver {
|
||||
LLVMContext& Context;
|
||||
const char *ToolName; // argv[0] of bugpoint
|
||||
std::string ReferenceOutputFile; // Name of `good' output file
|
||||
Module *Program; // The raw program, linked together
|
||||
std::vector<std::string> PassesToRun;
|
||||
AbstractInterpreter *Interpreter; // How to run the program
|
||||
AbstractInterpreter *SafeInterpreter; // To generate reference output, etc.
|
||||
GCC *gcc;
|
||||
bool run_find_bugs;
|
||||
unsigned Timeout;
|
||||
unsigned MemoryLimit;
|
||||
bool UseValgrind;
|
||||
|
||||
// FIXME: sort out public/private distinctions...
|
||||
friend class ReducePassList;
|
||||
friend class ReduceMisCodegenFunctions;
|
||||
|
||||
public:
|
||||
BugDriver(const char *toolname, bool find_bugs,
|
||||
unsigned timeout, unsigned memlimit, bool use_valgrind,
|
||||
LLVMContext& ctxt);
|
||||
~BugDriver();
|
||||
|
||||
const char *getToolName() const { return ToolName; }
|
||||
|
||||
LLVMContext& getContext() const { return Context; }
|
||||
|
||||
// Set up methods... these methods are used to copy information about the
|
||||
// command line arguments into instance variables of BugDriver.
|
||||
//
|
||||
bool addSources(const std::vector<std::string> &FileNames);
|
||||
void addPass(std::string p) { PassesToRun.push_back(p); }
|
||||
void setPassesToRun(const std::vector<std::string> &PTR) {
|
||||
PassesToRun = PTR;
|
||||
}
|
||||
const std::vector<std::string> &getPassesToRun() const {
|
||||
return PassesToRun;
|
||||
}
|
||||
|
||||
/// run - The top level method that is invoked after all of the instance
|
||||
/// variables are set up from command line arguments. The \p as_child argument
|
||||
/// indicates whether the driver is to run in parent mode or child mode.
|
||||
///
|
||||
bool run(std::string &ErrMsg);
|
||||
|
||||
/// debugOptimizerCrash - This method is called when some optimizer pass
|
||||
/// crashes on input. It attempts to prune down the testcase to something
|
||||
/// reasonable, and figure out exactly which pass is crashing.
|
||||
///
|
||||
bool debugOptimizerCrash(const std::string &ID = "passes");
|
||||
|
||||
/// debugCodeGeneratorCrash - This method is called when the code generator
|
||||
/// crashes on an input. It attempts to reduce the input as much as possible
|
||||
/// while still causing the code generator to crash.
|
||||
bool debugCodeGeneratorCrash(std::string &Error);
|
||||
|
||||
/// debugMiscompilation - This method is used when the passes selected are not
|
||||
/// crashing, but the generated output is semantically different from the
|
||||
/// input.
|
||||
void debugMiscompilation(std::string *Error);
|
||||
|
||||
/// debugPassMiscompilation - This method is called when the specified pass
|
||||
/// miscompiles Program as input. It tries to reduce the testcase to
|
||||
/// something that smaller that still miscompiles the program.
|
||||
/// ReferenceOutput contains the filename of the file containing the output we
|
||||
/// are to match.
|
||||
///
|
||||
bool debugPassMiscompilation(const PassInfo *ThePass,
|
||||
const std::string &ReferenceOutput);
|
||||
|
||||
/// compileSharedObject - This method creates a SharedObject from a given
|
||||
/// BitcodeFile for debugging a code generator.
|
||||
///
|
||||
std::string compileSharedObject(const std::string &BitcodeFile,
|
||||
std::string &Error);
|
||||
|
||||
/// debugCodeGenerator - This method narrows down a module to a function or
|
||||
/// set of functions, using the CBE as a ``safe'' code generator for other
|
||||
/// functions that are not under consideration.
|
||||
bool debugCodeGenerator(std::string *Error);
|
||||
|
||||
/// isExecutingJIT - Returns true if bugpoint is currently testing the JIT
|
||||
///
|
||||
bool isExecutingJIT();
|
||||
|
||||
/// runPasses - Run all of the passes in the "PassesToRun" list, discard the
|
||||
/// output, and return true if any of the passes crashed.
|
||||
bool runPasses(Module *M) const {
|
||||
return runPasses(M, PassesToRun);
|
||||
}
|
||||
|
||||
Module *getProgram() const { return Program; }
|
||||
|
||||
/// swapProgramIn - Set the current module to the specified module, returning
|
||||
/// the old one.
|
||||
Module *swapProgramIn(Module *M) {
|
||||
Module *OldProgram = Program;
|
||||
Program = M;
|
||||
return OldProgram;
|
||||
}
|
||||
|
||||
AbstractInterpreter *switchToSafeInterpreter() {
|
||||
AbstractInterpreter *Old = Interpreter;
|
||||
Interpreter = (AbstractInterpreter*)SafeInterpreter;
|
||||
return Old;
|
||||
}
|
||||
|
||||
void switchToInterpreter(AbstractInterpreter *AI) {
|
||||
Interpreter = AI;
|
||||
}
|
||||
|
||||
/// setNewProgram - If we reduce or update the program somehow, call this
|
||||
/// method to update bugdriver with it. This deletes the old module and sets
|
||||
/// the specified one as the current program.
|
||||
void setNewProgram(Module *M);
|
||||
|
||||
/// compileProgram - Try to compile the specified module, returning false and
|
||||
/// setting Error if an error occurs. This is used for code generation
|
||||
/// crash testing.
|
||||
///
|
||||
void compileProgram(Module *M, std::string *Error) const;
|
||||
|
||||
/// executeProgram - This method runs "Program", capturing the output of the
|
||||
/// program to a file. A recommended filename may be optionally specified.
|
||||
///
|
||||
std::string executeProgram(const Module *Program,
|
||||
std::string OutputFilename,
|
||||
std::string Bitcode,
|
||||
const std::string &SharedObjects,
|
||||
AbstractInterpreter *AI,
|
||||
std::string *Error) const;
|
||||
|
||||
/// executeProgramSafely - Used to create reference output with the "safe"
|
||||
/// backend, if reference output is not provided. If there is a problem with
|
||||
/// the code generator (e.g., llc crashes), this will return false and set
|
||||
/// Error.
|
||||
///
|
||||
std::string executeProgramSafely(const Module *Program,
|
||||
std::string OutputFile,
|
||||
std::string *Error) const;
|
||||
|
||||
/// createReferenceFile - calls compileProgram and then records the output
|
||||
/// into ReferenceOutputFile. Returns true if reference file created, false
|
||||
/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
|
||||
/// this function.
|
||||
///
|
||||
bool createReferenceFile(Module *M, const std::string &Filename
|
||||
= "bugpoint.reference.out");
|
||||
|
||||
/// diffProgram - This method executes the specified module and diffs the
|
||||
/// output against the file specified by ReferenceOutputFile. If the output
|
||||
/// is different, 1 is returned. If there is a problem with the code
|
||||
/// generator (e.g., llc crashes), this will return -1 and set Error.
|
||||
///
|
||||
bool diffProgram(const Module *Program,
|
||||
const std::string &BitcodeFile = "",
|
||||
const std::string &SharedObj = "",
|
||||
bool RemoveBitcode = false,
|
||||
std::string *Error = 0) const;
|
||||
|
||||
/// EmitProgressBitcode - This function is used to output M to a file named
|
||||
/// "bugpoint-ID.bc".
|
||||
///
|
||||
void EmitProgressBitcode(const Module *M, const std::string &ID,
|
||||
bool NoFlyer = false) const;
|
||||
|
||||
/// deleteInstructionFromProgram - This method clones the current Program and
|
||||
/// deletes the specified instruction from the cloned module. It then runs a
|
||||
/// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code
|
||||
/// which depends on the value. The modified module is then returned.
|
||||
///
|
||||
Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp);
|
||||
|
||||
/// performFinalCleanups - This method clones the current Program and performs
|
||||
/// a series of cleanups intended to get rid of extra cruft on the module. If
|
||||
/// the MayModifySemantics argument is true, then the cleanups is allowed to
|
||||
/// modify how the code behaves.
|
||||
///
|
||||
Module *performFinalCleanups(Module *M, bool MayModifySemantics = false);
|
||||
|
||||
/// ExtractLoop - Given a module, extract up to one loop from it into a new
|
||||
/// function. This returns null if there are no extractable loops in the
|
||||
/// program or if the loop extractor crashes.
|
||||
Module *ExtractLoop(Module *M);
|
||||
|
||||
/// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
|
||||
/// into their own functions. The only detail is that M is actually a module
|
||||
/// cloned from the one the BBs are in, so some mapping needs to be performed.
|
||||
/// If this operation fails for some reason (ie the implementation is buggy),
|
||||
/// this function should return null, otherwise it returns a new Module.
|
||||
Module *ExtractMappedBlocksFromModule(const std::vector<BasicBlock*> &BBs,
|
||||
Module *M);
|
||||
|
||||
/// runPassesOn - Carefully run the specified set of pass on the specified
|
||||
/// module, returning the transformed module on success, or a null pointer on
|
||||
/// failure. If AutoDebugCrashes is set to true, then bugpoint will
|
||||
/// automatically attempt to track down a crashing pass if one exists, and
|
||||
/// this method will never return null.
|
||||
Module *runPassesOn(Module *M, const std::vector<std::string> &Passes,
|
||||
bool AutoDebugCrashes = false, unsigned NumExtraArgs = 0,
|
||||
const char * const *ExtraArgs = NULL);
|
||||
|
||||
/// runPasses - Run the specified passes on Program, outputting a bitcode
|
||||
/// file and writting the filename into OutputFile if successful. If the
|
||||
/// optimizations fail for some reason (optimizer crashes), return true,
|
||||
/// otherwise return false. If DeleteOutput is set to true, the bitcode is
|
||||
/// deleted on success, and the filename string is undefined. This prints to
|
||||
/// outs() a single line message indicating whether compilation was successful
|
||||
/// or failed, unless Quiet is set. ExtraArgs specifies additional arguments
|
||||
/// to pass to the child bugpoint instance.
|
||||
///
|
||||
bool runPasses(Module *Program,
|
||||
const std::vector<std::string> &PassesToRun,
|
||||
std::string &OutputFilename, bool DeleteOutput = false,
|
||||
bool Quiet = false, unsigned NumExtraArgs = 0,
|
||||
const char * const *ExtraArgs = NULL) const;
|
||||
|
||||
/// runManyPasses - Take the specified pass list and create different
|
||||
/// combinations of passes to compile the program with. Compile the program with
|
||||
/// each set and mark test to see if it compiled correctly. If the passes
|
||||
/// compiled correctly output nothing and rearrange the passes into a new order.
|
||||
/// If the passes did not compile correctly, output the command required to
|
||||
/// recreate the failure. This returns true if a compiler error is found.
|
||||
///
|
||||
bool runManyPasses(const std::vector<std::string> &AllPasses,
|
||||
std::string &ErrMsg);
|
||||
|
||||
/// writeProgramToFile - This writes the current "Program" to the named
|
||||
/// bitcode file. If an error occurs, true is returned.
|
||||
///
|
||||
bool writeProgramToFile(const std::string &Filename, const Module *M) const;
|
||||
|
||||
private:
|
||||
/// runPasses - Just like the method above, but this just returns true or
|
||||
/// false indicating whether or not the optimizer crashed on the specified
|
||||
/// input (true = crashed).
|
||||
///
|
||||
bool runPasses(Module *M,
|
||||
const std::vector<std::string> &PassesToRun,
|
||||
bool DeleteOutput = true) const {
|
||||
std::string Filename;
|
||||
return runPasses(M, PassesToRun, Filename, DeleteOutput);
|
||||
}
|
||||
|
||||
/// initializeExecutionEnvironment - This method is used to set up the
|
||||
/// environment for executing LLVM programs.
|
||||
///
|
||||
bool initializeExecutionEnvironment();
|
||||
};
|
||||
|
||||
/// ParseInputFile - Given a bitcode or assembly input filename, parse and
|
||||
/// return it, or return null if not possible.
|
||||
///
|
||||
Module *ParseInputFile(const std::string &InputFilename,
|
||||
LLVMContext& ctxt);
|
||||
|
||||
|
||||
/// getPassesString - Turn a list of passes into a string which indicates the
|
||||
/// command line options that must be passed to add the passes.
|
||||
///
|
||||
std::string getPassesString(const std::vector<std::string> &Passes);
|
||||
|
||||
/// PrintFunctionList - prints out list of problematic functions
|
||||
///
|
||||
void PrintFunctionList(const std::vector<Function*> &Funcs);
|
||||
|
||||
/// PrintGlobalVariableList - prints out list of problematic global variables
|
||||
///
|
||||
void PrintGlobalVariableList(const std::vector<GlobalVariable*> &GVs);
|
||||
|
||||
// DeleteFunctionBody - "Remove" the function by deleting all of it's basic
|
||||
// blocks, making it external.
|
||||
//
|
||||
void DeleteFunctionBody(Function *F);
|
||||
|
||||
/// SplitFunctionsOutOfModule - Given a module and a list of functions in the
|
||||
/// module, split the functions OUT of the specified module, and place them in
|
||||
/// the new module.
|
||||
Module *SplitFunctionsOutOfModule(Module *M, const std::vector<Function*> &F,
|
||||
ValueToValueMapTy &VMap);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
14
contrib/llvm/tools/bugpoint/CMakeLists.txt
Normal file
14
contrib/llvm/tools/bugpoint/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo
|
||||
linker bitreader bitwriter)
|
||||
|
||||
add_llvm_tool(bugpoint
|
||||
BugDriver.cpp
|
||||
CrashDebugger.cpp
|
||||
ExecutionDriver.cpp
|
||||
ExtractFunction.cpp
|
||||
FindBugs.cpp
|
||||
Miscompilation.cpp
|
||||
OptimizerDriver.cpp
|
||||
ToolRunner.cpp
|
||||
bugpoint.cpp
|
||||
)
|
667
contrib/llvm/tools/bugpoint/CrashDebugger.cpp
Normal file
667
contrib/llvm/tools/bugpoint/CrashDebugger.cpp
Normal file
@ -0,0 +1,667 @@
|
||||
//===- CrashDebugger.cpp - Debug compilation crashes ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the bugpoint internals that narrow down compilation crashes
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "ToolRunner.h"
|
||||
#include "ListReducer.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/ValueSymbolTable.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include <set>
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
cl::opt<bool>
|
||||
KeepMain("keep-main",
|
||||
cl::desc("Force function reduction to keep main"),
|
||||
cl::init(false));
|
||||
cl::opt<bool>
|
||||
NoGlobalRM ("disable-global-remove",
|
||||
cl::desc("Do not remove global variables"),
|
||||
cl::init(false));
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
class ReducePassList : public ListReducer<std::string> {
|
||||
BugDriver &BD;
|
||||
public:
|
||||
ReducePassList(BugDriver &bd) : BD(bd) {}
|
||||
|
||||
// doTest - Return true iff running the "removed" passes succeeds, and
|
||||
// running the "Kept" passes fail when run on the output of the "removed"
|
||||
// passes. If we return true, we update the current module of bugpoint.
|
||||
//
|
||||
virtual TestResult doTest(std::vector<std::string> &Removed,
|
||||
std::vector<std::string> &Kept,
|
||||
std::string &Error);
|
||||
};
|
||||
}
|
||||
|
||||
ReducePassList::TestResult
|
||||
ReducePassList::doTest(std::vector<std::string> &Prefix,
|
||||
std::vector<std::string> &Suffix,
|
||||
std::string &Error) {
|
||||
sys::Path PrefixOutput;
|
||||
Module *OrigProgram = 0;
|
||||
if (!Prefix.empty()) {
|
||||
outs() << "Checking to see if these passes crash: "
|
||||
<< getPassesString(Prefix) << ": ";
|
||||
std::string PfxOutput;
|
||||
if (BD.runPasses(BD.getProgram(), Prefix, PfxOutput))
|
||||
return KeepPrefix;
|
||||
|
||||
PrefixOutput.set(PfxOutput);
|
||||
OrigProgram = BD.Program;
|
||||
|
||||
BD.Program = ParseInputFile(PrefixOutput.str(), BD.getContext());
|
||||
if (BD.Program == 0) {
|
||||
errs() << BD.getToolName() << ": Error reading bitcode file '"
|
||||
<< PrefixOutput.str() << "'!\n";
|
||||
exit(1);
|
||||
}
|
||||
PrefixOutput.eraseFromDisk();
|
||||
}
|
||||
|
||||
outs() << "Checking to see if these passes crash: "
|
||||
<< getPassesString(Suffix) << ": ";
|
||||
|
||||
if (BD.runPasses(BD.getProgram(), Suffix)) {
|
||||
delete OrigProgram; // The suffix crashes alone...
|
||||
return KeepSuffix;
|
||||
}
|
||||
|
||||
// Nothing failed, restore state...
|
||||
if (OrigProgram) {
|
||||
delete BD.Program;
|
||||
BD.Program = OrigProgram;
|
||||
}
|
||||
return NoFailure;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// ReduceCrashingGlobalVariables - This works by removing the global
|
||||
/// variable's initializer and seeing if the program still crashes. If it
|
||||
/// does, then we keep that program and try again.
|
||||
///
|
||||
class ReduceCrashingGlobalVariables : public ListReducer<GlobalVariable*> {
|
||||
BugDriver &BD;
|
||||
bool (*TestFn)(const BugDriver &, Module *);
|
||||
public:
|
||||
ReduceCrashingGlobalVariables(BugDriver &bd,
|
||||
bool (*testFn)(const BugDriver &, Module *))
|
||||
: BD(bd), TestFn(testFn) {}
|
||||
|
||||
virtual TestResult doTest(std::vector<GlobalVariable*> &Prefix,
|
||||
std::vector<GlobalVariable*> &Kept,
|
||||
std::string &Error) {
|
||||
if (!Kept.empty() && TestGlobalVariables(Kept))
|
||||
return KeepSuffix;
|
||||
if (!Prefix.empty() && TestGlobalVariables(Prefix))
|
||||
return KeepPrefix;
|
||||
return NoFailure;
|
||||
}
|
||||
|
||||
bool TestGlobalVariables(std::vector<GlobalVariable*> &GVs);
|
||||
};
|
||||
}
|
||||
|
||||
bool
|
||||
ReduceCrashingGlobalVariables::TestGlobalVariables(
|
||||
std::vector<GlobalVariable*> &GVs) {
|
||||
// Clone the program to try hacking it apart...
|
||||
ValueToValueMapTy VMap;
|
||||
Module *M = CloneModule(BD.getProgram(), VMap);
|
||||
|
||||
// Convert list to set for fast lookup...
|
||||
std::set<GlobalVariable*> GVSet;
|
||||
|
||||
for (unsigned i = 0, e = GVs.size(); i != e; ++i) {
|
||||
GlobalVariable* CMGV = cast<GlobalVariable>(VMap[GVs[i]]);
|
||||
assert(CMGV && "Global Variable not in module?!");
|
||||
GVSet.insert(CMGV);
|
||||
}
|
||||
|
||||
outs() << "Checking for crash with only these global variables: ";
|
||||
PrintGlobalVariableList(GVs);
|
||||
outs() << ": ";
|
||||
|
||||
// Loop over and delete any global variables which we aren't supposed to be
|
||||
// playing with...
|
||||
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
|
||||
I != E; ++I)
|
||||
if (I->hasInitializer() && !GVSet.count(I)) {
|
||||
I->setInitializer(0);
|
||||
I->setLinkage(GlobalValue::ExternalLinkage);
|
||||
}
|
||||
|
||||
// Try running the hacked up program...
|
||||
if (TestFn(BD, M)) {
|
||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||
|
||||
// Make sure to use global variable pointers that point into the now-current
|
||||
// module.
|
||||
GVs.assign(GVSet.begin(), GVSet.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
delete M;
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
/// ReduceCrashingFunctions reducer - This works by removing functions and
|
||||
/// seeing if the program still crashes. If it does, then keep the newer,
|
||||
/// smaller program.
|
||||
///
|
||||
class ReduceCrashingFunctions : public ListReducer<Function*> {
|
||||
BugDriver &BD;
|
||||
bool (*TestFn)(const BugDriver &, Module *);
|
||||
public:
|
||||
ReduceCrashingFunctions(BugDriver &bd,
|
||||
bool (*testFn)(const BugDriver &, Module *))
|
||||
: BD(bd), TestFn(testFn) {}
|
||||
|
||||
virtual TestResult doTest(std::vector<Function*> &Prefix,
|
||||
std::vector<Function*> &Kept,
|
||||
std::string &Error) {
|
||||
if (!Kept.empty() && TestFuncs(Kept))
|
||||
return KeepSuffix;
|
||||
if (!Prefix.empty() && TestFuncs(Prefix))
|
||||
return KeepPrefix;
|
||||
return NoFailure;
|
||||
}
|
||||
|
||||
bool TestFuncs(std::vector<Function*> &Prefix);
|
||||
};
|
||||
}
|
||||
|
||||
bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
|
||||
|
||||
//if main isn't present, claim there is no problem
|
||||
if (KeepMain && find(Funcs.begin(), Funcs.end(),
|
||||
BD.getProgram()->getFunction("main")) == Funcs.end())
|
||||
return false;
|
||||
|
||||
// Clone the program to try hacking it apart...
|
||||
ValueToValueMapTy VMap;
|
||||
Module *M = CloneModule(BD.getProgram(), VMap);
|
||||
|
||||
// Convert list to set for fast lookup...
|
||||
std::set<Function*> Functions;
|
||||
for (unsigned i = 0, e = Funcs.size(); i != e; ++i) {
|
||||
Function *CMF = cast<Function>(VMap[Funcs[i]]);
|
||||
assert(CMF && "Function not in module?!");
|
||||
assert(CMF->getFunctionType() == Funcs[i]->getFunctionType() && "wrong ty");
|
||||
assert(CMF->getName() == Funcs[i]->getName() && "wrong name");
|
||||
Functions.insert(CMF);
|
||||
}
|
||||
|
||||
outs() << "Checking for crash with only these functions: ";
|
||||
PrintFunctionList(Funcs);
|
||||
outs() << ": ";
|
||||
|
||||
// Loop over and delete any functions which we aren't supposed to be playing
|
||||
// with...
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
if (!I->isDeclaration() && !Functions.count(I))
|
||||
DeleteFunctionBody(I);
|
||||
|
||||
// Try running the hacked up program...
|
||||
if (TestFn(BD, M)) {
|
||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||
|
||||
// Make sure to use function pointers that point into the now-current
|
||||
// module.
|
||||
Funcs.assign(Functions.begin(), Functions.end());
|
||||
return true;
|
||||
}
|
||||
delete M;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
/// ReduceCrashingBlocks reducer - This works by setting the terminators of
|
||||
/// all terminators except the specified basic blocks to a 'ret' instruction,
|
||||
/// then running the simplify-cfg pass. This has the effect of chopping up
|
||||
/// the CFG really fast which can reduce large functions quickly.
|
||||
///
|
||||
class ReduceCrashingBlocks : public ListReducer<const BasicBlock*> {
|
||||
BugDriver &BD;
|
||||
bool (*TestFn)(const BugDriver &, Module *);
|
||||
public:
|
||||
ReduceCrashingBlocks(BugDriver &bd,
|
||||
bool (*testFn)(const BugDriver &, Module *))
|
||||
: BD(bd), TestFn(testFn) {}
|
||||
|
||||
virtual TestResult doTest(std::vector<const BasicBlock*> &Prefix,
|
||||
std::vector<const BasicBlock*> &Kept,
|
||||
std::string &Error) {
|
||||
if (!Kept.empty() && TestBlocks(Kept))
|
||||
return KeepSuffix;
|
||||
if (!Prefix.empty() && TestBlocks(Prefix))
|
||||
return KeepPrefix;
|
||||
return NoFailure;
|
||||
}
|
||||
|
||||
bool TestBlocks(std::vector<const BasicBlock*> &Prefix);
|
||||
};
|
||||
}
|
||||
|
||||
bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
|
||||
// Clone the program to try hacking it apart...
|
||||
ValueToValueMapTy VMap;
|
||||
Module *M = CloneModule(BD.getProgram(), VMap);
|
||||
|
||||
// Convert list to set for fast lookup...
|
||||
SmallPtrSet<BasicBlock*, 8> Blocks;
|
||||
for (unsigned i = 0, e = BBs.size(); i != e; ++i)
|
||||
Blocks.insert(cast<BasicBlock>(VMap[BBs[i]]));
|
||||
|
||||
outs() << "Checking for crash with only these blocks:";
|
||||
unsigned NumPrint = Blocks.size();
|
||||
if (NumPrint > 10) NumPrint = 10;
|
||||
for (unsigned i = 0, e = NumPrint; i != e; ++i)
|
||||
outs() << " " << BBs[i]->getName();
|
||||
if (NumPrint < Blocks.size())
|
||||
outs() << "... <" << Blocks.size() << " total>";
|
||||
outs() << ": ";
|
||||
|
||||
// Loop over and delete any hack up any blocks that are not listed...
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
for (Function::iterator BB = I->begin(), E = I->end(); BB != E; ++BB)
|
||||
if (!Blocks.count(BB) && BB->getTerminator()->getNumSuccessors()) {
|
||||
// Loop over all of the successors of this block, deleting any PHI nodes
|
||||
// that might include it.
|
||||
for (succ_iterator SI = succ_begin(BB), E = succ_end(BB); SI != E; ++SI)
|
||||
(*SI)->removePredecessor(BB);
|
||||
|
||||
TerminatorInst *BBTerm = BB->getTerminator();
|
||||
|
||||
if (!BB->getTerminator()->getType()->isVoidTy())
|
||||
BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType()));
|
||||
|
||||
// Replace the old terminator instruction.
|
||||
BB->getInstList().pop_back();
|
||||
new UnreachableInst(BB->getContext(), BB);
|
||||
}
|
||||
|
||||
// The CFG Simplifier pass may delete one of the basic blocks we are
|
||||
// interested in. If it does we need to take the block out of the list. Make
|
||||
// a "persistent mapping" by turning basic blocks into <function, name> pairs.
|
||||
// This won't work well if blocks are unnamed, but that is just the risk we
|
||||
// have to take.
|
||||
std::vector<std::pair<std::string, std::string> > BlockInfo;
|
||||
|
||||
for (SmallPtrSet<BasicBlock*, 8>::iterator I = Blocks.begin(),
|
||||
E = Blocks.end(); I != E; ++I)
|
||||
BlockInfo.push_back(std::make_pair((*I)->getParent()->getName(),
|
||||
(*I)->getName()));
|
||||
|
||||
// Now run the CFG simplify pass on the function...
|
||||
std::vector<std::string> Passes;
|
||||
Passes.push_back("simplifycfg");
|
||||
Passes.push_back("verify");
|
||||
Module *New = BD.runPassesOn(M, Passes);
|
||||
delete M;
|
||||
if (!New) {
|
||||
errs() << "simplifycfg failed!\n";
|
||||
exit(1);
|
||||
}
|
||||
M = New;
|
||||
|
||||
// Try running on the hacked up program...
|
||||
if (TestFn(BD, M)) {
|
||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||
|
||||
// Make sure to use basic block pointers that point into the now-current
|
||||
// module, and that they don't include any deleted blocks.
|
||||
BBs.clear();
|
||||
const ValueSymbolTable &GST = M->getValueSymbolTable();
|
||||
for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) {
|
||||
Function *F = cast<Function>(GST.lookup(BlockInfo[i].first));
|
||||
ValueSymbolTable &ST = F->getValueSymbolTable();
|
||||
Value* V = ST.lookup(BlockInfo[i].second);
|
||||
if (V && V->getType() == Type::getLabelTy(V->getContext()))
|
||||
BBs.push_back(cast<BasicBlock>(V));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
delete M; // It didn't crash, try something else.
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// ReduceCrashingInstructions reducer - This works by removing the specified
|
||||
/// non-terminator instructions and replacing them with undef.
|
||||
///
|
||||
class ReduceCrashingInstructions : public ListReducer<const Instruction*> {
|
||||
BugDriver &BD;
|
||||
bool (*TestFn)(const BugDriver &, Module *);
|
||||
public:
|
||||
ReduceCrashingInstructions(BugDriver &bd,
|
||||
bool (*testFn)(const BugDriver &, Module *))
|
||||
: BD(bd), TestFn(testFn) {}
|
||||
|
||||
virtual TestResult doTest(std::vector<const Instruction*> &Prefix,
|
||||
std::vector<const Instruction*> &Kept,
|
||||
std::string &Error) {
|
||||
if (!Kept.empty() && TestInsts(Kept))
|
||||
return KeepSuffix;
|
||||
if (!Prefix.empty() && TestInsts(Prefix))
|
||||
return KeepPrefix;
|
||||
return NoFailure;
|
||||
}
|
||||
|
||||
bool TestInsts(std::vector<const Instruction*> &Prefix);
|
||||
};
|
||||
}
|
||||
|
||||
bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
|
||||
&Insts) {
|
||||
// Clone the program to try hacking it apart...
|
||||
ValueToValueMapTy VMap;
|
||||
Module *M = CloneModule(BD.getProgram(), VMap);
|
||||
|
||||
// Convert list to set for fast lookup...
|
||||
SmallPtrSet<Instruction*, 64> Instructions;
|
||||
for (unsigned i = 0, e = Insts.size(); i != e; ++i) {
|
||||
assert(!isa<TerminatorInst>(Insts[i]));
|
||||
Instructions.insert(cast<Instruction>(VMap[Insts[i]]));
|
||||
}
|
||||
|
||||
outs() << "Checking for crash with only " << Instructions.size();
|
||||
if (Instructions.size() == 1)
|
||||
outs() << " instruction: ";
|
||||
else
|
||||
outs() << " instructions: ";
|
||||
|
||||
for (Module::iterator MI = M->begin(), ME = M->end(); MI != ME; ++MI)
|
||||
for (Function::iterator FI = MI->begin(), FE = MI->end(); FI != FE; ++FI)
|
||||
for (BasicBlock::iterator I = FI->begin(), E = FI->end(); I != E;) {
|
||||
Instruction *Inst = I++;
|
||||
if (!Instructions.count(Inst) && !isa<TerminatorInst>(Inst)) {
|
||||
if (!Inst->getType()->isVoidTy())
|
||||
Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
|
||||
Inst->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that this is still valid.
|
||||
PassManager Passes;
|
||||
Passes.add(createVerifierPass());
|
||||
Passes.run(*M);
|
||||
|
||||
// Try running on the hacked up program...
|
||||
if (TestFn(BD, M)) {
|
||||
BD.setNewProgram(M); // It crashed, keep the trimmed version...
|
||||
|
||||
// Make sure to use instruction pointers that point into the now-current
|
||||
// module, and that they don't include any deleted blocks.
|
||||
Insts.clear();
|
||||
for (SmallPtrSet<Instruction*, 64>::const_iterator I = Instructions.begin(),
|
||||
E = Instructions.end(); I != E; ++I)
|
||||
Insts.push_back(*I);
|
||||
return true;
|
||||
}
|
||||
delete M; // It didn't crash, try something else.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// DebugACrash - Given a predicate that determines whether a component crashes
|
||||
/// on a program, try to destructively reduce the program while still keeping
|
||||
/// the predicate true.
|
||||
static bool DebugACrash(BugDriver &BD,
|
||||
bool (*TestFn)(const BugDriver &, Module *),
|
||||
std::string &Error) {
|
||||
// See if we can get away with nuking some of the global variable initializers
|
||||
// in the program...
|
||||
if (!NoGlobalRM &&
|
||||
BD.getProgram()->global_begin() != BD.getProgram()->global_end()) {
|
||||
// Now try to reduce the number of global variable initializers in the
|
||||
// module to something small.
|
||||
Module *M = CloneModule(BD.getProgram());
|
||||
bool DeletedInit = false;
|
||||
|
||||
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
|
||||
I != E; ++I)
|
||||
if (I->hasInitializer()) {
|
||||
I->setInitializer(0);
|
||||
I->setLinkage(GlobalValue::ExternalLinkage);
|
||||
DeletedInit = true;
|
||||
}
|
||||
|
||||
if (!DeletedInit) {
|
||||
delete M; // No change made...
|
||||
} else {
|
||||
// See if the program still causes a crash...
|
||||
outs() << "\nChecking to see if we can delete global inits: ";
|
||||
|
||||
if (TestFn(BD, M)) { // Still crashes?
|
||||
BD.setNewProgram(M);
|
||||
outs() << "\n*** Able to remove all global initializers!\n";
|
||||
} else { // No longer crashes?
|
||||
outs() << " - Removing all global inits hides problem!\n";
|
||||
delete M;
|
||||
|
||||
std::vector<GlobalVariable*> GVs;
|
||||
|
||||
for (Module::global_iterator I = BD.getProgram()->global_begin(),
|
||||
E = BD.getProgram()->global_end(); I != E; ++I)
|
||||
if (I->hasInitializer())
|
||||
GVs.push_back(I);
|
||||
|
||||
if (GVs.size() > 1 && !BugpointIsInterrupted) {
|
||||
outs() << "\n*** Attempting to reduce the number of global "
|
||||
<< "variables in the testcase\n";
|
||||
|
||||
unsigned OldSize = GVs.size();
|
||||
ReduceCrashingGlobalVariables(BD, TestFn).reduceList(GVs, Error);
|
||||
if (!Error.empty())
|
||||
return true;
|
||||
|
||||
if (GVs.size() < OldSize)
|
||||
BD.EmitProgressBitcode(BD.getProgram(), "reduced-global-variables");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now try to reduce the number of functions in the module to something small.
|
||||
std::vector<Function*> Functions;
|
||||
for (Module::iterator I = BD.getProgram()->begin(),
|
||||
E = BD.getProgram()->end(); I != E; ++I)
|
||||
if (!I->isDeclaration())
|
||||
Functions.push_back(I);
|
||||
|
||||
if (Functions.size() > 1 && !BugpointIsInterrupted) {
|
||||
outs() << "\n*** Attempting to reduce the number of functions "
|
||||
"in the testcase\n";
|
||||
|
||||
unsigned OldSize = Functions.size();
|
||||
ReduceCrashingFunctions(BD, TestFn).reduceList(Functions, Error);
|
||||
|
||||
if (Functions.size() < OldSize)
|
||||
BD.EmitProgressBitcode(BD.getProgram(), "reduced-function");
|
||||
}
|
||||
|
||||
// Attempt to delete entire basic blocks at a time to speed up
|
||||
// convergence... this actually works by setting the terminator of the blocks
|
||||
// to a return instruction then running simplifycfg, which can potentially
|
||||
// shrinks the code dramatically quickly
|
||||
//
|
||||
if (!DisableSimplifyCFG && !BugpointIsInterrupted) {
|
||||
std::vector<const BasicBlock*> Blocks;
|
||||
for (Module::const_iterator I = BD.getProgram()->begin(),
|
||||
E = BD.getProgram()->end(); I != E; ++I)
|
||||
for (Function::const_iterator FI = I->begin(), E = I->end(); FI !=E; ++FI)
|
||||
Blocks.push_back(FI);
|
||||
unsigned OldSize = Blocks.size();
|
||||
ReduceCrashingBlocks(BD, TestFn).reduceList(Blocks, Error);
|
||||
if (Blocks.size() < OldSize)
|
||||
BD.EmitProgressBitcode(BD.getProgram(), "reduced-blocks");
|
||||
}
|
||||
|
||||
// Attempt to delete instructions using bisection. This should help out nasty
|
||||
// cases with large basic blocks where the problem is at one end.
|
||||
if (!BugpointIsInterrupted) {
|
||||
std::vector<const Instruction*> Insts;
|
||||
for (Module::const_iterator MI = BD.getProgram()->begin(),
|
||||
ME = BD.getProgram()->end(); MI != ME; ++MI)
|
||||
for (Function::const_iterator FI = MI->begin(), FE = MI->end(); FI != FE;
|
||||
++FI)
|
||||
for (BasicBlock::const_iterator I = FI->begin(), E = FI->end();
|
||||
I != E; ++I)
|
||||
if (!isa<TerminatorInst>(I))
|
||||
Insts.push_back(I);
|
||||
|
||||
ReduceCrashingInstructions(BD, TestFn).reduceList(Insts, Error);
|
||||
}
|
||||
|
||||
// FIXME: This should use the list reducer to converge faster by deleting
|
||||
// larger chunks of instructions at a time!
|
||||
unsigned Simplification = 2;
|
||||
do {
|
||||
if (BugpointIsInterrupted) break;
|
||||
--Simplification;
|
||||
outs() << "\n*** Attempting to reduce testcase by deleting instruc"
|
||||
<< "tions: Simplification Level #" << Simplification << '\n';
|
||||
|
||||
// Now that we have deleted the functions that are unnecessary for the
|
||||
// program, try to remove instructions that are not necessary to cause the
|
||||
// crash. To do this, we loop through all of the instructions in the
|
||||
// remaining functions, deleting them (replacing any values produced with
|
||||
// nulls), and then running ADCE and SimplifyCFG. If the transformed input
|
||||
// still triggers failure, keep deleting until we cannot trigger failure
|
||||
// anymore.
|
||||
//
|
||||
unsigned InstructionsToSkipBeforeDeleting = 0;
|
||||
TryAgain:
|
||||
|
||||
// Loop over all of the (non-terminator) instructions remaining in the
|
||||
// function, attempting to delete them.
|
||||
unsigned CurInstructionNum = 0;
|
||||
for (Module::const_iterator FI = BD.getProgram()->begin(),
|
||||
E = BD.getProgram()->end(); FI != E; ++FI)
|
||||
if (!FI->isDeclaration())
|
||||
for (Function::const_iterator BI = FI->begin(), E = FI->end(); BI != E;
|
||||
++BI)
|
||||
for (BasicBlock::const_iterator I = BI->begin(), E = --BI->end();
|
||||
I != E; ++I, ++CurInstructionNum)
|
||||
if (InstructionsToSkipBeforeDeleting) {
|
||||
--InstructionsToSkipBeforeDeleting;
|
||||
} else {
|
||||
if (BugpointIsInterrupted) goto ExitLoops;
|
||||
|
||||
outs() << "Checking instruction: " << *I;
|
||||
Module *M = BD.deleteInstructionFromProgram(I, Simplification);
|
||||
|
||||
// Find out if the pass still crashes on this pass...
|
||||
if (TestFn(BD, M)) {
|
||||
// Yup, it does, we delete the old module, and continue trying
|
||||
// to reduce the testcase...
|
||||
BD.setNewProgram(M);
|
||||
InstructionsToSkipBeforeDeleting = CurInstructionNum;
|
||||
goto TryAgain; // I wish I had a multi-level break here!
|
||||
}
|
||||
|
||||
// This pass didn't crash without this instruction, try the next
|
||||
// one.
|
||||
delete M;
|
||||
}
|
||||
|
||||
if (InstructionsToSkipBeforeDeleting) {
|
||||
InstructionsToSkipBeforeDeleting = 0;
|
||||
goto TryAgain;
|
||||
}
|
||||
|
||||
} while (Simplification);
|
||||
ExitLoops:
|
||||
|
||||
// Try to clean up the testcase by running funcresolve and globaldce...
|
||||
if (!BugpointIsInterrupted) {
|
||||
outs() << "\n*** Attempting to perform final cleanups: ";
|
||||
Module *M = CloneModule(BD.getProgram());
|
||||
M = BD.performFinalCleanups(M, true);
|
||||
|
||||
// Find out if the pass still crashes on the cleaned up program...
|
||||
if (TestFn(BD, M)) {
|
||||
BD.setNewProgram(M); // Yup, it does, keep the reduced version...
|
||||
} else {
|
||||
delete M;
|
||||
}
|
||||
}
|
||||
|
||||
BD.EmitProgressBitcode(BD.getProgram(), "reduced-simplified");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool TestForOptimizerCrash(const BugDriver &BD, Module *M) {
|
||||
return BD.runPasses(M);
|
||||
}
|
||||
|
||||
/// debugOptimizerCrash - This method is called when some pass crashes on input.
|
||||
/// It attempts to prune down the testcase to something reasonable, and figure
|
||||
/// out exactly which pass is crashing.
|
||||
///
|
||||
bool BugDriver::debugOptimizerCrash(const std::string &ID) {
|
||||
outs() << "\n*** Debugging optimizer crash!\n";
|
||||
|
||||
std::string Error;
|
||||
// Reduce the list of passes which causes the optimizer to crash...
|
||||
if (!BugpointIsInterrupted)
|
||||
ReducePassList(*this).reduceList(PassesToRun, Error);
|
||||
assert(Error.empty());
|
||||
|
||||
outs() << "\n*** Found crashing pass"
|
||||
<< (PassesToRun.size() == 1 ? ": " : "es: ")
|
||||
<< getPassesString(PassesToRun) << '\n';
|
||||
|
||||
EmitProgressBitcode(Program, ID);
|
||||
|
||||
bool Success = DebugACrash(*this, TestForOptimizerCrash, Error);
|
||||
assert(Error.empty());
|
||||
return Success;
|
||||
}
|
||||
|
||||
static bool TestForCodeGenCrash(const BugDriver &BD, Module *M) {
|
||||
std::string Error;
|
||||
BD.compileProgram(M, &Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << "<crash>\n";
|
||||
return true; // Tool is still crashing.
|
||||
}
|
||||
errs() << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
/// debugCodeGeneratorCrash - This method is called when the code generator
|
||||
/// crashes on an input. It attempts to reduce the input as much as possible
|
||||
/// while still causing the code generator to crash.
|
||||
bool BugDriver::debugCodeGeneratorCrash(std::string &Error) {
|
||||
errs() << "*** Debugging code generator crash!\n";
|
||||
|
||||
return DebugACrash(*this, TestForCodeGenCrash, Error);
|
||||
}
|
516
contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
Normal file
516
contrib/llvm/tools/bugpoint/ExecutionDriver.cpp
Normal file
@ -0,0 +1,516 @@
|
||||
//===- ExecutionDriver.cpp - Allow execution of LLVM program --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains code used to execute the program utilizing one of the
|
||||
// various ways of running LLVM bitcode.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "ToolRunner.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <fstream>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
// OutputType - Allow the user to specify the way code should be run, to test
|
||||
// for miscompilation.
|
||||
//
|
||||
enum OutputType {
|
||||
AutoPick, RunLLI, RunJIT, RunLLC, RunLLCIA, RunCBE, CBE_bug, LLC_Safe,
|
||||
CompileCustom, Custom
|
||||
};
|
||||
|
||||
cl::opt<double>
|
||||
AbsTolerance("abs-tolerance", cl::desc("Absolute error tolerated"),
|
||||
cl::init(0.0));
|
||||
cl::opt<double>
|
||||
RelTolerance("rel-tolerance", cl::desc("Relative error tolerated"),
|
||||
cl::init(0.0));
|
||||
|
||||
cl::opt<OutputType>
|
||||
InterpreterSel(cl::desc("Specify the \"test\" i.e. suspect back-end:"),
|
||||
cl::values(clEnumValN(AutoPick, "auto", "Use best guess"),
|
||||
clEnumValN(RunLLI, "run-int",
|
||||
"Execute with the interpreter"),
|
||||
clEnumValN(RunJIT, "run-jit", "Execute with JIT"),
|
||||
clEnumValN(RunLLC, "run-llc", "Compile with LLC"),
|
||||
clEnumValN(RunLLCIA, "run-llc-ia",
|
||||
"Compile with LLC with integrated assembler"),
|
||||
clEnumValN(RunCBE, "run-cbe", "Compile with CBE"),
|
||||
clEnumValN(CBE_bug,"cbe-bug", "Find CBE bugs"),
|
||||
clEnumValN(LLC_Safe, "llc-safe", "Use LLC for all"),
|
||||
clEnumValN(CompileCustom, "compile-custom",
|
||||
"Use -compile-command to define a command to "
|
||||
"compile the bitcode. Useful to avoid linking."),
|
||||
clEnumValN(Custom, "run-custom",
|
||||
"Use -exec-command to define a command to execute "
|
||||
"the bitcode. Useful for cross-compilation."),
|
||||
clEnumValEnd),
|
||||
cl::init(AutoPick));
|
||||
|
||||
cl::opt<OutputType>
|
||||
SafeInterpreterSel(cl::desc("Specify \"safe\" i.e. known-good backend:"),
|
||||
cl::values(clEnumValN(AutoPick, "safe-auto", "Use best guess"),
|
||||
clEnumValN(RunLLC, "safe-run-llc", "Compile with LLC"),
|
||||
clEnumValN(RunCBE, "safe-run-cbe", "Compile with CBE"),
|
||||
clEnumValN(Custom, "safe-run-custom",
|
||||
"Use -exec-command to define a command to execute "
|
||||
"the bitcode. Useful for cross-compilation."),
|
||||
clEnumValEnd),
|
||||
cl::init(AutoPick));
|
||||
|
||||
cl::opt<std::string>
|
||||
SafeInterpreterPath("safe-path",
|
||||
cl::desc("Specify the path to the \"safe\" backend program"),
|
||||
cl::init(""));
|
||||
|
||||
cl::opt<bool>
|
||||
AppendProgramExitCode("append-exit-code",
|
||||
cl::desc("Append the exit code to the output so it gets diff'd too"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<std::string>
|
||||
InputFile("input", cl::init("/dev/null"),
|
||||
cl::desc("Filename to pipe in as stdin (default: /dev/null)"));
|
||||
|
||||
cl::list<std::string>
|
||||
AdditionalSOs("additional-so",
|
||||
cl::desc("Additional shared objects to load "
|
||||
"into executing programs"));
|
||||
|
||||
cl::list<std::string>
|
||||
AdditionalLinkerArgs("Xlinker",
|
||||
cl::desc("Additional arguments to pass to the linker"));
|
||||
|
||||
cl::opt<std::string>
|
||||
CustomCompileCommand("compile-command", cl::init("llc"),
|
||||
cl::desc("Command to compile the bitcode (use with -compile-custom) "
|
||||
"(default: llc)"));
|
||||
|
||||
cl::opt<std::string>
|
||||
CustomExecCommand("exec-command", cl::init("simulate"),
|
||||
cl::desc("Command to execute the bitcode (use with -run-custom) "
|
||||
"(default: simulate)"));
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
// Anything specified after the --args option are taken as arguments to the
|
||||
// program being debugged.
|
||||
cl::list<std::string>
|
||||
InputArgv("args", cl::Positional, cl::desc("<program arguments>..."),
|
||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||
|
||||
cl::opt<std::string>
|
||||
OutputPrefix("output-prefix", cl::init("bugpoint"),
|
||||
cl::desc("Prefix to use for outputs (default: 'bugpoint')"));
|
||||
}
|
||||
|
||||
namespace {
|
||||
cl::list<std::string>
|
||||
ToolArgv("tool-args", cl::Positional, cl::desc("<tool arguments>..."),
|
||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||
|
||||
cl::list<std::string>
|
||||
SafeToolArgv("safe-tool-args", cl::Positional,
|
||||
cl::desc("<safe-tool arguments>..."),
|
||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||
|
||||
cl::opt<std::string>
|
||||
GCCBinary("gcc", cl::init("gcc"),
|
||||
cl::desc("The gcc binary to use. (default 'gcc')"));
|
||||
|
||||
cl::list<std::string>
|
||||
GCCToolArgv("gcc-tool-args", cl::Positional,
|
||||
cl::desc("<gcc-tool arguments>..."),
|
||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// BugDriver method implementation
|
||||
//
|
||||
|
||||
/// initializeExecutionEnvironment - This method is used to set up the
|
||||
/// environment for executing LLVM programs.
|
||||
///
|
||||
bool BugDriver::initializeExecutionEnvironment() {
|
||||
outs() << "Initializing execution environment: ";
|
||||
|
||||
// Create an instance of the AbstractInterpreter interface as specified on
|
||||
// the command line
|
||||
SafeInterpreter = 0;
|
||||
std::string Message;
|
||||
|
||||
switch (InterpreterSel) {
|
||||
case AutoPick:
|
||||
InterpreterSel = RunCBE;
|
||||
Interpreter =
|
||||
AbstractInterpreter::createCBE(getToolName(), Message, GCCBinary,
|
||||
&ToolArgv, &GCCToolArgv);
|
||||
if (!Interpreter) {
|
||||
InterpreterSel = RunJIT;
|
||||
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
|
||||
&ToolArgv);
|
||||
}
|
||||
if (!Interpreter) {
|
||||
InterpreterSel = RunLLC;
|
||||
Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
|
||||
GCCBinary, &ToolArgv,
|
||||
&GCCToolArgv);
|
||||
}
|
||||
if (!Interpreter) {
|
||||
InterpreterSel = RunLLI;
|
||||
Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
|
||||
&ToolArgv);
|
||||
}
|
||||
if (!Interpreter) {
|
||||
InterpreterSel = AutoPick;
|
||||
Message = "Sorry, I can't automatically select an interpreter!\n";
|
||||
}
|
||||
break;
|
||||
case RunLLI:
|
||||
Interpreter = AbstractInterpreter::createLLI(getToolName(), Message,
|
||||
&ToolArgv);
|
||||
break;
|
||||
case RunLLC:
|
||||
case RunLLCIA:
|
||||
case LLC_Safe:
|
||||
Interpreter = AbstractInterpreter::createLLC(getToolName(), Message,
|
||||
GCCBinary, &ToolArgv,
|
||||
&GCCToolArgv,
|
||||
InterpreterSel == RunLLCIA);
|
||||
break;
|
||||
case RunJIT:
|
||||
Interpreter = AbstractInterpreter::createJIT(getToolName(), Message,
|
||||
&ToolArgv);
|
||||
break;
|
||||
case RunCBE:
|
||||
case CBE_bug:
|
||||
Interpreter = AbstractInterpreter::createCBE(getToolName(), Message,
|
||||
GCCBinary, &ToolArgv,
|
||||
&GCCToolArgv);
|
||||
break;
|
||||
case CompileCustom:
|
||||
Interpreter =
|
||||
AbstractInterpreter::createCustomCompiler(Message, CustomCompileCommand);
|
||||
break;
|
||||
case Custom:
|
||||
Interpreter =
|
||||
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
|
||||
break;
|
||||
default:
|
||||
Message = "Sorry, this back-end is not supported by bugpoint right now!\n";
|
||||
break;
|
||||
}
|
||||
if (!Interpreter)
|
||||
errs() << Message;
|
||||
else // Display informational messages on stdout instead of stderr
|
||||
outs() << Message;
|
||||
|
||||
std::string Path = SafeInterpreterPath;
|
||||
if (Path.empty())
|
||||
Path = getToolName();
|
||||
std::vector<std::string> SafeToolArgs = SafeToolArgv;
|
||||
switch (SafeInterpreterSel) {
|
||||
case AutoPick:
|
||||
// In "cbe-bug" mode, default to using LLC as the "safe" backend.
|
||||
if (!SafeInterpreter &&
|
||||
InterpreterSel == CBE_bug) {
|
||||
SafeInterpreterSel = RunLLC;
|
||||
SafeToolArgs.push_back("--relocation-model=pic");
|
||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
||||
GCCBinary,
|
||||
&SafeToolArgs,
|
||||
&GCCToolArgv);
|
||||
}
|
||||
|
||||
// In "llc-safe" mode, default to using LLC as the "safe" backend.
|
||||
if (!SafeInterpreter &&
|
||||
InterpreterSel == LLC_Safe) {
|
||||
SafeInterpreterSel = RunLLC;
|
||||
SafeToolArgs.push_back("--relocation-model=pic");
|
||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
||||
GCCBinary,
|
||||
&SafeToolArgs,
|
||||
&GCCToolArgv);
|
||||
}
|
||||
|
||||
// Pick a backend that's different from the test backend. The JIT and
|
||||
// LLC backends share a lot of code, so prefer to use the CBE as the
|
||||
// safe back-end when testing them.
|
||||
if (!SafeInterpreter &&
|
||||
InterpreterSel != RunCBE) {
|
||||
SafeInterpreterSel = RunCBE;
|
||||
SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message,
|
||||
GCCBinary,
|
||||
&SafeToolArgs,
|
||||
&GCCToolArgv);
|
||||
}
|
||||
if (!SafeInterpreter &&
|
||||
InterpreterSel != RunLLC &&
|
||||
InterpreterSel != RunJIT) {
|
||||
SafeInterpreterSel = RunLLC;
|
||||
SafeToolArgs.push_back("--relocation-model=pic");
|
||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
||||
GCCBinary,
|
||||
&SafeToolArgs,
|
||||
&GCCToolArgv);
|
||||
}
|
||||
if (!SafeInterpreter) {
|
||||
SafeInterpreterSel = AutoPick;
|
||||
Message = "Sorry, I can't automatically select an interpreter!\n";
|
||||
}
|
||||
break;
|
||||
case RunLLC:
|
||||
case RunLLCIA:
|
||||
SafeToolArgs.push_back("--relocation-model=pic");
|
||||
SafeInterpreter = AbstractInterpreter::createLLC(Path.c_str(), Message,
|
||||
GCCBinary, &SafeToolArgs,
|
||||
&GCCToolArgv,
|
||||
SafeInterpreterSel == RunLLCIA);
|
||||
break;
|
||||
case RunCBE:
|
||||
SafeInterpreter = AbstractInterpreter::createCBE(Path.c_str(), Message,
|
||||
GCCBinary, &SafeToolArgs,
|
||||
&GCCToolArgv);
|
||||
break;
|
||||
case Custom:
|
||||
SafeInterpreter =
|
||||
AbstractInterpreter::createCustomExecutor(Message, CustomExecCommand);
|
||||
break;
|
||||
default:
|
||||
Message = "Sorry, this back-end is not supported by bugpoint as the "
|
||||
"\"safe\" backend right now!\n";
|
||||
break;
|
||||
}
|
||||
if (!SafeInterpreter) { outs() << Message << "\nExiting.\n"; exit(1); }
|
||||
|
||||
gcc = GCC::create(Message, GCCBinary, &GCCToolArgv);
|
||||
if (!gcc) { outs() << Message << "\nExiting.\n"; exit(1); }
|
||||
|
||||
// If there was an error creating the selected interpreter, quit with error.
|
||||
return Interpreter == 0;
|
||||
}
|
||||
|
||||
/// compileProgram - Try to compile the specified module, returning false and
|
||||
/// setting Error if an error occurs. This is used for code generation
|
||||
/// crash testing.
|
||||
///
|
||||
void BugDriver::compileProgram(Module *M, std::string *Error) const {
|
||||
// Emit the program to a bitcode file...
|
||||
sys::Path BitcodeFile (OutputPrefix + "-test-program.bc");
|
||||
std::string ErrMsg;
|
||||
if (BitcodeFile.makeUnique(true, &ErrMsg)) {
|
||||
errs() << ToolName << ": Error making unique filename: " << ErrMsg
|
||||
<< "\n";
|
||||
exit(1);
|
||||
}
|
||||
if (writeProgramToFile(BitcodeFile.str(), M)) {
|
||||
errs() << ToolName << ": Error emitting bitcode to file '"
|
||||
<< BitcodeFile.str() << "'!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Remove the temporary bitcode file when we are done.
|
||||
FileRemover BitcodeFileRemover(BitcodeFile.str(), !SaveTemps);
|
||||
|
||||
// Actually compile the program!
|
||||
Interpreter->compileProgram(BitcodeFile.str(), Error, Timeout, MemoryLimit);
|
||||
}
|
||||
|
||||
|
||||
/// executeProgram - This method runs "Program", capturing the output of the
|
||||
/// program to a file, returning the filename of the file. A recommended
|
||||
/// filename may be optionally specified.
|
||||
///
|
||||
std::string BugDriver::executeProgram(const Module *Program,
|
||||
std::string OutputFile,
|
||||
std::string BitcodeFile,
|
||||
const std::string &SharedObj,
|
||||
AbstractInterpreter *AI,
|
||||
std::string *Error) const {
|
||||
if (AI == 0) AI = Interpreter;
|
||||
assert(AI && "Interpreter should have been created already!");
|
||||
bool CreatedBitcode = false;
|
||||
std::string ErrMsg;
|
||||
if (BitcodeFile.empty()) {
|
||||
// Emit the program to a bitcode file...
|
||||
sys::Path uniqueFilename(OutputPrefix + "-test-program.bc");
|
||||
if (uniqueFilename.makeUnique(true, &ErrMsg)) {
|
||||
errs() << ToolName << ": Error making unique filename: "
|
||||
<< ErrMsg << "!\n";
|
||||
exit(1);
|
||||
}
|
||||
BitcodeFile = uniqueFilename.str();
|
||||
|
||||
if (writeProgramToFile(BitcodeFile, Program)) {
|
||||
errs() << ToolName << ": Error emitting bitcode to file '"
|
||||
<< BitcodeFile << "'!\n";
|
||||
exit(1);
|
||||
}
|
||||
CreatedBitcode = true;
|
||||
}
|
||||
|
||||
// Remove the temporary bitcode file when we are done.
|
||||
sys::Path BitcodePath(BitcodeFile);
|
||||
FileRemover BitcodeFileRemover(BitcodePath.str(),
|
||||
CreatedBitcode && !SaveTemps);
|
||||
|
||||
if (OutputFile.empty()) OutputFile = OutputPrefix + "-execution-output";
|
||||
|
||||
// Check to see if this is a valid output filename...
|
||||
sys::Path uniqueFile(OutputFile);
|
||||
if (uniqueFile.makeUnique(true, &ErrMsg)) {
|
||||
errs() << ToolName << ": Error making unique filename: "
|
||||
<< ErrMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
OutputFile = uniqueFile.str();
|
||||
|
||||
// Figure out which shared objects to run, if any.
|
||||
std::vector<std::string> SharedObjs(AdditionalSOs);
|
||||
if (!SharedObj.empty())
|
||||
SharedObjs.push_back(SharedObj);
|
||||
|
||||
int RetVal = AI->ExecuteProgram(BitcodeFile, InputArgv, InputFile, OutputFile,
|
||||
Error, AdditionalLinkerArgs, SharedObjs,
|
||||
Timeout, MemoryLimit);
|
||||
if (!Error->empty())
|
||||
return OutputFile;
|
||||
|
||||
if (RetVal == -1) {
|
||||
errs() << "<timeout>";
|
||||
static bool FirstTimeout = true;
|
||||
if (FirstTimeout) {
|
||||
outs() << "\n"
|
||||
"*** Program execution timed out! This mechanism is designed to handle\n"
|
||||
" programs stuck in infinite loops gracefully. The -timeout option\n"
|
||||
" can be used to change the timeout threshold or disable it completely\n"
|
||||
" (with -timeout=0). This message is only displayed once.\n";
|
||||
FirstTimeout = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (AppendProgramExitCode) {
|
||||
std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);
|
||||
outFile << "exit " << RetVal << '\n';
|
||||
outFile.close();
|
||||
}
|
||||
|
||||
// Return the filename we captured the output to.
|
||||
return OutputFile;
|
||||
}
|
||||
|
||||
/// executeProgramSafely - Used to create reference output with the "safe"
|
||||
/// backend, if reference output is not provided.
|
||||
///
|
||||
std::string BugDriver::executeProgramSafely(const Module *Program,
|
||||
std::string OutputFile,
|
||||
std::string *Error) const {
|
||||
return executeProgram(Program, OutputFile, "", "", SafeInterpreter, Error);
|
||||
}
|
||||
|
||||
std::string BugDriver::compileSharedObject(const std::string &BitcodeFile,
|
||||
std::string &Error) {
|
||||
assert(Interpreter && "Interpreter should have been created already!");
|
||||
sys::Path OutputFile;
|
||||
|
||||
// Using the known-good backend.
|
||||
GCC::FileType FT = SafeInterpreter->OutputCode(BitcodeFile, OutputFile,
|
||||
Error);
|
||||
if (!Error.empty())
|
||||
return "";
|
||||
|
||||
std::string SharedObjectFile;
|
||||
bool Failure = gcc->MakeSharedObject(OutputFile.str(), FT, SharedObjectFile,
|
||||
AdditionalLinkerArgs, Error);
|
||||
if (!Error.empty())
|
||||
return "";
|
||||
if (Failure)
|
||||
exit(1);
|
||||
|
||||
// Remove the intermediate C file
|
||||
OutputFile.eraseFromDisk();
|
||||
|
||||
return "./" + SharedObjectFile;
|
||||
}
|
||||
|
||||
/// createReferenceFile - calls compileProgram and then records the output
|
||||
/// into ReferenceOutputFile. Returns true if reference file created, false
|
||||
/// otherwise. Note: initializeExecutionEnvironment should be called BEFORE
|
||||
/// this function.
|
||||
///
|
||||
bool BugDriver::createReferenceFile(Module *M, const std::string &Filename) {
|
||||
std::string Error;
|
||||
compileProgram(Program, &Error);
|
||||
if (!Error.empty())
|
||||
return false;
|
||||
|
||||
ReferenceOutputFile = executeProgramSafely(Program, Filename, &Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << Error;
|
||||
if (Interpreter != SafeInterpreter) {
|
||||
errs() << "*** There is a bug running the \"safe\" backend. Either"
|
||||
<< " debug it (for example with the -run-cbe bugpoint option,"
|
||||
<< " if CBE is being used as the \"safe\" backend), or fix the"
|
||||
<< " error some other way.\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
outs() << "\nReference output is: " << ReferenceOutputFile << "\n\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// diffProgram - This method executes the specified module and diffs the
|
||||
/// output against the file specified by ReferenceOutputFile. If the output
|
||||
/// is different, 1 is returned. If there is a problem with the code
|
||||
/// generator (e.g., llc crashes), this will set ErrMsg.
|
||||
///
|
||||
bool BugDriver::diffProgram(const Module *Program,
|
||||
const std::string &BitcodeFile,
|
||||
const std::string &SharedObject,
|
||||
bool RemoveBitcode,
|
||||
std::string *ErrMsg) const {
|
||||
// Execute the program, generating an output file...
|
||||
sys::Path Output(executeProgram(Program, "", BitcodeFile, SharedObject, 0,
|
||||
ErrMsg));
|
||||
if (!ErrMsg->empty())
|
||||
return false;
|
||||
|
||||
std::string Error;
|
||||
bool FilesDifferent = false;
|
||||
if (int Diff = DiffFilesWithTolerance(sys::Path(ReferenceOutputFile),
|
||||
sys::Path(Output.str()),
|
||||
AbsTolerance, RelTolerance, &Error)) {
|
||||
if (Diff == 2) {
|
||||
errs() << "While diffing output: " << Error << '\n';
|
||||
exit(1);
|
||||
}
|
||||
FilesDifferent = true;
|
||||
}
|
||||
else {
|
||||
// Remove the generated output if there are no differences.
|
||||
Output.eraseFromDisk();
|
||||
}
|
||||
|
||||
// Remove the bitcode file if we are supposed to.
|
||||
if (RemoveBitcode)
|
||||
sys::Path(BitcodeFile).eraseFromDisk();
|
||||
return FilesDifferent;
|
||||
}
|
||||
|
||||
bool BugDriver::isExecutingJIT() {
|
||||
return InterpreterSel == RunJIT;
|
||||
}
|
||||
|
370
contrib/llvm/tools/bugpoint/ExtractFunction.cpp
Normal file
370
contrib/llvm/tools/bugpoint/ExtractFunction.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
//===- ExtractFunction.cpp - Extract a function from Program --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements several methods that are used to extract functions,
|
||||
// loops, or portions of a module from the rest of the module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/DerivedTypes.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Assembly/Writer.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include "llvm/Transforms/Utils/FunctionUtils.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include <set>
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
bool DisableSimplifyCFG = false;
|
||||
extern cl::opt<std::string> OutputPrefix;
|
||||
} // End llvm namespace
|
||||
|
||||
namespace {
|
||||
cl::opt<bool>
|
||||
NoDCE ("disable-dce",
|
||||
cl::desc("Do not use the -dce pass to reduce testcases"));
|
||||
cl::opt<bool, true>
|
||||
NoSCFG("disable-simplifycfg", cl::location(DisableSimplifyCFG),
|
||||
cl::desc("Do not use the -simplifycfg pass to reduce testcases"));
|
||||
}
|
||||
|
||||
/// deleteInstructionFromProgram - This method clones the current Program and
|
||||
/// deletes the specified instruction from the cloned module. It then runs a
|
||||
/// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code which
|
||||
/// depends on the value. The modified module is then returned.
|
||||
///
|
||||
Module *BugDriver::deleteInstructionFromProgram(const Instruction *I,
|
||||
unsigned Simplification) {
|
||||
// FIXME, use vmap?
|
||||
Module *Clone = CloneModule(Program);
|
||||
|
||||
const BasicBlock *PBB = I->getParent();
|
||||
const Function *PF = PBB->getParent();
|
||||
|
||||
Module::iterator RFI = Clone->begin(); // Get iterator to corresponding fn
|
||||
std::advance(RFI, std::distance(PF->getParent()->begin(),
|
||||
Module::const_iterator(PF)));
|
||||
|
||||
Function::iterator RBI = RFI->begin(); // Get iterator to corresponding BB
|
||||
std::advance(RBI, std::distance(PF->begin(), Function::const_iterator(PBB)));
|
||||
|
||||
BasicBlock::iterator RI = RBI->begin(); // Get iterator to corresponding inst
|
||||
std::advance(RI, std::distance(PBB->begin(), BasicBlock::const_iterator(I)));
|
||||
Instruction *TheInst = RI; // Got the corresponding instruction!
|
||||
|
||||
// If this instruction produces a value, replace any users with null values
|
||||
if (!TheInst->getType()->isVoidTy())
|
||||
TheInst->replaceAllUsesWith(Constant::getNullValue(TheInst->getType()));
|
||||
|
||||
// Remove the instruction from the program.
|
||||
TheInst->getParent()->getInstList().erase(TheInst);
|
||||
|
||||
// Spiff up the output a little bit.
|
||||
std::vector<std::string> Passes;
|
||||
|
||||
/// Can we get rid of the -disable-* options?
|
||||
if (Simplification > 1 && !NoDCE)
|
||||
Passes.push_back("dce");
|
||||
if (Simplification && !DisableSimplifyCFG)
|
||||
Passes.push_back("simplifycfg"); // Delete dead control flow
|
||||
|
||||
Passes.push_back("verify");
|
||||
Module *New = runPassesOn(Clone, Passes);
|
||||
delete Clone;
|
||||
if (!New) {
|
||||
errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n";
|
||||
exit(1);
|
||||
}
|
||||
return New;
|
||||
}
|
||||
|
||||
/// performFinalCleanups - This method clones the current Program and performs
|
||||
/// a series of cleanups intended to get rid of extra cruft on the module
|
||||
/// before handing it to the user.
|
||||
///
|
||||
Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) {
|
||||
// Make all functions external, so GlobalDCE doesn't delete them...
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
I->setLinkage(GlobalValue::ExternalLinkage);
|
||||
|
||||
std::vector<std::string> CleanupPasses;
|
||||
CleanupPasses.push_back("globaldce");
|
||||
|
||||
if (MayModifySemantics)
|
||||
CleanupPasses.push_back("deadarghaX0r");
|
||||
else
|
||||
CleanupPasses.push_back("deadargelim");
|
||||
|
||||
Module *New = runPassesOn(M, CleanupPasses);
|
||||
if (New == 0) {
|
||||
errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n";
|
||||
return M;
|
||||
}
|
||||
delete M;
|
||||
return New;
|
||||
}
|
||||
|
||||
|
||||
/// ExtractLoop - Given a module, extract up to one loop from it into a new
|
||||
/// function. This returns null if there are no extractable loops in the
|
||||
/// program or if the loop extractor crashes.
|
||||
Module *BugDriver::ExtractLoop(Module *M) {
|
||||
std::vector<std::string> LoopExtractPasses;
|
||||
LoopExtractPasses.push_back("loop-extract-single");
|
||||
|
||||
Module *NewM = runPassesOn(M, LoopExtractPasses);
|
||||
if (NewM == 0) {
|
||||
outs() << "*** Loop extraction failed: ";
|
||||
EmitProgressBitcode(M, "loopextraction", true);
|
||||
outs() << "*** Sorry. :( Please report a bug!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check to see if we created any new functions. If not, no loops were
|
||||
// extracted and we should return null. Limit the number of loops we extract
|
||||
// to avoid taking forever.
|
||||
static unsigned NumExtracted = 32;
|
||||
if (M->size() == NewM->size() || --NumExtracted == 0) {
|
||||
delete NewM;
|
||||
return 0;
|
||||
} else {
|
||||
assert(M->size() < NewM->size() && "Loop extract removed functions?");
|
||||
Module::iterator MI = NewM->begin();
|
||||
for (unsigned i = 0, e = M->size(); i != e; ++i)
|
||||
++MI;
|
||||
}
|
||||
|
||||
return NewM;
|
||||
}
|
||||
|
||||
|
||||
// DeleteFunctionBody - "Remove" the function by deleting all of its basic
|
||||
// blocks, making it external.
|
||||
//
|
||||
void llvm::DeleteFunctionBody(Function *F) {
|
||||
// delete the body of the function...
|
||||
F->deleteBody();
|
||||
assert(F->isDeclaration() && "This didn't make the function external!");
|
||||
}
|
||||
|
||||
/// GetTorInit - Given a list of entries for static ctors/dtors, return them
|
||||
/// as a constant array.
|
||||
static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) {
|
||||
assert(!TorList.empty() && "Don't create empty tor list!");
|
||||
std::vector<Constant*> ArrayElts;
|
||||
Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
|
||||
|
||||
StructType *STy =
|
||||
StructType::get(Int32Ty, TorList[0].first->getType(), NULL);
|
||||
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
|
||||
Constant *Elts[] = {
|
||||
ConstantInt::get(Int32Ty, TorList[i].second),
|
||||
TorList[i].first
|
||||
};
|
||||
ArrayElts.push_back(ConstantStruct::get(STy, Elts));
|
||||
}
|
||||
return ConstantArray::get(ArrayType::get(ArrayElts[0]->getType(),
|
||||
ArrayElts.size()),
|
||||
ArrayElts);
|
||||
}
|
||||
|
||||
/// SplitStaticCtorDtor - A module was recently split into two parts, M1/M2, and
|
||||
/// M1 has all of the global variables. If M2 contains any functions that are
|
||||
/// static ctors/dtors, we need to add an llvm.global_[cd]tors global to M2, and
|
||||
/// prune appropriate entries out of M1s list.
|
||||
static void SplitStaticCtorDtor(const char *GlobalName, Module *M1, Module *M2,
|
||||
ValueToValueMapTy &VMap) {
|
||||
GlobalVariable *GV = M1->getNamedGlobal(GlobalName);
|
||||
if (!GV || GV->isDeclaration() || GV->hasLocalLinkage() ||
|
||||
!GV->use_empty()) return;
|
||||
|
||||
std::vector<std::pair<Function*, int> > M1Tors, M2Tors;
|
||||
ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());
|
||||
if (!InitList) return;
|
||||
|
||||
for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) {
|
||||
if (ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i))){
|
||||
if (CS->getNumOperands() != 2) return; // Not array of 2-element structs.
|
||||
|
||||
if (CS->getOperand(1)->isNullValue())
|
||||
break; // Found a null terminator, stop here.
|
||||
|
||||
ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0));
|
||||
int Priority = CI ? CI->getSExtValue() : 0;
|
||||
|
||||
Constant *FP = CS->getOperand(1);
|
||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP))
|
||||
if (CE->isCast())
|
||||
FP = CE->getOperand(0);
|
||||
if (Function *F = dyn_cast<Function>(FP)) {
|
||||
if (!F->isDeclaration())
|
||||
M1Tors.push_back(std::make_pair(F, Priority));
|
||||
else {
|
||||
// Map to M2's version of the function.
|
||||
F = cast<Function>(VMap[F]);
|
||||
M2Tors.push_back(std::make_pair(F, Priority));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GV->eraseFromParent();
|
||||
if (!M1Tors.empty()) {
|
||||
Constant *M1Init = GetTorInit(M1Tors);
|
||||
new GlobalVariable(*M1, M1Init->getType(), false,
|
||||
GlobalValue::AppendingLinkage,
|
||||
M1Init, GlobalName);
|
||||
}
|
||||
|
||||
GV = M2->getNamedGlobal(GlobalName);
|
||||
assert(GV && "Not a clone of M1?");
|
||||
assert(GV->use_empty() && "llvm.ctors shouldn't have uses!");
|
||||
|
||||
GV->eraseFromParent();
|
||||
if (!M2Tors.empty()) {
|
||||
Constant *M2Init = GetTorInit(M2Tors);
|
||||
new GlobalVariable(*M2, M2Init->getType(), false,
|
||||
GlobalValue::AppendingLinkage,
|
||||
M2Init, GlobalName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// SplitFunctionsOutOfModule - Given a module and a list of functions in the
|
||||
/// module, split the functions OUT of the specified module, and place them in
|
||||
/// the new module.
|
||||
Module *
|
||||
llvm::SplitFunctionsOutOfModule(Module *M,
|
||||
const std::vector<Function*> &F,
|
||||
ValueToValueMapTy &VMap) {
|
||||
// Make sure functions & globals are all external so that linkage
|
||||
// between the two modules will work.
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
|
||||
I->setLinkage(GlobalValue::ExternalLinkage);
|
||||
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
|
||||
I != E; ++I) {
|
||||
if (I->hasName() && I->getName()[0] == '\01')
|
||||
I->setName(I->getName().substr(1));
|
||||
I->setLinkage(GlobalValue::ExternalLinkage);
|
||||
}
|
||||
|
||||
ValueToValueMapTy NewVMap;
|
||||
Module *New = CloneModule(M, NewVMap);
|
||||
|
||||
// Make sure global initializers exist only in the safe module (CBE->.so)
|
||||
for (Module::global_iterator I = New->global_begin(), E = New->global_end();
|
||||
I != E; ++I)
|
||||
I->setInitializer(0); // Delete the initializer to make it external
|
||||
|
||||
// Remove the Test functions from the Safe module
|
||||
std::set<Function *> TestFunctions;
|
||||
for (unsigned i = 0, e = F.size(); i != e; ++i) {
|
||||
Function *TNOF = cast<Function>(VMap[F[i]]);
|
||||
DEBUG(errs() << "Removing function ");
|
||||
DEBUG(WriteAsOperand(errs(), TNOF, false));
|
||||
DEBUG(errs() << "\n");
|
||||
TestFunctions.insert(cast<Function>(NewVMap[TNOF]));
|
||||
DeleteFunctionBody(TNOF); // Function is now external in this module!
|
||||
}
|
||||
|
||||
|
||||
// Remove the Safe functions from the Test module
|
||||
for (Module::iterator I = New->begin(), E = New->end(); I != E; ++I)
|
||||
if (!TestFunctions.count(I))
|
||||
DeleteFunctionBody(I);
|
||||
|
||||
|
||||
// Make sure that there is a global ctor/dtor array in both halves of the
|
||||
// module if they both have static ctor/dtor functions.
|
||||
SplitStaticCtorDtor("llvm.global_ctors", M, New, NewVMap);
|
||||
SplitStaticCtorDtor("llvm.global_dtors", M, New, NewVMap);
|
||||
|
||||
return New;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic Block Extraction Code
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
|
||||
/// into their own functions. The only detail is that M is actually a module
|
||||
/// cloned from the one the BBs are in, so some mapping needs to be performed.
|
||||
/// If this operation fails for some reason (ie the implementation is buggy),
|
||||
/// this function should return null, otherwise it returns a new Module.
|
||||
Module *BugDriver::ExtractMappedBlocksFromModule(const
|
||||
std::vector<BasicBlock*> &BBs,
|
||||
Module *M) {
|
||||
sys::Path uniqueFilename(OutputPrefix + "-extractblocks");
|
||||
std::string ErrMsg;
|
||||
if (uniqueFilename.createTemporaryFileOnDisk(true, &ErrMsg)) {
|
||||
outs() << "*** Basic Block extraction failed!\n";
|
||||
errs() << "Error creating temporary file: " << ErrMsg << "\n";
|
||||
EmitProgressBitcode(M, "basicblockextractfail", true);
|
||||
return 0;
|
||||
}
|
||||
sys::RemoveFileOnSignal(uniqueFilename);
|
||||
|
||||
std::string ErrorInfo;
|
||||
tool_output_file BlocksToNotExtractFile(uniqueFilename.c_str(), ErrorInfo);
|
||||
if (!ErrorInfo.empty()) {
|
||||
outs() << "*** Basic Block extraction failed!\n";
|
||||
errs() << "Error writing list of blocks to not extract: " << ErrorInfo
|
||||
<< "\n";
|
||||
EmitProgressBitcode(M, "basicblockextractfail", true);
|
||||
return 0;
|
||||
}
|
||||
for (std::vector<BasicBlock*>::const_iterator I = BBs.begin(), E = BBs.end();
|
||||
I != E; ++I) {
|
||||
BasicBlock *BB = *I;
|
||||
// If the BB doesn't have a name, give it one so we have something to key
|
||||
// off of.
|
||||
if (!BB->hasName()) BB->setName("tmpbb");
|
||||
BlocksToNotExtractFile.os() << BB->getParent()->getNameStr() << " "
|
||||
<< BB->getName() << "\n";
|
||||
}
|
||||
BlocksToNotExtractFile.os().close();
|
||||
if (BlocksToNotExtractFile.os().has_error()) {
|
||||
errs() << "Error writing list of blocks to not extract: " << ErrorInfo
|
||||
<< "\n";
|
||||
EmitProgressBitcode(M, "basicblockextractfail", true);
|
||||
BlocksToNotExtractFile.os().clear_error();
|
||||
return 0;
|
||||
}
|
||||
BlocksToNotExtractFile.keep();
|
||||
|
||||
std::string uniqueFN = "--extract-blocks-file=" + uniqueFilename.str();
|
||||
const char *ExtraArg = uniqueFN.c_str();
|
||||
|
||||
std::vector<std::string> PI;
|
||||
PI.push_back("extract-blocks");
|
||||
Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg);
|
||||
|
||||
uniqueFilename.eraseFromDisk(); // Free disk space
|
||||
|
||||
if (Ret == 0) {
|
||||
outs() << "*** Basic Block extraction failed, please report a bug!\n";
|
||||
EmitProgressBitcode(M, "basicblockextractfail", true);
|
||||
}
|
||||
return Ret;
|
||||
}
|
113
contrib/llvm/tools/bugpoint/FindBugs.cpp
Normal file
113
contrib/llvm/tools/bugpoint/FindBugs.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
//===-- FindBugs.cpp - Run Many Different Optimizations -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an interface that allows bugpoint to choose different
|
||||
// combinations of optimizations to run on the selected input. Bugpoint will
|
||||
// run these optimizations and record the success/failure of each. This way
|
||||
// we can hopefully spot bugs in the optimizations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "ToolRunner.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
using namespace llvm;
|
||||
|
||||
/// runManyPasses - Take the specified pass list and create different
|
||||
/// combinations of passes to compile the program with. Compile the program with
|
||||
/// each set and mark test to see if it compiled correctly. If the passes
|
||||
/// compiled correctly output nothing and rearrange the passes into a new order.
|
||||
/// If the passes did not compile correctly, output the command required to
|
||||
/// recreate the failure. This returns true if a compiler error is found.
|
||||
///
|
||||
bool BugDriver::runManyPasses(const std::vector<std::string> &AllPasses,
|
||||
std::string &ErrMsg) {
|
||||
setPassesToRun(AllPasses);
|
||||
outs() << "Starting bug finding procedure...\n\n";
|
||||
|
||||
// Creating a reference output if necessary
|
||||
if (initializeExecutionEnvironment()) return false;
|
||||
|
||||
outs() << "\n";
|
||||
if (ReferenceOutputFile.empty()) {
|
||||
outs() << "Generating reference output from raw program: \n";
|
||||
if (!createReferenceFile(Program))
|
||||
return false;
|
||||
}
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
unsigned num = 1;
|
||||
while(1) {
|
||||
//
|
||||
// Step 1: Randomize the order of the optimizer passes.
|
||||
//
|
||||
std::random_shuffle(PassesToRun.begin(), PassesToRun.end());
|
||||
|
||||
//
|
||||
// Step 2: Run optimizer passes on the program and check for success.
|
||||
//
|
||||
outs() << "Running selected passes on program to test for crash: ";
|
||||
for(int i = 0, e = PassesToRun.size(); i != e; i++) {
|
||||
outs() << "-" << PassesToRun[i] << " ";
|
||||
}
|
||||
|
||||
std::string Filename;
|
||||
if(runPasses(Program, PassesToRun, Filename, false)) {
|
||||
outs() << "\n";
|
||||
outs() << "Optimizer passes caused failure!\n\n";
|
||||
debugOptimizerCrash();
|
||||
return true;
|
||||
} else {
|
||||
outs() << "Combination " << num << " optimized successfully!\n";
|
||||
}
|
||||
|
||||
//
|
||||
// Step 3: Compile the optimized code.
|
||||
//
|
||||
outs() << "Running the code generator to test for a crash: ";
|
||||
std::string Error;
|
||||
compileProgram(Program, &Error);
|
||||
if (!Error.empty()) {
|
||||
outs() << "\n*** compileProgram threw an exception: ";
|
||||
outs() << Error;
|
||||
return debugCodeGeneratorCrash(ErrMsg);
|
||||
}
|
||||
outs() << '\n';
|
||||
|
||||
//
|
||||
// Step 4: Run the program and compare its output to the reference
|
||||
// output (created above).
|
||||
//
|
||||
outs() << "*** Checking if passes caused miscompliation:\n";
|
||||
bool Diff = diffProgram(Program, Filename, "", false, &Error);
|
||||
if (Error.empty() && Diff) {
|
||||
outs() << "\n*** diffProgram returned true!\n";
|
||||
debugMiscompilation(&Error);
|
||||
if (Error.empty())
|
||||
return true;
|
||||
}
|
||||
if (!Error.empty()) {
|
||||
errs() << Error;
|
||||
debugCodeGeneratorCrash(ErrMsg);
|
||||
return true;
|
||||
}
|
||||
outs() << "\n*** diff'd output matches!\n";
|
||||
|
||||
sys::Path(Filename).eraseFromDisk();
|
||||
|
||||
outs() << "\n\n";
|
||||
num++;
|
||||
} //end while
|
||||
|
||||
// Unreachable.
|
||||
}
|
201
contrib/llvm/tools/bugpoint/ListReducer.h
Normal file
201
contrib/llvm/tools/bugpoint/ListReducer.h
Normal file
@ -0,0 +1,201 @@
|
||||
//===- ListReducer.h - Trim down list while retaining property --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class is to be used as a base class for operations that want to zero in
|
||||
// on a subset of the input which still causes the bug we are tracking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BUGPOINT_LIST_REDUCER_H
|
||||
#define BUGPOINT_LIST_REDUCER_H
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern bool BugpointIsInterrupted;
|
||||
|
||||
template<typename ElTy>
|
||||
struct ListReducer {
|
||||
enum TestResult {
|
||||
NoFailure, // No failure of the predicate was detected
|
||||
KeepSuffix, // The suffix alone satisfies the predicate
|
||||
KeepPrefix, // The prefix alone satisfies the predicate
|
||||
InternalError // Encountered an error trying to run the predicate
|
||||
};
|
||||
|
||||
virtual ~ListReducer() {}
|
||||
|
||||
// doTest - This virtual function should be overriden by subclasses to
|
||||
// implement the test desired. The testcase is only required to test to see
|
||||
// if the Kept list still satisfies the property, but if it is going to check
|
||||
// the prefix anyway, it can.
|
||||
//
|
||||
virtual TestResult doTest(std::vector<ElTy> &Prefix,
|
||||
std::vector<ElTy> &Kept,
|
||||
std::string &Error) = 0;
|
||||
|
||||
// reduceList - This function attempts to reduce the length of the specified
|
||||
// list while still maintaining the "test" property. This is the core of the
|
||||
// "work" that bugpoint does.
|
||||
//
|
||||
bool reduceList(std::vector<ElTy> &TheList, std::string &Error) {
|
||||
std::vector<ElTy> empty;
|
||||
std::srand(0x6e5ea738); // Seed the random number generator
|
||||
switch (doTest(TheList, empty, Error)) {
|
||||
case KeepPrefix:
|
||||
if (TheList.size() == 1) // we are done, it's the base case and it fails
|
||||
return true;
|
||||
else
|
||||
break; // there's definitely an error, but we need to narrow it down
|
||||
|
||||
case KeepSuffix:
|
||||
// cannot be reached!
|
||||
llvm_unreachable("bugpoint ListReducer internal error: "
|
||||
"selected empty set.");
|
||||
|
||||
case NoFailure:
|
||||
return false; // there is no failure with the full set of passes/funcs!
|
||||
|
||||
case InternalError:
|
||||
assert(!Error.empty());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Maximal number of allowed splitting iterations,
|
||||
// before the elements are randomly shuffled.
|
||||
const unsigned MaxIterationsWithoutProgress = 3;
|
||||
bool ShufflingEnabled = true;
|
||||
|
||||
Backjump:
|
||||
unsigned MidTop = TheList.size();
|
||||
unsigned MaxIterations = MaxIterationsWithoutProgress;
|
||||
unsigned NumOfIterationsWithoutProgress = 0;
|
||||
while (MidTop > 1) { // Binary split reduction loop
|
||||
// Halt if the user presses ctrl-c.
|
||||
if (BugpointIsInterrupted) {
|
||||
errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the loop doesn't make satisfying progress, try shuffling.
|
||||
// The purpose of shuffling is to avoid the heavy tails of the
|
||||
// distribution (improving the speed of convergence).
|
||||
if (ShufflingEnabled &&
|
||||
NumOfIterationsWithoutProgress > MaxIterations) {
|
||||
std::vector<ElTy> ShuffledList(TheList);
|
||||
std::random_shuffle(ShuffledList.begin(), ShuffledList.end());
|
||||
errs() << "\n\n*** Testing shuffled set...\n\n";
|
||||
// Check that random shuffle doesn't loose the bug
|
||||
if (doTest(ShuffledList, empty, Error) == KeepPrefix) {
|
||||
// If the bug is still here, use the shuffled list.
|
||||
TheList.swap(ShuffledList);
|
||||
MidTop = TheList.size();
|
||||
// Must increase the shuffling treshold to avoid the small
|
||||
// probability of inifinite looping without making progress.
|
||||
MaxIterations += 2;
|
||||
errs() << "\n\n*** Shuffling does not hide the bug...\n\n";
|
||||
} else {
|
||||
ShufflingEnabled = false; // Disable shuffling further on
|
||||
errs() << "\n\n*** Shuffling hides the bug...\n\n";
|
||||
}
|
||||
NumOfIterationsWithoutProgress = 0;
|
||||
}
|
||||
|
||||
unsigned Mid = MidTop / 2;
|
||||
std::vector<ElTy> Prefix(TheList.begin(), TheList.begin()+Mid);
|
||||
std::vector<ElTy> Suffix(TheList.begin()+Mid, TheList.end());
|
||||
|
||||
switch (doTest(Prefix, Suffix, Error)) {
|
||||
case KeepSuffix:
|
||||
// The property still holds. We can just drop the prefix elements, and
|
||||
// shorten the list to the "kept" elements.
|
||||
TheList.swap(Suffix);
|
||||
MidTop = TheList.size();
|
||||
// Reset progress treshold and progress counter
|
||||
MaxIterations = MaxIterationsWithoutProgress;
|
||||
NumOfIterationsWithoutProgress = 0;
|
||||
break;
|
||||
case KeepPrefix:
|
||||
// The predicate still holds, shorten the list to the prefix elements.
|
||||
TheList.swap(Prefix);
|
||||
MidTop = TheList.size();
|
||||
// Reset progress treshold and progress counter
|
||||
MaxIterations = MaxIterationsWithoutProgress;
|
||||
NumOfIterationsWithoutProgress = 0;
|
||||
break;
|
||||
case NoFailure:
|
||||
// Otherwise the property doesn't hold. Some of the elements we removed
|
||||
// must be necessary to maintain the property.
|
||||
MidTop = Mid;
|
||||
NumOfIterationsWithoutProgress++;
|
||||
break;
|
||||
case InternalError:
|
||||
return true; // Error was set by doTest.
|
||||
}
|
||||
assert(Error.empty() && "doTest did not return InternalError for error");
|
||||
}
|
||||
|
||||
// Probability of backjumping from the trimming loop back to the binary
|
||||
// split reduction loop.
|
||||
const int BackjumpProbability = 10;
|
||||
|
||||
// Okay, we trimmed as much off the top and the bottom of the list as we
|
||||
// could. If there is more than two elements in the list, try deleting
|
||||
// interior elements and testing that.
|
||||
//
|
||||
if (TheList.size() > 2) {
|
||||
bool Changed = true;
|
||||
std::vector<ElTy> EmptyList;
|
||||
while (Changed) { // Trimming loop.
|
||||
Changed = false;
|
||||
|
||||
// If the binary split reduction loop made an unfortunate sequence of
|
||||
// splits, the trimming loop might be left off with a huge number of
|
||||
// remaining elements (large search space). Backjumping out of that
|
||||
// search space and attempting a different split can significantly
|
||||
// improve the convergence speed.
|
||||
if (std::rand() % 100 < BackjumpProbability)
|
||||
goto Backjump;
|
||||
|
||||
for (unsigned i = 1; i < TheList.size()-1; ++i) { // Check interior elts
|
||||
if (BugpointIsInterrupted) {
|
||||
errs() << "\n\n*** Reduction Interrupted, cleaning up...\n\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<ElTy> TestList(TheList);
|
||||
TestList.erase(TestList.begin()+i);
|
||||
|
||||
if (doTest(EmptyList, TestList, Error) == KeepSuffix) {
|
||||
// We can trim down the list!
|
||||
TheList.swap(TestList);
|
||||
--i; // Don't skip an element of the list
|
||||
Changed = true;
|
||||
}
|
||||
if (!Error.empty())
|
||||
return true;
|
||||
}
|
||||
// This can take a long time if left uncontrolled. For now, don't
|
||||
// iterate.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // there are some failure and we've narrowed them down
|
||||
}
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
16
contrib/llvm/tools/bugpoint/Makefile
Normal file
16
contrib/llvm/tools/bugpoint/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
##===- tools/bugpoint/Makefile -----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = bugpoint
|
||||
|
||||
LINK_COMPONENTS := asmparser instrumentation scalaropts ipo \
|
||||
linker bitreader bitwriter
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
1078
contrib/llvm/tools/bugpoint/Miscompilation.cpp
Normal file
1078
contrib/llvm/tools/bugpoint/Miscompilation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
265
contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
Normal file
265
contrib/llvm/tools/bugpoint/OptimizerDriver.cpp
Normal file
@ -0,0 +1,265 @@
|
||||
//===- OptimizerDriver.cpp - Allow BugPoint to run passes safely ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines an interface that allows bugpoint to run various passes
|
||||
// without the threat of a buggy pass corrupting bugpoint (of course, bugpoint
|
||||
// may have its own bugs, but that's another story...). It achieves this by
|
||||
// forking a copy of itself and having the child process do the optimizations.
|
||||
// If this client dies, we can always fork a new one. :)
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
|
||||
#define DONT_GET_PLUGIN_LOADER_OPTION
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
|
||||
#include <fstream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
extern cl::opt<std::string> OutputPrefix;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// ChildOutput - This option captures the name of the child output file that
|
||||
// is set up by the parent bugpoint process
|
||||
cl::opt<std::string> ChildOutput("child-output", cl::ReallyHidden);
|
||||
}
|
||||
|
||||
/// writeProgramToFile - This writes the current "Program" to the named bitcode
|
||||
/// file. If an error occurs, true is returned.
|
||||
///
|
||||
bool BugDriver::writeProgramToFile(const std::string &Filename,
|
||||
const Module *M) const {
|
||||
std::string ErrInfo;
|
||||
tool_output_file Out(Filename.c_str(), ErrInfo,
|
||||
raw_fd_ostream::F_Binary);
|
||||
if (ErrInfo.empty()) {
|
||||
WriteBitcodeToFile(M, Out.os());
|
||||
Out.os().close();
|
||||
if (!Out.os().has_error()) {
|
||||
Out.keep();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Out.os().clear_error();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/// EmitProgressBitcode - This function is used to output the current Program
|
||||
/// to a file named "bugpoint-ID.bc".
|
||||
///
|
||||
void BugDriver::EmitProgressBitcode(const Module *M,
|
||||
const std::string &ID,
|
||||
bool NoFlyer) const {
|
||||
// Output the input to the current pass to a bitcode file, emit a message
|
||||
// telling the user how to reproduce it: opt -foo blah.bc
|
||||
//
|
||||
std::string Filename = OutputPrefix + "-" + ID + ".bc";
|
||||
if (writeProgramToFile(Filename, M)) {
|
||||
errs() << "Error opening file '" << Filename << "' for writing!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
outs() << "Emitted bitcode to '" << Filename << "'\n";
|
||||
if (NoFlyer || PassesToRun.empty()) return;
|
||||
outs() << "\n*** You can reproduce the problem with: ";
|
||||
if (UseValgrind) outs() << "valgrind ";
|
||||
outs() << "opt " << Filename << " ";
|
||||
outs() << getPassesString(PassesToRun) << "\n";
|
||||
}
|
||||
|
||||
cl::opt<bool> SilencePasses("silence-passes",
|
||||
cl::desc("Suppress output of running passes (both stdout and stderr)"));
|
||||
|
||||
static cl::list<std::string> OptArgs("opt-args", cl::Positional,
|
||||
cl::desc("<opt arguments>..."),
|
||||
cl::ZeroOrMore, cl::PositionalEatsArgs);
|
||||
|
||||
/// runPasses - Run the specified passes on Program, outputting a bitcode file
|
||||
/// and writing the filename into OutputFile if successful. If the
|
||||
/// optimizations fail for some reason (optimizer crashes), return true,
|
||||
/// otherwise return false. If DeleteOutput is set to true, the bitcode is
|
||||
/// deleted on success, and the filename string is undefined. This prints to
|
||||
/// outs() a single line message indicating whether compilation was successful
|
||||
/// or failed.
|
||||
///
|
||||
bool BugDriver::runPasses(Module *Program,
|
||||
const std::vector<std::string> &Passes,
|
||||
std::string &OutputFilename, bool DeleteOutput,
|
||||
bool Quiet, unsigned NumExtraArgs,
|
||||
const char * const *ExtraArgs) const {
|
||||
// setup the output file name
|
||||
outs().flush();
|
||||
sys::Path uniqueFilename(OutputPrefix + "-output.bc");
|
||||
std::string ErrMsg;
|
||||
if (uniqueFilename.makeUnique(true, &ErrMsg)) {
|
||||
errs() << getToolName() << ": Error making unique filename: "
|
||||
<< ErrMsg << "\n";
|
||||
return(1);
|
||||
}
|
||||
OutputFilename = uniqueFilename.str();
|
||||
|
||||
// set up the input file name
|
||||
sys::Path inputFilename(OutputPrefix + "-input.bc");
|
||||
if (inputFilename.makeUnique(true, &ErrMsg)) {
|
||||
errs() << getToolName() << ": Error making unique filename: "
|
||||
<< ErrMsg << "\n";
|
||||
return(1);
|
||||
}
|
||||
|
||||
std::string ErrInfo;
|
||||
tool_output_file InFile(inputFilename.c_str(), ErrInfo,
|
||||
raw_fd_ostream::F_Binary);
|
||||
|
||||
|
||||
if (!ErrInfo.empty()) {
|
||||
errs() << "Error opening bitcode file: " << inputFilename.str() << "\n";
|
||||
return 1;
|
||||
}
|
||||
WriteBitcodeToFile(Program, InFile.os());
|
||||
InFile.os().close();
|
||||
if (InFile.os().has_error()) {
|
||||
errs() << "Error writing bitcode file: " << inputFilename.str() << "\n";
|
||||
InFile.os().clear_error();
|
||||
return 1;
|
||||
}
|
||||
|
||||
sys::Path tool = PrependMainExecutablePath("opt", getToolName(),
|
||||
(void*)"opt");
|
||||
if (tool.empty()) {
|
||||
errs() << "Cannot find `opt' in executable directory!\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Ok, everything that could go wrong before running opt is done.
|
||||
InFile.keep();
|
||||
|
||||
// setup the child process' arguments
|
||||
SmallVector<const char*, 8> Args;
|
||||
std::string Opt = tool.str();
|
||||
if (UseValgrind) {
|
||||
Args.push_back("valgrind");
|
||||
Args.push_back("--error-exitcode=1");
|
||||
Args.push_back("-q");
|
||||
Args.push_back(tool.c_str());
|
||||
} else
|
||||
Args.push_back(Opt.c_str());
|
||||
|
||||
Args.push_back("-o");
|
||||
Args.push_back(OutputFilename.c_str());
|
||||
for (unsigned i = 0, e = OptArgs.size(); i != e; ++i)
|
||||
Args.push_back(OptArgs[i].c_str());
|
||||
std::vector<std::string> pass_args;
|
||||
for (unsigned i = 0, e = PluginLoader::getNumPlugins(); i != e; ++i) {
|
||||
pass_args.push_back( std::string("-load"));
|
||||
pass_args.push_back( PluginLoader::getPlugin(i));
|
||||
}
|
||||
for (std::vector<std::string>::const_iterator I = Passes.begin(),
|
||||
E = Passes.end(); I != E; ++I )
|
||||
pass_args.push_back( std::string("-") + (*I) );
|
||||
for (std::vector<std::string>::const_iterator I = pass_args.begin(),
|
||||
E = pass_args.end(); I != E; ++I )
|
||||
Args.push_back(I->c_str());
|
||||
Args.push_back(inputFilename.c_str());
|
||||
for (unsigned i = 0; i < NumExtraArgs; ++i)
|
||||
Args.push_back(*ExtraArgs);
|
||||
Args.push_back(0);
|
||||
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i = 0, e = Args.size()-1; i != e; ++i)
|
||||
errs() << " " << Args[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
|
||||
sys::Path prog;
|
||||
if (UseValgrind)
|
||||
prog = sys::Program::FindProgramByName("valgrind");
|
||||
else
|
||||
prog = tool;
|
||||
|
||||
// Redirect stdout and stderr to nowhere if SilencePasses is given
|
||||
sys::Path Nowhere;
|
||||
const sys::Path *Redirects[3] = {0, &Nowhere, &Nowhere};
|
||||
|
||||
int result = sys::Program::ExecuteAndWait(prog, Args.data(), 0,
|
||||
(SilencePasses ? Redirects : 0),
|
||||
Timeout, MemoryLimit, &ErrMsg);
|
||||
|
||||
// If we are supposed to delete the bitcode file or if the passes crashed,
|
||||
// remove it now. This may fail if the file was never created, but that's ok.
|
||||
if (DeleteOutput || result != 0)
|
||||
sys::Path(OutputFilename).eraseFromDisk();
|
||||
|
||||
// Remove the temporary input file as well
|
||||
inputFilename.eraseFromDisk();
|
||||
|
||||
if (!Quiet) {
|
||||
if (result == 0)
|
||||
outs() << "Success!\n";
|
||||
else if (result > 0)
|
||||
outs() << "Exited with error code '" << result << "'\n";
|
||||
else if (result < 0) {
|
||||
if (result == -1)
|
||||
outs() << "Execute failed: " << ErrMsg << "\n";
|
||||
else
|
||||
outs() << "Crashed: " << ErrMsg << "\n";
|
||||
}
|
||||
if (result & 0x01000000)
|
||||
outs() << "Dumped core\n";
|
||||
}
|
||||
|
||||
// Was the child successful?
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
|
||||
/// runPassesOn - Carefully run the specified set of pass on the specified
|
||||
/// module, returning the transformed module on success, or a null pointer on
|
||||
/// failure.
|
||||
Module *BugDriver::runPassesOn(Module *M,
|
||||
const std::vector<std::string> &Passes,
|
||||
bool AutoDebugCrashes, unsigned NumExtraArgs,
|
||||
const char * const *ExtraArgs) {
|
||||
std::string BitcodeResult;
|
||||
if (runPasses(M, Passes, BitcodeResult, false/*delete*/, true/*quiet*/,
|
||||
NumExtraArgs, ExtraArgs)) {
|
||||
if (AutoDebugCrashes) {
|
||||
errs() << " Error running this sequence of passes"
|
||||
<< " on the input program!\n";
|
||||
delete swapProgramIn(M);
|
||||
EmitProgressBitcode(M, "pass-error", false);
|
||||
exit(debugOptimizerCrash());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Module *Ret = ParseInputFile(BitcodeResult, Context);
|
||||
if (Ret == 0) {
|
||||
errs() << getToolName() << ": Error reading bitcode file '"
|
||||
<< BitcodeResult << "'!\n";
|
||||
exit(1);
|
||||
}
|
||||
sys::Path(BitcodeResult).eraseFromDisk(); // No longer need the file on disk
|
||||
return Ret;
|
||||
}
|
977
contrib/llvm/tools/bugpoint/ToolRunner.cpp
Normal file
977
contrib/llvm/tools/bugpoint/ToolRunner.cpp
Normal file
@ -0,0 +1,977 @@
|
||||
//===-- ToolRunner.cpp ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the interfaces described in the ToolRunner.h file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "toolrunner"
|
||||
#include "ToolRunner.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Config/config.h" // for HAVE_LINK_R
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
cl::opt<bool>
|
||||
SaveTemps("save-temps", cl::init(false), cl::desc("Save temporary files"));
|
||||
}
|
||||
|
||||
namespace {
|
||||
cl::opt<std::string>
|
||||
RemoteClient("remote-client",
|
||||
cl::desc("Remote execution client (rsh/ssh)"));
|
||||
|
||||
cl::opt<std::string>
|
||||
RemoteHost("remote-host",
|
||||
cl::desc("Remote execution (rsh/ssh) host"));
|
||||
|
||||
cl::opt<std::string>
|
||||
RemotePort("remote-port",
|
||||
cl::desc("Remote execution (rsh/ssh) port"));
|
||||
|
||||
cl::opt<std::string>
|
||||
RemoteUser("remote-user",
|
||||
cl::desc("Remote execution (rsh/ssh) user id"));
|
||||
|
||||
cl::opt<std::string>
|
||||
RemoteExtra("remote-extra-options",
|
||||
cl::desc("Remote execution (rsh/ssh) extra options"));
|
||||
}
|
||||
|
||||
/// RunProgramWithTimeout - This function provides an alternate interface
|
||||
/// to the sys::Program::ExecuteAndWait interface.
|
||||
/// @see sys::Program::ExecuteAndWait
|
||||
static int RunProgramWithTimeout(const sys::Path &ProgramPath,
|
||||
const char **Args,
|
||||
const sys::Path &StdInFile,
|
||||
const sys::Path &StdOutFile,
|
||||
const sys::Path &StdErrFile,
|
||||
unsigned NumSeconds = 0,
|
||||
unsigned MemoryLimit = 0,
|
||||
std::string *ErrMsg = 0) {
|
||||
const sys::Path* redirects[3];
|
||||
redirects[0] = &StdInFile;
|
||||
redirects[1] = &StdOutFile;
|
||||
redirects[2] = &StdErrFile;
|
||||
|
||||
#if 0 // For debug purposes
|
||||
{
|
||||
errs() << "RUN:";
|
||||
for (unsigned i = 0; Args[i]; ++i)
|
||||
errs() << " " << Args[i];
|
||||
errs() << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
return
|
||||
sys::Program::ExecuteAndWait(ProgramPath, Args, 0, redirects,
|
||||
NumSeconds, MemoryLimit, ErrMsg);
|
||||
}
|
||||
|
||||
/// RunProgramRemotelyWithTimeout - This function runs the given program
|
||||
/// remotely using the given remote client and the sys::Program::ExecuteAndWait.
|
||||
/// Returns the remote program exit code or reports a remote client error if it
|
||||
/// fails. Remote client is required to return 255 if it failed or program exit
|
||||
/// code otherwise.
|
||||
/// @see sys::Program::ExecuteAndWait
|
||||
static int RunProgramRemotelyWithTimeout(const sys::Path &RemoteClientPath,
|
||||
const char **Args,
|
||||
const sys::Path &StdInFile,
|
||||
const sys::Path &StdOutFile,
|
||||
const sys::Path &StdErrFile,
|
||||
unsigned NumSeconds = 0,
|
||||
unsigned MemoryLimit = 0) {
|
||||
const sys::Path* redirects[3];
|
||||
redirects[0] = &StdInFile;
|
||||
redirects[1] = &StdOutFile;
|
||||
redirects[2] = &StdErrFile;
|
||||
|
||||
#if 0 // For debug purposes
|
||||
{
|
||||
errs() << "RUN:";
|
||||
for (unsigned i = 0; Args[i]; ++i)
|
||||
errs() << " " << Args[i];
|
||||
errs() << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Run the program remotely with the remote client
|
||||
int ReturnCode = sys::Program::ExecuteAndWait(RemoteClientPath, Args,
|
||||
0, redirects, NumSeconds, MemoryLimit);
|
||||
|
||||
// Has the remote client fail?
|
||||
if (255 == ReturnCode) {
|
||||
std::ostringstream OS;
|
||||
OS << "\nError running remote client:\n ";
|
||||
for (const char **Arg = Args; *Arg; ++Arg)
|
||||
OS << " " << *Arg;
|
||||
OS << "\n";
|
||||
|
||||
// The error message is in the output file, let's print it out from there.
|
||||
std::ifstream ErrorFile(StdOutFile.c_str());
|
||||
if (ErrorFile) {
|
||||
std::copy(std::istreambuf_iterator<char>(ErrorFile),
|
||||
std::istreambuf_iterator<char>(),
|
||||
std::ostreambuf_iterator<char>(OS));
|
||||
ErrorFile.close();
|
||||
}
|
||||
|
||||
errs() << OS;
|
||||
}
|
||||
|
||||
return ReturnCode;
|
||||
}
|
||||
|
||||
static std::string ProcessFailure(sys::Path ProgPath, const char** Args,
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0) {
|
||||
std::ostringstream OS;
|
||||
OS << "\nError running tool:\n ";
|
||||
for (const char **Arg = Args; *Arg; ++Arg)
|
||||
OS << " " << *Arg;
|
||||
OS << "\n";
|
||||
|
||||
// Rerun the compiler, capturing any error messages to print them.
|
||||
sys::Path ErrorFilename("bugpoint.program_error_messages");
|
||||
std::string ErrMsg;
|
||||
if (ErrorFilename.makeUnique(true, &ErrMsg)) {
|
||||
errs() << "Error making unique filename: " << ErrMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
RunProgramWithTimeout(ProgPath, Args, sys::Path(""), ErrorFilename,
|
||||
ErrorFilename, Timeout, MemoryLimit);
|
||||
// FIXME: check return code ?
|
||||
|
||||
// Print out the error messages generated by GCC if possible...
|
||||
std::ifstream ErrorFile(ErrorFilename.c_str());
|
||||
if (ErrorFile) {
|
||||
std::copy(std::istreambuf_iterator<char>(ErrorFile),
|
||||
std::istreambuf_iterator<char>(),
|
||||
std::ostreambuf_iterator<char>(OS));
|
||||
ErrorFile.close();
|
||||
}
|
||||
|
||||
ErrorFilename.eraseFromDisk();
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// LLI Implementation of AbstractIntepreter interface
|
||||
//
|
||||
namespace {
|
||||
class LLI : public AbstractInterpreter {
|
||||
std::string LLIPath; // The path to the LLI executable
|
||||
std::vector<std::string> ToolArgs; // Args to pass to LLI
|
||||
public:
|
||||
LLI(const std::string &Path, const std::vector<std::string> *Args)
|
||||
: LLIPath(Path) {
|
||||
ToolArgs.clear ();
|
||||
if (Args) { ToolArgs = *Args; }
|
||||
}
|
||||
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs,
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
};
|
||||
}
|
||||
|
||||
int LLI::ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs,
|
||||
const std::vector<std::string> &SharedLibs,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
std::vector<const char*> LLIArgs;
|
||||
LLIArgs.push_back(LLIPath.c_str());
|
||||
LLIArgs.push_back("-force-interpreter=true");
|
||||
|
||||
for (std::vector<std::string>::const_iterator i = SharedLibs.begin(),
|
||||
e = SharedLibs.end(); i != e; ++i) {
|
||||
LLIArgs.push_back("-load");
|
||||
LLIArgs.push_back((*i).c_str());
|
||||
}
|
||||
|
||||
// Add any extra LLI args.
|
||||
for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
|
||||
LLIArgs.push_back(ToolArgs[i].c_str());
|
||||
|
||||
LLIArgs.push_back(Bitcode.c_str());
|
||||
// Add optional parameters to the running program from Argv
|
||||
for (unsigned i=0, e = Args.size(); i != e; ++i)
|
||||
LLIArgs.push_back(Args[i].c_str());
|
||||
LLIArgs.push_back(0);
|
||||
|
||||
outs() << "<lli>"; outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i=0, e = LLIArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << LLIArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
return RunProgramWithTimeout(sys::Path(LLIPath), &LLIArgs[0],
|
||||
sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
|
||||
Timeout, MemoryLimit, Error);
|
||||
}
|
||||
|
||||
// LLI create method - Try to find the LLI executable
|
||||
AbstractInterpreter *AbstractInterpreter::createLLI(const char *Argv0,
|
||||
std::string &Message,
|
||||
const std::vector<std::string> *ToolArgs) {
|
||||
std::string LLIPath =
|
||||
PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createLLI).str();
|
||||
if (!LLIPath.empty()) {
|
||||
Message = "Found lli: " + LLIPath + "\n";
|
||||
return new LLI(LLIPath, ToolArgs);
|
||||
}
|
||||
|
||||
Message = "Cannot find `lli' in executable directory!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Custom compiler command implementation of AbstractIntepreter interface
|
||||
//
|
||||
// Allows using a custom command for compiling the bitcode, thus allows, for
|
||||
// example, to compile a bitcode fragment without linking or executing, then
|
||||
// using a custom wrapper script to check for compiler errors.
|
||||
namespace {
|
||||
class CustomCompiler : public AbstractInterpreter {
|
||||
std::string CompilerCommand;
|
||||
std::vector<std::string> CompilerArgs;
|
||||
public:
|
||||
CustomCompiler(
|
||||
const std::string &CompilerCmd, std::vector<std::string> CompArgs) :
|
||||
CompilerCommand(CompilerCmd), CompilerArgs(CompArgs) {}
|
||||
|
||||
virtual void compileProgram(const std::string &Bitcode,
|
||||
std::string *Error,
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0) {
|
||||
*Error = "Execution not supported with -compile-custom";
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void CustomCompiler::compileProgram(const std::string &Bitcode,
|
||||
std::string *Error,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
|
||||
std::vector<const char*> ProgramArgs;
|
||||
ProgramArgs.push_back(CompilerCommand.c_str());
|
||||
|
||||
for (std::size_t i = 0; i < CompilerArgs.size(); ++i)
|
||||
ProgramArgs.push_back(CompilerArgs.at(i).c_str());
|
||||
ProgramArgs.push_back(Bitcode.c_str());
|
||||
ProgramArgs.push_back(0);
|
||||
|
||||
// Add optional parameters to the running program from Argv
|
||||
for (unsigned i = 0, e = CompilerArgs.size(); i != e; ++i)
|
||||
ProgramArgs.push_back(CompilerArgs[i].c_str());
|
||||
|
||||
if (RunProgramWithTimeout( sys::Path(CompilerCommand), &ProgramArgs[0],
|
||||
sys::Path(), sys::Path(), sys::Path(),
|
||||
Timeout, MemoryLimit, Error))
|
||||
*Error = ProcessFailure(sys::Path(CompilerCommand), &ProgramArgs[0],
|
||||
Timeout, MemoryLimit);
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// Custom execution command implementation of AbstractIntepreter interface
|
||||
//
|
||||
// Allows using a custom command for executing the bitcode, thus allows,
|
||||
// for example, to invoke a cross compiler for code generation followed by
|
||||
// a simulator that executes the generated binary.
|
||||
namespace {
|
||||
class CustomExecutor : public AbstractInterpreter {
|
||||
std::string ExecutionCommand;
|
||||
std::vector<std::string> ExecutorArgs;
|
||||
public:
|
||||
CustomExecutor(
|
||||
const std::string &ExecutionCmd, std::vector<std::string> ExecArgs) :
|
||||
ExecutionCommand(ExecutionCmd), ExecutorArgs(ExecArgs) {}
|
||||
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs,
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
};
|
||||
}
|
||||
|
||||
int CustomExecutor::ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs,
|
||||
const std::vector<std::string> &SharedLibs,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
|
||||
std::vector<const char*> ProgramArgs;
|
||||
ProgramArgs.push_back(ExecutionCommand.c_str());
|
||||
|
||||
for (std::size_t i = 0; i < ExecutorArgs.size(); ++i)
|
||||
ProgramArgs.push_back(ExecutorArgs.at(i).c_str());
|
||||
ProgramArgs.push_back(Bitcode.c_str());
|
||||
ProgramArgs.push_back(0);
|
||||
|
||||
// Add optional parameters to the running program from Argv
|
||||
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||
ProgramArgs.push_back(Args[i].c_str());
|
||||
|
||||
return RunProgramWithTimeout(
|
||||
sys::Path(ExecutionCommand),
|
||||
&ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile),
|
||||
sys::Path(OutputFile), Timeout, MemoryLimit, Error);
|
||||
}
|
||||
|
||||
// Tokenize the CommandLine to the command and the args to allow
|
||||
// defining a full command line as the command instead of just the
|
||||
// executed program. We cannot just pass the whole string after the command
|
||||
// as a single argument because then program sees only a single
|
||||
// command line argument (with spaces in it: "foo bar" instead
|
||||
// of "foo" and "bar").
|
||||
//
|
||||
// code borrowed from:
|
||||
// http://oopweb.com/CPP/Documents/CPPHOWTO/Volume/C++Programming-HOWTO-7.html
|
||||
static void lexCommand(std::string &Message, const std::string &CommandLine,
|
||||
std::string &CmdPath, std::vector<std::string> Args) {
|
||||
|
||||
std::string Command = "";
|
||||
std::string delimiters = " ";
|
||||
|
||||
std::string::size_type lastPos = CommandLine.find_first_not_of(delimiters, 0);
|
||||
std::string::size_type pos = CommandLine.find_first_of(delimiters, lastPos);
|
||||
|
||||
while (std::string::npos != pos || std::string::npos != lastPos) {
|
||||
std::string token = CommandLine.substr(lastPos, pos - lastPos);
|
||||
if (Command == "")
|
||||
Command = token;
|
||||
else
|
||||
Args.push_back(token);
|
||||
// Skip delimiters. Note the "not_of"
|
||||
lastPos = CommandLine.find_first_not_of(delimiters, pos);
|
||||
// Find next "non-delimiter"
|
||||
pos = CommandLine.find_first_of(delimiters, lastPos);
|
||||
}
|
||||
|
||||
CmdPath = sys::Program::FindProgramByName(Command).str();
|
||||
if (CmdPath.empty()) {
|
||||
Message =
|
||||
std::string("Cannot find '") + Command +
|
||||
"' in PATH!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
Message = "Found command in: " + CmdPath + "\n";
|
||||
}
|
||||
|
||||
// Custom execution environment create method, takes the execution command
|
||||
// as arguments
|
||||
AbstractInterpreter *AbstractInterpreter::createCustomCompiler(
|
||||
std::string &Message,
|
||||
const std::string &CompileCommandLine) {
|
||||
|
||||
std::string CmdPath;
|
||||
std::vector<std::string> Args;
|
||||
lexCommand(Message, CompileCommandLine, CmdPath, Args);
|
||||
if (CmdPath.empty())
|
||||
return 0;
|
||||
|
||||
return new CustomCompiler(CmdPath, Args);
|
||||
}
|
||||
|
||||
// Custom execution environment create method, takes the execution command
|
||||
// as arguments
|
||||
AbstractInterpreter *AbstractInterpreter::createCustomExecutor(
|
||||
std::string &Message,
|
||||
const std::string &ExecCommandLine) {
|
||||
|
||||
|
||||
std::string CmdPath;
|
||||
std::vector<std::string> Args;
|
||||
lexCommand(Message, ExecCommandLine, CmdPath, Args);
|
||||
if (CmdPath.empty())
|
||||
return 0;
|
||||
|
||||
return new CustomExecutor(CmdPath, Args);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LLC Implementation of AbstractIntepreter interface
|
||||
//
|
||||
GCC::FileType LLC::OutputCode(const std::string &Bitcode,
|
||||
sys::Path &OutputAsmFile, std::string &Error,
|
||||
unsigned Timeout, unsigned MemoryLimit) {
|
||||
const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s");
|
||||
sys::Path uniqueFile(Bitcode + Suffix);
|
||||
std::string ErrMsg;
|
||||
if (uniqueFile.makeUnique(true, &ErrMsg)) {
|
||||
errs() << "Error making unique filename: " << ErrMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
OutputAsmFile = uniqueFile;
|
||||
std::vector<const char *> LLCArgs;
|
||||
LLCArgs.push_back(LLCPath.c_str());
|
||||
|
||||
// Add any extra LLC args.
|
||||
for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
|
||||
LLCArgs.push_back(ToolArgs[i].c_str());
|
||||
|
||||
LLCArgs.push_back("-o");
|
||||
LLCArgs.push_back(OutputAsmFile.c_str()); // Output to the Asm file
|
||||
LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode
|
||||
|
||||
if (UseIntegratedAssembler)
|
||||
LLCArgs.push_back("-filetype=obj");
|
||||
|
||||
LLCArgs.push_back (0);
|
||||
|
||||
outs() << (UseIntegratedAssembler ? "<llc-ia>" : "<llc>");
|
||||
outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << LLCArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
if (RunProgramWithTimeout(sys::Path(LLCPath), &LLCArgs[0],
|
||||
sys::Path(), sys::Path(), sys::Path(),
|
||||
Timeout, MemoryLimit))
|
||||
Error = ProcessFailure(sys::Path(LLCPath), &LLCArgs[0],
|
||||
Timeout, MemoryLimit);
|
||||
return UseIntegratedAssembler ? GCC::ObjectFile : GCC::AsmFile;
|
||||
}
|
||||
|
||||
void LLC::compileProgram(const std::string &Bitcode, std::string *Error,
|
||||
unsigned Timeout, unsigned MemoryLimit) {
|
||||
sys::Path OutputAsmFile;
|
||||
OutputCode(Bitcode, OutputAsmFile, *Error, Timeout, MemoryLimit);
|
||||
OutputAsmFile.eraseFromDisk();
|
||||
}
|
||||
|
||||
int LLC::ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &ArgsForGCC,
|
||||
const std::vector<std::string> &SharedLibs,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
|
||||
sys::Path OutputAsmFile;
|
||||
GCC::FileType FileKind = OutputCode(Bitcode, OutputAsmFile, *Error, Timeout,
|
||||
MemoryLimit);
|
||||
FileRemover OutFileRemover(OutputAsmFile.str(), !SaveTemps);
|
||||
|
||||
std::vector<std::string> GCCArgs(ArgsForGCC);
|
||||
GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end());
|
||||
|
||||
// Assuming LLC worked, compile the result with GCC and run it.
|
||||
return gcc->ExecuteProgram(OutputAsmFile.str(), Args, FileKind,
|
||||
InputFile, OutputFile, Error, GCCArgs,
|
||||
Timeout, MemoryLimit);
|
||||
}
|
||||
|
||||
/// createLLC - Try to find the LLC executable
|
||||
///
|
||||
LLC *AbstractInterpreter::createLLC(const char *Argv0,
|
||||
std::string &Message,
|
||||
const std::string &GCCBinary,
|
||||
const std::vector<std::string> *Args,
|
||||
const std::vector<std::string> *GCCArgs,
|
||||
bool UseIntegratedAssembler) {
|
||||
std::string LLCPath =
|
||||
PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createLLC).str();
|
||||
if (LLCPath.empty()) {
|
||||
Message = "Cannot find `llc' in executable directory!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
Message = "Found llc: " + LLCPath + "\n";
|
||||
GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs);
|
||||
if (!gcc) {
|
||||
errs() << Message << "\n";
|
||||
exit(1);
|
||||
}
|
||||
return new LLC(LLCPath, gcc, Args, UseIntegratedAssembler);
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// JIT Implementation of AbstractIntepreter interface
|
||||
//
|
||||
namespace {
|
||||
class JIT : public AbstractInterpreter {
|
||||
std::string LLIPath; // The path to the LLI executable
|
||||
std::vector<std::string> ToolArgs; // Args to pass to LLI
|
||||
public:
|
||||
JIT(const std::string &Path, const std::vector<std::string> *Args)
|
||||
: LLIPath(Path) {
|
||||
ToolArgs.clear ();
|
||||
if (Args) { ToolArgs = *Args; }
|
||||
}
|
||||
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
};
|
||||
}
|
||||
|
||||
int JIT::ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs,
|
||||
const std::vector<std::string> &SharedLibs,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
// Construct a vector of parameters, incorporating those from the command-line
|
||||
std::vector<const char*> JITArgs;
|
||||
JITArgs.push_back(LLIPath.c_str());
|
||||
JITArgs.push_back("-force-interpreter=false");
|
||||
|
||||
// Add any extra LLI args.
|
||||
for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
|
||||
JITArgs.push_back(ToolArgs[i].c_str());
|
||||
|
||||
for (unsigned i = 0, e = SharedLibs.size(); i != e; ++i) {
|
||||
JITArgs.push_back("-load");
|
||||
JITArgs.push_back(SharedLibs[i].c_str());
|
||||
}
|
||||
JITArgs.push_back(Bitcode.c_str());
|
||||
// Add optional parameters to the running program from Argv
|
||||
for (unsigned i=0, e = Args.size(); i != e; ++i)
|
||||
JITArgs.push_back(Args[i].c_str());
|
||||
JITArgs.push_back(0);
|
||||
|
||||
outs() << "<jit>"; outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i=0, e = JITArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << JITArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
DEBUG(errs() << "\nSending output to " << OutputFile << "\n");
|
||||
return RunProgramWithTimeout(sys::Path(LLIPath), &JITArgs[0],
|
||||
sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
|
||||
Timeout, MemoryLimit, Error);
|
||||
}
|
||||
|
||||
/// createJIT - Try to find the LLI executable
|
||||
///
|
||||
AbstractInterpreter *AbstractInterpreter::createJIT(const char *Argv0,
|
||||
std::string &Message, const std::vector<std::string> *Args) {
|
||||
std::string LLIPath =
|
||||
PrependMainExecutablePath("lli", Argv0, (void *)(intptr_t)&createJIT).str();
|
||||
if (!LLIPath.empty()) {
|
||||
Message = "Found lli: " + LLIPath + "\n";
|
||||
return new JIT(LLIPath, Args);
|
||||
}
|
||||
|
||||
Message = "Cannot find `lli' in executable directory!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
GCC::FileType CBE::OutputCode(const std::string &Bitcode,
|
||||
sys::Path &OutputCFile, std::string &Error,
|
||||
unsigned Timeout, unsigned MemoryLimit) {
|
||||
sys::Path uniqueFile(Bitcode+".cbe.c");
|
||||
std::string ErrMsg;
|
||||
if (uniqueFile.makeUnique(true, &ErrMsg)) {
|
||||
errs() << "Error making unique filename: " << ErrMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
OutputCFile = uniqueFile;
|
||||
std::vector<const char *> LLCArgs;
|
||||
LLCArgs.push_back(LLCPath.c_str());
|
||||
|
||||
// Add any extra LLC args.
|
||||
for (unsigned i = 0, e = ToolArgs.size(); i != e; ++i)
|
||||
LLCArgs.push_back(ToolArgs[i].c_str());
|
||||
|
||||
LLCArgs.push_back("-o");
|
||||
LLCArgs.push_back(OutputCFile.c_str()); // Output to the C file
|
||||
LLCArgs.push_back("-march=c"); // Output C language
|
||||
LLCArgs.push_back(Bitcode.c_str()); // This is the input bitcode
|
||||
LLCArgs.push_back(0);
|
||||
|
||||
outs() << "<cbe>"; outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i = 0, e = LLCArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << LLCArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
if (RunProgramWithTimeout(LLCPath, &LLCArgs[0], sys::Path(), sys::Path(),
|
||||
sys::Path(), Timeout, MemoryLimit))
|
||||
Error = ProcessFailure(LLCPath, &LLCArgs[0], Timeout, MemoryLimit);
|
||||
return GCC::CFile;
|
||||
}
|
||||
|
||||
void CBE::compileProgram(const std::string &Bitcode, std::string *Error,
|
||||
unsigned Timeout, unsigned MemoryLimit) {
|
||||
sys::Path OutputCFile;
|
||||
OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit);
|
||||
OutputCFile.eraseFromDisk();
|
||||
}
|
||||
|
||||
int CBE::ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &ArgsForGCC,
|
||||
const std::vector<std::string> &SharedLibs,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
sys::Path OutputCFile;
|
||||
OutputCode(Bitcode, OutputCFile, *Error, Timeout, MemoryLimit);
|
||||
|
||||
FileRemover CFileRemove(OutputCFile.str(), !SaveTemps);
|
||||
|
||||
std::vector<std::string> GCCArgs(ArgsForGCC);
|
||||
GCCArgs.insert(GCCArgs.end(), SharedLibs.begin(), SharedLibs.end());
|
||||
|
||||
return gcc->ExecuteProgram(OutputCFile.str(), Args, GCC::CFile,
|
||||
InputFile, OutputFile, Error, GCCArgs,
|
||||
Timeout, MemoryLimit);
|
||||
}
|
||||
|
||||
/// createCBE - Try to find the 'llc' executable
|
||||
///
|
||||
CBE *AbstractInterpreter::createCBE(const char *Argv0,
|
||||
std::string &Message,
|
||||
const std::string &GCCBinary,
|
||||
const std::vector<std::string> *Args,
|
||||
const std::vector<std::string> *GCCArgs) {
|
||||
sys::Path LLCPath =
|
||||
PrependMainExecutablePath("llc", Argv0, (void *)(intptr_t)&createCBE);
|
||||
if (LLCPath.isEmpty()) {
|
||||
Message =
|
||||
"Cannot find `llc' in executable directory!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
Message = "Found llc: " + LLCPath.str() + "\n";
|
||||
GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs);
|
||||
if (!gcc) {
|
||||
errs() << Message << "\n";
|
||||
exit(1);
|
||||
}
|
||||
return new CBE(LLCPath, gcc, Args);
|
||||
}
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// GCC abstraction
|
||||
//
|
||||
|
||||
static bool IsARMArchitecture(std::vector<const char*> Args) {
|
||||
for (std::vector<const char*>::const_iterator
|
||||
I = Args.begin(), E = Args.end(); I != E; ++I) {
|
||||
if (StringRef(*I).equals_lower("-arch")) {
|
||||
++I;
|
||||
if (I != E && StringRef(*I).substr(0, strlen("arm")).equals_lower("arm"))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GCC::ExecuteProgram(const std::string &ProgramFile,
|
||||
const std::vector<std::string> &Args,
|
||||
FileType fileType,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &ArgsForGCC,
|
||||
unsigned Timeout,
|
||||
unsigned MemoryLimit) {
|
||||
std::vector<const char*> GCCArgs;
|
||||
|
||||
GCCArgs.push_back(GCCPath.c_str());
|
||||
|
||||
if (TargetTriple.getArch() == Triple::x86)
|
||||
GCCArgs.push_back("-m32");
|
||||
|
||||
for (std::vector<std::string>::const_iterator
|
||||
I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I)
|
||||
GCCArgs.push_back(I->c_str());
|
||||
|
||||
// Specify -x explicitly in case the extension is wonky
|
||||
if (fileType != ObjectFile) {
|
||||
GCCArgs.push_back("-x");
|
||||
if (fileType == CFile) {
|
||||
GCCArgs.push_back("c");
|
||||
GCCArgs.push_back("-fno-strict-aliasing");
|
||||
} else {
|
||||
GCCArgs.push_back("assembler");
|
||||
|
||||
// For ARM architectures we don't want this flag. bugpoint isn't
|
||||
// explicitly told what architecture it is working on, so we get
|
||||
// it from gcc flags
|
||||
if (TargetTriple.isOSDarwin() && !IsARMArchitecture(GCCArgs))
|
||||
GCCArgs.push_back("-force_cpusubtype_ALL");
|
||||
}
|
||||
}
|
||||
|
||||
GCCArgs.push_back(ProgramFile.c_str()); // Specify the input filename.
|
||||
|
||||
GCCArgs.push_back("-x");
|
||||
GCCArgs.push_back("none");
|
||||
GCCArgs.push_back("-o");
|
||||
sys::Path OutputBinary (ProgramFile+".gcc.exe");
|
||||
std::string ErrMsg;
|
||||
if (OutputBinary.makeUnique(true, &ErrMsg)) {
|
||||
errs() << "Error making unique filename: " << ErrMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
GCCArgs.push_back(OutputBinary.c_str()); // Output to the right file...
|
||||
|
||||
// Add any arguments intended for GCC. We locate them here because this is
|
||||
// most likely -L and -l options that need to come before other libraries but
|
||||
// after the source. Other options won't be sensitive to placement on the
|
||||
// command line, so this should be safe.
|
||||
for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i)
|
||||
GCCArgs.push_back(ArgsForGCC[i].c_str());
|
||||
|
||||
GCCArgs.push_back("-lm"); // Hard-code the math library...
|
||||
GCCArgs.push_back("-O2"); // Optimize the program a bit...
|
||||
#if defined (HAVE_LINK_R)
|
||||
GCCArgs.push_back("-Wl,-R."); // Search this dir for .so files
|
||||
#endif
|
||||
if (TargetTriple.getArch() == Triple::sparc)
|
||||
GCCArgs.push_back("-mcpu=v9");
|
||||
GCCArgs.push_back(0); // NULL terminator
|
||||
|
||||
outs() << "<gcc>"; outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << GCCArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
|
||||
sys::Path())) {
|
||||
*Error = ProcessFailure(GCCPath, &GCCArgs[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<const char*> ProgramArgs;
|
||||
|
||||
// Declared here so that the destructor only runs after
|
||||
// ProgramArgs is used.
|
||||
std::string Exec;
|
||||
|
||||
if (RemoteClientPath.isEmpty())
|
||||
ProgramArgs.push_back(OutputBinary.c_str());
|
||||
else {
|
||||
ProgramArgs.push_back(RemoteClientPath.c_str());
|
||||
ProgramArgs.push_back(RemoteHost.c_str());
|
||||
if (!RemoteUser.empty()) {
|
||||
ProgramArgs.push_back("-l");
|
||||
ProgramArgs.push_back(RemoteUser.c_str());
|
||||
}
|
||||
if (!RemotePort.empty()) {
|
||||
ProgramArgs.push_back("-p");
|
||||
ProgramArgs.push_back(RemotePort.c_str());
|
||||
}
|
||||
if (!RemoteExtra.empty()) {
|
||||
ProgramArgs.push_back(RemoteExtra.c_str());
|
||||
}
|
||||
|
||||
// Full path to the binary. We need to cd to the exec directory because
|
||||
// there is a dylib there that the exec expects to find in the CWD
|
||||
char* env_pwd = getenv("PWD");
|
||||
Exec = "cd ";
|
||||
Exec += env_pwd;
|
||||
Exec += "; ./";
|
||||
Exec += OutputBinary.c_str();
|
||||
ProgramArgs.push_back(Exec.c_str());
|
||||
}
|
||||
|
||||
// Add optional parameters to the running program from Argv
|
||||
for (unsigned i = 0, e = Args.size(); i != e; ++i)
|
||||
ProgramArgs.push_back(Args[i].c_str());
|
||||
ProgramArgs.push_back(0); // NULL terminator
|
||||
|
||||
// Now that we have a binary, run it!
|
||||
outs() << "<program>"; outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i = 0, e = ProgramArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << ProgramArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
|
||||
FileRemover OutputBinaryRemover(OutputBinary.str(), !SaveTemps);
|
||||
|
||||
if (RemoteClientPath.isEmpty()) {
|
||||
DEBUG(errs() << "<run locally>");
|
||||
int ExitCode = RunProgramWithTimeout(OutputBinary, &ProgramArgs[0],
|
||||
sys::Path(InputFile), sys::Path(OutputFile), sys::Path(OutputFile),
|
||||
Timeout, MemoryLimit, Error);
|
||||
// Treat a signal (usually SIGSEGV) or timeout as part of the program output
|
||||
// so that crash-causing miscompilation is handled seamlessly.
|
||||
if (ExitCode < -1) {
|
||||
std::ofstream outFile(OutputFile.c_str(), std::ios_base::app);
|
||||
outFile << *Error << '\n';
|
||||
outFile.close();
|
||||
Error->clear();
|
||||
}
|
||||
return ExitCode;
|
||||
} else {
|
||||
outs() << "<run remotely>"; outs().flush();
|
||||
return RunProgramRemotelyWithTimeout(sys::Path(RemoteClientPath),
|
||||
&ProgramArgs[0], sys::Path(InputFile), sys::Path(OutputFile),
|
||||
sys::Path(OutputFile), Timeout, MemoryLimit);
|
||||
}
|
||||
}
|
||||
|
||||
int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||
std::string &OutputFile,
|
||||
const std::vector<std::string> &ArgsForGCC,
|
||||
std::string &Error) {
|
||||
sys::Path uniqueFilename(InputFile+LTDL_SHLIB_EXT);
|
||||
std::string ErrMsg;
|
||||
if (uniqueFilename.makeUnique(true, &ErrMsg)) {
|
||||
errs() << "Error making unique filename: " << ErrMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
OutputFile = uniqueFilename.str();
|
||||
|
||||
std::vector<const char*> GCCArgs;
|
||||
|
||||
GCCArgs.push_back(GCCPath.c_str());
|
||||
|
||||
if (TargetTriple.getArch() == Triple::x86)
|
||||
GCCArgs.push_back("-m32");
|
||||
|
||||
for (std::vector<std::string>::const_iterator
|
||||
I = gccArgs.begin(), E = gccArgs.end(); I != E; ++I)
|
||||
GCCArgs.push_back(I->c_str());
|
||||
|
||||
// Compile the C/asm file into a shared object
|
||||
if (fileType != ObjectFile) {
|
||||
GCCArgs.push_back("-x");
|
||||
GCCArgs.push_back(fileType == AsmFile ? "assembler" : "c");
|
||||
}
|
||||
GCCArgs.push_back("-fno-strict-aliasing");
|
||||
GCCArgs.push_back(InputFile.c_str()); // Specify the input filename.
|
||||
GCCArgs.push_back("-x");
|
||||
GCCArgs.push_back("none");
|
||||
if (TargetTriple.getArch() == Triple::sparc)
|
||||
GCCArgs.push_back("-G"); // Compile a shared library, `-G' for Sparc
|
||||
else if (TargetTriple.isOSDarwin()) {
|
||||
// link all source files into a single module in data segment, rather than
|
||||
// generating blocks. dynamic_lookup requires that you set
|
||||
// MACOSX_DEPLOYMENT_TARGET=10.3 in your env. FIXME: it would be better for
|
||||
// bugpoint to just pass that in the environment of GCC.
|
||||
GCCArgs.push_back("-single_module");
|
||||
GCCArgs.push_back("-dynamiclib"); // `-dynamiclib' for MacOS X/PowerPC
|
||||
GCCArgs.push_back("-undefined");
|
||||
GCCArgs.push_back("dynamic_lookup");
|
||||
} else
|
||||
GCCArgs.push_back("-shared"); // `-shared' for Linux/X86, maybe others
|
||||
|
||||
if ((TargetTriple.getArch() == Triple::alpha) ||
|
||||
(TargetTriple.getArch() == Triple::x86_64))
|
||||
GCCArgs.push_back("-fPIC"); // Requires shared objs to contain PIC
|
||||
|
||||
if (TargetTriple.getArch() == Triple::sparc)
|
||||
GCCArgs.push_back("-mcpu=v9");
|
||||
|
||||
GCCArgs.push_back("-o");
|
||||
GCCArgs.push_back(OutputFile.c_str()); // Output to the right filename.
|
||||
GCCArgs.push_back("-O2"); // Optimize the program a bit.
|
||||
|
||||
|
||||
|
||||
// Add any arguments intended for GCC. We locate them here because this is
|
||||
// most likely -L and -l options that need to come before other libraries but
|
||||
// after the source. Other options won't be sensitive to placement on the
|
||||
// command line, so this should be safe.
|
||||
for (unsigned i = 0, e = ArgsForGCC.size(); i != e; ++i)
|
||||
GCCArgs.push_back(ArgsForGCC[i].c_str());
|
||||
GCCArgs.push_back(0); // NULL terminator
|
||||
|
||||
|
||||
|
||||
outs() << "<gcc>"; outs().flush();
|
||||
DEBUG(errs() << "\nAbout to run:\t";
|
||||
for (unsigned i = 0, e = GCCArgs.size()-1; i != e; ++i)
|
||||
errs() << " " << GCCArgs[i];
|
||||
errs() << "\n";
|
||||
);
|
||||
if (RunProgramWithTimeout(GCCPath, &GCCArgs[0], sys::Path(), sys::Path(),
|
||||
sys::Path())) {
|
||||
Error = ProcessFailure(GCCPath, &GCCArgs[0]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// create - Try to find the `gcc' executable
|
||||
///
|
||||
GCC *GCC::create(std::string &Message,
|
||||
const std::string &GCCBinary,
|
||||
const std::vector<std::string> *Args) {
|
||||
sys::Path GCCPath = sys::Program::FindProgramByName(GCCBinary);
|
||||
if (GCCPath.isEmpty()) {
|
||||
Message = "Cannot find `"+ GCCBinary +"' in PATH!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
sys::Path RemoteClientPath;
|
||||
if (!RemoteClient.empty())
|
||||
RemoteClientPath = sys::Program::FindProgramByName(RemoteClient);
|
||||
|
||||
Message = "Found gcc: " + GCCPath.str() + "\n";
|
||||
return new GCC(GCCPath, RemoteClientPath, Args);
|
||||
}
|
247
contrib/llvm/tools/bugpoint/ToolRunner.h
Normal file
247
contrib/llvm/tools/bugpoint/ToolRunner.h
Normal file
@ -0,0 +1,247 @@
|
||||
//===-- tools/bugpoint/ToolRunner.h -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file exposes an abstraction around a platform C compiler, used to
|
||||
// compile C and assembly code. It also exposes an "AbstractIntepreter"
|
||||
// interface, which is used to execute code using one of the LLVM execution
|
||||
// engines.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BUGPOINT_TOOLRUNNER_H
|
||||
#define BUGPOINT_TOOLRUNNER_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern cl::opt<bool> SaveTemps;
|
||||
extern Triple TargetTriple;
|
||||
|
||||
class CBE;
|
||||
class LLC;
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// GCC abstraction
|
||||
//
|
||||
class GCC {
|
||||
sys::Path GCCPath; // The path to the gcc executable.
|
||||
sys::Path RemoteClientPath; // The path to the rsh / ssh executable.
|
||||
std::vector<std::string> gccArgs; // GCC-specific arguments.
|
||||
GCC(const sys::Path &gccPath, const sys::Path &RemotePath,
|
||||
const std::vector<std::string> *GCCArgs)
|
||||
: GCCPath(gccPath), RemoteClientPath(RemotePath) {
|
||||
if (GCCArgs) gccArgs = *GCCArgs;
|
||||
}
|
||||
public:
|
||||
enum FileType { AsmFile, ObjectFile, CFile };
|
||||
|
||||
static GCC *create(std::string &Message,
|
||||
const std::string &GCCBinary,
|
||||
const std::vector<std::string> *Args);
|
||||
|
||||
/// ExecuteProgram - Execute the program specified by "ProgramFile" (which is
|
||||
/// either a .s file, or a .c file, specified by FileType), with the specified
|
||||
/// arguments. Standard input is specified with InputFile, and standard
|
||||
/// Output is captured to the specified OutputFile location. The SharedLibs
|
||||
/// option specifies optional native shared objects that can be loaded into
|
||||
/// the program for execution.
|
||||
///
|
||||
int ExecuteProgram(const std::string &ProgramFile,
|
||||
const std::vector<std::string> &Args,
|
||||
FileType fileType,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error = 0,
|
||||
const std::vector<std::string> &GCCArgs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
|
||||
/// MakeSharedObject - This compiles the specified file (which is either a .c
|
||||
/// file or a .s file) into a shared object.
|
||||
///
|
||||
int MakeSharedObject(const std::string &InputFile, FileType fileType,
|
||||
std::string &OutputFile,
|
||||
const std::vector<std::string> &ArgsForGCC,
|
||||
std::string &Error);
|
||||
};
|
||||
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
/// AbstractInterpreter Class - Subclasses of this class are used to execute
|
||||
/// LLVM bitcode in a variety of ways. This abstract interface hides this
|
||||
/// complexity behind a simple interface.
|
||||
///
|
||||
class AbstractInterpreter {
|
||||
public:
|
||||
static CBE *createCBE(const char *Argv0, std::string &Message,
|
||||
const std::string &GCCBinary,
|
||||
const std::vector<std::string> *Args = 0,
|
||||
const std::vector<std::string> *GCCArgs = 0);
|
||||
static LLC *createLLC(const char *Argv0, std::string &Message,
|
||||
const std::string &GCCBinary,
|
||||
const std::vector<std::string> *Args = 0,
|
||||
const std::vector<std::string> *GCCArgs = 0,
|
||||
bool UseIntegratedAssembler = false);
|
||||
|
||||
static AbstractInterpreter* createLLI(const char *Argv0, std::string &Message,
|
||||
const std::vector<std::string> *Args=0);
|
||||
|
||||
static AbstractInterpreter* createJIT(const char *Argv0, std::string &Message,
|
||||
const std::vector<std::string> *Args=0);
|
||||
|
||||
static AbstractInterpreter*
|
||||
createCustomCompiler(std::string &Message,
|
||||
const std::string &CompileCommandLine);
|
||||
|
||||
static AbstractInterpreter*
|
||||
createCustomExecutor(std::string &Message,
|
||||
const std::string &ExecCommandLine);
|
||||
|
||||
|
||||
virtual ~AbstractInterpreter() {}
|
||||
|
||||
/// compileProgram - Compile the specified program from bitcode to executable
|
||||
/// code. This does not produce any output, it is only used when debugging
|
||||
/// the code generator. It returns false if the code generator fails.
|
||||
virtual void compileProgram(const std::string &Bitcode, std::string *Error,
|
||||
unsigned Timeout = 0, unsigned MemoryLimit = 0) {}
|
||||
|
||||
/// OutputCode - Compile the specified program from bitcode to code
|
||||
/// understood by the GCC driver (either C or asm). If the code generator
|
||||
/// fails, it sets Error, otherwise, this function returns the type of code
|
||||
/// emitted.
|
||||
virtual GCC::FileType OutputCode(const std::string &Bitcode,
|
||||
sys::Path &OutFile, std::string &Error,
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0) {
|
||||
Error = "OutputCode not supported by this AbstractInterpreter!";
|
||||
return GCC::AsmFile;
|
||||
}
|
||||
|
||||
/// ExecuteProgram - Run the specified bitcode file, emitting output to the
|
||||
/// specified filename. This sets RetVal to the exit code of the program or
|
||||
/// returns false if a problem was encountered that prevented execution of
|
||||
/// the program.
|
||||
///
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0) = 0;
|
||||
};
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// CBE Implementation of AbstractIntepreter interface
|
||||
//
|
||||
class CBE : public AbstractInterpreter {
|
||||
sys::Path LLCPath; // The path to the `llc' executable.
|
||||
std::vector<std::string> ToolArgs; // Extra args to pass to LLC.
|
||||
GCC *gcc;
|
||||
public:
|
||||
CBE(const sys::Path &llcPath, GCC *Gcc,
|
||||
const std::vector<std::string> *Args)
|
||||
: LLCPath(llcPath), gcc(Gcc) {
|
||||
ToolArgs.clear ();
|
||||
if (Args) ToolArgs = *Args;
|
||||
}
|
||||
~CBE() { delete gcc; }
|
||||
|
||||
/// compileProgram - Compile the specified program from bitcode to executable
|
||||
/// code. This does not produce any output, it is only used when debugging
|
||||
/// the code generator. Returns false if the code generator fails.
|
||||
virtual void compileProgram(const std::string &Bitcode, std::string *Error,
|
||||
unsigned Timeout = 0, unsigned MemoryLimit = 0);
|
||||
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
|
||||
/// OutputCode - Compile the specified program from bitcode to code
|
||||
/// understood by the GCC driver (either C or asm). If the code generator
|
||||
/// fails, it sets Error, otherwise, this function returns the type of code
|
||||
/// emitted.
|
||||
virtual GCC::FileType OutputCode(const std::string &Bitcode,
|
||||
sys::Path &OutFile, std::string &Error,
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
};
|
||||
|
||||
|
||||
//===---------------------------------------------------------------------===//
|
||||
// LLC Implementation of AbstractIntepreter interface
|
||||
//
|
||||
class LLC : public AbstractInterpreter {
|
||||
std::string LLCPath; // The path to the LLC executable.
|
||||
std::vector<std::string> ToolArgs; // Extra args to pass to LLC.
|
||||
GCC *gcc;
|
||||
bool UseIntegratedAssembler;
|
||||
public:
|
||||
LLC(const std::string &llcPath, GCC *Gcc,
|
||||
const std::vector<std::string> *Args,
|
||||
bool useIntegratedAssembler)
|
||||
: LLCPath(llcPath), gcc(Gcc),
|
||||
UseIntegratedAssembler(useIntegratedAssembler) {
|
||||
ToolArgs.clear();
|
||||
if (Args) ToolArgs = *Args;
|
||||
}
|
||||
~LLC() { delete gcc; }
|
||||
|
||||
/// compileProgram - Compile the specified program from bitcode to executable
|
||||
/// code. This does not produce any output, it is only used when debugging
|
||||
/// the code generator. Returns false if the code generator fails.
|
||||
virtual void compileProgram(const std::string &Bitcode, std::string *Error,
|
||||
unsigned Timeout = 0, unsigned MemoryLimit = 0);
|
||||
|
||||
virtual int ExecuteProgram(const std::string &Bitcode,
|
||||
const std::vector<std::string> &Args,
|
||||
const std::string &InputFile,
|
||||
const std::string &OutputFile,
|
||||
std::string *Error,
|
||||
const std::vector<std::string> &GCCArgs =
|
||||
std::vector<std::string>(),
|
||||
const std::vector<std::string> &SharedLibs =
|
||||
std::vector<std::string>(),
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
|
||||
/// OutputCode - Compile the specified program from bitcode to code
|
||||
/// understood by the GCC driver (either C or asm). If the code generator
|
||||
/// fails, it sets Error, otherwise, this function returns the type of code
|
||||
/// emitted.
|
||||
virtual GCC::FileType OutputCode(const std::string &Bitcode,
|
||||
sys::Path &OutFile, std::string &Error,
|
||||
unsigned Timeout = 0,
|
||||
unsigned MemoryLimit = 0);
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
209
contrib/llvm/tools/bugpoint/bugpoint.cpp
Normal file
209
contrib/llvm/tools/bugpoint/bugpoint.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
//===- bugpoint.cpp - The LLVM Bugpoint utility ---------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This program is an automated compiler debugger tool. It is used to narrow
|
||||
// down miscompilations and crash problems to a specific pass in the compiler,
|
||||
// and the specific Module or Function input that is causing the problem.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BugDriver.h"
|
||||
#include "ToolRunner.h"
|
||||
#include "llvm/LinkAllPasses.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Support/PassNameParser.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Valgrind.h"
|
||||
#include "llvm/LinkAllVMCore.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
|
||||
//Enable this macro to debug bugpoint itself.
|
||||
//#define DEBUG_BUGPOINT 1
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<bool>
|
||||
FindBugs("find-bugs", cl::desc("Run many different optimization sequences "
|
||||
"on program to find bugs"), cl::init(false));
|
||||
|
||||
static cl::list<std::string>
|
||||
InputFilenames(cl::Positional, cl::OneOrMore,
|
||||
cl::desc("<input llvm ll/bc files>"));
|
||||
|
||||
static cl::opt<unsigned>
|
||||
TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
|
||||
cl::desc("Number of seconds program is allowed to run before it "
|
||||
"is killed (default is 300s), 0 disables timeout"));
|
||||
|
||||
static cl::opt<int>
|
||||
MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"),
|
||||
cl::desc("Maximum amount of memory to use. 0 disables check."
|
||||
" Defaults to 100MB (800MB under valgrind)."));
|
||||
|
||||
static cl::opt<bool>
|
||||
UseValgrind("enable-valgrind",
|
||||
cl::desc("Run optimizations through valgrind"));
|
||||
|
||||
// The AnalysesList is automatically populated with registered Passes by the
|
||||
// PassNameParser.
|
||||
//
|
||||
static cl::list<const PassInfo*, bool, PassNameParser>
|
||||
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<bool>
|
||||
StandardCompileOpts("std-compile-opts",
|
||||
cl::desc("Include the standard compile time optimizations"));
|
||||
|
||||
static cl::opt<bool>
|
||||
StandardLinkOpts("std-link-opts",
|
||||
cl::desc("Include the standard link time optimizations"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OptLevelO1("O1",
|
||||
cl::desc("Optimization level 1. Similar to llvm-gcc -O1"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OptLevelO2("O2",
|
||||
cl::desc("Optimization level 2. Similar to llvm-gcc -O2"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OptLevelO3("O3",
|
||||
cl::desc("Optimization level 3. Similar to llvm-gcc -O3"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OverrideTriple("mtriple", cl::desc("Override target triple for module"));
|
||||
|
||||
/// BugpointIsInterrupted - Set to true when the user presses ctrl-c.
|
||||
bool llvm::BugpointIsInterrupted = false;
|
||||
|
||||
#ifndef DEBUG_BUGPOINT
|
||||
static void BugpointInterruptFunction() {
|
||||
BugpointIsInterrupted = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Hack to capture a pass list.
|
||||
namespace {
|
||||
class AddToDriver : public FunctionPassManager {
|
||||
BugDriver &D;
|
||||
public:
|
||||
AddToDriver(BugDriver &_D) : FunctionPassManager(0), D(_D) {}
|
||||
|
||||
virtual void add(Pass *P) {
|
||||
const void *ID = P->getPassID();
|
||||
const PassInfo *PI = PassRegistry::getPassRegistry()->getPassInfo(ID);
|
||||
D.addPass(PI->getPassArgument());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
#ifndef DEBUG_BUGPOINT
|
||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||
llvm::PrettyStackTraceProgram X(argc, argv);
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
#endif
|
||||
|
||||
// Initialize passes
|
||||
PassRegistry &Registry = *PassRegistry::getPassRegistry();
|
||||
initializeCore(Registry);
|
||||
initializeScalarOpts(Registry);
|
||||
initializeIPO(Registry);
|
||||
initializeAnalysis(Registry);
|
||||
initializeIPA(Registry);
|
||||
initializeTransformUtils(Registry);
|
||||
initializeInstCombine(Registry);
|
||||
initializeInstrumentation(Registry);
|
||||
initializeTarget(Registry);
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"LLVM automatic testcase reducer. See\nhttp://"
|
||||
"llvm.org/cmds/bugpoint.html"
|
||||
" for more information.\n");
|
||||
#ifndef DEBUG_BUGPOINT
|
||||
sys::SetInterruptFunction(BugpointInterruptFunction);
|
||||
#endif
|
||||
|
||||
LLVMContext& Context = getGlobalContext();
|
||||
// If we have an override, set it and then track the triple we want Modules
|
||||
// to use.
|
||||
if (!OverrideTriple.empty()) {
|
||||
TargetTriple.setTriple(Triple::normalize(OverrideTriple));
|
||||
outs() << "Override triple set to '" << TargetTriple.getTriple() << "'\n";
|
||||
}
|
||||
|
||||
if (MemoryLimit < 0) {
|
||||
// Set the default MemoryLimit. Be sure to update the flag's description if
|
||||
// you change this.
|
||||
if (sys::RunningOnValgrind() || UseValgrind)
|
||||
MemoryLimit = 800;
|
||||
else
|
||||
MemoryLimit = 100;
|
||||
}
|
||||
|
||||
BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit,
|
||||
UseValgrind, Context);
|
||||
if (D.addSources(InputFilenames)) return 1;
|
||||
|
||||
AddToDriver PM(D);
|
||||
if (StandardCompileOpts) {
|
||||
PassManagerBuilder Builder;
|
||||
Builder.OptLevel = 3;
|
||||
Builder.Inliner = createFunctionInliningPass();
|
||||
Builder.populateModulePassManager(PM);
|
||||
}
|
||||
|
||||
if (StandardLinkOpts) {
|
||||
PassManagerBuilder Builder;
|
||||
Builder.populateLTOPassManager(PM, /*Internalize=*/true,
|
||||
/*RunInliner=*/true);
|
||||
}
|
||||
|
||||
if (OptLevelO1 || OptLevelO2 || OptLevelO3) {
|
||||
PassManagerBuilder Builder;
|
||||
if (OptLevelO1)
|
||||
Builder.Inliner = createAlwaysInlinerPass();
|
||||
else if (OptLevelO2)
|
||||
Builder.Inliner = createFunctionInliningPass(225);
|
||||
else
|
||||
Builder.Inliner = createFunctionInliningPass(275);
|
||||
|
||||
// Note that although clang/llvm-gcc use two separate passmanagers
|
||||
// here, it shouldn't normally make a difference.
|
||||
Builder.populateFunctionPassManager(PM);
|
||||
Builder.populateModulePassManager(PM);
|
||||
}
|
||||
|
||||
for (std::vector<const PassInfo*>::iterator I = PassList.begin(),
|
||||
E = PassList.end();
|
||||
I != E; ++I) {
|
||||
const PassInfo* PI = *I;
|
||||
D.addPass(PI->getPassArgument());
|
||||
}
|
||||
|
||||
// Bugpoint has the ability of generating a plethora of core files, so to
|
||||
// avoid filling up the disk, we prevent it
|
||||
#ifndef DEBUG_BUGPOINT
|
||||
sys::Process::PreventCoreFiles();
|
||||
#endif
|
||||
|
||||
std::string Error;
|
||||
bool Failure = D.run(Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << Error;
|
||||
return 1;
|
||||
}
|
||||
return Failure;
|
||||
}
|
5
contrib/llvm/tools/llc/CMakeLists.txt
Normal file
5
contrib/llvm/tools/llc/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser)
|
||||
|
||||
add_llvm_tool(llc
|
||||
llc.cpp
|
||||
)
|
21
contrib/llvm/tools/llc/Makefile
Normal file
21
contrib/llvm/tools/llc/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
#===- tools/llc/Makefile -----------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llc
|
||||
|
||||
# Include this here so we can get the configuration of the targets
|
||||
# that have been configured for construction. We have to do this
|
||||
# early so we can set up LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) bitreader asmparser
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
381
contrib/llvm/tools/llc/llc.cpp
Normal file
381
contrib/llvm/tools/llc/llc.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
//===-- llc.cpp - Implement the LLVM Native Code Generator ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is the llc code generator driver. It provides a convenient
|
||||
// command-line interface for generating native assembly-language code
|
||||
// or C code, given LLVM bitcode.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
|
||||
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
// General options for llc. Other pass-specific options are specified
|
||||
// within the corresponding llc passes, and target-specific options
|
||||
// and back-end code generation options are specified with the target machine.
|
||||
//
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename"));
|
||||
|
||||
// Determine optimization level.
|
||||
static cl::opt<char>
|
||||
OptLevel("O",
|
||||
cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
|
||||
"(default = '-O2')"),
|
||||
cl::Prefix,
|
||||
cl::ZeroOrMore,
|
||||
cl::init(' '));
|
||||
|
||||
static cl::opt<std::string>
|
||||
TargetTriple("mtriple", cl::desc("Override target triple for module"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
MArch("march", cl::desc("Architecture to generate code for (see --version)"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
MCPU("mcpu",
|
||||
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
||||
cl::value_desc("cpu-name"),
|
||||
cl::init(""));
|
||||
|
||||
static cl::list<std::string>
|
||||
MAttrs("mattr",
|
||||
cl::CommaSeparated,
|
||||
cl::desc("Target specific attributes (-mattr=help for details)"),
|
||||
cl::value_desc("a1,+a2,-a3,..."));
|
||||
|
||||
static cl::opt<Reloc::Model>
|
||||
RelocModel("relocation-model",
|
||||
cl::desc("Choose relocation model"),
|
||||
cl::init(Reloc::Default),
|
||||
cl::values(
|
||||
clEnumValN(Reloc::Default, "default",
|
||||
"Target default relocation model"),
|
||||
clEnumValN(Reloc::Static, "static",
|
||||
"Non-relocatable code"),
|
||||
clEnumValN(Reloc::PIC_, "pic",
|
||||
"Fully relocatable, position independent code"),
|
||||
clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
|
||||
"Relocatable external references, non-relocatable code"),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::opt<llvm::CodeModel::Model>
|
||||
CMModel("code-model",
|
||||
cl::desc("Choose code model"),
|
||||
cl::init(CodeModel::Default),
|
||||
cl::values(clEnumValN(CodeModel::Default, "default",
|
||||
"Target default code model"),
|
||||
clEnumValN(CodeModel::Small, "small",
|
||||
"Small code model"),
|
||||
clEnumValN(CodeModel::Kernel, "kernel",
|
||||
"Kernel code model"),
|
||||
clEnumValN(CodeModel::Medium, "medium",
|
||||
"Medium code model"),
|
||||
clEnumValN(CodeModel::Large, "large",
|
||||
"Large code model"),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::opt<bool>
|
||||
RelaxAll("mc-relax-all",
|
||||
cl::desc("When used with filetype=obj, "
|
||||
"relax all fixups in the emitted object file"));
|
||||
|
||||
cl::opt<TargetMachine::CodeGenFileType>
|
||||
FileType("filetype", cl::init(TargetMachine::CGFT_AssemblyFile),
|
||||
cl::desc("Choose a file type (not all types are supported by all targets):"),
|
||||
cl::values(
|
||||
clEnumValN(TargetMachine::CGFT_AssemblyFile, "asm",
|
||||
"Emit an assembly ('.s') file"),
|
||||
clEnumValN(TargetMachine::CGFT_ObjectFile, "obj",
|
||||
"Emit a native object ('.o') file [experimental]"),
|
||||
clEnumValN(TargetMachine::CGFT_Null, "null",
|
||||
"Emit nothing, for performance testing"),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<bool> NoVerify("disable-verify", cl::Hidden,
|
||||
cl::desc("Do not verify input module"));
|
||||
|
||||
cl::opt<bool> DisableDotLoc("disable-dot-loc", cl::Hidden,
|
||||
cl::desc("Do not use .loc entries"));
|
||||
|
||||
cl::opt<bool> DisableCFI("disable-cfi", cl::Hidden,
|
||||
cl::desc("Do not use .cfi_* directives"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableRedZone("disable-red-zone",
|
||||
cl::desc("Do not emit code that uses the red zone."),
|
||||
cl::init(false));
|
||||
|
||||
// GetFileNameRoot - Helper function to get the basename of a filename.
|
||||
static inline std::string
|
||||
GetFileNameRoot(const std::string &InputFilename) {
|
||||
std::string IFN = InputFilename;
|
||||
std::string outputFilename;
|
||||
int Len = IFN.length();
|
||||
if ((Len > 2) &&
|
||||
IFN[Len-3] == '.' &&
|
||||
((IFN[Len-2] == 'b' && IFN[Len-1] == 'c') ||
|
||||
(IFN[Len-2] == 'l' && IFN[Len-1] == 'l'))) {
|
||||
outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
|
||||
} else {
|
||||
outputFilename = IFN;
|
||||
}
|
||||
return outputFilename;
|
||||
}
|
||||
|
||||
static tool_output_file *GetOutputStream(const char *TargetName,
|
||||
Triple::OSType OS,
|
||||
const char *ProgName) {
|
||||
// If we don't yet have an output filename, make one.
|
||||
if (OutputFilename.empty()) {
|
||||
if (InputFilename == "-")
|
||||
OutputFilename = "-";
|
||||
else {
|
||||
OutputFilename = GetFileNameRoot(InputFilename);
|
||||
|
||||
switch (FileType) {
|
||||
default: assert(0 && "Unknown file type");
|
||||
case TargetMachine::CGFT_AssemblyFile:
|
||||
if (TargetName[0] == 'c') {
|
||||
if (TargetName[1] == 0)
|
||||
OutputFilename += ".cbe.c";
|
||||
else if (TargetName[1] == 'p' && TargetName[2] == 'p')
|
||||
OutputFilename += ".cpp";
|
||||
else
|
||||
OutputFilename += ".s";
|
||||
} else
|
||||
OutputFilename += ".s";
|
||||
break;
|
||||
case TargetMachine::CGFT_ObjectFile:
|
||||
if (OS == Triple::Win32)
|
||||
OutputFilename += ".obj";
|
||||
else
|
||||
OutputFilename += ".o";
|
||||
break;
|
||||
case TargetMachine::CGFT_Null:
|
||||
OutputFilename += ".null";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decide if we need "binary" output.
|
||||
bool Binary = false;
|
||||
switch (FileType) {
|
||||
default: assert(0 && "Unknown file type");
|
||||
case TargetMachine::CGFT_AssemblyFile:
|
||||
break;
|
||||
case TargetMachine::CGFT_ObjectFile:
|
||||
case TargetMachine::CGFT_Null:
|
||||
Binary = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Open the file.
|
||||
std::string error;
|
||||
unsigned OpenFlags = 0;
|
||||
if (Binary) OpenFlags |= raw_fd_ostream::F_Binary;
|
||||
tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error,
|
||||
OpenFlags);
|
||||
if (!error.empty()) {
|
||||
errs() << error << '\n';
|
||||
delete FDOut;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return FDOut;
|
||||
}
|
||||
|
||||
// main - Entry point for the llc compiler.
|
||||
//
|
||||
int main(int argc, char **argv) {
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
// Enable debug stream buffering.
|
||||
EnableDebugBuffering = true;
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
// Initialize targets first, so that --version shows registered targets.
|
||||
InitializeAllTargets();
|
||||
InitializeAllTargetMCs();
|
||||
InitializeAllAsmPrinters();
|
||||
InitializeAllAsmParsers();
|
||||
|
||||
// Register the target printer for --version.
|
||||
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
|
||||
|
||||
// Load the module to be compiled...
|
||||
SMDiagnostic Err;
|
||||
std::auto_ptr<Module> M;
|
||||
|
||||
M.reset(ParseIRFile(InputFilename, Err, Context));
|
||||
if (M.get() == 0) {
|
||||
Err.Print(argv[0], errs());
|
||||
return 1;
|
||||
}
|
||||
Module &mod = *M.get();
|
||||
|
||||
// If we are supposed to override the target triple, do so now.
|
||||
if (!TargetTriple.empty())
|
||||
mod.setTargetTriple(Triple::normalize(TargetTriple));
|
||||
|
||||
Triple TheTriple(mod.getTargetTriple());
|
||||
if (TheTriple.getTriple().empty())
|
||||
TheTriple.setTriple(sys::getHostTriple());
|
||||
|
||||
// Allocate target machine. First, check whether the user has explicitly
|
||||
// specified an architecture to compile for. If so we have to look it up by
|
||||
// name, because it might be a backend that has no mapping to a target triple.
|
||||
const Target *TheTarget = 0;
|
||||
if (!MArch.empty()) {
|
||||
for (TargetRegistry::iterator it = TargetRegistry::begin(),
|
||||
ie = TargetRegistry::end(); it != ie; ++it) {
|
||||
if (MArch == it->getName()) {
|
||||
TheTarget = &*it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TheTarget) {
|
||||
errs() << argv[0] << ": error: invalid target '" << MArch << "'.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Adjust the triple to match (if known), otherwise stick with the
|
||||
// module/host triple.
|
||||
Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch);
|
||||
if (Type != Triple::UnknownArch)
|
||||
TheTriple.setArch(Type);
|
||||
} else {
|
||||
std::string Err;
|
||||
TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Err);
|
||||
if (TheTarget == 0) {
|
||||
errs() << argv[0] << ": error auto-selecting target for module '"
|
||||
<< Err << "'. Please use the -march option to explicitly "
|
||||
<< "pick a target.\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Package up features to be passed to target/subtarget
|
||||
std::string FeaturesStr;
|
||||
if (MAttrs.size()) {
|
||||
SubtargetFeatures Features;
|
||||
for (unsigned i = 0; i != MAttrs.size(); ++i)
|
||||
Features.AddFeature(MAttrs[i]);
|
||||
FeaturesStr = Features.getString();
|
||||
}
|
||||
|
||||
std::auto_ptr<TargetMachine>
|
||||
target(TheTarget->createTargetMachine(TheTriple.getTriple(),
|
||||
MCPU, FeaturesStr,
|
||||
RelocModel, CMModel));
|
||||
assert(target.get() && "Could not allocate target machine!");
|
||||
TargetMachine &Target = *target.get();
|
||||
|
||||
if (DisableDotLoc)
|
||||
Target.setMCUseLoc(false);
|
||||
|
||||
if (DisableCFI)
|
||||
Target.setMCUseCFI(false);
|
||||
|
||||
// Disable .loc support for older OS X versions.
|
||||
if (TheTriple.isMacOSX() &&
|
||||
TheTriple.isMacOSXVersionLT(10, 6))
|
||||
Target.setMCUseLoc(false);
|
||||
|
||||
// Figure out where we are going to send the output...
|
||||
OwningPtr<tool_output_file> Out
|
||||
(GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0]));
|
||||
if (!Out) return 1;
|
||||
|
||||
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
|
||||
switch (OptLevel) {
|
||||
default:
|
||||
errs() << argv[0] << ": invalid optimization level.\n";
|
||||
return 1;
|
||||
case ' ': break;
|
||||
case '0': OLvl = CodeGenOpt::None; break;
|
||||
case '1': OLvl = CodeGenOpt::Less; break;
|
||||
case '2': OLvl = CodeGenOpt::Default; break;
|
||||
case '3': OLvl = CodeGenOpt::Aggressive; break;
|
||||
}
|
||||
|
||||
// Build up all of the passes that we want to do to the module.
|
||||
PassManager PM;
|
||||
|
||||
// Add the target data from the target machine, if it exists, or the module.
|
||||
if (const TargetData *TD = Target.getTargetData())
|
||||
PM.add(new TargetData(*TD));
|
||||
else
|
||||
PM.add(new TargetData(&mod));
|
||||
|
||||
// Override default to generate verbose assembly.
|
||||
Target.setAsmVerbosityDefault(true);
|
||||
|
||||
if (RelaxAll) {
|
||||
if (FileType != TargetMachine::CGFT_ObjectFile)
|
||||
errs() << argv[0]
|
||||
<< ": warning: ignoring -mc-relax-all because filetype != obj";
|
||||
else
|
||||
Target.setMCRelaxAll(true);
|
||||
}
|
||||
|
||||
{
|
||||
formatted_raw_ostream FOS(Out->os());
|
||||
|
||||
// Ask the target to add backend passes as necessary.
|
||||
if (Target.addPassesToEmitFile(PM, FOS, FileType, OLvl, NoVerify)) {
|
||||
errs() << argv[0] << ": target does not support generation of this"
|
||||
<< " file type!\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Before executing passes, print the final values of the LLVM options.
|
||||
cl::PrintOptionValues();
|
||||
|
||||
PM.run(mod);
|
||||
}
|
||||
|
||||
// Declare success.
|
||||
Out->keep();
|
||||
|
||||
return 0;
|
||||
}
|
5
contrib/llvm/tools/lli/CMakeLists.txt
Normal file
5
contrib/llvm/tools/lli/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser selectiondag)
|
||||
|
||||
add_llvm_tool(lli
|
||||
lli.cpp
|
||||
)
|
15
contrib/llvm/tools/lli/Makefile
Normal file
15
contrib/llvm/tools/lli/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
##===- tools/lli/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL := ../..
|
||||
TOOLNAME := lli
|
||||
LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag
|
||||
|
||||
# Enable JIT support
|
||||
include $(LEVEL)/Makefile.common
|
305
contrib/llvm/tools/lli/lli.cpp
Normal file
305
contrib/llvm/tools/lli/lli.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
//===- lli.cpp - LLVM Interpreter / Dynamic compiler ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility provides a simple wrapper around the LLVM Execution Engines,
|
||||
// which allow the direct execution of LLVM programs through a Just-In-Time
|
||||
// compiler, or through an interpreter if no JIT is available for this platform.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
|
||||
#include "llvm/ExecutionEngine/GenericValue.h"
|
||||
#include "llvm/ExecutionEngine/Interpreter.h"
|
||||
#include "llvm/ExecutionEngine/JIT.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#include "llvm/ExecutionEngine/MCJIT.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include <cerrno>
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#include <cygwin/version.h>
|
||||
#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007
|
||||
#define DO_NOTHING_ATEXIT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
cl::opt<std::string>
|
||||
InputFile(cl::desc("<input bitcode>"), cl::Positional, cl::init("-"));
|
||||
|
||||
cl::list<std::string>
|
||||
InputArgv(cl::ConsumeAfter, cl::desc("<program arguments>..."));
|
||||
|
||||
cl::opt<bool> ForceInterpreter("force-interpreter",
|
||||
cl::desc("Force interpretation: disable JIT"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<bool> UseMCJIT(
|
||||
"use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"),
|
||||
cl::init(false));
|
||||
|
||||
// Determine optimization level.
|
||||
cl::opt<char>
|
||||
OptLevel("O",
|
||||
cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
|
||||
"(default = '-O2')"),
|
||||
cl::Prefix,
|
||||
cl::ZeroOrMore,
|
||||
cl::init(' '));
|
||||
|
||||
cl::opt<std::string>
|
||||
TargetTriple("mtriple", cl::desc("Override target triple for module"));
|
||||
|
||||
cl::opt<std::string>
|
||||
MArch("march",
|
||||
cl::desc("Architecture to generate assembly for (see --version)"));
|
||||
|
||||
cl::opt<std::string>
|
||||
MCPU("mcpu",
|
||||
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
||||
cl::value_desc("cpu-name"),
|
||||
cl::init(""));
|
||||
|
||||
cl::list<std::string>
|
||||
MAttrs("mattr",
|
||||
cl::CommaSeparated,
|
||||
cl::desc("Target specific attributes (-mattr=help for details)"),
|
||||
cl::value_desc("a1,+a2,-a3,..."));
|
||||
|
||||
cl::opt<std::string>
|
||||
EntryFunc("entry-function",
|
||||
cl::desc("Specify the entry function (default = 'main') "
|
||||
"of the executable"),
|
||||
cl::value_desc("function"),
|
||||
cl::init("main"));
|
||||
|
||||
cl::opt<std::string>
|
||||
FakeArgv0("fake-argv0",
|
||||
cl::desc("Override the 'argv[0]' value passed into the executing"
|
||||
" program"), cl::value_desc("executable"));
|
||||
|
||||
cl::opt<bool>
|
||||
DisableCoreFiles("disable-core-files", cl::Hidden,
|
||||
cl::desc("Disable emission of core files if possible"));
|
||||
|
||||
cl::opt<bool>
|
||||
NoLazyCompilation("disable-lazy-compilation",
|
||||
cl::desc("Disable JIT lazy compilation"),
|
||||
cl::init(false));
|
||||
|
||||
cl::opt<Reloc::Model>
|
||||
RelocModel("relocation-model",
|
||||
cl::desc("Choose relocation model"),
|
||||
cl::init(Reloc::Default),
|
||||
cl::values(
|
||||
clEnumValN(Reloc::Default, "default",
|
||||
"Target default relocation model"),
|
||||
clEnumValN(Reloc::Static, "static",
|
||||
"Non-relocatable code"),
|
||||
clEnumValN(Reloc::PIC_, "pic",
|
||||
"Fully relocatable, position independent code"),
|
||||
clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
|
||||
"Relocatable external references, non-relocatable code"),
|
||||
clEnumValEnd));
|
||||
|
||||
cl::opt<llvm::CodeModel::Model>
|
||||
CMModel("code-model",
|
||||
cl::desc("Choose code model"),
|
||||
cl::init(CodeModel::JITDefault),
|
||||
cl::values(clEnumValN(CodeModel::JITDefault, "default",
|
||||
"Target default JIT code model"),
|
||||
clEnumValN(CodeModel::Small, "small",
|
||||
"Small code model"),
|
||||
clEnumValN(CodeModel::Kernel, "kernel",
|
||||
"Kernel code model"),
|
||||
clEnumValN(CodeModel::Medium, "medium",
|
||||
"Medium code model"),
|
||||
clEnumValN(CodeModel::Large, "large",
|
||||
"Large code model"),
|
||||
clEnumValEnd));
|
||||
|
||||
}
|
||||
|
||||
static ExecutionEngine *EE = 0;
|
||||
|
||||
static void do_shutdown() {
|
||||
// Cygwin-1.5 invokes DLL's dtors before atexit handler.
|
||||
#ifndef DO_NOTHING_ATEXIT
|
||||
delete EE;
|
||||
llvm_shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// main Driver function
|
||||
//
|
||||
int main(int argc, char **argv, char * const *envp) {
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
atexit(do_shutdown); // Call llvm_shutdown() on exit.
|
||||
|
||||
// If we have a native target, initialize it to ensure it is linked in and
|
||||
// usable by the JIT.
|
||||
InitializeNativeTarget();
|
||||
InitializeNativeTargetAsmPrinter();
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"llvm interpreter & dynamic compiler\n");
|
||||
|
||||
// If the user doesn't want core files, disable them.
|
||||
if (DisableCoreFiles)
|
||||
sys::Process::PreventCoreFiles();
|
||||
|
||||
// Load the bitcode...
|
||||
SMDiagnostic Err;
|
||||
Module *Mod = ParseIRFile(InputFile, Err, Context);
|
||||
if (!Mod) {
|
||||
Err.Print(argv[0], errs());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If not jitting lazily, load the whole bitcode file eagerly too.
|
||||
std::string ErrorMsg;
|
||||
if (NoLazyCompilation) {
|
||||
if (Mod->MaterializeAllPermanently(&ErrorMsg)) {
|
||||
errs() << argv[0] << ": bitcode didn't read correctly.\n";
|
||||
errs() << "Reason: " << ErrorMsg << "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
EngineBuilder builder(Mod);
|
||||
builder.setMArch(MArch);
|
||||
builder.setMCPU(MCPU);
|
||||
builder.setMAttrs(MAttrs);
|
||||
builder.setRelocationModel(RelocModel);
|
||||
builder.setCodeModel(CMModel);
|
||||
builder.setErrorStr(&ErrorMsg);
|
||||
builder.setEngineKind(ForceInterpreter
|
||||
? EngineKind::Interpreter
|
||||
: EngineKind::JIT);
|
||||
|
||||
// If we are supposed to override the target triple, do so now.
|
||||
if (!TargetTriple.empty())
|
||||
Mod->setTargetTriple(Triple::normalize(TargetTriple));
|
||||
|
||||
// Enable MCJIT, if desired.
|
||||
if (UseMCJIT)
|
||||
builder.setUseMCJIT(true);
|
||||
|
||||
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
|
||||
switch (OptLevel) {
|
||||
default:
|
||||
errs() << argv[0] << ": invalid optimization level.\n";
|
||||
return 1;
|
||||
case ' ': break;
|
||||
case '0': OLvl = CodeGenOpt::None; break;
|
||||
case '1': OLvl = CodeGenOpt::Less; break;
|
||||
case '2': OLvl = CodeGenOpt::Default; break;
|
||||
case '3': OLvl = CodeGenOpt::Aggressive; break;
|
||||
}
|
||||
builder.setOptLevel(OLvl);
|
||||
|
||||
EE = builder.create();
|
||||
if (!EE) {
|
||||
if (!ErrorMsg.empty())
|
||||
errs() << argv[0] << ": error creating EE: " << ErrorMsg << "\n";
|
||||
else
|
||||
errs() << argv[0] << ": unknown error creating EE!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
EE->RegisterJITEventListener(createOProfileJITEventListener());
|
||||
|
||||
EE->DisableLazyCompilation(NoLazyCompilation);
|
||||
|
||||
// If the user specifically requested an argv[0] to pass into the program,
|
||||
// do it now.
|
||||
if (!FakeArgv0.empty()) {
|
||||
InputFile = FakeArgv0;
|
||||
} else {
|
||||
// Otherwise, if there is a .bc suffix on the executable strip it off, it
|
||||
// might confuse the program.
|
||||
if (StringRef(InputFile).endswith(".bc"))
|
||||
InputFile.erase(InputFile.length() - 3);
|
||||
}
|
||||
|
||||
// Add the module's name to the start of the vector of arguments to main().
|
||||
InputArgv.insert(InputArgv.begin(), InputFile);
|
||||
|
||||
// Call the main function from M as if its signature were:
|
||||
// int main (int argc, char **argv, const char **envp)
|
||||
// using the contents of Args to determine argc & argv, and the contents of
|
||||
// EnvVars to determine envp.
|
||||
//
|
||||
Function *EntryFn = Mod->getFunction(EntryFunc);
|
||||
if (!EntryFn) {
|
||||
errs() << '\'' << EntryFunc << "\' function not found in module.\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If the program doesn't explicitly call exit, we will need the Exit
|
||||
// function later on to make an explicit call, so get the function now.
|
||||
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
|
||||
Type::getInt32Ty(Context),
|
||||
NULL);
|
||||
|
||||
// Reset errno to zero on entry to main.
|
||||
errno = 0;
|
||||
|
||||
// Run static constructors.
|
||||
EE->runStaticConstructorsDestructors(false);
|
||||
|
||||
if (NoLazyCompilation) {
|
||||
for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
|
||||
Function *Fn = &*I;
|
||||
if (Fn != EntryFn && !Fn->isDeclaration())
|
||||
EE->getPointerToFunction(Fn);
|
||||
}
|
||||
}
|
||||
|
||||
// Run main.
|
||||
int Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp);
|
||||
|
||||
// Run static destructors.
|
||||
EE->runStaticConstructorsDestructors(true);
|
||||
|
||||
// If the program didn't call exit explicitly, we should call it now.
|
||||
// This ensures that any atexit handlers get called correctly.
|
||||
if (Function *ExitF = dyn_cast<Function>(Exit)) {
|
||||
std::vector<GenericValue> Args;
|
||||
GenericValue ResultGV;
|
||||
ResultGV.IntVal = APInt(32, Result);
|
||||
Args.push_back(ResultGV);
|
||||
EE->runFunction(ExitF, Args);
|
||||
errs() << "ERROR: exit(" << Result << ") returned!\n";
|
||||
abort();
|
||||
} else {
|
||||
errs() << "ERROR: exit defined with wrong prototype!\n";
|
||||
abort();
|
||||
}
|
||||
}
|
8
contrib/llvm/tools/llvm-ar/CMakeLists.txt
Normal file
8
contrib/llvm/tools/llvm-ar/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
set(LLVM_LINK_COMPONENTS archive)
|
||||
set(LLVM_REQUIRES_EH 1)
|
||||
|
||||
add_llvm_tool(llvm-ar
|
||||
llvm-ar.cpp
|
||||
)
|
||||
|
||||
# TODO: Support check-local.
|
25
contrib/llvm/tools/llvm-ar/Makefile
Normal file
25
contrib/llvm/tools/llvm-ar/Makefile
Normal file
@ -0,0 +1,25 @@
|
||||
##===- tools/llvm-ar/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-ar
|
||||
LINK_COMPONENTS = archive
|
||||
REQUIRES_EH := 1
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
||||
check-local::
|
||||
$(Echo) Checking llvm-ar
|
||||
$(Verb) $(ToolDir)/llvm-ar zRrS nada.a .
|
||||
$(Verb) $(ToolDir)/llvm-ar tv nada.a | \
|
||||
grep Debug/llvm-ar.d >/dev/null 2>&1
|
||||
$(Verb) $(RM) -f nada.a
|
781
contrib/llvm/tools/llvm-ar/llvm-ar.cpp
Normal file
781
contrib/llvm/tools/llvm-ar/llvm-ar.cpp
Normal file
@ -0,0 +1,781 @@
|
||||
//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Builds up (relatively) standard unix archive files (.a) containing LLVM
|
||||
// bitcode or other files.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Bitcode/Archive.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
using namespace llvm;
|
||||
|
||||
// Option for compatibility with AIX, not used but must allow it to be present.
|
||||
static cl::opt<bool>
|
||||
X32Option ("X32_64", cl::Hidden,
|
||||
cl::desc("Ignored option for compatibility with AIX"));
|
||||
|
||||
// llvm-ar operation code and modifier flags. This must come first.
|
||||
static cl::opt<std::string>
|
||||
Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]..."));
|
||||
|
||||
// llvm-ar remaining positional arguments.
|
||||
static cl::list<std::string>
|
||||
RestOfArgs(cl::Positional, cl::OneOrMore,
|
||||
cl::desc("[relpos] [count] <archive-file> [members]..."));
|
||||
|
||||
// MoreHelp - Provide additional help output explaining the operations and
|
||||
// modifiers of llvm-ar. This object instructs the CommandLine library
|
||||
// to print the text of the constructor when the --help option is given.
|
||||
static cl::extrahelp MoreHelp(
|
||||
"\nOPERATIONS:\n"
|
||||
" d[NsS] - delete file(s) from the archive\n"
|
||||
" m[abiSs] - move file(s) in the archive\n"
|
||||
" p[kN] - print file(s) found in the archive\n"
|
||||
" q[ufsS] - quick append file(s) to the archive\n"
|
||||
" r[abfiuzRsS] - replace or insert file(s) into the archive\n"
|
||||
" t - display contents of archive\n"
|
||||
" x[No] - extract file(s) from the archive\n"
|
||||
"\nMODIFIERS (operation specific):\n"
|
||||
" [a] - put file(s) after [relpos]\n"
|
||||
" [b] - put file(s) before [relpos] (same as [i])\n"
|
||||
" [f] - truncate inserted file names\n"
|
||||
" [i] - put file(s) before [relpos] (same as [b])\n"
|
||||
" [k] - always print bitcode files (default is to skip them)\n"
|
||||
" [N] - use instance [count] of name\n"
|
||||
" [o] - preserve original dates\n"
|
||||
" [P] - use full path names when matching\n"
|
||||
" [R] - recurse through directories when inserting\n"
|
||||
" [s] - create an archive index (cf. ranlib)\n"
|
||||
" [S] - do not build a symbol table\n"
|
||||
" [u] - update only files newer than archive contents\n"
|
||||
" [z] - compress files before inserting/extracting\n"
|
||||
"\nMODIFIERS (generic):\n"
|
||||
" [c] - do not warn if the library had to be created\n"
|
||||
" [v] - be verbose about actions taken\n"
|
||||
" [V] - be *really* verbose about actions taken\n"
|
||||
);
|
||||
|
||||
// This enumeration delineates the kinds of operations on an archive
|
||||
// that are permitted.
|
||||
enum ArchiveOperation {
|
||||
NoOperation, ///< An operation hasn't been specified
|
||||
Print, ///< Print the contents of the archive
|
||||
Delete, ///< Delete the specified members
|
||||
Move, ///< Move members to end or as given by {a,b,i} modifiers
|
||||
QuickAppend, ///< Quickly append to end of archive
|
||||
ReplaceOrInsert, ///< Replace or Insert members
|
||||
DisplayTable, ///< Display the table of contents
|
||||
Extract ///< Extract files back to file system
|
||||
};
|
||||
|
||||
// Modifiers to follow operation to vary behavior
|
||||
bool AddAfter = false; ///< 'a' modifier
|
||||
bool AddBefore = false; ///< 'b' modifier
|
||||
bool Create = false; ///< 'c' modifier
|
||||
bool TruncateNames = false; ///< 'f' modifier
|
||||
bool InsertBefore = false; ///< 'i' modifier
|
||||
bool DontSkipBitcode = false; ///< 'k' modifier
|
||||
bool UseCount = false; ///< 'N' modifier
|
||||
bool OriginalDates = false; ///< 'o' modifier
|
||||
bool FullPath = false; ///< 'P' modifier
|
||||
bool RecurseDirectories = false; ///< 'R' modifier
|
||||
bool SymTable = true; ///< 's' & 'S' modifiers
|
||||
bool OnlyUpdate = false; ///< 'u' modifier
|
||||
bool Verbose = false; ///< 'v' modifier
|
||||
bool ReallyVerbose = false; ///< 'V' modifier
|
||||
bool Compression = false; ///< 'z' modifier
|
||||
|
||||
// Relative Positional Argument (for insert/move). This variable holds
|
||||
// the name of the archive member to which the 'a', 'b' or 'i' modifier
|
||||
// refers. Only one of 'a', 'b' or 'i' can be specified so we only need
|
||||
// one variable.
|
||||
std::string RelPos;
|
||||
|
||||
// Select which of multiple entries in the archive with the same name should be
|
||||
// used (specified with -N) for the delete and extract operations.
|
||||
int Count = 1;
|
||||
|
||||
// This variable holds the name of the archive file as given on the
|
||||
// command line.
|
||||
std::string ArchiveName;
|
||||
|
||||
// This variable holds the list of member files to proecess, as given
|
||||
// on the command line.
|
||||
std::vector<std::string> Members;
|
||||
|
||||
// This variable holds the (possibly expanded) list of path objects that
|
||||
// correspond to files we will
|
||||
std::set<sys::Path> Paths;
|
||||
|
||||
// The Archive object to which all the editing operations will be sent.
|
||||
Archive* TheArchive = 0;
|
||||
|
||||
// getRelPos - Extract the member filename from the command line for
|
||||
// the [relpos] argument associated with a, b, and i modifiers
|
||||
void getRelPos() {
|
||||
if(RestOfArgs.size() > 0) {
|
||||
RelPos = RestOfArgs[0];
|
||||
RestOfArgs.erase(RestOfArgs.begin());
|
||||
}
|
||||
else
|
||||
throw "Expected [relpos] for a, b, or i modifier";
|
||||
}
|
||||
|
||||
// getCount - Extract the [count] argument associated with the N modifier
|
||||
// from the command line and check its value.
|
||||
void getCount() {
|
||||
if(RestOfArgs.size() > 0) {
|
||||
Count = atoi(RestOfArgs[0].c_str());
|
||||
RestOfArgs.erase(RestOfArgs.begin());
|
||||
}
|
||||
else
|
||||
throw "Expected [count] value with N modifier";
|
||||
|
||||
// Non-positive counts are not allowed
|
||||
if (Count < 1)
|
||||
throw "Invalid [count] value (not a positive integer)";
|
||||
}
|
||||
|
||||
// getArchive - Get the archive file name from the command line
|
||||
void getArchive() {
|
||||
if(RestOfArgs.size() > 0) {
|
||||
ArchiveName = RestOfArgs[0];
|
||||
RestOfArgs.erase(RestOfArgs.begin());
|
||||
}
|
||||
else
|
||||
throw "An archive name must be specified.";
|
||||
}
|
||||
|
||||
// getMembers - Copy over remaining items in RestOfArgs to our Members vector
|
||||
// This is just for clarity.
|
||||
void getMembers() {
|
||||
if(RestOfArgs.size() > 0)
|
||||
Members = std::vector<std::string>(RestOfArgs);
|
||||
}
|
||||
|
||||
// parseCommandLine - Parse the command line options as presented and return the
|
||||
// operation specified. Process all modifiers and check to make sure that
|
||||
// constraints on modifier/operation pairs have not been violated.
|
||||
ArchiveOperation parseCommandLine() {
|
||||
|
||||
// Keep track of number of operations. We can only specify one
|
||||
// per execution.
|
||||
unsigned NumOperations = 0;
|
||||
|
||||
// Keep track of the number of positional modifiers (a,b,i). Only
|
||||
// one can be specified.
|
||||
unsigned NumPositional = 0;
|
||||
|
||||
// Keep track of which operation was requested
|
||||
ArchiveOperation Operation = NoOperation;
|
||||
|
||||
for(unsigned i=0; i<Options.size(); ++i) {
|
||||
switch(Options[i]) {
|
||||
case 'd': ++NumOperations; Operation = Delete; break;
|
||||
case 'm': ++NumOperations; Operation = Move ; break;
|
||||
case 'p': ++NumOperations; Operation = Print; break;
|
||||
case 'q': ++NumOperations; Operation = QuickAppend; break;
|
||||
case 'r': ++NumOperations; Operation = ReplaceOrInsert; break;
|
||||
case 't': ++NumOperations; Operation = DisplayTable; break;
|
||||
case 'x': ++NumOperations; Operation = Extract; break;
|
||||
case 'c': Create = true; break;
|
||||
case 'f': TruncateNames = true; break;
|
||||
case 'k': DontSkipBitcode = true; break;
|
||||
case 'l': /* accepted but unused */ break;
|
||||
case 'o': OriginalDates = true; break;
|
||||
case 'P': FullPath = true; break;
|
||||
case 'R': RecurseDirectories = true; break;
|
||||
case 's': SymTable = true; break;
|
||||
case 'S': SymTable = false; break;
|
||||
case 'u': OnlyUpdate = true; break;
|
||||
case 'v': Verbose = true; break;
|
||||
case 'V': Verbose = ReallyVerbose = true; break;
|
||||
case 'z': Compression = true; break;
|
||||
case 'a':
|
||||
getRelPos();
|
||||
AddAfter = true;
|
||||
NumPositional++;
|
||||
break;
|
||||
case 'b':
|
||||
getRelPos();
|
||||
AddBefore = true;
|
||||
NumPositional++;
|
||||
break;
|
||||
case 'i':
|
||||
getRelPos();
|
||||
InsertBefore = true;
|
||||
NumPositional++;
|
||||
break;
|
||||
case 'N':
|
||||
getCount();
|
||||
UseCount = true;
|
||||
break;
|
||||
default:
|
||||
cl::PrintHelpMessage();
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, the next thing on the command line must be
|
||||
// the archive name.
|
||||
getArchive();
|
||||
|
||||
// Everything on the command line at this point is a member.
|
||||
getMembers();
|
||||
|
||||
// Perform various checks on the operation/modifier specification
|
||||
// to make sure we are dealing with a legal request.
|
||||
if (NumOperations == 0)
|
||||
throw "You must specify at least one of the operations";
|
||||
if (NumOperations > 1)
|
||||
throw "Only one operation may be specified";
|
||||
if (NumPositional > 1)
|
||||
throw "You may only specify one of a, b, and i modifiers";
|
||||
if (AddAfter || AddBefore || InsertBefore)
|
||||
if (Operation != Move && Operation != ReplaceOrInsert)
|
||||
throw "The 'a', 'b' and 'i' modifiers can only be specified with "
|
||||
"the 'm' or 'r' operations";
|
||||
if (RecurseDirectories && Operation != ReplaceOrInsert)
|
||||
throw "The 'R' modifiers is only applicabe to the 'r' operation";
|
||||
if (OriginalDates && Operation != Extract)
|
||||
throw "The 'o' modifier is only applicable to the 'x' operation";
|
||||
if (TruncateNames && Operation!=QuickAppend && Operation!=ReplaceOrInsert)
|
||||
throw "The 'f' modifier is only applicable to the 'q' and 'r' operations";
|
||||
if (OnlyUpdate && Operation != ReplaceOrInsert)
|
||||
throw "The 'u' modifier is only applicable to the 'r' operation";
|
||||
if (Compression && Operation!=ReplaceOrInsert && Operation!=Extract)
|
||||
throw "The 'z' modifier is only applicable to the 'r' and 'x' operations";
|
||||
if (Count > 1 && Members.size() > 1)
|
||||
throw "Only one member name may be specified with the 'N' modifier";
|
||||
|
||||
// Return the parsed operation to the caller
|
||||
return Operation;
|
||||
}
|
||||
|
||||
// recurseDirectories - Implements the "R" modifier. This function scans through
|
||||
// the Paths vector (built by buildPaths, below) and replaces any directories it
|
||||
// finds with all the files in that directory (recursively). It uses the
|
||||
// sys::Path::getDirectoryContent method to perform the actual directory scans.
|
||||
bool
|
||||
recurseDirectories(const sys::Path& path,
|
||||
std::set<sys::Path>& result, std::string* ErrMsg) {
|
||||
result.clear();
|
||||
if (RecurseDirectories) {
|
||||
std::set<sys::Path> content;
|
||||
if (path.getDirectoryContents(content, ErrMsg))
|
||||
return true;
|
||||
|
||||
for (std::set<sys::Path>::iterator I = content.begin(), E = content.end();
|
||||
I != E; ++I) {
|
||||
// Make sure it exists and is a directory
|
||||
sys::PathWithStatus PwS(*I);
|
||||
const sys::FileStatus *Status = PwS.getFileStatus(false, ErrMsg);
|
||||
if (!Status)
|
||||
return true;
|
||||
if (Status->isDir) {
|
||||
std::set<sys::Path> moreResults;
|
||||
if (recurseDirectories(*I, moreResults, ErrMsg))
|
||||
return true;
|
||||
result.insert(moreResults.begin(), moreResults.end());
|
||||
} else {
|
||||
result.insert(*I);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// buildPaths - Convert the strings in the Members vector to sys::Path objects
|
||||
// and make sure they are valid and exist exist. This check is only needed for
|
||||
// the operations that add/replace files to the archive ('q' and 'r')
|
||||
bool buildPaths(bool checkExistence, std::string* ErrMsg) {
|
||||
for (unsigned i = 0; i < Members.size(); i++) {
|
||||
sys::Path aPath;
|
||||
if (!aPath.set(Members[i]))
|
||||
throw std::string("File member name invalid: ") + Members[i];
|
||||
if (checkExistence) {
|
||||
bool Exists;
|
||||
if (sys::fs::exists(aPath.str(), Exists) || !Exists)
|
||||
throw std::string("File does not exist: ") + Members[i];
|
||||
std::string Err;
|
||||
sys::PathWithStatus PwS(aPath);
|
||||
const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
|
||||
if (!si)
|
||||
throw Err;
|
||||
if (si->isDir) {
|
||||
std::set<sys::Path> dirpaths;
|
||||
if (recurseDirectories(aPath, dirpaths, ErrMsg))
|
||||
return true;
|
||||
Paths.insert(dirpaths.begin(),dirpaths.end());
|
||||
} else {
|
||||
Paths.insert(aPath);
|
||||
}
|
||||
} else {
|
||||
Paths.insert(aPath);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// printSymbolTable - print out the archive's symbol table.
|
||||
void printSymbolTable() {
|
||||
outs() << "\nArchive Symbol Table:\n";
|
||||
const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
|
||||
for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
|
||||
I != E; ++I ) {
|
||||
unsigned offset = TheArchive->getFirstFileOffset() + I->second;
|
||||
outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
// doPrint - Implements the 'p' operation. This function traverses the archive
|
||||
// looking for members that match the path list. It is careful to uncompress
|
||||
// things that should be and to skip bitcode files unless the 'k' modifier was
|
||||
// given.
|
||||
bool doPrint(std::string* ErrMsg) {
|
||||
if (buildPaths(false, ErrMsg))
|
||||
return true;
|
||||
unsigned countDown = Count;
|
||||
for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
|
||||
I != E; ++I ) {
|
||||
if (Paths.empty() ||
|
||||
(std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
|
||||
if (countDown == 1) {
|
||||
const char* data = reinterpret_cast<const char*>(I->getData());
|
||||
|
||||
// Skip things that don't make sense to print
|
||||
if (I->isLLVMSymbolTable() || I->isSVR4SymbolTable() ||
|
||||
I->isBSD4SymbolTable() || (!DontSkipBitcode && I->isBitcode()))
|
||||
continue;
|
||||
|
||||
if (Verbose)
|
||||
outs() << "Printing " << I->getPath().str() << "\n";
|
||||
|
||||
unsigned len = I->getSize();
|
||||
outs().write(data, len);
|
||||
} else {
|
||||
countDown--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// putMode - utility function for printing out the file mode when the 't'
|
||||
// operation is in verbose mode.
|
||||
void
|
||||
printMode(unsigned mode) {
|
||||
if (mode & 004)
|
||||
outs() << "r";
|
||||
else
|
||||
outs() << "-";
|
||||
if (mode & 002)
|
||||
outs() << "w";
|
||||
else
|
||||
outs() << "-";
|
||||
if (mode & 001)
|
||||
outs() << "x";
|
||||
else
|
||||
outs() << "-";
|
||||
}
|
||||
|
||||
// doDisplayTable - Implement the 't' operation. This function prints out just
|
||||
// the file names of each of the members. However, if verbose mode is requested
|
||||
// ('v' modifier) then the file type, permission mode, user, group, size, and
|
||||
// modification time are also printed.
|
||||
bool
|
||||
doDisplayTable(std::string* ErrMsg) {
|
||||
if (buildPaths(false, ErrMsg))
|
||||
return true;
|
||||
for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
|
||||
I != E; ++I ) {
|
||||
if (Paths.empty() ||
|
||||
(std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
|
||||
if (Verbose) {
|
||||
// FIXME: Output should be this format:
|
||||
// Zrw-r--r-- 500/ 500 525 Nov 8 17:42 2004 Makefile
|
||||
if (I->isBitcode())
|
||||
outs() << "b";
|
||||
else if (I->isCompressed())
|
||||
outs() << "Z";
|
||||
else
|
||||
outs() << " ";
|
||||
unsigned mode = I->getMode();
|
||||
printMode((mode >> 6) & 007);
|
||||
printMode((mode >> 3) & 007);
|
||||
printMode(mode & 007);
|
||||
outs() << " " << format("%4u", I->getUser());
|
||||
outs() << "/" << format("%4u", I->getGroup());
|
||||
outs() << " " << format("%8u", I->getSize());
|
||||
outs() << " " << format("%20s", I->getModTime().str().substr(4).c_str());
|
||||
outs() << " " << I->getPath().str() << "\n";
|
||||
} else {
|
||||
outs() << I->getPath().str() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ReallyVerbose)
|
||||
printSymbolTable();
|
||||
return false;
|
||||
}
|
||||
|
||||
// doExtract - Implement the 'x' operation. This function extracts files back to
|
||||
// the file system, making sure to uncompress any that were compressed
|
||||
bool
|
||||
doExtract(std::string* ErrMsg) {
|
||||
if (buildPaths(false, ErrMsg))
|
||||
return true;
|
||||
for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
|
||||
I != E; ++I ) {
|
||||
if (Paths.empty() ||
|
||||
(std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) {
|
||||
|
||||
// Make sure the intervening directories are created
|
||||
if (I->hasPath()) {
|
||||
sys::Path dirs(I->getPath());
|
||||
dirs.eraseComponent();
|
||||
if (dirs.createDirectoryOnDisk(/*create_parents=*/true, ErrMsg))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Open up a file stream for writing
|
||||
std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
|
||||
std::ios::binary;
|
||||
std::ofstream file(I->getPath().c_str(), io_mode);
|
||||
|
||||
// Get the data and its length
|
||||
const char* data = reinterpret_cast<const char*>(I->getData());
|
||||
unsigned len = I->getSize();
|
||||
|
||||
// Write the data.
|
||||
file.write(data,len);
|
||||
file.close();
|
||||
|
||||
// If we're supposed to retain the original modification times, etc. do so
|
||||
// now.
|
||||
if (OriginalDates)
|
||||
I->getPath().setStatusInfoOnDisk(I->getFileStatus());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// doDelete - Implement the delete operation. This function deletes zero or more
|
||||
// members from the archive. Note that if the count is specified, there should
|
||||
// be no more than one path in the Paths list or else this algorithm breaks.
|
||||
// That check is enforced in parseCommandLine (above).
|
||||
bool
|
||||
doDelete(std::string* ErrMsg) {
|
||||
if (buildPaths(false, ErrMsg))
|
||||
return true;
|
||||
if (Paths.empty())
|
||||
return false;
|
||||
unsigned countDown = Count;
|
||||
for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
|
||||
I != E; ) {
|
||||
if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) {
|
||||
if (countDown == 1) {
|
||||
Archive::iterator J = I;
|
||||
++I;
|
||||
TheArchive->erase(J);
|
||||
} else
|
||||
countDown--;
|
||||
} else {
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
// We're done editting, reconstruct the archive.
|
||||
if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
|
||||
return true;
|
||||
if (ReallyVerbose)
|
||||
printSymbolTable();
|
||||
return false;
|
||||
}
|
||||
|
||||
// doMore - Implement the move operation. This function re-arranges just the
|
||||
// order of the archive members so that when the archive is written the move
|
||||
// of the members is accomplished. Note the use of the RelPos variable to
|
||||
// determine where the items should be moved to.
|
||||
bool
|
||||
doMove(std::string* ErrMsg) {
|
||||
if (buildPaths(false, ErrMsg))
|
||||
return true;
|
||||
|
||||
// By default and convention the place to move members to is the end of the
|
||||
// archive.
|
||||
Archive::iterator moveto_spot = TheArchive->end();
|
||||
|
||||
// However, if the relative positioning modifiers were used, we need to scan
|
||||
// the archive to find the member in question. If we don't find it, its no
|
||||
// crime, we just move to the end.
|
||||
if (AddBefore || InsertBefore || AddAfter) {
|
||||
for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
|
||||
I != E; ++I ) {
|
||||
if (RelPos == I->getPath().str()) {
|
||||
if (AddAfter) {
|
||||
moveto_spot = I;
|
||||
moveto_spot++;
|
||||
} else {
|
||||
moveto_spot = I;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keep a list of the paths remaining to be moved
|
||||
std::set<sys::Path> remaining(Paths);
|
||||
|
||||
// Scan the archive again, this time looking for the members to move to the
|
||||
// moveto_spot.
|
||||
for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end();
|
||||
I != E && !remaining.empty(); ++I ) {
|
||||
std::set<sys::Path>::iterator found =
|
||||
std::find(remaining.begin(),remaining.end(),I->getPath());
|
||||
if (found != remaining.end()) {
|
||||
if (I != moveto_spot)
|
||||
TheArchive->splice(moveto_spot,*TheArchive,I);
|
||||
remaining.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
// We're done editting, reconstruct the archive.
|
||||
if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
|
||||
return true;
|
||||
if (ReallyVerbose)
|
||||
printSymbolTable();
|
||||
return false;
|
||||
}
|
||||
|
||||
// doQuickAppend - Implements the 'q' operation. This function just
|
||||
// indiscriminantly adds the members to the archive and rebuilds it.
|
||||
bool
|
||||
doQuickAppend(std::string* ErrMsg) {
|
||||
// Get the list of paths to append.
|
||||
if (buildPaths(true, ErrMsg))
|
||||
return true;
|
||||
if (Paths.empty())
|
||||
return false;
|
||||
|
||||
// Append them quickly.
|
||||
for (std::set<sys::Path>::iterator PI = Paths.begin(), PE = Paths.end();
|
||||
PI != PE; ++PI) {
|
||||
if (TheArchive->addFileBefore(*PI,TheArchive->end(),ErrMsg))
|
||||
return true;
|
||||
}
|
||||
|
||||
// We're done editting, reconstruct the archive.
|
||||
if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
|
||||
return true;
|
||||
if (ReallyVerbose)
|
||||
printSymbolTable();
|
||||
return false;
|
||||
}
|
||||
|
||||
// doReplaceOrInsert - Implements the 'r' operation. This function will replace
|
||||
// any existing files or insert new ones into the archive.
|
||||
bool
|
||||
doReplaceOrInsert(std::string* ErrMsg) {
|
||||
|
||||
// Build the list of files to be added/replaced.
|
||||
if (buildPaths(true, ErrMsg))
|
||||
return true;
|
||||
if (Paths.empty())
|
||||
return false;
|
||||
|
||||
// Keep track of the paths that remain to be inserted.
|
||||
std::set<sys::Path> remaining(Paths);
|
||||
|
||||
// Default the insertion spot to the end of the archive
|
||||
Archive::iterator insert_spot = TheArchive->end();
|
||||
|
||||
// Iterate over the archive contents
|
||||
for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end();
|
||||
I != E && !remaining.empty(); ++I ) {
|
||||
|
||||
// Determine if this archive member matches one of the paths we're trying
|
||||
// to replace.
|
||||
|
||||
std::set<sys::Path>::iterator found = remaining.end();
|
||||
for (std::set<sys::Path>::iterator RI = remaining.begin(),
|
||||
RE = remaining.end(); RI != RE; ++RI ) {
|
||||
std::string compare(RI->str());
|
||||
if (TruncateNames && compare.length() > 15) {
|
||||
const char* nm = compare.c_str();
|
||||
unsigned len = compare.length();
|
||||
size_t slashpos = compare.rfind('/');
|
||||
if (slashpos != std::string::npos) {
|
||||
nm += slashpos + 1;
|
||||
len -= slashpos +1;
|
||||
}
|
||||
if (len > 15)
|
||||
len = 15;
|
||||
compare.assign(nm,len);
|
||||
}
|
||||
if (compare == I->getPath().str()) {
|
||||
found = RI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != remaining.end()) {
|
||||
std::string Err;
|
||||
sys::PathWithStatus PwS(*found);
|
||||
const sys::FileStatus *si = PwS.getFileStatus(false, &Err);
|
||||
if (!si)
|
||||
return true;
|
||||
if (!si->isDir) {
|
||||
if (OnlyUpdate) {
|
||||
// Replace the item only if it is newer.
|
||||
if (si->modTime > I->getModTime())
|
||||
if (I->replaceWith(*found, ErrMsg))
|
||||
return true;
|
||||
} else {
|
||||
// Replace the item regardless of time stamp
|
||||
if (I->replaceWith(*found, ErrMsg))
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// We purposefully ignore directories.
|
||||
}
|
||||
|
||||
// Remove it from our "to do" list
|
||||
remaining.erase(found);
|
||||
}
|
||||
|
||||
// Determine if this is the place where we should insert
|
||||
if ((AddBefore || InsertBefore) && RelPos == I->getPath().str())
|
||||
insert_spot = I;
|
||||
else if (AddAfter && RelPos == I->getPath().str()) {
|
||||
insert_spot = I;
|
||||
insert_spot++;
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't replace all the members, some will remain and need to be
|
||||
// inserted at the previously computed insert-spot.
|
||||
if (!remaining.empty()) {
|
||||
for (std::set<sys::Path>::iterator PI = remaining.begin(),
|
||||
PE = remaining.end(); PI != PE; ++PI) {
|
||||
if (TheArchive->addFileBefore(*PI,insert_spot, ErrMsg))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We're done editting, reconstruct the archive.
|
||||
if (TheArchive->writeToDisk(SymTable,TruncateNames,Compression,ErrMsg))
|
||||
return true;
|
||||
if (ReallyVerbose)
|
||||
printSymbolTable();
|
||||
return false;
|
||||
}
|
||||
|
||||
// main - main program for llvm-ar .. see comments in the code
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
// Have the command line options parsed and handle things
|
||||
// like --help and --version.
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"LLVM Archiver (llvm-ar)\n\n"
|
||||
" This program archives bitcode files into single libraries\n"
|
||||
);
|
||||
|
||||
int exitCode = 0;
|
||||
|
||||
// Make sure we don't exit with "unhandled exception".
|
||||
try {
|
||||
// Do our own parsing of the command line because the CommandLine utility
|
||||
// can't handle the grouped positional parameters without a dash.
|
||||
ArchiveOperation Operation = parseCommandLine();
|
||||
|
||||
// Check the path name of the archive
|
||||
sys::Path ArchivePath;
|
||||
if (!ArchivePath.set(ArchiveName))
|
||||
throw std::string("Archive name invalid: ") + ArchiveName;
|
||||
|
||||
// Create or open the archive object.
|
||||
bool Exists;
|
||||
if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists) {
|
||||
// Produce a warning if we should and we're creating the archive
|
||||
if (!Create)
|
||||
errs() << argv[0] << ": creating " << ArchivePath.str() << "\n";
|
||||
TheArchive = Archive::CreateEmpty(ArchivePath, Context);
|
||||
TheArchive->writeToDisk();
|
||||
} else {
|
||||
std::string Error;
|
||||
TheArchive = Archive::OpenAndLoad(ArchivePath, Context, &Error);
|
||||
if (TheArchive == 0) {
|
||||
errs() << argv[0] << ": error loading '" << ArchivePath.str() << "': "
|
||||
<< Error << "!\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we're not fooling ourselves.
|
||||
assert(TheArchive && "Unable to instantiate the archive");
|
||||
|
||||
// Make sure we clean up the archive even on failure.
|
||||
std::auto_ptr<Archive> AutoArchive(TheArchive);
|
||||
|
||||
// Perform the operation
|
||||
std::string ErrMsg;
|
||||
bool haveError = false;
|
||||
switch (Operation) {
|
||||
case Print: haveError = doPrint(&ErrMsg); break;
|
||||
case Delete: haveError = doDelete(&ErrMsg); break;
|
||||
case Move: haveError = doMove(&ErrMsg); break;
|
||||
case QuickAppend: haveError = doQuickAppend(&ErrMsg); break;
|
||||
case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break;
|
||||
case DisplayTable: haveError = doDisplayTable(&ErrMsg); break;
|
||||
case Extract: haveError = doExtract(&ErrMsg); break;
|
||||
case NoOperation:
|
||||
errs() << argv[0] << ": No operation was selected.\n";
|
||||
break;
|
||||
}
|
||||
if (haveError) {
|
||||
errs() << argv[0] << ": " << ErrMsg << "\n";
|
||||
return 1;
|
||||
}
|
||||
} catch (const char*msg) {
|
||||
// These errors are usage errors, thrown only by the various checks in the
|
||||
// code above.
|
||||
errs() << argv[0] << ": " << msg << "\n\n";
|
||||
cl::PrintHelpMessage();
|
||||
exitCode = 1;
|
||||
} catch (const std::string& msg) {
|
||||
// These errors are thrown by LLVM libraries (e.g. lib System) and represent
|
||||
// a more serious error so we bump the exitCode and don't print the usage.
|
||||
errs() << argv[0] << ": " << msg << "\n";
|
||||
exitCode = 2;
|
||||
} catch (...) {
|
||||
// This really shouldn't happen, but just in case ....
|
||||
errs() << argv[0] << ": An unexpected unknown exception occurred.\n";
|
||||
exitCode = 3;
|
||||
}
|
||||
|
||||
// Return result code back to operating system.
|
||||
return exitCode;
|
||||
}
|
6
contrib/llvm/tools/llvm-as/CMakeLists.txt
Normal file
6
contrib/llvm/tools/llvm-as/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS asmparser bitwriter)
|
||||
set(LLVM_REQUIRES_EH 1)
|
||||
|
||||
add_llvm_tool(llvm-as
|
||||
llvm-as.cpp
|
||||
)
|
17
contrib/llvm/tools/llvm-as/Makefile
Normal file
17
contrib/llvm/tools/llvm-as/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-as/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llvm-as
|
||||
LINK_COMPONENTS := asmparser bitwriter
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
119
contrib/llvm/tools/llvm-as/llvm-as.cpp
Normal file
119
contrib/llvm/tools/llvm-as/llvm-as.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
//===--- llvm-as.cpp - The low-level LLVM assembler -----------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility may be invoked in the following manner:
|
||||
// llvm-as --help - Output information about command line switches
|
||||
// llvm-as [options] - Read LLVM asm from stdin, write bitcode to stdout
|
||||
// llvm-as [options] x.ll - Read LLVM asm from the x.ll file, write bitcode
|
||||
// to the x.bc file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Assembly/Parser.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input .llvm file>"), cl::init("-"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Override output filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Force("f", cl::desc("Enable binary output on terminals"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableOutput("disable-output", cl::desc("Disable output"), cl::init(false));
|
||||
|
||||
static cl::opt<bool>
|
||||
DumpAsm("d", cl::desc("Print assembly as parsed"), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableVerify("disable-verify", cl::Hidden,
|
||||
cl::desc("Do not run verifier on input LLVM (dangerous!)"));
|
||||
|
||||
static void WriteOutputFile(const Module *M) {
|
||||
// Infer the output filename if needed.
|
||||
if (OutputFilename.empty()) {
|
||||
if (InputFilename == "-") {
|
||||
OutputFilename = "-";
|
||||
} else {
|
||||
std::string IFN = InputFilename;
|
||||
int Len = IFN.length();
|
||||
if (IFN[Len-3] == '.' && IFN[Len-2] == 'l' && IFN[Len-1] == 'l') {
|
||||
// Source ends in .ll
|
||||
OutputFilename = std::string(IFN.begin(), IFN.end()-3);
|
||||
} else {
|
||||
OutputFilename = IFN; // Append a .bc to it
|
||||
}
|
||||
OutputFilename += ".bc";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ErrorInfo;
|
||||
OwningPtr<tool_output_file> Out
|
||||
(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary));
|
||||
if (!ErrorInfo.empty()) {
|
||||
errs() << ErrorInfo << '\n';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (Force || !CheckBitcodeOutputToConsole(Out->os(), true))
|
||||
WriteBitcodeToFile(M, Out->os());
|
||||
|
||||
// Declare success.
|
||||
Out->keep();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n");
|
||||
|
||||
// Parse the file now...
|
||||
SMDiagnostic Err;
|
||||
std::auto_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context));
|
||||
if (M.get() == 0) {
|
||||
Err.Print(argv[0], errs());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!DisableVerify) {
|
||||
std::string Err;
|
||||
if (verifyModule(*M.get(), ReturnStatusAction, &Err)) {
|
||||
errs() << argv[0]
|
||||
<< ": assembly parsed, but does not verify as correct!\n";
|
||||
errs() << Err;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (DumpAsm) errs() << "Here's the assembly:\n" << *M.get();
|
||||
|
||||
if (!DisableOutput)
|
||||
WriteOutputFile(M.get());
|
||||
|
||||
return 0;
|
||||
}
|
6
contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt
Normal file
6
contrib/llvm/tools/llvm-bcanalyzer/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS bitreader)
|
||||
set(LLVM_REQUIRES_EH 1)
|
||||
|
||||
add_llvm_tool(llvm-bcanalyzer
|
||||
llvm-bcanalyzer.cpp
|
||||
)
|
17
contrib/llvm/tools/llvm-bcanalyzer/Makefile
Normal file
17
contrib/llvm/tools/llvm-bcanalyzer/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-bcanalyzer/Makefile ----------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-bcanalyzer
|
||||
LINK_COMPONENTS := bitreader
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
629
contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
Normal file
629
contrib/llvm/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
Normal file
@ -0,0 +1,629 @@
|
||||
//===-- llvm-bcanalyzer.cpp - Bitcode Analyzer --------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tool may be invoked in the following manner:
|
||||
// llvm-bcanalyzer [options] - Read LLVM bitcode from stdin
|
||||
// llvm-bcanalyzer [options] x.bc - Read LLVM bitcode from the x.bc file
|
||||
//
|
||||
// Options:
|
||||
// --help - Output information about command line switches
|
||||
// --dump - Dump low-level bitcode structure in readable format
|
||||
//
|
||||
// This tool provides analytical information about a bitcode file. It is
|
||||
// intended as an aid to developers of bitcode reading and writing software. It
|
||||
// produces on std::out a summary of the bitcode file that shows various
|
||||
// statistics about the contents of the file. By default this information is
|
||||
// detailed and contains information about individual bitcode blocks and the
|
||||
// functions in the module.
|
||||
// The tool is also able to print a bitcode file in a straight forward text
|
||||
// format that shows the containment and relationships of the information in
|
||||
// the bitcode file (-dump option).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Bitcode/BitstreamReader.h"
|
||||
#include "llvm/Bitcode/LLVMBitCodes.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <cstdio>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
|
||||
|
||||
static cl::opt<bool> Dump("dump", cl::desc("Dump low level bitcode trace"));
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Bitcode specific analysis.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static cl::opt<bool> NoHistogram("disable-histogram",
|
||||
cl::desc("Do not print per-code histogram"));
|
||||
|
||||
static cl::opt<bool>
|
||||
NonSymbolic("non-symbolic",
|
||||
cl::desc("Emit numeric info in dump even if"
|
||||
" symbolic info is available"));
|
||||
|
||||
namespace {
|
||||
|
||||
/// CurStreamTypeType - A type for CurStreamType
|
||||
enum CurStreamTypeType {
|
||||
UnknownBitstream,
|
||||
LLVMIRBitstream
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/// CurStreamType - If we can sniff the flavor of this stream, we can produce
|
||||
/// better dump info.
|
||||
static CurStreamTypeType CurStreamType;
|
||||
|
||||
|
||||
/// GetBlockName - Return a symbolic block name if known, otherwise return
|
||||
/// null.
|
||||
static const char *GetBlockName(unsigned BlockID,
|
||||
const BitstreamReader &StreamFile) {
|
||||
// Standard blocks for all bitcode files.
|
||||
if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
|
||||
if (BlockID == bitc::BLOCKINFO_BLOCK_ID)
|
||||
return "BLOCKINFO_BLOCK";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check to see if we have a blockinfo record for this block, with a name.
|
||||
if (const BitstreamReader::BlockInfo *Info =
|
||||
StreamFile.getBlockInfo(BlockID)) {
|
||||
if (!Info->Name.empty())
|
||||
return Info->Name.c_str();
|
||||
}
|
||||
|
||||
|
||||
if (CurStreamType != LLVMIRBitstream) return 0;
|
||||
|
||||
switch (BlockID) {
|
||||
default: return 0;
|
||||
case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK";
|
||||
case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK";
|
||||
case bitc::TYPE_BLOCK_ID_OLD: return "TYPE_BLOCK_ID_OLD";
|
||||
case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID";
|
||||
case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK";
|
||||
case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK";
|
||||
case bitc::TYPE_SYMTAB_BLOCK_ID_OLD: return "TYPE_SYMTAB_OLD";
|
||||
case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB";
|
||||
case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK";
|
||||
case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK";
|
||||
}
|
||||
}
|
||||
|
||||
/// GetCodeName - Return a symbolic code name if known, otherwise return
|
||||
/// null.
|
||||
static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
|
||||
const BitstreamReader &StreamFile) {
|
||||
// Standard blocks for all bitcode files.
|
||||
if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
|
||||
if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::BLOCKINFO_CODE_SETBID: return "SETBID";
|
||||
case bitc::BLOCKINFO_CODE_BLOCKNAME: return "BLOCKNAME";
|
||||
case bitc::BLOCKINFO_CODE_SETRECORDNAME: return "SETRECORDNAME";
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check to see if we have a blockinfo record for this record, with a name.
|
||||
if (const BitstreamReader::BlockInfo *Info =
|
||||
StreamFile.getBlockInfo(BlockID)) {
|
||||
for (unsigned i = 0, e = Info->RecordNames.size(); i != e; ++i)
|
||||
if (Info->RecordNames[i].first == CodeID)
|
||||
return Info->RecordNames[i].second.c_str();
|
||||
}
|
||||
|
||||
|
||||
if (CurStreamType != LLVMIRBitstream) return 0;
|
||||
|
||||
switch (BlockID) {
|
||||
default: return 0;
|
||||
case bitc::MODULE_BLOCK_ID:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::MODULE_CODE_VERSION: return "VERSION";
|
||||
case bitc::MODULE_CODE_TRIPLE: return "TRIPLE";
|
||||
case bitc::MODULE_CODE_DATALAYOUT: return "DATALAYOUT";
|
||||
case bitc::MODULE_CODE_ASM: return "ASM";
|
||||
case bitc::MODULE_CODE_SECTIONNAME: return "SECTIONNAME";
|
||||
case bitc::MODULE_CODE_DEPLIB: return "DEPLIB";
|
||||
case bitc::MODULE_CODE_GLOBALVAR: return "GLOBALVAR";
|
||||
case bitc::MODULE_CODE_FUNCTION: return "FUNCTION";
|
||||
case bitc::MODULE_CODE_ALIAS: return "ALIAS";
|
||||
case bitc::MODULE_CODE_PURGEVALS: return "PURGEVALS";
|
||||
case bitc::MODULE_CODE_GCNAME: return "GCNAME";
|
||||
}
|
||||
case bitc::PARAMATTR_BLOCK_ID:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::PARAMATTR_CODE_ENTRY: return "ENTRY";
|
||||
}
|
||||
case bitc::TYPE_BLOCK_ID_OLD:
|
||||
case bitc::TYPE_BLOCK_ID_NEW:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::TYPE_CODE_NUMENTRY: return "NUMENTRY";
|
||||
case bitc::TYPE_CODE_VOID: return "VOID";
|
||||
case bitc::TYPE_CODE_FLOAT: return "FLOAT";
|
||||
case bitc::TYPE_CODE_DOUBLE: return "DOUBLE";
|
||||
case bitc::TYPE_CODE_LABEL: return "LABEL";
|
||||
case bitc::TYPE_CODE_OPAQUE: return "OPAQUE";
|
||||
case bitc::TYPE_CODE_INTEGER: return "INTEGER";
|
||||
case bitc::TYPE_CODE_POINTER: return "POINTER";
|
||||
case bitc::TYPE_CODE_FUNCTION: return "FUNCTION";
|
||||
case bitc::TYPE_CODE_STRUCT_OLD: return "STRUCT_OLD";
|
||||
case bitc::TYPE_CODE_ARRAY: return "ARRAY";
|
||||
case bitc::TYPE_CODE_VECTOR: return "VECTOR";
|
||||
case bitc::TYPE_CODE_X86_FP80: return "X86_FP80";
|
||||
case bitc::TYPE_CODE_FP128: return "FP128";
|
||||
case bitc::TYPE_CODE_PPC_FP128: return "PPC_FP128";
|
||||
case bitc::TYPE_CODE_METADATA: return "METADATA";
|
||||
case bitc::TYPE_CODE_STRUCT_ANON: return "STRUCT_ANON";
|
||||
case bitc::TYPE_CODE_STRUCT_NAME: return "STRUCT_NAME";
|
||||
case bitc::TYPE_CODE_STRUCT_NAMED: return "STRUCT_NAMED";
|
||||
}
|
||||
|
||||
case bitc::CONSTANTS_BLOCK_ID:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::CST_CODE_SETTYPE: return "SETTYPE";
|
||||
case bitc::CST_CODE_NULL: return "NULL";
|
||||
case bitc::CST_CODE_UNDEF: return "UNDEF";
|
||||
case bitc::CST_CODE_INTEGER: return "INTEGER";
|
||||
case bitc::CST_CODE_WIDE_INTEGER: return "WIDE_INTEGER";
|
||||
case bitc::CST_CODE_FLOAT: return "FLOAT";
|
||||
case bitc::CST_CODE_AGGREGATE: return "AGGREGATE";
|
||||
case bitc::CST_CODE_STRING: return "STRING";
|
||||
case bitc::CST_CODE_CSTRING: return "CSTRING";
|
||||
case bitc::CST_CODE_CE_BINOP: return "CE_BINOP";
|
||||
case bitc::CST_CODE_CE_CAST: return "CE_CAST";
|
||||
case bitc::CST_CODE_CE_GEP: return "CE_GEP";
|
||||
case bitc::CST_CODE_CE_INBOUNDS_GEP: return "CE_INBOUNDS_GEP";
|
||||
case bitc::CST_CODE_CE_SELECT: return "CE_SELECT";
|
||||
case bitc::CST_CODE_CE_EXTRACTELT: return "CE_EXTRACTELT";
|
||||
case bitc::CST_CODE_CE_INSERTELT: return "CE_INSERTELT";
|
||||
case bitc::CST_CODE_CE_SHUFFLEVEC: return "CE_SHUFFLEVEC";
|
||||
case bitc::CST_CODE_CE_CMP: return "CE_CMP";
|
||||
case bitc::CST_CODE_INLINEASM: return "INLINEASM";
|
||||
case bitc::CST_CODE_CE_SHUFVEC_EX: return "CE_SHUFVEC_EX";
|
||||
}
|
||||
case bitc::FUNCTION_BLOCK_ID:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::FUNC_CODE_DECLAREBLOCKS: return "DECLAREBLOCKS";
|
||||
|
||||
case bitc::FUNC_CODE_INST_BINOP: return "INST_BINOP";
|
||||
case bitc::FUNC_CODE_INST_CAST: return "INST_CAST";
|
||||
case bitc::FUNC_CODE_INST_GEP: return "INST_GEP";
|
||||
case bitc::FUNC_CODE_INST_INBOUNDS_GEP: return "INST_INBOUNDS_GEP";
|
||||
case bitc::FUNC_CODE_INST_SELECT: return "INST_SELECT";
|
||||
case bitc::FUNC_CODE_INST_EXTRACTELT: return "INST_EXTRACTELT";
|
||||
case bitc::FUNC_CODE_INST_INSERTELT: return "INST_INSERTELT";
|
||||
case bitc::FUNC_CODE_INST_SHUFFLEVEC: return "INST_SHUFFLEVEC";
|
||||
case bitc::FUNC_CODE_INST_CMP: return "INST_CMP";
|
||||
|
||||
case bitc::FUNC_CODE_INST_RET: return "INST_RET";
|
||||
case bitc::FUNC_CODE_INST_BR: return "INST_BR";
|
||||
case bitc::FUNC_CODE_INST_SWITCH: return "INST_SWITCH";
|
||||
case bitc::FUNC_CODE_INST_INVOKE: return "INST_INVOKE";
|
||||
case bitc::FUNC_CODE_INST_UNWIND: return "INST_UNWIND";
|
||||
case bitc::FUNC_CODE_INST_UNREACHABLE: return "INST_UNREACHABLE";
|
||||
|
||||
case bitc::FUNC_CODE_INST_PHI: return "INST_PHI";
|
||||
case bitc::FUNC_CODE_INST_ALLOCA: return "INST_ALLOCA";
|
||||
case bitc::FUNC_CODE_INST_LOAD: return "INST_LOAD";
|
||||
case bitc::FUNC_CODE_INST_VAARG: return "INST_VAARG";
|
||||
case bitc::FUNC_CODE_INST_STORE: return "INST_STORE";
|
||||
case bitc::FUNC_CODE_INST_EXTRACTVAL: return "INST_EXTRACTVAL";
|
||||
case bitc::FUNC_CODE_INST_INSERTVAL: return "INST_INSERTVAL";
|
||||
case bitc::FUNC_CODE_INST_CMP2: return "INST_CMP2";
|
||||
case bitc::FUNC_CODE_INST_VSELECT: return "INST_VSELECT";
|
||||
case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: return "DEBUG_LOC_AGAIN";
|
||||
case bitc::FUNC_CODE_INST_CALL: return "INST_CALL";
|
||||
case bitc::FUNC_CODE_DEBUG_LOC: return "DEBUG_LOC";
|
||||
}
|
||||
case bitc::TYPE_SYMTAB_BLOCK_ID_OLD:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::TST_CODE_ENTRY: return "ENTRY";
|
||||
}
|
||||
case bitc::VALUE_SYMTAB_BLOCK_ID:
|
||||
switch (CodeID) {
|
||||
default: return 0;
|
||||
case bitc::VST_CODE_ENTRY: return "ENTRY";
|
||||
case bitc::VST_CODE_BBENTRY: return "BBENTRY";
|
||||
}
|
||||
case bitc::METADATA_ATTACHMENT_ID:
|
||||
switch(CodeID) {
|
||||
default:return 0;
|
||||
case bitc::METADATA_ATTACHMENT: return "METADATA_ATTACHMENT";
|
||||
}
|
||||
case bitc::METADATA_BLOCK_ID:
|
||||
switch(CodeID) {
|
||||
default:return 0;
|
||||
case bitc::METADATA_STRING: return "METADATA_STRING";
|
||||
case bitc::METADATA_NAME: return "METADATA_NAME";
|
||||
case bitc::METADATA_KIND: return "METADATA_KIND";
|
||||
case bitc::METADATA_NODE: return "METADATA_NODE";
|
||||
case bitc::METADATA_FN_NODE: return "METADATA_FN_NODE";
|
||||
case bitc::METADATA_NAMED_NODE: return "METADATA_NAMED_NODE";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PerRecordStats {
|
||||
unsigned NumInstances;
|
||||
unsigned NumAbbrev;
|
||||
uint64_t TotalBits;
|
||||
|
||||
PerRecordStats() : NumInstances(0), NumAbbrev(0), TotalBits(0) {}
|
||||
};
|
||||
|
||||
struct PerBlockIDStats {
|
||||
/// NumInstances - This the number of times this block ID has been seen.
|
||||
unsigned NumInstances;
|
||||
|
||||
/// NumBits - The total size in bits of all of these blocks.
|
||||
uint64_t NumBits;
|
||||
|
||||
/// NumSubBlocks - The total number of blocks these blocks contain.
|
||||
unsigned NumSubBlocks;
|
||||
|
||||
/// NumAbbrevs - The total number of abbreviations.
|
||||
unsigned NumAbbrevs;
|
||||
|
||||
/// NumRecords - The total number of records these blocks contain, and the
|
||||
/// number that are abbreviated.
|
||||
unsigned NumRecords, NumAbbreviatedRecords;
|
||||
|
||||
/// CodeFreq - Keep track of the number of times we see each code.
|
||||
std::vector<PerRecordStats> CodeFreq;
|
||||
|
||||
PerBlockIDStats()
|
||||
: NumInstances(0), NumBits(0),
|
||||
NumSubBlocks(0), NumAbbrevs(0), NumRecords(0), NumAbbreviatedRecords(0) {}
|
||||
};
|
||||
|
||||
static std::map<unsigned, PerBlockIDStats> BlockIDStats;
|
||||
|
||||
|
||||
|
||||
/// Error - All bitcode analysis errors go through this function, making this a
|
||||
/// good place to breakpoint if debugging.
|
||||
static bool Error(const std::string &Err) {
|
||||
errs() << Err << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// ParseBlock - Read a block, updating statistics, etc.
|
||||
static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) {
|
||||
std::string Indent(IndentLevel*2, ' ');
|
||||
uint64_t BlockBitStart = Stream.GetCurrentBitNo();
|
||||
unsigned BlockID = Stream.ReadSubBlockID();
|
||||
|
||||
// Get the statistics for this BlockID.
|
||||
PerBlockIDStats &BlockStats = BlockIDStats[BlockID];
|
||||
|
||||
BlockStats.NumInstances++;
|
||||
|
||||
// BLOCKINFO is a special part of the stream.
|
||||
if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
|
||||
if (Dump) errs() << Indent << "<BLOCKINFO_BLOCK/>\n";
|
||||
if (Stream.ReadBlockInfoBlock())
|
||||
return Error("Malformed BlockInfoBlock");
|
||||
uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
|
||||
BlockStats.NumBits += BlockBitEnd-BlockBitStart;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned NumWords = 0;
|
||||
if (Stream.EnterSubBlock(BlockID, &NumWords))
|
||||
return Error("Malformed block record");
|
||||
|
||||
const char *BlockName = 0;
|
||||
if (Dump) {
|
||||
errs() << Indent << "<";
|
||||
if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader())))
|
||||
errs() << BlockName;
|
||||
else
|
||||
errs() << "UnknownBlock" << BlockID;
|
||||
|
||||
if (NonSymbolic && BlockName)
|
||||
errs() << " BlockID=" << BlockID;
|
||||
|
||||
errs() << " NumWords=" << NumWords
|
||||
<< " BlockCodeSize=" << Stream.GetAbbrevIDWidth() << ">\n";
|
||||
}
|
||||
|
||||
SmallVector<uint64_t, 64> Record;
|
||||
|
||||
// Read all the records for this block.
|
||||
while (1) {
|
||||
if (Stream.AtEndOfStream())
|
||||
return Error("Premature end of bitstream");
|
||||
|
||||
uint64_t RecordStartBit = Stream.GetCurrentBitNo();
|
||||
|
||||
// Read the code for this record.
|
||||
unsigned AbbrevID = Stream.ReadCode();
|
||||
switch (AbbrevID) {
|
||||
case bitc::END_BLOCK: {
|
||||
if (Stream.ReadBlockEnd())
|
||||
return Error("Error at end of block");
|
||||
uint64_t BlockBitEnd = Stream.GetCurrentBitNo();
|
||||
BlockStats.NumBits += BlockBitEnd-BlockBitStart;
|
||||
if (Dump) {
|
||||
errs() << Indent << "</";
|
||||
if (BlockName)
|
||||
errs() << BlockName << ">\n";
|
||||
else
|
||||
errs() << "UnknownBlock" << BlockID << ">\n";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case bitc::ENTER_SUBBLOCK: {
|
||||
uint64_t SubBlockBitStart = Stream.GetCurrentBitNo();
|
||||
if (ParseBlock(Stream, IndentLevel+1))
|
||||
return true;
|
||||
++BlockStats.NumSubBlocks;
|
||||
uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo();
|
||||
|
||||
// Don't include subblock sizes in the size of this block.
|
||||
BlockBitStart += SubBlockBitEnd-SubBlockBitStart;
|
||||
break;
|
||||
}
|
||||
case bitc::DEFINE_ABBREV:
|
||||
Stream.ReadAbbrevRecord();
|
||||
++BlockStats.NumAbbrevs;
|
||||
break;
|
||||
default:
|
||||
Record.clear();
|
||||
|
||||
++BlockStats.NumRecords;
|
||||
if (AbbrevID != bitc::UNABBREV_RECORD)
|
||||
++BlockStats.NumAbbreviatedRecords;
|
||||
|
||||
const char *BlobStart = 0;
|
||||
unsigned BlobLen = 0;
|
||||
unsigned Code = Stream.ReadRecord(AbbrevID, Record, BlobStart, BlobLen);
|
||||
|
||||
|
||||
|
||||
// Increment the # occurrences of this code.
|
||||
if (BlockStats.CodeFreq.size() <= Code)
|
||||
BlockStats.CodeFreq.resize(Code+1);
|
||||
BlockStats.CodeFreq[Code].NumInstances++;
|
||||
BlockStats.CodeFreq[Code].TotalBits +=
|
||||
Stream.GetCurrentBitNo()-RecordStartBit;
|
||||
if (AbbrevID != bitc::UNABBREV_RECORD)
|
||||
BlockStats.CodeFreq[Code].NumAbbrev++;
|
||||
|
||||
if (Dump) {
|
||||
errs() << Indent << " <";
|
||||
if (const char *CodeName =
|
||||
GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
|
||||
errs() << CodeName;
|
||||
else
|
||||
errs() << "UnknownCode" << Code;
|
||||
if (NonSymbolic &&
|
||||
GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
|
||||
errs() << " codeid=" << Code;
|
||||
if (AbbrevID != bitc::UNABBREV_RECORD)
|
||||
errs() << " abbrevid=" << AbbrevID;
|
||||
|
||||
for (unsigned i = 0, e = Record.size(); i != e; ++i)
|
||||
errs() << " op" << i << "=" << (int64_t)Record[i];
|
||||
|
||||
errs() << "/>";
|
||||
|
||||
if (BlobStart) {
|
||||
errs() << " blob data = ";
|
||||
bool BlobIsPrintable = true;
|
||||
for (unsigned i = 0; i != BlobLen; ++i)
|
||||
if (!isprint(BlobStart[i])) {
|
||||
BlobIsPrintable = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (BlobIsPrintable)
|
||||
errs() << "'" << std::string(BlobStart, BlobStart+BlobLen) <<"'";
|
||||
else
|
||||
errs() << "unprintable, " << BlobLen << " bytes.";
|
||||
}
|
||||
|
||||
errs() << "\n";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintSize(double Bits) {
|
||||
fprintf(stderr, "%.2f/%.2fB/%luW", Bits, Bits/8,(unsigned long)(Bits/32));
|
||||
}
|
||||
static void PrintSize(uint64_t Bits) {
|
||||
fprintf(stderr, "%lub/%.2fB/%luW", (unsigned long)Bits,
|
||||
(double)Bits/8, (unsigned long)(Bits/32));
|
||||
}
|
||||
|
||||
|
||||
/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
|
||||
static int AnalyzeBitcode() {
|
||||
// Read the input file.
|
||||
OwningPtr<MemoryBuffer> MemBuf;
|
||||
|
||||
if (error_code ec =
|
||||
MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), MemBuf))
|
||||
return Error("Error reading '" + InputFilename + "': " + ec.message());
|
||||
|
||||
if (MemBuf->getBufferSize() & 3)
|
||||
return Error("Bitcode stream should be a multiple of 4 bytes in length");
|
||||
|
||||
unsigned char *BufPtr = (unsigned char *)MemBuf->getBufferStart();
|
||||
unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize();
|
||||
|
||||
// If we have a wrapper header, parse it and ignore the non-bc file contents.
|
||||
// The magic number is 0x0B17C0DE stored in little endian.
|
||||
if (isBitcodeWrapper(BufPtr, EndBufPtr))
|
||||
if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr))
|
||||
return Error("Invalid bitcode wrapper header");
|
||||
|
||||
BitstreamReader StreamFile(BufPtr, EndBufPtr);
|
||||
BitstreamCursor Stream(StreamFile);
|
||||
StreamFile.CollectBlockInfoNames();
|
||||
|
||||
// Read the stream signature.
|
||||
char Signature[6];
|
||||
Signature[0] = Stream.Read(8);
|
||||
Signature[1] = Stream.Read(8);
|
||||
Signature[2] = Stream.Read(4);
|
||||
Signature[3] = Stream.Read(4);
|
||||
Signature[4] = Stream.Read(4);
|
||||
Signature[5] = Stream.Read(4);
|
||||
|
||||
// Autodetect the file contents, if it is one we know.
|
||||
CurStreamType = UnknownBitstream;
|
||||
if (Signature[0] == 'B' && Signature[1] == 'C' &&
|
||||
Signature[2] == 0x0 && Signature[3] == 0xC &&
|
||||
Signature[4] == 0xE && Signature[5] == 0xD)
|
||||
CurStreamType = LLVMIRBitstream;
|
||||
|
||||
unsigned NumTopBlocks = 0;
|
||||
|
||||
// Parse the top-level structure. We only allow blocks at the top-level.
|
||||
while (!Stream.AtEndOfStream()) {
|
||||
unsigned Code = Stream.ReadCode();
|
||||
if (Code != bitc::ENTER_SUBBLOCK)
|
||||
return Error("Invalid record at top-level");
|
||||
|
||||
if (ParseBlock(Stream, 0))
|
||||
return true;
|
||||
++NumTopBlocks;
|
||||
}
|
||||
|
||||
if (Dump) errs() << "\n\n";
|
||||
|
||||
uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT;
|
||||
// Print a summary of the read file.
|
||||
errs() << "Summary of " << InputFilename << ":\n";
|
||||
errs() << " Total size: ";
|
||||
PrintSize(BufferSizeBits);
|
||||
errs() << "\n";
|
||||
errs() << " Stream type: ";
|
||||
switch (CurStreamType) {
|
||||
default: assert(0 && "Unknown bitstream type");
|
||||
case UnknownBitstream: errs() << "unknown\n"; break;
|
||||
case LLVMIRBitstream: errs() << "LLVM IR\n"; break;
|
||||
}
|
||||
errs() << " # Toplevel Blocks: " << NumTopBlocks << "\n";
|
||||
errs() << "\n";
|
||||
|
||||
// Emit per-block stats.
|
||||
errs() << "Per-block Summary:\n";
|
||||
for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
|
||||
E = BlockIDStats.end(); I != E; ++I) {
|
||||
errs() << " Block ID #" << I->first;
|
||||
if (const char *BlockName = GetBlockName(I->first, StreamFile))
|
||||
errs() << " (" << BlockName << ")";
|
||||
errs() << ":\n";
|
||||
|
||||
const PerBlockIDStats &Stats = I->second;
|
||||
errs() << " Num Instances: " << Stats.NumInstances << "\n";
|
||||
errs() << " Total Size: ";
|
||||
PrintSize(Stats.NumBits);
|
||||
errs() << "\n";
|
||||
double pct = (Stats.NumBits * 100.0) / BufferSizeBits;
|
||||
errs() << " Percent of file: " << format("%2.4f%%", pct) << "\n";
|
||||
if (Stats.NumInstances > 1) {
|
||||
errs() << " Average Size: ";
|
||||
PrintSize(Stats.NumBits/(double)Stats.NumInstances);
|
||||
errs() << "\n";
|
||||
errs() << " Tot/Avg SubBlocks: " << Stats.NumSubBlocks << "/"
|
||||
<< Stats.NumSubBlocks/(double)Stats.NumInstances << "\n";
|
||||
errs() << " Tot/Avg Abbrevs: " << Stats.NumAbbrevs << "/"
|
||||
<< Stats.NumAbbrevs/(double)Stats.NumInstances << "\n";
|
||||
errs() << " Tot/Avg Records: " << Stats.NumRecords << "/"
|
||||
<< Stats.NumRecords/(double)Stats.NumInstances << "\n";
|
||||
} else {
|
||||
errs() << " Num SubBlocks: " << Stats.NumSubBlocks << "\n";
|
||||
errs() << " Num Abbrevs: " << Stats.NumAbbrevs << "\n";
|
||||
errs() << " Num Records: " << Stats.NumRecords << "\n";
|
||||
}
|
||||
if (Stats.NumRecords) {
|
||||
double pct = (Stats.NumAbbreviatedRecords * 100.0) / Stats.NumRecords;
|
||||
errs() << " Percent Abbrevs: " << format("%2.4f%%", pct) << "\n";
|
||||
}
|
||||
errs() << "\n";
|
||||
|
||||
// Print a histogram of the codes we see.
|
||||
if (!NoHistogram && !Stats.CodeFreq.empty()) {
|
||||
std::vector<std::pair<unsigned, unsigned> > FreqPairs; // <freq,code>
|
||||
for (unsigned i = 0, e = Stats.CodeFreq.size(); i != e; ++i)
|
||||
if (unsigned Freq = Stats.CodeFreq[i].NumInstances)
|
||||
FreqPairs.push_back(std::make_pair(Freq, i));
|
||||
std::stable_sort(FreqPairs.begin(), FreqPairs.end());
|
||||
std::reverse(FreqPairs.begin(), FreqPairs.end());
|
||||
|
||||
errs() << "\tRecord Histogram:\n";
|
||||
fprintf(stderr, "\t\t Count # Bits %% Abv Record Kind\n");
|
||||
for (unsigned i = 0, e = FreqPairs.size(); i != e; ++i) {
|
||||
const PerRecordStats &RecStats = Stats.CodeFreq[FreqPairs[i].second];
|
||||
|
||||
fprintf(stderr, "\t\t%7d %9lu ", RecStats.NumInstances,
|
||||
(unsigned long)RecStats.TotalBits);
|
||||
|
||||
if (RecStats.NumAbbrev)
|
||||
fprintf(stderr, "%7.2f ",
|
||||
(double)RecStats.NumAbbrev/RecStats.NumInstances*100);
|
||||
else
|
||||
fprintf(stderr, " ");
|
||||
|
||||
if (const char *CodeName =
|
||||
GetCodeName(FreqPairs[i].second, I->first, StreamFile))
|
||||
fprintf(stderr, "%s\n", CodeName);
|
||||
else
|
||||
fprintf(stderr, "UnknownCode%d\n", FreqPairs[i].second);
|
||||
}
|
||||
errs() << "\n";
|
||||
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm-bcanalyzer file analyzer\n");
|
||||
|
||||
return AnalyzeBitcode();
|
||||
}
|
8
contrib/llvm/tools/llvm-diff/CMakeLists.txt
Normal file
8
contrib/llvm/tools/llvm-diff/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
set(LLVM_LINK_COMPONENTS support asmparser bitreader)
|
||||
|
||||
add_llvm_tool(llvm-diff
|
||||
llvm-diff.cpp
|
||||
DiffConsumer.cpp
|
||||
DiffLog.cpp
|
||||
DifferenceEngine.cpp
|
||||
)
|
209
contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
Normal file
209
contrib/llvm/tools/llvm-diff/DiffConsumer.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
//===-- DiffConsumer.cpp - Difference Consumer ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This files implements the the LLVM difference Consumer
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DiffConsumer.h"
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static void ComputeNumbering(Function *F, DenseMap<Value*,unsigned> &Numbering){
|
||||
unsigned IN = 0;
|
||||
|
||||
// Arguments get the first numbers.
|
||||
for (Function::arg_iterator
|
||||
AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
|
||||
if (!AI->hasName())
|
||||
Numbering[&*AI] = IN++;
|
||||
|
||||
// Walk the basic blocks in order.
|
||||
for (Function::iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) {
|
||||
if (!FI->hasName())
|
||||
Numbering[&*FI] = IN++;
|
||||
|
||||
// Walk the instructions in order.
|
||||
for (BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ++BI)
|
||||
// void instructions don't get numbers.
|
||||
if (!BI->hasName() && !BI->getType()->isVoidTy())
|
||||
Numbering[&*BI] = IN++;
|
||||
}
|
||||
|
||||
assert(!Numbering.empty() && "asked for numbering but numbering was no-op");
|
||||
}
|
||||
|
||||
|
||||
void DiffConsumer::printValue(Value *V, bool isL) {
|
||||
if (V->hasName()) {
|
||||
out << (isa<GlobalValue>(V) ? '@' : '%') << V->getName();
|
||||
return;
|
||||
}
|
||||
if (V->getType()->isVoidTy()) {
|
||||
if (isa<StoreInst>(V)) {
|
||||
out << "store to ";
|
||||
printValue(cast<StoreInst>(V)->getPointerOperand(), isL);
|
||||
} else if (isa<CallInst>(V)) {
|
||||
out << "call to ";
|
||||
printValue(cast<CallInst>(V)->getCalledValue(), isL);
|
||||
} else if (isa<InvokeInst>(V)) {
|
||||
out << "invoke to ";
|
||||
printValue(cast<InvokeInst>(V)->getCalledValue(), isL);
|
||||
} else {
|
||||
out << *V;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned N = contexts.size();
|
||||
while (N > 0) {
|
||||
--N;
|
||||
DiffContext &ctxt = contexts[N];
|
||||
if (!ctxt.IsFunction) continue;
|
||||
if (isL) {
|
||||
if (ctxt.LNumbering.empty())
|
||||
ComputeNumbering(cast<Function>(ctxt.L), ctxt.LNumbering);
|
||||
out << '%' << ctxt.LNumbering[V];
|
||||
return;
|
||||
} else {
|
||||
if (ctxt.RNumbering.empty())
|
||||
ComputeNumbering(cast<Function>(ctxt.R), ctxt.RNumbering);
|
||||
out << '%' << ctxt.RNumbering[V];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out << "<anonymous>";
|
||||
}
|
||||
|
||||
void DiffConsumer::header() {
|
||||
if (contexts.empty()) return;
|
||||
for (SmallVectorImpl<DiffContext>::iterator
|
||||
I = contexts.begin(), E = contexts.end(); I != E; ++I) {
|
||||
if (I->Differences) continue;
|
||||
if (isa<Function>(I->L)) {
|
||||
// Extra newline between functions.
|
||||
if (Differences) out << "\n";
|
||||
|
||||
Function *L = cast<Function>(I->L);
|
||||
Function *R = cast<Function>(I->R);
|
||||
if (L->getName() != R->getName())
|
||||
out << "in function " << L->getName()
|
||||
<< " / " << R->getName() << ":\n";
|
||||
else
|
||||
out << "in function " << L->getName() << ":\n";
|
||||
} else if (isa<BasicBlock>(I->L)) {
|
||||
BasicBlock *L = cast<BasicBlock>(I->L);
|
||||
BasicBlock *R = cast<BasicBlock>(I->R);
|
||||
if (L->hasName() && R->hasName() && L->getName() == R->getName())
|
||||
out << " in block %" << L->getName() << ":\n";
|
||||
else {
|
||||
out << " in block ";
|
||||
printValue(L, true);
|
||||
out << " / ";
|
||||
printValue(R, false);
|
||||
out << ":\n";
|
||||
}
|
||||
} else if (isa<Instruction>(I->L)) {
|
||||
out << " in instruction ";
|
||||
printValue(I->L, true);
|
||||
out << " / ";
|
||||
printValue(I->R, false);
|
||||
out << ":\n";
|
||||
}
|
||||
|
||||
I->Differences = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DiffConsumer::indent() {
|
||||
unsigned N = Indent;
|
||||
while (N--) out << ' ';
|
||||
}
|
||||
|
||||
bool DiffConsumer::hadDifferences() const {
|
||||
return Differences;
|
||||
}
|
||||
|
||||
void DiffConsumer::enterContext(Value *L, Value *R) {
|
||||
contexts.push_back(DiffContext(L, R));
|
||||
Indent += 2;
|
||||
}
|
||||
|
||||
void DiffConsumer::exitContext() {
|
||||
Differences |= contexts.back().Differences;
|
||||
contexts.pop_back();
|
||||
Indent -= 2;
|
||||
}
|
||||
|
||||
void DiffConsumer::log(StringRef text) {
|
||||
header();
|
||||
indent();
|
||||
out << text << '\n';
|
||||
}
|
||||
|
||||
void DiffConsumer::logf(const LogBuilder &Log) {
|
||||
header();
|
||||
indent();
|
||||
|
||||
unsigned arg = 0;
|
||||
|
||||
StringRef format = Log.getFormat();
|
||||
while (true) {
|
||||
size_t percent = format.find('%');
|
||||
if (percent == StringRef::npos) {
|
||||
out << format;
|
||||
break;
|
||||
}
|
||||
assert(format[percent] == '%');
|
||||
|
||||
if (percent > 0) out << format.substr(0, percent);
|
||||
|
||||
switch (format[percent+1]) {
|
||||
case '%': out << '%'; break;
|
||||
case 'l': printValue(Log.getArgument(arg++), true); break;
|
||||
case 'r': printValue(Log.getArgument(arg++), false); break;
|
||||
default: llvm_unreachable("unknown format character");
|
||||
}
|
||||
|
||||
format = format.substr(percent+2);
|
||||
}
|
||||
|
||||
out << '\n';
|
||||
}
|
||||
|
||||
void DiffConsumer::logd(const DiffLogBuilder &Log) {
|
||||
header();
|
||||
|
||||
for (unsigned I = 0, E = Log.getNumLines(); I != E; ++I) {
|
||||
indent();
|
||||
switch (Log.getLineKind(I)) {
|
||||
case DC_match:
|
||||
out << " ";
|
||||
Log.getLeft(I)->dump();
|
||||
//printValue(Log.getLeft(I), true);
|
||||
break;
|
||||
case DC_left:
|
||||
out << "< ";
|
||||
Log.getLeft(I)->dump();
|
||||
//printValue(Log.getLeft(I), true);
|
||||
break;
|
||||
case DC_right:
|
||||
out << "> ";
|
||||
Log.getRight(I)->dump();
|
||||
//printValue(Log.getRight(I), false);
|
||||
break;
|
||||
}
|
||||
//out << "\n";
|
||||
}
|
||||
}
|
92
contrib/llvm/tools/llvm-diff/DiffConsumer.h
Normal file
92
contrib/llvm/tools/llvm-diff/DiffConsumer.h
Normal file
@ -0,0 +1,92 @@
|
||||
//===-- DiffConsumer.h - Difference Consumer --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines the interface to the LLVM difference Consumer
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LLVM_DIFFCONSUMER_H_
|
||||
#define _LLVM_DIFFCONSUMER_H_
|
||||
|
||||
#include "DiffLog.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
class Value;
|
||||
class Function;
|
||||
|
||||
/// The interface for consumers of difference data.
|
||||
class Consumer {
|
||||
public:
|
||||
/// Record that a local context has been entered. Left and
|
||||
/// Right are IR "containers" of some sort which are being
|
||||
/// considered for structural equivalence: global variables,
|
||||
/// functions, blocks, instructions, etc.
|
||||
virtual void enterContext(Value *Left, Value *Right) = 0;
|
||||
|
||||
/// Record that a local context has been exited.
|
||||
virtual void exitContext() = 0;
|
||||
|
||||
/// Record a difference within the current context.
|
||||
virtual void log(StringRef Text) = 0;
|
||||
|
||||
/// Record a formatted difference within the current context.
|
||||
virtual void logf(const LogBuilder &Log) = 0;
|
||||
|
||||
/// Record a line-by-line instruction diff.
|
||||
virtual void logd(const DiffLogBuilder &Log) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Consumer() {}
|
||||
};
|
||||
|
||||
class DiffConsumer : public Consumer {
|
||||
private:
|
||||
struct DiffContext {
|
||||
DiffContext(Value *L, Value *R)
|
||||
: L(L), R(R), Differences(false), IsFunction(isa<Function>(L)) {}
|
||||
Value *L;
|
||||
Value *R;
|
||||
bool Differences;
|
||||
bool IsFunction;
|
||||
DenseMap<Value*,unsigned> LNumbering;
|
||||
DenseMap<Value*,unsigned> RNumbering;
|
||||
};
|
||||
|
||||
raw_ostream &out;
|
||||
Module *LModule;
|
||||
Module *RModule;
|
||||
SmallVector<DiffContext, 5> contexts;
|
||||
bool Differences;
|
||||
unsigned Indent;
|
||||
|
||||
void printValue(Value *V, bool isL);
|
||||
void header();
|
||||
void indent();
|
||||
|
||||
public:
|
||||
DiffConsumer(Module *L, Module *R)
|
||||
: out(errs()), LModule(L), RModule(R), Differences(false), Indent(0) {}
|
||||
|
||||
bool hadDifferences() const;
|
||||
void enterContext(Value *L, Value *R);
|
||||
void exitContext();
|
||||
void log(StringRef text);
|
||||
void logf(const LogBuilder &Log);
|
||||
void logd(const DiffLogBuilder &Log);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
53
contrib/llvm/tools/llvm-diff/DiffLog.cpp
Normal file
53
contrib/llvm/tools/llvm-diff/DiffLog.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines the interface to the LLVM difference log builder.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DiffLog.h"
|
||||
#include "DiffConsumer.h"
|
||||
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
LogBuilder::~LogBuilder() {
|
||||
consumer.logf(*this);
|
||||
}
|
||||
|
||||
StringRef LogBuilder::getFormat() const { return Format; }
|
||||
|
||||
unsigned LogBuilder::getNumArguments() const { return Arguments.size(); }
|
||||
Value *LogBuilder::getArgument(unsigned I) const { return Arguments[I]; }
|
||||
|
||||
DiffLogBuilder::~DiffLogBuilder() { consumer.logd(*this); }
|
||||
|
||||
void DiffLogBuilder::addMatch(Instruction *L, Instruction *R) {
|
||||
Diff.push_back(DiffRecord(L, R));
|
||||
}
|
||||
void DiffLogBuilder::addLeft(Instruction *L) {
|
||||
// HACK: VS 2010 has a bug in the stdlib that requires this.
|
||||
Diff.push_back(DiffRecord(L, DiffRecord::second_type(0)));
|
||||
}
|
||||
void DiffLogBuilder::addRight(Instruction *R) {
|
||||
// HACK: VS 2010 has a bug in the stdlib that requires this.
|
||||
Diff.push_back(DiffRecord(DiffRecord::first_type(0), R));
|
||||
}
|
||||
|
||||
unsigned DiffLogBuilder::getNumLines() const { return Diff.size(); }
|
||||
|
||||
DiffChange DiffLogBuilder::getLineKind(unsigned I) const {
|
||||
return (Diff[I].first ? (Diff[I].second ? DC_match : DC_left)
|
||||
: DC_right);
|
||||
}
|
||||
Instruction *DiffLogBuilder::getLeft(unsigned I) const { return Diff[I].first; }
|
||||
Instruction *DiffLogBuilder::getRight(unsigned I) const { return Diff[I].second; }
|
80
contrib/llvm/tools/llvm-diff/DiffLog.h
Normal file
80
contrib/llvm/tools/llvm-diff/DiffLog.h
Normal file
@ -0,0 +1,80 @@
|
||||
//===-- DiffLog.h - Difference Log Builder and accessories ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines the interface to the LLVM difference log builder.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LLVM_DIFFLOG_H_
|
||||
#define _LLVM_DIFFLOG_H_
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
class Instruction;
|
||||
class Value;
|
||||
class Consumer;
|
||||
|
||||
/// Trichotomy assumption
|
||||
enum DiffChange { DC_match, DC_left, DC_right };
|
||||
|
||||
/// A temporary-object class for building up log messages.
|
||||
class LogBuilder {
|
||||
Consumer &consumer;
|
||||
|
||||
/// The use of a stored StringRef here is okay because
|
||||
/// LogBuilder should be used only as a temporary, and as a
|
||||
/// temporary it will be destructed before whatever temporary
|
||||
/// might be initializing this format.
|
||||
StringRef Format;
|
||||
|
||||
SmallVector<Value*, 4> Arguments;
|
||||
|
||||
public:
|
||||
LogBuilder(Consumer &c, StringRef Format)
|
||||
: consumer(c), Format(Format) {}
|
||||
|
||||
LogBuilder &operator<<(Value *V) {
|
||||
Arguments.push_back(V);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~LogBuilder();
|
||||
|
||||
StringRef getFormat() const;
|
||||
unsigned getNumArguments() const;
|
||||
Value *getArgument(unsigned I) const;
|
||||
};
|
||||
|
||||
/// A temporary-object class for building up diff messages.
|
||||
class DiffLogBuilder {
|
||||
typedef std::pair<Instruction*,Instruction*> DiffRecord;
|
||||
SmallVector<DiffRecord, 20> Diff;
|
||||
|
||||
Consumer &consumer;
|
||||
|
||||
public:
|
||||
DiffLogBuilder(Consumer &c) : consumer(c) {}
|
||||
~DiffLogBuilder();
|
||||
|
||||
void addMatch(Instruction *L, Instruction *R);
|
||||
// HACK: VS 2010 has a bug in the stdlib that requires this.
|
||||
void addLeft(Instruction *L);
|
||||
void addRight(Instruction *R);
|
||||
|
||||
unsigned getNumLines() const;
|
||||
DiffChange getLineKind(unsigned I) const;
|
||||
Instruction *getLeft(unsigned I) const;
|
||||
Instruction *getRight(unsigned I) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
677
contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
Normal file
677
contrib/llvm/tools/llvm-diff/DifferenceEngine.cpp
Normal file
@ -0,0 +1,677 @@
|
||||
//===-- DifferenceEngine.cpp - Structural function/module comparison ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines the implementation of the LLVM difference
|
||||
// engine, which structurally compares global values within a module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DifferenceEngine.h"
|
||||
|
||||
#include "llvm/Constants.h"
|
||||
#include "llvm/Function.h"
|
||||
#include "llvm/Instructions.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
/// A priority queue, implemented as a heap.
|
||||
template <class T, class Sorter, unsigned InlineCapacity>
|
||||
class PriorityQueue {
|
||||
Sorter Precedes;
|
||||
llvm::SmallVector<T, InlineCapacity> Storage;
|
||||
|
||||
public:
|
||||
PriorityQueue(const Sorter &Precedes) : Precedes(Precedes) {}
|
||||
|
||||
/// Checks whether the heap is empty.
|
||||
bool empty() const { return Storage.empty(); }
|
||||
|
||||
/// Insert a new value on the heap.
|
||||
void insert(const T &V) {
|
||||
unsigned Index = Storage.size();
|
||||
Storage.push_back(V);
|
||||
if (Index == 0) return;
|
||||
|
||||
T *data = Storage.data();
|
||||
while (true) {
|
||||
unsigned Target = (Index + 1) / 2 - 1;
|
||||
if (!Precedes(data[Index], data[Target])) return;
|
||||
std::swap(data[Index], data[Target]);
|
||||
if (Target == 0) return;
|
||||
Index = Target;
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the minimum value in the heap. Only valid on a non-empty heap.
|
||||
T remove_min() {
|
||||
assert(!empty());
|
||||
T tmp = Storage[0];
|
||||
|
||||
unsigned NewSize = Storage.size() - 1;
|
||||
if (NewSize) {
|
||||
// Move the slot at the end to the beginning.
|
||||
if (isPodLike<T>::value)
|
||||
Storage[0] = Storage[NewSize];
|
||||
else
|
||||
std::swap(Storage[0], Storage[NewSize]);
|
||||
|
||||
// Bubble the root up as necessary.
|
||||
unsigned Index = 0;
|
||||
while (true) {
|
||||
// With a 1-based index, the children would be Index*2 and Index*2+1.
|
||||
unsigned R = (Index + 1) * 2;
|
||||
unsigned L = R - 1;
|
||||
|
||||
// If R is out of bounds, we're done after this in any case.
|
||||
if (R >= NewSize) {
|
||||
// If L is also out of bounds, we're done immediately.
|
||||
if (L >= NewSize) break;
|
||||
|
||||
// Otherwise, test whether we should swap L and Index.
|
||||
if (Precedes(Storage[L], Storage[Index]))
|
||||
std::swap(Storage[L], Storage[Index]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherwise, we need to compare with the smaller of L and R.
|
||||
// Prefer R because it's closer to the end of the array.
|
||||
unsigned IndexToTest = (Precedes(Storage[L], Storage[R]) ? L : R);
|
||||
|
||||
// If Index is >= the min of L and R, then heap ordering is restored.
|
||||
if (!Precedes(Storage[IndexToTest], Storage[Index]))
|
||||
break;
|
||||
|
||||
// Otherwise, keep bubbling up.
|
||||
std::swap(Storage[IndexToTest], Storage[Index]);
|
||||
Index = IndexToTest;
|
||||
}
|
||||
}
|
||||
Storage.pop_back();
|
||||
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// A function-scope difference engine.
|
||||
class FunctionDifferenceEngine {
|
||||
DifferenceEngine &Engine;
|
||||
|
||||
/// The current mapping from old local values to new local values.
|
||||
DenseMap<Value*, Value*> Values;
|
||||
|
||||
/// The current mapping from old blocks to new blocks.
|
||||
DenseMap<BasicBlock*, BasicBlock*> Blocks;
|
||||
|
||||
DenseSet<std::pair<Value*, Value*> > TentativeValues;
|
||||
|
||||
unsigned getUnprocPredCount(BasicBlock *Block) const {
|
||||
unsigned Count = 0;
|
||||
for (pred_iterator I = pred_begin(Block), E = pred_end(Block); I != E; ++I)
|
||||
if (!Blocks.count(*I)) Count++;
|
||||
return Count;
|
||||
}
|
||||
|
||||
typedef std::pair<BasicBlock*, BasicBlock*> BlockPair;
|
||||
|
||||
/// A type which sorts a priority queue by the number of unprocessed
|
||||
/// predecessor blocks it has remaining.
|
||||
///
|
||||
/// This is actually really expensive to calculate.
|
||||
struct QueueSorter {
|
||||
const FunctionDifferenceEngine &fde;
|
||||
explicit QueueSorter(const FunctionDifferenceEngine &fde) : fde(fde) {}
|
||||
|
||||
bool operator()(const BlockPair &Old, const BlockPair &New) {
|
||||
return fde.getUnprocPredCount(Old.first)
|
||||
< fde.getUnprocPredCount(New.first);
|
||||
}
|
||||
};
|
||||
|
||||
/// A queue of unified blocks to process.
|
||||
PriorityQueue<BlockPair, QueueSorter, 20> Queue;
|
||||
|
||||
/// Try to unify the given two blocks. Enqueues them for processing
|
||||
/// if they haven't already been processed.
|
||||
///
|
||||
/// Returns true if there was a problem unifying them.
|
||||
bool tryUnify(BasicBlock *L, BasicBlock *R) {
|
||||
BasicBlock *&Ref = Blocks[L];
|
||||
|
||||
if (Ref) {
|
||||
if (Ref == R) return false;
|
||||
|
||||
Engine.logf("successor %l cannot be equivalent to %r; "
|
||||
"it's already equivalent to %r")
|
||||
<< L << R << Ref;
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref = R;
|
||||
Queue.insert(BlockPair(L, R));
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Unifies two instructions, given that they're known not to have
|
||||
/// structural differences.
|
||||
void unify(Instruction *L, Instruction *R) {
|
||||
DifferenceEngine::Context C(Engine, L, R);
|
||||
|
||||
bool Result = diff(L, R, true, true);
|
||||
assert(!Result && "structural differences second time around?");
|
||||
(void) Result;
|
||||
if (!L->use_empty())
|
||||
Values[L] = R;
|
||||
}
|
||||
|
||||
void processQueue() {
|
||||
while (!Queue.empty()) {
|
||||
BlockPair Pair = Queue.remove_min();
|
||||
diff(Pair.first, Pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
void diff(BasicBlock *L, BasicBlock *R) {
|
||||
DifferenceEngine::Context C(Engine, L, R);
|
||||
|
||||
BasicBlock::iterator LI = L->begin(), LE = L->end();
|
||||
BasicBlock::iterator RI = R->begin();
|
||||
|
||||
llvm::SmallVector<std::pair<Instruction*,Instruction*>, 20> TentativePairs;
|
||||
|
||||
do {
|
||||
assert(LI != LE && RI != R->end());
|
||||
Instruction *LeftI = &*LI, *RightI = &*RI;
|
||||
|
||||
// If the instructions differ, start the more sophisticated diff
|
||||
// algorithm at the start of the block.
|
||||
if (diff(LeftI, RightI, false, false)) {
|
||||
TentativeValues.clear();
|
||||
return runBlockDiff(L->begin(), R->begin());
|
||||
}
|
||||
|
||||
// Otherwise, tentatively unify them.
|
||||
if (!LeftI->use_empty())
|
||||
TentativeValues.insert(std::make_pair(LeftI, RightI));
|
||||
|
||||
++LI, ++RI;
|
||||
} while (LI != LE); // This is sufficient: we can't get equality of
|
||||
// terminators if there are residual instructions.
|
||||
|
||||
// Unify everything in the block, non-tentatively this time.
|
||||
TentativeValues.clear();
|
||||
for (LI = L->begin(), RI = R->begin(); LI != LE; ++LI, ++RI)
|
||||
unify(&*LI, &*RI);
|
||||
}
|
||||
|
||||
bool matchForBlockDiff(Instruction *L, Instruction *R);
|
||||
void runBlockDiff(BasicBlock::iterator LI, BasicBlock::iterator RI);
|
||||
|
||||
bool diffCallSites(CallSite L, CallSite R, bool Complain) {
|
||||
// FIXME: call attributes
|
||||
if (!equivalentAsOperands(L.getCalledValue(), R.getCalledValue())) {
|
||||
if (Complain) Engine.log("called functions differ");
|
||||
return true;
|
||||
}
|
||||
if (L.arg_size() != R.arg_size()) {
|
||||
if (Complain) Engine.log("argument counts differ");
|
||||
return true;
|
||||
}
|
||||
for (unsigned I = 0, E = L.arg_size(); I != E; ++I)
|
||||
if (!equivalentAsOperands(L.getArgument(I), R.getArgument(I))) {
|
||||
if (Complain)
|
||||
Engine.logf("arguments %l and %r differ")
|
||||
<< L.getArgument(I) << R.getArgument(I);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool diff(Instruction *L, Instruction *R, bool Complain, bool TryUnify) {
|
||||
// FIXME: metadata (if Complain is set)
|
||||
|
||||
// Different opcodes always imply different operations.
|
||||
if (L->getOpcode() != R->getOpcode()) {
|
||||
if (Complain) Engine.log("different instruction types");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isa<CmpInst>(L)) {
|
||||
if (cast<CmpInst>(L)->getPredicate()
|
||||
!= cast<CmpInst>(R)->getPredicate()) {
|
||||
if (Complain) Engine.log("different predicates");
|
||||
return true;
|
||||
}
|
||||
} else if (isa<CallInst>(L)) {
|
||||
return diffCallSites(CallSite(L), CallSite(R), Complain);
|
||||
} else if (isa<PHINode>(L)) {
|
||||
// FIXME: implement.
|
||||
|
||||
// This is really weird; type uniquing is broken?
|
||||
if (L->getType() != R->getType()) {
|
||||
if (!L->getType()->isPointerTy() || !R->getType()->isPointerTy()) {
|
||||
if (Complain) Engine.log("different phi types");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
// Terminators.
|
||||
} else if (isa<InvokeInst>(L)) {
|
||||
InvokeInst *LI = cast<InvokeInst>(L);
|
||||
InvokeInst *RI = cast<InvokeInst>(R);
|
||||
if (diffCallSites(CallSite(LI), CallSite(RI), Complain))
|
||||
return true;
|
||||
|
||||
if (TryUnify) {
|
||||
tryUnify(LI->getNormalDest(), RI->getNormalDest());
|
||||
tryUnify(LI->getUnwindDest(), RI->getUnwindDest());
|
||||
}
|
||||
return false;
|
||||
|
||||
} else if (isa<BranchInst>(L)) {
|
||||
BranchInst *LI = cast<BranchInst>(L);
|
||||
BranchInst *RI = cast<BranchInst>(R);
|
||||
if (LI->isConditional() != RI->isConditional()) {
|
||||
if (Complain) Engine.log("branch conditionality differs");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (LI->isConditional()) {
|
||||
if (!equivalentAsOperands(LI->getCondition(), RI->getCondition())) {
|
||||
if (Complain) Engine.log("branch conditions differ");
|
||||
return true;
|
||||
}
|
||||
if (TryUnify) tryUnify(LI->getSuccessor(1), RI->getSuccessor(1));
|
||||
}
|
||||
if (TryUnify) tryUnify(LI->getSuccessor(0), RI->getSuccessor(0));
|
||||
return false;
|
||||
|
||||
} else if (isa<SwitchInst>(L)) {
|
||||
SwitchInst *LI = cast<SwitchInst>(L);
|
||||
SwitchInst *RI = cast<SwitchInst>(R);
|
||||
if (!equivalentAsOperands(LI->getCondition(), RI->getCondition())) {
|
||||
if (Complain) Engine.log("switch conditions differ");
|
||||
return true;
|
||||
}
|
||||
if (TryUnify) tryUnify(LI->getDefaultDest(), RI->getDefaultDest());
|
||||
|
||||
bool Difference = false;
|
||||
|
||||
DenseMap<ConstantInt*,BasicBlock*> LCases;
|
||||
for (unsigned I = 1, E = LI->getNumCases(); I != E; ++I)
|
||||
LCases[LI->getCaseValue(I)] = LI->getSuccessor(I);
|
||||
for (unsigned I = 1, E = RI->getNumCases(); I != E; ++I) {
|
||||
ConstantInt *CaseValue = RI->getCaseValue(I);
|
||||
BasicBlock *LCase = LCases[CaseValue];
|
||||
if (LCase) {
|
||||
if (TryUnify) tryUnify(LCase, RI->getSuccessor(I));
|
||||
LCases.erase(CaseValue);
|
||||
} else if (!Difference) {
|
||||
if (Complain)
|
||||
Engine.logf("right switch has extra case %r") << CaseValue;
|
||||
Difference = true;
|
||||
}
|
||||
}
|
||||
if (!Difference)
|
||||
for (DenseMap<ConstantInt*,BasicBlock*>::iterator
|
||||
I = LCases.begin(), E = LCases.end(); I != E; ++I) {
|
||||
if (Complain)
|
||||
Engine.logf("left switch has extra case %l") << I->first;
|
||||
Difference = true;
|
||||
}
|
||||
return Difference;
|
||||
} else if (isa<UnreachableInst>(L)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (L->getNumOperands() != R->getNumOperands()) {
|
||||
if (Complain) Engine.log("instructions have different operand counts");
|
||||
return true;
|
||||
}
|
||||
|
||||
for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I) {
|
||||
Value *LO = L->getOperand(I), *RO = R->getOperand(I);
|
||||
if (!equivalentAsOperands(LO, RO)) {
|
||||
if (Complain) Engine.logf("operands %l and %r differ") << LO << RO;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool equivalentAsOperands(Constant *L, Constant *R) {
|
||||
// Use equality as a preliminary filter.
|
||||
if (L == R)
|
||||
return true;
|
||||
|
||||
if (L->getValueID() != R->getValueID())
|
||||
return false;
|
||||
|
||||
// Ask the engine about global values.
|
||||
if (isa<GlobalValue>(L))
|
||||
return Engine.equivalentAsOperands(cast<GlobalValue>(L),
|
||||
cast<GlobalValue>(R));
|
||||
|
||||
// Compare constant expressions structurally.
|
||||
if (isa<ConstantExpr>(L))
|
||||
return equivalentAsOperands(cast<ConstantExpr>(L),
|
||||
cast<ConstantExpr>(R));
|
||||
|
||||
// Nulls of the "same type" don't always actually have the same
|
||||
// type; I don't know why. Just white-list them.
|
||||
if (isa<ConstantPointerNull>(L))
|
||||
return true;
|
||||
|
||||
// Block addresses only match if we've already encountered the
|
||||
// block. FIXME: tentative matches?
|
||||
if (isa<BlockAddress>(L))
|
||||
return Blocks[cast<BlockAddress>(L)->getBasicBlock()]
|
||||
== cast<BlockAddress>(R)->getBasicBlock();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool equivalentAsOperands(ConstantExpr *L, ConstantExpr *R) {
|
||||
if (L == R)
|
||||
return true;
|
||||
if (L->getOpcode() != R->getOpcode())
|
||||
return false;
|
||||
|
||||
switch (L->getOpcode()) {
|
||||
case Instruction::ICmp:
|
||||
case Instruction::FCmp:
|
||||
if (L->getPredicate() != R->getPredicate())
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Instruction::GetElementPtr:
|
||||
// FIXME: inbounds?
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (L->getNumOperands() != R->getNumOperands())
|
||||
return false;
|
||||
|
||||
for (unsigned I = 0, E = L->getNumOperands(); I != E; ++I)
|
||||
if (!equivalentAsOperands(L->getOperand(I), R->getOperand(I)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool equivalentAsOperands(Value *L, Value *R) {
|
||||
// Fall out if the values have different kind.
|
||||
// This possibly shouldn't take priority over oracles.
|
||||
if (L->getValueID() != R->getValueID())
|
||||
return false;
|
||||
|
||||
// Value subtypes: Argument, Constant, Instruction, BasicBlock,
|
||||
// InlineAsm, MDNode, MDString, PseudoSourceValue
|
||||
|
||||
if (isa<Constant>(L))
|
||||
return equivalentAsOperands(cast<Constant>(L), cast<Constant>(R));
|
||||
|
||||
if (isa<Instruction>(L))
|
||||
return Values[L] == R || TentativeValues.count(std::make_pair(L, R));
|
||||
|
||||
if (isa<Argument>(L))
|
||||
return Values[L] == R;
|
||||
|
||||
if (isa<BasicBlock>(L))
|
||||
return Blocks[cast<BasicBlock>(L)] != R;
|
||||
|
||||
// Pretend everything else is identical.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Avoid a gcc warning about accessing 'this' in an initializer.
|
||||
FunctionDifferenceEngine *this_() { return this; }
|
||||
|
||||
public:
|
||||
FunctionDifferenceEngine(DifferenceEngine &Engine) :
|
||||
Engine(Engine), Queue(QueueSorter(*this_())) {}
|
||||
|
||||
void diff(Function *L, Function *R) {
|
||||
if (L->arg_size() != R->arg_size())
|
||||
Engine.log("different argument counts");
|
||||
|
||||
// Map the arguments.
|
||||
for (Function::arg_iterator
|
||||
LI = L->arg_begin(), LE = L->arg_end(),
|
||||
RI = R->arg_begin(), RE = R->arg_end();
|
||||
LI != LE && RI != RE; ++LI, ++RI)
|
||||
Values[&*LI] = &*RI;
|
||||
|
||||
tryUnify(&*L->begin(), &*R->begin());
|
||||
processQueue();
|
||||
}
|
||||
};
|
||||
|
||||
struct DiffEntry {
|
||||
DiffEntry() : Cost(0) {}
|
||||
|
||||
unsigned Cost;
|
||||
llvm::SmallVector<char, 8> Path; // actually of DifferenceEngine::DiffChange
|
||||
};
|
||||
|
||||
bool FunctionDifferenceEngine::matchForBlockDiff(Instruction *L,
|
||||
Instruction *R) {
|
||||
return !diff(L, R, false, false);
|
||||
}
|
||||
|
||||
void FunctionDifferenceEngine::runBlockDiff(BasicBlock::iterator LStart,
|
||||
BasicBlock::iterator RStart) {
|
||||
BasicBlock::iterator LE = LStart->getParent()->end();
|
||||
BasicBlock::iterator RE = RStart->getParent()->end();
|
||||
|
||||
unsigned NL = std::distance(LStart, LE);
|
||||
|
||||
SmallVector<DiffEntry, 20> Paths1(NL+1);
|
||||
SmallVector<DiffEntry, 20> Paths2(NL+1);
|
||||
|
||||
DiffEntry *Cur = Paths1.data();
|
||||
DiffEntry *Next = Paths2.data();
|
||||
|
||||
const unsigned LeftCost = 2;
|
||||
const unsigned RightCost = 2;
|
||||
const unsigned MatchCost = 0;
|
||||
|
||||
assert(TentativeValues.empty());
|
||||
|
||||
// Initialize the first column.
|
||||
for (unsigned I = 0; I != NL+1; ++I) {
|
||||
Cur[I].Cost = I * LeftCost;
|
||||
for (unsigned J = 0; J != I; ++J)
|
||||
Cur[I].Path.push_back(DC_left);
|
||||
}
|
||||
|
||||
for (BasicBlock::iterator RI = RStart; RI != RE; ++RI) {
|
||||
// Initialize the first row.
|
||||
Next[0] = Cur[0];
|
||||
Next[0].Cost += RightCost;
|
||||
Next[0].Path.push_back(DC_right);
|
||||
|
||||
unsigned Index = 1;
|
||||
for (BasicBlock::iterator LI = LStart; LI != LE; ++LI, ++Index) {
|
||||
if (matchForBlockDiff(&*LI, &*RI)) {
|
||||
Next[Index] = Cur[Index-1];
|
||||
Next[Index].Cost += MatchCost;
|
||||
Next[Index].Path.push_back(DC_match);
|
||||
TentativeValues.insert(std::make_pair(&*LI, &*RI));
|
||||
} else if (Next[Index-1].Cost <= Cur[Index].Cost) {
|
||||
Next[Index] = Next[Index-1];
|
||||
Next[Index].Cost += LeftCost;
|
||||
Next[Index].Path.push_back(DC_left);
|
||||
} else {
|
||||
Next[Index] = Cur[Index];
|
||||
Next[Index].Cost += RightCost;
|
||||
Next[Index].Path.push_back(DC_right);
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(Cur, Next);
|
||||
}
|
||||
|
||||
// We don't need the tentative values anymore; everything from here
|
||||
// on out should be non-tentative.
|
||||
TentativeValues.clear();
|
||||
|
||||
SmallVectorImpl<char> &Path = Cur[NL].Path;
|
||||
BasicBlock::iterator LI = LStart, RI = RStart;
|
||||
|
||||
DiffLogBuilder Diff(Engine.getConsumer());
|
||||
|
||||
// Drop trailing matches.
|
||||
while (Path.back() == DC_match)
|
||||
Path.pop_back();
|
||||
|
||||
// Skip leading matches.
|
||||
SmallVectorImpl<char>::iterator
|
||||
PI = Path.begin(), PE = Path.end();
|
||||
while (PI != PE && *PI == DC_match) {
|
||||
unify(&*LI, &*RI);
|
||||
++PI, ++LI, ++RI;
|
||||
}
|
||||
|
||||
for (; PI != PE; ++PI) {
|
||||
switch (static_cast<DiffChange>(*PI)) {
|
||||
case DC_match:
|
||||
assert(LI != LE && RI != RE);
|
||||
{
|
||||
Instruction *L = &*LI, *R = &*RI;
|
||||
unify(L, R);
|
||||
Diff.addMatch(L, R);
|
||||
}
|
||||
++LI; ++RI;
|
||||
break;
|
||||
|
||||
case DC_left:
|
||||
assert(LI != LE);
|
||||
Diff.addLeft(&*LI);
|
||||
++LI;
|
||||
break;
|
||||
|
||||
case DC_right:
|
||||
assert(RI != RE);
|
||||
Diff.addRight(&*RI);
|
||||
++RI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Finishing unifying and complaining about the tails of the block,
|
||||
// which should be matches all the way through.
|
||||
while (LI != LE) {
|
||||
assert(RI != RE);
|
||||
unify(&*LI, &*RI);
|
||||
++LI, ++RI;
|
||||
}
|
||||
|
||||
// If the terminators have different kinds, but one is an invoke and the
|
||||
// other is an unconditional branch immediately following a call, unify
|
||||
// the results and the destinations.
|
||||
TerminatorInst *LTerm = LStart->getParent()->getTerminator();
|
||||
TerminatorInst *RTerm = RStart->getParent()->getTerminator();
|
||||
if (isa<BranchInst>(LTerm) && isa<InvokeInst>(RTerm)) {
|
||||
if (cast<BranchInst>(LTerm)->isConditional()) return;
|
||||
BasicBlock::iterator I = LTerm;
|
||||
if (I == LStart->getParent()->begin()) return;
|
||||
--I;
|
||||
if (!isa<CallInst>(*I)) return;
|
||||
CallInst *LCall = cast<CallInst>(&*I);
|
||||
InvokeInst *RInvoke = cast<InvokeInst>(RTerm);
|
||||
if (!equivalentAsOperands(LCall->getCalledValue(), RInvoke->getCalledValue()))
|
||||
return;
|
||||
if (!LCall->use_empty())
|
||||
Values[LCall] = RInvoke;
|
||||
tryUnify(LTerm->getSuccessor(0), RInvoke->getNormalDest());
|
||||
} else if (isa<InvokeInst>(LTerm) && isa<BranchInst>(RTerm)) {
|
||||
if (cast<BranchInst>(RTerm)->isConditional()) return;
|
||||
BasicBlock::iterator I = RTerm;
|
||||
if (I == RStart->getParent()->begin()) return;
|
||||
--I;
|
||||
if (!isa<CallInst>(*I)) return;
|
||||
CallInst *RCall = cast<CallInst>(I);
|
||||
InvokeInst *LInvoke = cast<InvokeInst>(LTerm);
|
||||
if (!equivalentAsOperands(LInvoke->getCalledValue(), RCall->getCalledValue()))
|
||||
return;
|
||||
if (!LInvoke->use_empty())
|
||||
Values[LInvoke] = RCall;
|
||||
tryUnify(LInvoke->getNormalDest(), RTerm->getSuccessor(0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DifferenceEngine::diff(Function *L, Function *R) {
|
||||
Context C(*this, L, R);
|
||||
|
||||
// FIXME: types
|
||||
// FIXME: attributes and CC
|
||||
// FIXME: parameter attributes
|
||||
|
||||
// If both are declarations, we're done.
|
||||
if (L->empty() && R->empty())
|
||||
return;
|
||||
else if (L->empty())
|
||||
log("left function is declaration, right function is definition");
|
||||
else if (R->empty())
|
||||
log("right function is declaration, left function is definition");
|
||||
else
|
||||
FunctionDifferenceEngine(*this).diff(L, R);
|
||||
}
|
||||
|
||||
void DifferenceEngine::diff(Module *L, Module *R) {
|
||||
StringSet<> LNames;
|
||||
SmallVector<std::pair<Function*,Function*>, 20> Queue;
|
||||
|
||||
for (Module::iterator I = L->begin(), E = L->end(); I != E; ++I) {
|
||||
Function *LFn = &*I;
|
||||
LNames.insert(LFn->getName());
|
||||
|
||||
if (Function *RFn = R->getFunction(LFn->getName()))
|
||||
Queue.push_back(std::make_pair(LFn, RFn));
|
||||
else
|
||||
logf("function %l exists only in left module") << LFn;
|
||||
}
|
||||
|
||||
for (Module::iterator I = R->begin(), E = R->end(); I != E; ++I) {
|
||||
Function *RFn = &*I;
|
||||
if (!LNames.count(RFn->getName()))
|
||||
logf("function %r exists only in right module") << RFn;
|
||||
}
|
||||
|
||||
for (SmallVectorImpl<std::pair<Function*,Function*> >::iterator
|
||||
I = Queue.begin(), E = Queue.end(); I != E; ++I)
|
||||
diff(I->first, I->second);
|
||||
}
|
||||
|
||||
bool DifferenceEngine::equivalentAsOperands(GlobalValue *L, GlobalValue *R) {
|
||||
if (globalValueOracle) return (*globalValueOracle)(L, R);
|
||||
return L->getName() == R->getName();
|
||||
}
|
91
contrib/llvm/tools/llvm-diff/DifferenceEngine.h
Normal file
91
contrib/llvm/tools/llvm-diff/DifferenceEngine.h
Normal file
@ -0,0 +1,91 @@
|
||||
//===-- DifferenceEngine.h - Module comparator ------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This header defines the interface to the LLVM difference engine,
|
||||
// which structurally compares functions within a module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LLVM_DIFFERENCE_ENGINE_H_
|
||||
#define _LLVM_DIFFERENCE_ENGINE_H_
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "DiffLog.h"
|
||||
#include "DiffConsumer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class GlobalValue;
|
||||
class Instruction;
|
||||
class LLVMContext;
|
||||
class Module;
|
||||
class Twine;
|
||||
class Value;
|
||||
|
||||
/// A class for performing structural comparisons of LLVM assembly.
|
||||
class DifferenceEngine {
|
||||
public:
|
||||
/// A RAII object for recording the current context.
|
||||
struct Context {
|
||||
Context(DifferenceEngine &Engine, Value *L, Value *R) : Engine(Engine) {
|
||||
Engine.consumer.enterContext(L, R);
|
||||
}
|
||||
|
||||
~Context() {
|
||||
Engine.consumer.exitContext();
|
||||
}
|
||||
|
||||
private:
|
||||
DifferenceEngine &Engine;
|
||||
};
|
||||
|
||||
/// An oracle for answering whether two values are equivalent as
|
||||
/// operands.
|
||||
struct Oracle {
|
||||
virtual bool operator()(Value *L, Value *R) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~Oracle() {}
|
||||
};
|
||||
|
||||
DifferenceEngine(LLVMContext &context, Consumer &consumer)
|
||||
: context(context), consumer(consumer), globalValueOracle(0) {}
|
||||
|
||||
void diff(Module *L, Module *R);
|
||||
void diff(Function *L, Function *R);
|
||||
void log(StringRef text) {
|
||||
consumer.log(text);
|
||||
}
|
||||
LogBuilder logf(StringRef text) {
|
||||
return LogBuilder(consumer, text);
|
||||
}
|
||||
Consumer& getConsumer() const { return consumer; }
|
||||
|
||||
/// Installs an oracle to decide whether two global values are
|
||||
/// equivalent as operands. Without an oracle, global values are
|
||||
/// considered equivalent as operands precisely when they have the
|
||||
/// same name.
|
||||
void setGlobalValueOracle(Oracle *oracle) {
|
||||
globalValueOracle = oracle;
|
||||
}
|
||||
|
||||
/// Determines whether two global values are equivalent.
|
||||
bool equivalentAsOperands(GlobalValue *L, GlobalValue *R);
|
||||
|
||||
private:
|
||||
LLVMContext &context;
|
||||
Consumer &consumer;
|
||||
Oracle *globalValueOracle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
17
contrib/llvm/tools/llvm-diff/Makefile
Normal file
17
contrib/llvm/tools/llvm-diff/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-diff/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llvm-diff
|
||||
LINK_COMPONENTS := asmparser bitreader
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
98
contrib/llvm/tools/llvm-diff/llvm-diff.cpp
Normal file
98
contrib/llvm/tools/llvm-diff/llvm-diff.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
//===-- llvm-diff.cpp - Module comparator command-line driver ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the command-line driver for the difference engine.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DiffLog.h"
|
||||
#include "DifferenceEngine.h"
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Reads a module from a file. On error, messages are written to stderr
|
||||
/// and null is returned.
|
||||
static Module *ReadModule(LLVMContext &Context, StringRef Name) {
|
||||
SMDiagnostic Diag;
|
||||
Module *M = ParseIRFile(Name, Diag, Context);
|
||||
if (!M)
|
||||
Diag.Print("llvmdiff", errs());
|
||||
return M;
|
||||
}
|
||||
|
||||
static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R,
|
||||
StringRef Name) {
|
||||
// Drop leading sigils from the global name.
|
||||
if (Name.startswith("@")) Name = Name.substr(1);
|
||||
|
||||
Function *LFn = L->getFunction(Name);
|
||||
Function *RFn = R->getFunction(Name);
|
||||
if (LFn && RFn)
|
||||
Engine.diff(LFn, RFn);
|
||||
else if (!LFn && !RFn)
|
||||
errs() << "No function named @" << Name << " in either module\n";
|
||||
else if (!LFn)
|
||||
errs() << "No function named @" << Name << " in left module\n";
|
||||
else
|
||||
errs() << "No function named @" << Name << " in right module\n";
|
||||
}
|
||||
|
||||
static cl::opt<std::string> LeftFilename(cl::Positional,
|
||||
cl::desc("<first file>"),
|
||||
cl::Required);
|
||||
static cl::opt<std::string> RightFilename(cl::Positional,
|
||||
cl::desc("<second file>"),
|
||||
cl::Required);
|
||||
static cl::list<std::string> GlobalsToCompare(cl::Positional,
|
||||
cl::desc("<globals to compare>"));
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
LLVMContext Context;
|
||||
|
||||
// Load both modules. Die if that fails.
|
||||
Module *LModule = ReadModule(Context, LeftFilename);
|
||||
Module *RModule = ReadModule(Context, RightFilename);
|
||||
if (!LModule || !RModule) return 1;
|
||||
|
||||
DiffConsumer Consumer(LModule, RModule);
|
||||
DifferenceEngine Engine(Context, Consumer);
|
||||
|
||||
// If any global names were given, just diff those.
|
||||
if (!GlobalsToCompare.empty()) {
|
||||
for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I)
|
||||
diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]);
|
||||
|
||||
// Otherwise, diff everything in the module.
|
||||
} else {
|
||||
Engine.diff(LModule, RModule);
|
||||
}
|
||||
|
||||
delete LModule;
|
||||
delete RModule;
|
||||
|
||||
return Consumer.hadDifferences();
|
||||
}
|
6
contrib/llvm/tools/llvm-dis/CMakeLists.txt
Normal file
6
contrib/llvm/tools/llvm-dis/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS bitreader analysis)
|
||||
set(LLVM_REQUIRES_EH 1)
|
||||
|
||||
add_llvm_tool(llvm-dis
|
||||
llvm-dis.cpp
|
||||
)
|
17
contrib/llvm/tools/llvm-dis/Makefile
Normal file
17
contrib/llvm/tools/llvm-dis/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-dis/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-dis
|
||||
LINK_COMPONENTS := bitreader analysis
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
186
contrib/llvm/tools/llvm-dis/llvm-dis.cpp
Normal file
186
contrib/llvm/tools/llvm-dis/llvm-dis.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
//===-- llvm-dis.cpp - The low-level LLVM disassembler --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility may be invoked in the following manner:
|
||||
// llvm-dis [options] - Read LLVM bitcode from stdin, write asm to stdout
|
||||
// llvm-dis [options] x.bc - Read LLVM bitcode from the x.bc file, write asm
|
||||
// to the x.ll file.
|
||||
// Options:
|
||||
// --help - Output information about command line switches
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Type.h"
|
||||
#include "llvm/IntrinsicInst.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/Assembly/AssemblyAnnotationWriter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Override output filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Force("f", cl::desc("Enable binary output on terminals"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DontPrint("disable-output", cl::desc("Don't output the .ll file"), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowAnnotations("show-annotations",
|
||||
cl::desc("Add informational comments to the .ll file"));
|
||||
|
||||
namespace {
|
||||
|
||||
static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
|
||||
OS << DL.getLine() << ":" << DL.getCol();
|
||||
if (MDNode *N = DL.getInlinedAt(getGlobalContext())) {
|
||||
DebugLoc IDL = DebugLoc::getFromDILocation(N);
|
||||
if (!IDL.isUnknown()) {
|
||||
OS << "@";
|
||||
printDebugLoc(IDL,OS);
|
||||
}
|
||||
}
|
||||
}
|
||||
class CommentWriter : public AssemblyAnnotationWriter {
|
||||
public:
|
||||
void emitFunctionAnnot(const Function *F,
|
||||
formatted_raw_ostream &OS) {
|
||||
OS << "; [#uses=" << F->getNumUses() << ']'; // Output # uses
|
||||
OS << '\n';
|
||||
}
|
||||
void printInfoComment(const Value &V, formatted_raw_ostream &OS) {
|
||||
bool Padded = false;
|
||||
if (!V.getType()->isVoidTy()) {
|
||||
OS.PadToColumn(50);
|
||||
Padded = true;
|
||||
OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]"; // Output # uses and type
|
||||
}
|
||||
if (const Instruction *I = dyn_cast<Instruction>(&V)) {
|
||||
const DebugLoc &DL = I->getDebugLoc();
|
||||
if (!DL.isUnknown()) {
|
||||
if (!Padded) {
|
||||
OS.PadToColumn(50);
|
||||
Padded = true;
|
||||
OS << ";";
|
||||
}
|
||||
OS << " [debug line = ";
|
||||
printDebugLoc(DL,OS);
|
||||
OS << "]";
|
||||
}
|
||||
if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) {
|
||||
DIVariable Var(DDI->getVariable());
|
||||
if (!Padded) {
|
||||
OS.PadToColumn(50);
|
||||
Padded = true;
|
||||
OS << ";";
|
||||
}
|
||||
OS << " [debug variable = " << Var.getName() << "]";
|
||||
}
|
||||
else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) {
|
||||
DIVariable Var(DVI->getVariable());
|
||||
if (!Padded) {
|
||||
OS.PadToColumn(50);
|
||||
Padded = true;
|
||||
OS << ";";
|
||||
}
|
||||
OS << " [debug variable = " << Var.getName() << "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n");
|
||||
|
||||
std::string ErrorMessage;
|
||||
std::auto_ptr<Module> M;
|
||||
|
||||
{
|
||||
OwningPtr<MemoryBuffer> BufferPtr;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr))
|
||||
ErrorMessage = ec.message();
|
||||
else
|
||||
M.reset(ParseBitcodeFile(BufferPtr.get(), Context, &ErrorMessage));
|
||||
}
|
||||
|
||||
if (M.get() == 0) {
|
||||
errs() << argv[0] << ": ";
|
||||
if (ErrorMessage.size())
|
||||
errs() << ErrorMessage << "\n";
|
||||
else
|
||||
errs() << "bitcode didn't read correctly.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Just use stdout. We won't actually print anything on it.
|
||||
if (DontPrint)
|
||||
OutputFilename = "-";
|
||||
|
||||
if (OutputFilename.empty()) { // Unspecified output, infer it.
|
||||
if (InputFilename == "-") {
|
||||
OutputFilename = "-";
|
||||
} else {
|
||||
const std::string &IFN = InputFilename;
|
||||
int Len = IFN.length();
|
||||
// If the source ends in .bc, strip it off.
|
||||
if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c')
|
||||
OutputFilename = std::string(IFN.begin(), IFN.end()-3)+".ll";
|
||||
else
|
||||
OutputFilename = IFN+".ll";
|
||||
}
|
||||
}
|
||||
|
||||
std::string ErrorInfo;
|
||||
OwningPtr<tool_output_file>
|
||||
Out(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary));
|
||||
if (!ErrorInfo.empty()) {
|
||||
errs() << ErrorInfo << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
OwningPtr<AssemblyAnnotationWriter> Annotator;
|
||||
if (ShowAnnotations)
|
||||
Annotator.reset(new CommentWriter());
|
||||
|
||||
// All that llvm-dis does is write the assembly to a file.
|
||||
if (!DontPrint)
|
||||
M->print(Out->os(), Annotator.get());
|
||||
|
||||
// Declare success.
|
||||
Out->keep();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
5
contrib/llvm/tools/llvm-extract/CMakeLists.txt
Normal file
5
contrib/llvm/tools/llvm-extract/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter)
|
||||
|
||||
add_llvm_tool(llvm-extract
|
||||
llvm-extract.cpp
|
||||
)
|
18
contrib/llvm/tools/llvm-extract/Makefile
Normal file
18
contrib/llvm/tools/llvm-extract/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
##===- tools/llvm-extract/Makefile -------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-extract
|
||||
LINK_COMPONENTS := ipo bitreader bitwriter asmparser
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
238
contrib/llvm/tools/llvm-extract/llvm-extract.cpp
Normal file
238
contrib/llvm/tools/llvm-extract/llvm-extract.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
//===- llvm-extract.cpp - LLVM function extraction utility ----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility changes the input module to only contain a single function,
|
||||
// which is primarily used for debugging transformations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Assembly/PrintModulePass.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
// InputFilename - The filename to read from.
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input bitcode file>"),
|
||||
cl::init("-"), cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Specify output filename"),
|
||||
cl::value_desc("filename"), cl::init("-"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Force("f", cl::desc("Enable binary output on terminals"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DeleteFn("delete", cl::desc("Delete specified Globals from Module"));
|
||||
|
||||
// ExtractFuncs - The functions to extract from the module.
|
||||
static cl::list<std::string>
|
||||
ExtractFuncs("func", cl::desc("Specify function to extract"),
|
||||
cl::ZeroOrMore, cl::value_desc("function"));
|
||||
|
||||
// ExtractRegExpFuncs - The functions, matched via regular expression, to
|
||||
// extract from the module.
|
||||
static cl::list<std::string>
|
||||
ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a "
|
||||
"regular expression"),
|
||||
cl::ZeroOrMore, cl::value_desc("rfunction"));
|
||||
|
||||
// ExtractGlobals - The globals to extract from the module.
|
||||
static cl::list<std::string>
|
||||
ExtractGlobals("glob", cl::desc("Specify global to extract"),
|
||||
cl::ZeroOrMore, cl::value_desc("global"));
|
||||
|
||||
// ExtractRegExpGlobals - The globals, matched via regular expression, to
|
||||
// extract from the module...
|
||||
static cl::list<std::string>
|
||||
ExtractRegExpGlobals("rglob", cl::desc("Specify global(s) to extract using a "
|
||||
"regular expression"),
|
||||
cl::ZeroOrMore, cl::value_desc("rglobal"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OutputAssembly("S",
|
||||
cl::desc("Write output as LLVM assembly"), cl::Hidden);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm extractor\n");
|
||||
|
||||
// Use lazy loading, since we only care about selected global values.
|
||||
SMDiagnostic Err;
|
||||
std::auto_ptr<Module> M;
|
||||
M.reset(getLazyIRFileModule(InputFilename, Err, Context));
|
||||
|
||||
if (M.get() == 0) {
|
||||
Err.Print(argv[0], errs());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Use SetVector to avoid duplicates.
|
||||
SetVector<GlobalValue *> GVs;
|
||||
|
||||
// Figure out which globals we should extract.
|
||||
for (size_t i = 0, e = ExtractGlobals.size(); i != e; ++i) {
|
||||
GlobalValue *GV = M.get()->getNamedGlobal(ExtractGlobals[i]);
|
||||
if (!GV) {
|
||||
errs() << argv[0] << ": program doesn't contain global named '"
|
||||
<< ExtractGlobals[i] << "'!\n";
|
||||
return 1;
|
||||
}
|
||||
GVs.insert(GV);
|
||||
}
|
||||
|
||||
// Extract globals via regular expression matching.
|
||||
for (size_t i = 0, e = ExtractRegExpGlobals.size(); i != e; ++i) {
|
||||
std::string Error;
|
||||
Regex RegEx(ExtractRegExpGlobals[i]);
|
||||
if (!RegEx.isValid(Error)) {
|
||||
errs() << argv[0] << ": '" << ExtractRegExpGlobals[i] << "' "
|
||||
"invalid regex: " << Error;
|
||||
}
|
||||
bool match = false;
|
||||
for (Module::global_iterator GV = M.get()->global_begin(),
|
||||
E = M.get()->global_end(); GV != E; GV++) {
|
||||
if (RegEx.match(GV->getName())) {
|
||||
GVs.insert(&*GV);
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
errs() << argv[0] << ": program doesn't contain global named '"
|
||||
<< ExtractRegExpGlobals[i] << "'!\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Figure out which functions we should extract.
|
||||
for (size_t i = 0, e = ExtractFuncs.size(); i != e; ++i) {
|
||||
GlobalValue *GV = M.get()->getFunction(ExtractFuncs[i]);
|
||||
if (!GV) {
|
||||
errs() << argv[0] << ": program doesn't contain function named '"
|
||||
<< ExtractFuncs[i] << "'!\n";
|
||||
return 1;
|
||||
}
|
||||
GVs.insert(GV);
|
||||
}
|
||||
// Extract functions via regular expression matching.
|
||||
for (size_t i = 0, e = ExtractRegExpFuncs.size(); i != e; ++i) {
|
||||
std::string Error;
|
||||
StringRef RegExStr = ExtractRegExpFuncs[i];
|
||||
Regex RegEx(RegExStr);
|
||||
if (!RegEx.isValid(Error)) {
|
||||
errs() << argv[0] << ": '" << ExtractRegExpFuncs[i] << "' "
|
||||
"invalid regex: " << Error;
|
||||
}
|
||||
bool match = false;
|
||||
for (Module::iterator F = M.get()->begin(), E = M.get()->end(); F != E;
|
||||
F++) {
|
||||
if (RegEx.match(F->getName())) {
|
||||
GVs.insert(&*F);
|
||||
match = true;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
errs() << argv[0] << ": program doesn't contain global named '"
|
||||
<< ExtractRegExpFuncs[i] << "'!\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Materialize requisite global values.
|
||||
if (!DeleteFn)
|
||||
for (size_t i = 0, e = GVs.size(); i != e; ++i) {
|
||||
GlobalValue *GV = GVs[i];
|
||||
if (GV->isMaterializable()) {
|
||||
std::string ErrInfo;
|
||||
if (GV->Materialize(&ErrInfo)) {
|
||||
errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Deleting. Materialize every GV that's *not* in GVs.
|
||||
SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end());
|
||||
for (Module::global_iterator I = M->global_begin(), E = M->global_end();
|
||||
I != E; ++I) {
|
||||
GlobalVariable *G = I;
|
||||
if (!GVSet.count(G) && G->isMaterializable()) {
|
||||
std::string ErrInfo;
|
||||
if (G->Materialize(&ErrInfo)) {
|
||||
errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
|
||||
Function *F = I;
|
||||
if (!GVSet.count(F) && F->isMaterializable()) {
|
||||
std::string ErrInfo;
|
||||
if (F->Materialize(&ErrInfo)) {
|
||||
errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In addition to deleting all other functions, we also want to spiff it
|
||||
// up a little bit. Do this now.
|
||||
PassManager Passes;
|
||||
Passes.add(new TargetData(M.get())); // Use correct TargetData
|
||||
|
||||
std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end());
|
||||
|
||||
Passes.add(createGVExtractionPass(Gvs, DeleteFn));
|
||||
if (!DeleteFn)
|
||||
Passes.add(createGlobalDCEPass()); // Delete unreachable globals
|
||||
Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info
|
||||
Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls
|
||||
|
||||
std::string ErrorInfo;
|
||||
tool_output_file Out(OutputFilename.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary);
|
||||
if (!ErrorInfo.empty()) {
|
||||
errs() << ErrorInfo << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (OutputAssembly)
|
||||
Passes.add(createPrintModulePass(&Out.os()));
|
||||
else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true))
|
||||
Passes.add(createBitcodeWriterPass(Out.os()));
|
||||
|
||||
Passes.run(*M.get());
|
||||
|
||||
// Declare success.
|
||||
Out.keep();
|
||||
|
||||
return 0;
|
||||
}
|
8
contrib/llvm/tools/llvm-ld/CMakeLists.txt
Normal file
8
contrib/llvm/tools/llvm-ld/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
set(LLVM_LINK_COMPONENTS ipo scalaropts linker archive bitwriter)
|
||||
|
||||
add_llvm_tool(llvm-ld
|
||||
Optimize.cpp
|
||||
llvm-ld.cpp
|
||||
)
|
||||
|
||||
add_dependencies(llvm-ld llvm-stub)
|
15
contrib/llvm/tools/llvm-ld/Makefile
Normal file
15
contrib/llvm/tools/llvm-ld/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
##===- tools/llvm-ld/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-ld
|
||||
LINK_COMPONENTS = ipo scalaropts linker archive bitwriter
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
130
contrib/llvm/tools/llvm-ld/Optimize.cpp
Normal file
130
contrib/llvm/tools/llvm-ld/Optimize.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
//===- Optimize.cpp - Optimize a complete program -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements all optimization of the linked module for llvm-ld.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/DynamicLibrary.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/PassNameParser.h"
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
using namespace llvm;
|
||||
|
||||
// Pass Name Options as generated by the PassNameParser
|
||||
static cl::list<const PassInfo*, bool, PassNameParser>
|
||||
OptimizationList(cl::desc("Optimizations available:"));
|
||||
|
||||
//Don't verify at the end
|
||||
static cl::opt<bool> DontVerify("disable-verify", cl::ReallyHidden);
|
||||
|
||||
static cl::opt<bool> DisableInline("disable-inlining",
|
||||
cl::desc("Do not run the inliner pass"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableOptimizations("disable-opt",
|
||||
cl::desc("Do not run any optimization passes"));
|
||||
|
||||
static cl::opt<bool> DisableInternalize("disable-internalize",
|
||||
cl::desc("Do not mark all symbols as internal"));
|
||||
|
||||
static cl::opt<bool> VerifyEach("verify-each",
|
||||
cl::desc("Verify intermediate results of all passes"));
|
||||
|
||||
static cl::alias ExportDynamic("export-dynamic",
|
||||
cl::aliasopt(DisableInternalize),
|
||||
cl::desc("Alias for -disable-internalize"));
|
||||
|
||||
static cl::opt<bool> Strip("strip-all",
|
||||
cl::desc("Strip all symbol info from executable"));
|
||||
|
||||
static cl::alias A0("s", cl::desc("Alias for --strip-all"),
|
||||
cl::aliasopt(Strip));
|
||||
|
||||
static cl::opt<bool> StripDebug("strip-debug",
|
||||
cl::desc("Strip debugger symbol info from executable"));
|
||||
|
||||
static cl::alias A1("S", cl::desc("Alias for --strip-debug"),
|
||||
cl::aliasopt(StripDebug));
|
||||
|
||||
// A utility function that adds a pass to the pass manager but will also add
|
||||
// a verifier pass after if we're supposed to verify.
|
||||
static inline void addPass(PassManager &PM, Pass *P) {
|
||||
// Add the pass to the pass manager...
|
||||
PM.add(P);
|
||||
|
||||
// If we are verifying all of the intermediate steps, add the verifier...
|
||||
if (VerifyEach)
|
||||
PM.add(createVerifierPass());
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
/// Optimize - Perform link time optimizations. This will run the scalar
|
||||
/// optimizations, any loaded plugin-optimization modules, and then the
|
||||
/// inter-procedural optimizations if applicable.
|
||||
void Optimize(Module *M) {
|
||||
|
||||
// Instantiate the pass manager to organize the passes.
|
||||
PassManager Passes;
|
||||
|
||||
// If we're verifying, start off with a verification pass.
|
||||
if (VerifyEach)
|
||||
Passes.add(createVerifierPass());
|
||||
|
||||
// Add an appropriate TargetData instance for this module...
|
||||
addPass(Passes, new TargetData(M));
|
||||
|
||||
if (!DisableOptimizations)
|
||||
PassManagerBuilder().populateLTOPassManager(Passes, !DisableInternalize,
|
||||
!DisableInline);
|
||||
|
||||
// If the -s or -S command line options were specified, strip the symbols out
|
||||
// of the resulting program to make it smaller. -s and -S are GNU ld options
|
||||
// that we are supporting; they alias -strip-all and -strip-debug.
|
||||
if (Strip || StripDebug)
|
||||
addPass(Passes, createStripSymbolsPass(StripDebug && !Strip));
|
||||
|
||||
// Create a new optimization pass for each one specified on the command line
|
||||
std::auto_ptr<TargetMachine> target;
|
||||
for (unsigned i = 0; i < OptimizationList.size(); ++i) {
|
||||
const PassInfo *Opt = OptimizationList[i];
|
||||
if (Opt->getNormalCtor())
|
||||
addPass(Passes, Opt->getNormalCtor()());
|
||||
else
|
||||
errs() << "llvm-ld: cannot create pass: " << Opt->getPassName()
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// The user's passes may leave cruft around. Clean up after them them but
|
||||
// only if we haven't got DisableOptimizations set
|
||||
if (!DisableOptimizations) {
|
||||
addPass(Passes, createInstructionCombiningPass());
|
||||
addPass(Passes, createCFGSimplificationPass());
|
||||
addPass(Passes, createAggressiveDCEPass());
|
||||
addPass(Passes, createGlobalDCEPass());
|
||||
}
|
||||
|
||||
// Make sure everything is still good.
|
||||
if (!DontVerify)
|
||||
Passes.add(createVerifierPass());
|
||||
|
||||
// Run our queue of passes all at once now, efficiently.
|
||||
Passes.run(*M);
|
||||
}
|
||||
|
||||
}
|
732
contrib/llvm/tools/llvm-ld/llvm-ld.cpp
Normal file
732
contrib/llvm/tools/llvm-ld/llvm-ld.cpp
Normal file
@ -0,0 +1,732 @@
|
||||
//===- llvm-ld.cpp - LLVM 'ld' compatible linker --------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility is intended to be compatible with GCC, and follows standard
|
||||
// system 'ld' conventions. As such, the default output file is ./a.out.
|
||||
// Additionally, this program outputs a shell script that is used to invoke LLI
|
||||
// to execute the program. In this manner, the generated executable (a.out for
|
||||
// example), is directly executable, whereas the bitcode file actually lives in
|
||||
// the a.out.bc file generated by this program.
|
||||
//
|
||||
// Note that if someone (or a script) deletes the executable program generated,
|
||||
// the .bc file will be left around. Considering that this is a temporary hack,
|
||||
// I'm not too worried about this.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LinkAllVMCore.h"
|
||||
#include "llvm/Linker.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
using namespace llvm;
|
||||
|
||||
// Rightly this should go in a header file but it just seems such a waste.
|
||||
namespace llvm {
|
||||
extern void Optimize(Module*);
|
||||
}
|
||||
|
||||
// Input/Output Options
|
||||
static cl::list<std::string> InputFilenames(cl::Positional, cl::OneOrMore,
|
||||
cl::desc("<input bitcode files>"));
|
||||
|
||||
static cl::opt<std::string> OutputFilename("o", cl::init("a.out"),
|
||||
cl::desc("Override output filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<std::string> BitcodeOutputFilename("b", cl::init(""),
|
||||
cl::desc("Override bitcode output filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<bool> Verbose("v",
|
||||
cl::desc("Print information about actions taken"));
|
||||
|
||||
static cl::list<std::string> LibPaths("L", cl::Prefix,
|
||||
cl::desc("Specify a library search path"),
|
||||
cl::value_desc("directory"));
|
||||
|
||||
static cl::list<std::string> FrameworkPaths("F", cl::Prefix,
|
||||
cl::desc("Specify a framework search path"),
|
||||
cl::value_desc("directory"));
|
||||
|
||||
static cl::list<std::string> Libraries("l", cl::Prefix,
|
||||
cl::desc("Specify libraries to link to"),
|
||||
cl::value_desc("library prefix"));
|
||||
|
||||
static cl::list<std::string> Frameworks("framework",
|
||||
cl::desc("Specify frameworks to link to"),
|
||||
cl::value_desc("framework"));
|
||||
|
||||
// Options to control the linking, optimization, and code gen processes
|
||||
static cl::opt<bool> LinkAsLibrary("link-as-library",
|
||||
cl::desc("Link the .bc files together as a library, not an executable"));
|
||||
|
||||
static cl::alias Relink("r", cl::aliasopt(LinkAsLibrary),
|
||||
cl::desc("Alias for -link-as-library"));
|
||||
|
||||
static cl::opt<bool> Native("native",
|
||||
cl::desc("Generate a native binary instead of a shell script"));
|
||||
|
||||
static cl::opt<bool>NativeCBE("native-cbe",
|
||||
cl::desc("Generate a native binary with the C backend and GCC"));
|
||||
|
||||
static cl::list<std::string> PostLinkOpts("post-link-opts",
|
||||
cl::value_desc("path"),
|
||||
cl::desc("Run one or more optimization programs after linking"));
|
||||
|
||||
static cl::list<std::string> XLinker("Xlinker", cl::value_desc("option"),
|
||||
cl::desc("Pass options to the system linker"));
|
||||
|
||||
// Compatibility options that llvm-ld ignores but are supported for
|
||||
// compatibility with LD
|
||||
static cl::opt<std::string> CO3("soname", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
static cl::opt<std::string> CO4("version-script", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
static cl::opt<bool> CO5("eh-frame-hdr", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
static cl::opt<std::string> CO6("h", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
static cl::opt<bool> CO7("start-group", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
static cl::opt<bool> CO8("end-group", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
static cl::opt<std::string> CO9("m", cl::Hidden,
|
||||
cl::desc("Compatibility option: ignored"));
|
||||
|
||||
/// This is just for convenience so it doesn't have to be passed around
|
||||
/// everywhere.
|
||||
static std::string progname;
|
||||
|
||||
/// FileRemover objects to clean up output files in the event of an error.
|
||||
static FileRemover OutputRemover;
|
||||
static FileRemover BitcodeOutputRemover;
|
||||
|
||||
/// PrintAndExit - Prints a message to standard error and exits with error code
|
||||
///
|
||||
/// Inputs:
|
||||
/// Message - The message to print to standard error.
|
||||
///
|
||||
static void PrintAndExit(const std::string &Message, Module *M, int errcode = 1) {
|
||||
errs() << progname << ": " << Message << "\n";
|
||||
delete M;
|
||||
llvm_shutdown();
|
||||
exit(errcode);
|
||||
}
|
||||
|
||||
static void PrintCommand(const std::vector<const char*> &args) {
|
||||
std::vector<const char*>::const_iterator I = args.begin(), E = args.end();
|
||||
for (; I != E; ++I)
|
||||
if (*I)
|
||||
errs() << "'" << *I << "'" << " ";
|
||||
errs() << "\n";
|
||||
}
|
||||
|
||||
/// CopyEnv - This function takes an array of environment variables and makes a
|
||||
/// copy of it. This copy can then be manipulated any way the caller likes
|
||||
/// without affecting the process's real environment.
|
||||
///
|
||||
/// Inputs:
|
||||
/// envp - An array of C strings containing an environment.
|
||||
///
|
||||
/// Return value:
|
||||
/// NULL - An error occurred.
|
||||
///
|
||||
/// Otherwise, a pointer to a new array of C strings is returned. Every string
|
||||
/// in the array is a duplicate of the one in the original array (i.e. we do
|
||||
/// not copy the char *'s from one array to another).
|
||||
///
|
||||
static char ** CopyEnv(char ** const envp) {
|
||||
// Count the number of entries in the old list;
|
||||
unsigned entries; // The number of entries in the old environment list
|
||||
for (entries = 0; envp[entries] != NULL; entries++)
|
||||
/*empty*/;
|
||||
|
||||
// Add one more entry for the NULL pointer that ends the list.
|
||||
++entries;
|
||||
|
||||
// If there are no entries at all, just return NULL.
|
||||
if (entries == 0)
|
||||
return NULL;
|
||||
|
||||
// Allocate a new environment list.
|
||||
char **newenv = new char* [entries];
|
||||
if (newenv == NULL)
|
||||
return NULL;
|
||||
|
||||
// Make a copy of the list. Don't forget the NULL that ends the list.
|
||||
entries = 0;
|
||||
while (envp[entries] != NULL) {
|
||||
size_t len = strlen(envp[entries]) + 1;
|
||||
newenv[entries] = new char[len];
|
||||
memcpy(newenv[entries], envp[entries], len);
|
||||
++entries;
|
||||
}
|
||||
newenv[entries] = NULL;
|
||||
|
||||
return newenv;
|
||||
}
|
||||
|
||||
|
||||
/// RemoveEnv - Remove the specified environment variable from the environment
|
||||
/// array.
|
||||
///
|
||||
/// Inputs:
|
||||
/// name - The name of the variable to remove. It cannot be NULL.
|
||||
/// envp - The array of environment variables. It cannot be NULL.
|
||||
///
|
||||
/// Notes:
|
||||
/// This is mainly done because functions to remove items from the environment
|
||||
/// are not available across all platforms. In particular, Solaris does not
|
||||
/// seem to have an unsetenv() function or a setenv() function (or they are
|
||||
/// undocumented if they do exist).
|
||||
///
|
||||
static void RemoveEnv(const char * name, char ** const envp) {
|
||||
for (unsigned index=0; envp[index] != NULL; index++) {
|
||||
// Find the first equals sign in the array and make it an EOS character.
|
||||
char *p = strchr (envp[index], '=');
|
||||
if (p == NULL)
|
||||
continue;
|
||||
else
|
||||
*p = '\0';
|
||||
|
||||
// Compare the two strings. If they are equal, zap this string.
|
||||
// Otherwise, restore it.
|
||||
if (!strcmp(name, envp[index]))
|
||||
*envp[index] = '\0';
|
||||
else
|
||||
*p = '=';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// GenerateBitcode - generates a bitcode file from the module provided
|
||||
void GenerateBitcode(Module* M, const std::string& FileName) {
|
||||
|
||||
if (Verbose)
|
||||
errs() << "Generating Bitcode To " << FileName << '\n';
|
||||
|
||||
// Create the output file.
|
||||
std::string ErrorInfo;
|
||||
tool_output_file Out(FileName.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary);
|
||||
if (!ErrorInfo.empty()) {
|
||||
PrintAndExit(ErrorInfo, M);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write it out
|
||||
WriteBitcodeToFile(M, Out.os());
|
||||
Out.keep();
|
||||
}
|
||||
|
||||
/// GenerateAssembly - generates a native assembly language source file from the
|
||||
/// specified bitcode file.
|
||||
///
|
||||
/// Inputs:
|
||||
/// InputFilename - The name of the input bitcode file.
|
||||
/// OutputFilename - The name of the file to generate.
|
||||
/// llc - The pathname to use for LLC.
|
||||
/// envp - The environment to use when running LLC.
|
||||
///
|
||||
/// Return non-zero value on error.
|
||||
///
|
||||
static int GenerateAssembly(const std::string &OutputFilename,
|
||||
const std::string &InputFilename,
|
||||
const sys::Path &llc,
|
||||
std::string &ErrMsg ) {
|
||||
// Run LLC to convert the bitcode file into assembly code.
|
||||
std::vector<const char*> args;
|
||||
args.push_back(llc.c_str());
|
||||
// We will use GCC to assemble the program so set the assembly syntax to AT&T,
|
||||
// regardless of what the target in the bitcode file is.
|
||||
args.push_back("-x86-asm-syntax=att");
|
||||
args.push_back("-o");
|
||||
args.push_back(OutputFilename.c_str());
|
||||
args.push_back(InputFilename.c_str());
|
||||
args.push_back(0);
|
||||
|
||||
if (Verbose) {
|
||||
errs() << "Generating Assembly With: \n";
|
||||
PrintCommand(args);
|
||||
}
|
||||
|
||||
return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg);
|
||||
}
|
||||
|
||||
/// GenerateCFile - generates a C source file from the specified bitcode file.
|
||||
static int GenerateCFile(const std::string &OutputFile,
|
||||
const std::string &InputFile,
|
||||
const sys::Path &llc,
|
||||
std::string& ErrMsg) {
|
||||
// Run LLC to convert the bitcode file into C.
|
||||
std::vector<const char*> args;
|
||||
args.push_back(llc.c_str());
|
||||
args.push_back("-march=c");
|
||||
args.push_back("-o");
|
||||
args.push_back(OutputFile.c_str());
|
||||
args.push_back(InputFile.c_str());
|
||||
args.push_back(0);
|
||||
|
||||
if (Verbose) {
|
||||
errs() << "Generating C Source With: \n";
|
||||
PrintCommand(args);
|
||||
}
|
||||
|
||||
return sys::Program::ExecuteAndWait(llc, &args[0], 0, 0, 0, 0, &ErrMsg);
|
||||
}
|
||||
|
||||
/// GenerateNative - generates a native object file from the
|
||||
/// specified bitcode file.
|
||||
///
|
||||
/// Inputs:
|
||||
/// InputFilename - The name of the input bitcode file.
|
||||
/// OutputFilename - The name of the file to generate.
|
||||
/// NativeLinkItems - The native libraries, files, code with which to link
|
||||
/// LibPaths - The list of directories in which to find libraries.
|
||||
/// FrameworksPaths - The list of directories in which to find frameworks.
|
||||
/// Frameworks - The list of frameworks (dynamic libraries)
|
||||
/// gcc - The pathname to use for GGC.
|
||||
/// envp - A copy of the process's current environment.
|
||||
///
|
||||
/// Outputs:
|
||||
/// None.
|
||||
///
|
||||
/// Returns non-zero value on error.
|
||||
///
|
||||
static int GenerateNative(const std::string &OutputFilename,
|
||||
const std::string &InputFilename,
|
||||
const Linker::ItemList &LinkItems,
|
||||
const sys::Path &gcc, char ** const envp,
|
||||
std::string& ErrMsg) {
|
||||
// Remove these environment variables from the environment of the
|
||||
// programs that we will execute. It appears that GCC sets these
|
||||
// environment variables so that the programs it uses can configure
|
||||
// themselves identically.
|
||||
//
|
||||
// However, when we invoke GCC below, we want it to use its normal
|
||||
// configuration. Hence, we must sanitize its environment.
|
||||
char ** clean_env = CopyEnv(envp);
|
||||
if (clean_env == NULL)
|
||||
return 1;
|
||||
RemoveEnv("LIBRARY_PATH", clean_env);
|
||||
RemoveEnv("COLLECT_GCC_OPTIONS", clean_env);
|
||||
RemoveEnv("GCC_EXEC_PREFIX", clean_env);
|
||||
RemoveEnv("COMPILER_PATH", clean_env);
|
||||
RemoveEnv("COLLECT_GCC", clean_env);
|
||||
|
||||
|
||||
// Run GCC to assemble and link the program into native code.
|
||||
//
|
||||
// Note:
|
||||
// We can't just assemble and link the file with the system assembler
|
||||
// and linker because we don't know where to put the _start symbol.
|
||||
// GCC mysteriously knows how to do it.
|
||||
std::vector<std::string> args;
|
||||
args.push_back(gcc.c_str());
|
||||
args.push_back("-fno-strict-aliasing");
|
||||
args.push_back("-O3");
|
||||
args.push_back("-o");
|
||||
args.push_back(OutputFilename);
|
||||
args.push_back(InputFilename);
|
||||
|
||||
// Add in the library and framework paths
|
||||
for (unsigned index = 0; index < LibPaths.size(); index++) {
|
||||
args.push_back("-L" + LibPaths[index]);
|
||||
}
|
||||
for (unsigned index = 0; index < FrameworkPaths.size(); index++) {
|
||||
args.push_back("-F" + FrameworkPaths[index]);
|
||||
}
|
||||
|
||||
// Add the requested options
|
||||
for (unsigned index = 0; index < XLinker.size(); index++)
|
||||
args.push_back(XLinker[index]);
|
||||
|
||||
// Add in the libraries to link.
|
||||
for (unsigned index = 0; index < LinkItems.size(); index++)
|
||||
if (LinkItems[index].first != "crtend") {
|
||||
if (LinkItems[index].second)
|
||||
args.push_back("-l" + LinkItems[index].first);
|
||||
else
|
||||
args.push_back(LinkItems[index].first);
|
||||
}
|
||||
|
||||
// Add in frameworks to link.
|
||||
for (unsigned index = 0; index < Frameworks.size(); index++) {
|
||||
args.push_back("-framework");
|
||||
args.push_back(Frameworks[index]);
|
||||
}
|
||||
|
||||
// Now that "args" owns all the std::strings for the arguments, call the c_str
|
||||
// method to get the underlying string array. We do this game so that the
|
||||
// std::string array is guaranteed to outlive the const char* array.
|
||||
std::vector<const char *> Args;
|
||||
for (unsigned i = 0, e = args.size(); i != e; ++i)
|
||||
Args.push_back(args[i].c_str());
|
||||
Args.push_back(0);
|
||||
|
||||
if (Verbose) {
|
||||
errs() << "Generating Native Executable With:\n";
|
||||
PrintCommand(Args);
|
||||
}
|
||||
|
||||
// Run the compiler to assembly and link together the program.
|
||||
int R = sys::Program::ExecuteAndWait(
|
||||
gcc, &Args[0], const_cast<const char **>(clean_env), 0, 0, 0, &ErrMsg);
|
||||
delete [] clean_env;
|
||||
return R;
|
||||
}
|
||||
|
||||
/// EmitShellScript - Output the wrapper file that invokes the JIT on the LLVM
|
||||
/// bitcode file for the program.
|
||||
static void EmitShellScript(char **argv, Module *M) {
|
||||
if (Verbose)
|
||||
errs() << "Emitting Shell Script\n";
|
||||
#if defined(_WIN32)
|
||||
// Windows doesn't support #!/bin/sh style shell scripts in .exe files. To
|
||||
// support windows systems, we copy the llvm-stub.exe executable from the
|
||||
// build tree to the destination file.
|
||||
std::string ErrMsg;
|
||||
sys::Path llvmstub = PrependMainExecutablePath("llvm-stub", argv[0],
|
||||
(void *)(intptr_t)&Optimize);
|
||||
if (llvmstub.isEmpty())
|
||||
PrintAndExit("Could not find llvm-stub.exe executable!", M);
|
||||
|
||||
if (0 != sys::CopyFile(sys::Path(OutputFilename), llvmstub, &ErrMsg))
|
||||
PrintAndExit(ErrMsg, M);
|
||||
|
||||
return;
|
||||
#endif
|
||||
|
||||
// Output the script to start the program...
|
||||
std::string ErrorInfo;
|
||||
tool_output_file Out2(OutputFilename.c_str(), ErrorInfo);
|
||||
if (!ErrorInfo.empty())
|
||||
PrintAndExit(ErrorInfo, M);
|
||||
|
||||
Out2.os() << "#!/bin/sh\n";
|
||||
// Allow user to setenv LLVMINTERP if lli is not in their PATH.
|
||||
Out2.os() << "lli=${LLVMINTERP-lli}\n";
|
||||
Out2.os() << "exec $lli \\\n";
|
||||
// gcc accepts -l<lib> and implicitly searches /lib and /usr/lib.
|
||||
LibPaths.push_back("/lib");
|
||||
LibPaths.push_back("/usr/lib");
|
||||
LibPaths.push_back("/usr/X11R6/lib");
|
||||
// We don't need to link in libc! In fact, /usr/lib/libc.so may not be a
|
||||
// shared object at all! See RH 8: plain text.
|
||||
std::vector<std::string>::iterator libc =
|
||||
std::find(Libraries.begin(), Libraries.end(), "c");
|
||||
if (libc != Libraries.end()) Libraries.erase(libc);
|
||||
// List all the shared object (native) libraries this executable will need
|
||||
// on the command line, so that we don't have to do this manually!
|
||||
for (std::vector<std::string>::iterator i = Libraries.begin(),
|
||||
e = Libraries.end(); i != e; ++i) {
|
||||
// try explicit -L arguments first:
|
||||
sys::Path FullLibraryPath;
|
||||
for (cl::list<std::string>::const_iterator P = LibPaths.begin(),
|
||||
E = LibPaths.end(); P != E; ++P) {
|
||||
FullLibraryPath = *P;
|
||||
FullLibraryPath.appendComponent("lib" + *i);
|
||||
FullLibraryPath.appendSuffix(sys::Path::GetDLLSuffix());
|
||||
if (!FullLibraryPath.isEmpty()) {
|
||||
if (!FullLibraryPath.isDynamicLibrary()) {
|
||||
// Not a native shared library; mark as invalid
|
||||
FullLibraryPath = sys::Path();
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
if (FullLibraryPath.isEmpty())
|
||||
FullLibraryPath = sys::Path::FindLibrary(*i);
|
||||
if (!FullLibraryPath.isEmpty())
|
||||
Out2.os() << " -load=" << FullLibraryPath.str() << " \\\n";
|
||||
}
|
||||
Out2.os() << " " << BitcodeOutputFilename << " ${1+\"$@\"}\n";
|
||||
Out2.keep();
|
||||
}
|
||||
|
||||
// BuildLinkItems -- This function generates a LinkItemList for the LinkItems
|
||||
// linker function by combining the Files and Libraries in the order they were
|
||||
// declared on the command line.
|
||||
static void BuildLinkItems(
|
||||
Linker::ItemList& Items,
|
||||
const cl::list<std::string>& Files,
|
||||
const cl::list<std::string>& Libraries) {
|
||||
|
||||
// Build the list of linkage items for LinkItems.
|
||||
|
||||
cl::list<std::string>::const_iterator fileIt = Files.begin();
|
||||
cl::list<std::string>::const_iterator libIt = Libraries.begin();
|
||||
|
||||
int libPos = -1, filePos = -1;
|
||||
while ( libIt != Libraries.end() || fileIt != Files.end() ) {
|
||||
if (libIt != Libraries.end())
|
||||
libPos = Libraries.getPosition(libIt - Libraries.begin());
|
||||
else
|
||||
libPos = -1;
|
||||
if (fileIt != Files.end())
|
||||
filePos = Files.getPosition(fileIt - Files.begin());
|
||||
else
|
||||
filePos = -1;
|
||||
|
||||
if (filePos != -1 && (libPos == -1 || filePos < libPos)) {
|
||||
// Add a source file
|
||||
Items.push_back(std::make_pair(*fileIt++, false));
|
||||
} else if (libPos != -1 && (filePos == -1 || libPos < filePos)) {
|
||||
// Add a library
|
||||
Items.push_back(std::make_pair(*libIt++, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
// Initialize passes
|
||||
PassRegistry &Registry = *PassRegistry::getPassRegistry();
|
||||
initializeCore(Registry);
|
||||
initializeScalarOpts(Registry);
|
||||
initializeIPO(Registry);
|
||||
initializeAnalysis(Registry);
|
||||
initializeIPA(Registry);
|
||||
initializeTransformUtils(Registry);
|
||||
initializeInstCombine(Registry);
|
||||
initializeTarget(Registry);
|
||||
|
||||
// Initial global variable above for convenience printing of program name.
|
||||
progname = sys::path::stem(argv[0]);
|
||||
|
||||
// Parse the command line options
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
if (!LinkAsLibrary) {
|
||||
// Default to "a.exe" instead of "a.out".
|
||||
if (OutputFilename.getNumOccurrences() == 0)
|
||||
OutputFilename = "a.exe";
|
||||
|
||||
// If there is no suffix add an "exe" one.
|
||||
if (sys::path::extension(OutputFilename).empty())
|
||||
OutputFilename.append(".exe");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Generate the bitcode for the optimized module.
|
||||
// If -b wasn't specified, use the name specified
|
||||
// with -o to construct BitcodeOutputFilename.
|
||||
if (BitcodeOutputFilename.empty()) {
|
||||
BitcodeOutputFilename = OutputFilename;
|
||||
if (!LinkAsLibrary) BitcodeOutputFilename += ".bc";
|
||||
}
|
||||
|
||||
// Arrange for the bitcode output file to be deleted on any errors.
|
||||
BitcodeOutputRemover.setFile(BitcodeOutputFilename);
|
||||
sys::RemoveFileOnSignal(sys::Path(BitcodeOutputFilename));
|
||||
|
||||
// Arrange for the output file to be deleted on any errors.
|
||||
if (!LinkAsLibrary) {
|
||||
OutputRemover.setFile(OutputFilename);
|
||||
sys::RemoveFileOnSignal(sys::Path(OutputFilename));
|
||||
}
|
||||
|
||||
// Construct a Linker (now that Verbose is set)
|
||||
Linker TheLinker(progname, OutputFilename, Context, Verbose);
|
||||
|
||||
// Keep track of the native link items (versus the bitcode items)
|
||||
Linker::ItemList NativeLinkItems;
|
||||
|
||||
// Add library paths to the linker
|
||||
TheLinker.addPaths(LibPaths);
|
||||
TheLinker.addSystemPaths();
|
||||
|
||||
// Remove any consecutive duplicates of the same library...
|
||||
Libraries.erase(std::unique(Libraries.begin(), Libraries.end()),
|
||||
Libraries.end());
|
||||
|
||||
if (LinkAsLibrary) {
|
||||
std::vector<sys::Path> Files;
|
||||
for (unsigned i = 0; i < InputFilenames.size(); ++i )
|
||||
Files.push_back(sys::Path(InputFilenames[i]));
|
||||
if (TheLinker.LinkInFiles(Files))
|
||||
return 1; // Error already printed
|
||||
|
||||
// The libraries aren't linked in but are noted as "dependent" in the
|
||||
// module.
|
||||
for (cl::list<std::string>::const_iterator I = Libraries.begin(),
|
||||
E = Libraries.end(); I != E ; ++I) {
|
||||
TheLinker.getModule()->addLibrary(*I);
|
||||
}
|
||||
} else {
|
||||
// Build a list of the items from our command line
|
||||
Linker::ItemList Items;
|
||||
BuildLinkItems(Items, InputFilenames, Libraries);
|
||||
|
||||
// Link all the items together
|
||||
if (TheLinker.LinkInItems(Items, NativeLinkItems) )
|
||||
return 1; // Error already printed
|
||||
}
|
||||
|
||||
std::auto_ptr<Module> Composite(TheLinker.releaseModule());
|
||||
|
||||
// Optimize the module
|
||||
Optimize(Composite.get());
|
||||
|
||||
// Generate the bitcode output.
|
||||
GenerateBitcode(Composite.get(), BitcodeOutputFilename);
|
||||
|
||||
// If we are not linking a library, generate either a native executable
|
||||
// or a JIT shell script, depending upon what the user wants.
|
||||
if (!LinkAsLibrary) {
|
||||
// If the user wants to run a post-link optimization, run it now.
|
||||
if (!PostLinkOpts.empty()) {
|
||||
std::vector<std::string> opts = PostLinkOpts;
|
||||
for (std::vector<std::string>::iterator I = opts.begin(),
|
||||
E = opts.end(); I != E; ++I) {
|
||||
sys::Path prog(*I);
|
||||
if (!prog.canExecute()) {
|
||||
prog = sys::Program::FindProgramByName(*I);
|
||||
if (prog.isEmpty())
|
||||
PrintAndExit(std::string("Optimization program '") + *I +
|
||||
"' is not found or not executable.", Composite.get());
|
||||
}
|
||||
// Get the program arguments
|
||||
sys::Path tmp_output("opt_result");
|
||||
std::string ErrMsg;
|
||||
if (tmp_output.createTemporaryFileOnDisk(true, &ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
|
||||
const char* args[4];
|
||||
args[0] = I->c_str();
|
||||
args[1] = BitcodeOutputFilename.c_str();
|
||||
args[2] = tmp_output.c_str();
|
||||
args[3] = 0;
|
||||
if (0 == sys::Program::ExecuteAndWait(prog, args, 0,0,0,0, &ErrMsg)) {
|
||||
if (tmp_output.isBitcodeFile()) {
|
||||
sys::Path target(BitcodeOutputFilename);
|
||||
target.eraseFromDisk();
|
||||
if (tmp_output.renamePathOnDisk(target, &ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get(), 2);
|
||||
} else
|
||||
PrintAndExit("Post-link optimization output is not bitcode",
|
||||
Composite.get());
|
||||
} else {
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user wants to generate a native executable, compile it from the
|
||||
// bitcode file.
|
||||
//
|
||||
// Otherwise, create a script that will run the bitcode through the JIT.
|
||||
if (Native) {
|
||||
// Name of the Assembly Language output file
|
||||
sys::Path AssemblyFile ( OutputFilename);
|
||||
AssemblyFile.appendSuffix("s");
|
||||
|
||||
// Mark the output files for removal.
|
||||
FileRemover AssemblyFileRemover(AssemblyFile.str());
|
||||
sys::RemoveFileOnSignal(AssemblyFile);
|
||||
|
||||
// Determine the locations of the llc and gcc programs.
|
||||
sys::Path llc = PrependMainExecutablePath("llc", argv[0],
|
||||
(void *)(intptr_t)&Optimize);
|
||||
if (llc.isEmpty())
|
||||
PrintAndExit("Failed to find llc", Composite.get());
|
||||
|
||||
sys::Path gcc = sys::Program::FindProgramByName("gcc");
|
||||
if (gcc.isEmpty())
|
||||
PrintAndExit("Failed to find gcc", Composite.get());
|
||||
|
||||
// Generate an assembly language file for the bitcode.
|
||||
std::string ErrMsg;
|
||||
if (0 != GenerateAssembly(AssemblyFile.str(), BitcodeOutputFilename,
|
||||
llc, ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
|
||||
if (0 != GenerateNative(OutputFilename, AssemblyFile.str(),
|
||||
NativeLinkItems, gcc, envp, ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
} else if (NativeCBE) {
|
||||
sys::Path CFile (OutputFilename);
|
||||
CFile.appendSuffix("cbe.c");
|
||||
|
||||
// Mark the output files for removal.
|
||||
FileRemover CFileRemover(CFile.str());
|
||||
sys::RemoveFileOnSignal(CFile);
|
||||
|
||||
// Determine the locations of the llc and gcc programs.
|
||||
sys::Path llc = PrependMainExecutablePath("llc", argv[0],
|
||||
(void *)(intptr_t)&Optimize);
|
||||
if (llc.isEmpty())
|
||||
PrintAndExit("Failed to find llc", Composite.get());
|
||||
|
||||
sys::Path gcc = sys::Program::FindProgramByName("gcc");
|
||||
if (gcc.isEmpty())
|
||||
PrintAndExit("Failed to find gcc", Composite.get());
|
||||
|
||||
// Generate an assembly language file for the bitcode.
|
||||
std::string ErrMsg;
|
||||
if (GenerateCFile(CFile.str(), BitcodeOutputFilename, llc, ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
|
||||
if (GenerateNative(OutputFilename, CFile.str(),
|
||||
NativeLinkItems, gcc, envp, ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
} else {
|
||||
EmitShellScript(argv, Composite.get());
|
||||
}
|
||||
|
||||
// Make the script executable...
|
||||
std::string ErrMsg;
|
||||
if (sys::Path(OutputFilename).makeExecutableOnDisk(&ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
|
||||
// Make the bitcode file readable and directly executable in LLEE as well
|
||||
if (sys::Path(BitcodeOutputFilename).makeExecutableOnDisk(&ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
|
||||
if (sys::Path(BitcodeOutputFilename).makeReadableOnDisk(&ErrMsg))
|
||||
PrintAndExit(ErrMsg, Composite.get());
|
||||
}
|
||||
|
||||
// Operations which may fail are now complete.
|
||||
BitcodeOutputRemover.releaseFile();
|
||||
if (!LinkAsLibrary)
|
||||
OutputRemover.releaseFile();
|
||||
|
||||
// Graceful exit
|
||||
return 0;
|
||||
}
|
5
contrib/llvm/tools/llvm-link/CMakeLists.txt
Normal file
5
contrib/llvm/tools/llvm-link/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser)
|
||||
|
||||
add_llvm_tool(llvm-link
|
||||
llvm-link.cpp
|
||||
)
|
17
contrib/llvm/tools/llvm-link/Makefile
Normal file
17
contrib/llvm/tools/llvm-link/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-link/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-link
|
||||
LINK_COMPONENTS = linker bitreader bitwriter asmparser
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
142
contrib/llvm/tools/llvm-link/llvm-link.cpp
Normal file
142
contrib/llvm/tools/llvm-link/llvm-link.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
//===- llvm-link.cpp - Low-level LLVM linker ------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility may be invoked in the following manner:
|
||||
// llvm-link a.bc b.bc c.bc -o x.bc
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Linker.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
static cl::list<std::string>
|
||||
InputFilenames(cl::Positional, cl::OneOrMore,
|
||||
cl::desc("<input bitcode files>"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Force("f", cl::desc("Enable binary output on terminals"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OutputAssembly("S",
|
||||
cl::desc("Write output as LLVM assembly"), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
Verbose("v", cl::desc("Print information about actions taken"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DumpAsm("d", cl::desc("Print assembly as linked"), cl::Hidden);
|
||||
|
||||
// LoadFile - Read the specified bitcode file in and return it. This routine
|
||||
// searches the link path for the specified file to try to find it...
|
||||
//
|
||||
static inline std::auto_ptr<Module> LoadFile(const char *argv0,
|
||||
const std::string &FN,
|
||||
LLVMContext& Context) {
|
||||
sys::Path Filename;
|
||||
if (!Filename.set(FN)) {
|
||||
errs() << "Invalid file name: '" << FN << "'\n";
|
||||
return std::auto_ptr<Module>();
|
||||
}
|
||||
|
||||
SMDiagnostic Err;
|
||||
if (Verbose) errs() << "Loading '" << Filename.c_str() << "'\n";
|
||||
Module* Result = 0;
|
||||
|
||||
const std::string &FNStr = Filename.str();
|
||||
Result = ParseIRFile(FNStr, Err, Context);
|
||||
if (Result) return std::auto_ptr<Module>(Result); // Load successful!
|
||||
|
||||
Err.Print(argv0, errs());
|
||||
return std::auto_ptr<Module>();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
|
||||
|
||||
unsigned BaseArg = 0;
|
||||
std::string ErrorMessage;
|
||||
|
||||
std::auto_ptr<Module> Composite(LoadFile(argv[0],
|
||||
InputFilenames[BaseArg], Context));
|
||||
if (Composite.get() == 0) {
|
||||
errs() << argv[0] << ": error loading file '"
|
||||
<< InputFilenames[BaseArg] << "'\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
|
||||
std::auto_ptr<Module> M(LoadFile(argv[0],
|
||||
InputFilenames[i], Context));
|
||||
if (M.get() == 0) {
|
||||
errs() << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n";
|
||||
|
||||
if (Linker::LinkModules(Composite.get(), M.get(), Linker::DestroySource,
|
||||
&ErrorMessage)) {
|
||||
errs() << argv[0] << ": link error in '" << InputFilenames[i]
|
||||
<< "': " << ErrorMessage << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Iterate over the -l list and link in any modules containing
|
||||
// global symbols that have not been resolved so far.
|
||||
|
||||
if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;
|
||||
|
||||
std::string ErrorInfo;
|
||||
tool_output_file Out(OutputFilename.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary);
|
||||
if (!ErrorInfo.empty()) {
|
||||
errs() << ErrorInfo << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (verifyModule(*Composite)) {
|
||||
errs() << argv[0] << ": linked module is broken!\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (Verbose) errs() << "Writing bitcode...\n";
|
||||
if (OutputAssembly) {
|
||||
Out.os() << *Composite;
|
||||
} else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true))
|
||||
WriteBitcodeToFile(Composite.get(), Out.os());
|
||||
|
||||
// Declare success.
|
||||
Out.keep();
|
||||
|
||||
return 0;
|
||||
}
|
6
contrib/llvm/tools/llvm-mc/CMakeLists.txt
Normal file
6
contrib/llvm/tools/llvm-mc/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC MCParser MCDisassembler)
|
||||
|
||||
add_llvm_tool(llvm-mc
|
||||
llvm-mc.cpp
|
||||
Disassembler.cpp
|
||||
)
|
368
contrib/llvm/tools/llvm-mc/Disassembler.cpp
Normal file
368
contrib/llvm/tools/llvm-mc/Disassembler.cpp
Normal file
@ -0,0 +1,368 @@
|
||||
//===- Disassembler.cpp - Disassembler for hex strings --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements the disassembler of strings of bytes written in
|
||||
// hexadecimal, from standard input or from a file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Disassembler.h"
|
||||
#include "../../lib/MC/MCDisassembler/EDDisassembler.h"
|
||||
#include "../../lib/MC/MCDisassembler/EDInst.h"
|
||||
#include "../../lib/MC/MCDisassembler/EDOperand.h"
|
||||
#include "../../lib/MC/MCDisassembler/EDToken.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/MemoryObject.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
typedef std::vector<std::pair<unsigned char, const char*> > ByteArrayTy;
|
||||
|
||||
namespace {
|
||||
class VectorMemoryObject : public MemoryObject {
|
||||
private:
|
||||
const ByteArrayTy &Bytes;
|
||||
public:
|
||||
VectorMemoryObject(const ByteArrayTy &bytes) : Bytes(bytes) {}
|
||||
|
||||
uint64_t getBase() const { return 0; }
|
||||
uint64_t getExtent() const { return Bytes.size(); }
|
||||
|
||||
int readByte(uint64_t Addr, uint8_t *Byte) const {
|
||||
if (Addr >= getExtent())
|
||||
return -1;
|
||||
*Byte = Bytes[Addr].first;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static bool PrintInsts(const MCDisassembler &DisAsm,
|
||||
MCInstPrinter &Printer, const ByteArrayTy &Bytes,
|
||||
SourceMgr &SM, raw_ostream &Out) {
|
||||
// Wrap the vector in a MemoryObject.
|
||||
VectorMemoryObject memoryObject(Bytes);
|
||||
|
||||
// Disassemble it to strings.
|
||||
uint64_t Size;
|
||||
uint64_t Index;
|
||||
|
||||
for (Index = 0; Index < Bytes.size(); Index += Size) {
|
||||
MCInst Inst;
|
||||
|
||||
MCDisassembler::DecodeStatus S;
|
||||
S = DisAsm.getInstruction(Inst, Size, memoryObject, Index,
|
||||
/*REMOVE*/ nulls(), nulls());
|
||||
switch (S) {
|
||||
case MCDisassembler::Fail:
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
|
||||
"invalid instruction encoding", "warning");
|
||||
if (Size == 0)
|
||||
Size = 1; // skip illegible bytes
|
||||
break;
|
||||
|
||||
case MCDisassembler::SoftFail:
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
|
||||
"potentially undefined instruction encoding", "warning");
|
||||
// Fall through
|
||||
|
||||
case MCDisassembler::Success:
|
||||
Printer.printInst(&Inst, Out, "");
|
||||
Out << "\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ByteArrayFromString(ByteArrayTy &ByteArray,
|
||||
StringRef &Str,
|
||||
SourceMgr &SM) {
|
||||
while (!Str.empty()) {
|
||||
// Strip horizontal whitespace.
|
||||
if (size_t Pos = Str.find_first_not_of(" \t\r")) {
|
||||
Str = Str.substr(Pos);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is the end of a line or start of a comment, remove the rest of
|
||||
// the line.
|
||||
if (Str[0] == '\n' || Str[0] == '#') {
|
||||
// Strip to the end of line if we already processed any bytes on this
|
||||
// line. This strips the comment and/or the \n.
|
||||
if (Str[0] == '\n') {
|
||||
Str = Str.substr(1);
|
||||
} else {
|
||||
Str = Str.substr(Str.find_first_of('\n'));
|
||||
if (!Str.empty())
|
||||
Str = Str.substr(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the current token.
|
||||
size_t Next = Str.find_first_of(" \t\n\r#");
|
||||
StringRef Value = Str.substr(0, Next);
|
||||
|
||||
// Convert to a byte and add to the byte vector.
|
||||
unsigned ByteVal;
|
||||
if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) {
|
||||
// If we have an error, print it and skip to the end of line.
|
||||
SM.PrintMessage(SMLoc::getFromPointer(Value.data()),
|
||||
"invalid input token", "error");
|
||||
Str = Str.substr(Str.find('\n'));
|
||||
ByteArray.clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data()));
|
||||
Str = Str.substr(Next);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Disassembler::disassemble(const Target &T,
|
||||
const std::string &Triple,
|
||||
const std::string &Cpu,
|
||||
const std::string &FeaturesStr,
|
||||
MemoryBuffer &Buffer,
|
||||
raw_ostream &Out) {
|
||||
// Set up disassembler.
|
||||
OwningPtr<const MCAsmInfo> AsmInfo(T.createMCAsmInfo(Triple));
|
||||
|
||||
if (!AsmInfo) {
|
||||
errs() << "error: no assembly info for target " << Triple << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
OwningPtr<const MCSubtargetInfo> STI(T.createMCSubtargetInfo(Triple, Cpu, FeaturesStr));
|
||||
if (!STI) {
|
||||
errs() << "error: no subtarget info for target " << Triple << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
OwningPtr<const MCDisassembler> DisAsm(T.createMCDisassembler(*STI));
|
||||
if (!DisAsm) {
|
||||
errs() << "error: no disassembler for target " << Triple << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
||||
OwningPtr<MCInstPrinter> IP(T.createMCInstPrinter(AsmPrinterVariant,
|
||||
*AsmInfo, *STI));
|
||||
if (!IP) {
|
||||
errs() << "error: no instruction printer for target " << Triple << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ErrorOccurred = false;
|
||||
|
||||
SourceMgr SM;
|
||||
SM.AddNewSourceBuffer(&Buffer, SMLoc());
|
||||
|
||||
// Convert the input to a vector for disassembly.
|
||||
ByteArrayTy ByteArray;
|
||||
StringRef Str = Buffer.getBuffer();
|
||||
|
||||
ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
|
||||
|
||||
if (!ByteArray.empty())
|
||||
ErrorOccurred |= PrintInsts(*DisAsm, *IP, ByteArray, SM, Out);
|
||||
|
||||
return ErrorOccurred;
|
||||
}
|
||||
|
||||
static int byteArrayReader(uint8_t *B, uint64_t A, void *Arg) {
|
||||
ByteArrayTy &ByteArray = *((ByteArrayTy*)Arg);
|
||||
|
||||
if (A >= ByteArray.size())
|
||||
return -1;
|
||||
|
||||
*B = ByteArray[A].first;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verboseEvaluator(uint64_t *V, unsigned R, void *Arg) {
|
||||
EDDisassembler &disassembler = *(EDDisassembler *)((void **)Arg)[0];
|
||||
raw_ostream &Out = *(raw_ostream *)((void **)Arg)[1];
|
||||
|
||||
if (const char *regName = disassembler.nameWithRegisterID(R))
|
||||
Out << "[" << regName << "/" << R << "]";
|
||||
|
||||
if (disassembler.registerIsStackPointer(R))
|
||||
Out << "(sp)";
|
||||
if (disassembler.registerIsProgramCounter(R))
|
||||
Out << "(pc)";
|
||||
|
||||
*V = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Disassembler::disassembleEnhanced(const std::string &TS,
|
||||
MemoryBuffer &Buffer,
|
||||
raw_ostream &Out) {
|
||||
ByteArrayTy ByteArray;
|
||||
StringRef Str = Buffer.getBuffer();
|
||||
SourceMgr SM;
|
||||
|
||||
SM.AddNewSourceBuffer(&Buffer, SMLoc());
|
||||
|
||||
if (ByteArrayFromString(ByteArray, Str, SM)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Triple T(TS);
|
||||
EDDisassembler::AssemblySyntax AS;
|
||||
|
||||
switch (T.getArch()) {
|
||||
default:
|
||||
errs() << "error: no default assembly syntax for " << TS.c_str() << "\n";
|
||||
return -1;
|
||||
case Triple::arm:
|
||||
case Triple::thumb:
|
||||
AS = EDDisassembler::kEDAssemblySyntaxARMUAL;
|
||||
break;
|
||||
case Triple::x86:
|
||||
case Triple::x86_64:
|
||||
AS = EDDisassembler::kEDAssemblySyntaxX86ATT;
|
||||
break;
|
||||
}
|
||||
|
||||
EDDisassembler::initialize();
|
||||
OwningPtr<EDDisassembler>
|
||||
disassembler(EDDisassembler::getDisassembler(TS.c_str(), AS));
|
||||
|
||||
if (disassembler == 0) {
|
||||
errs() << "error: couldn't get disassembler for " << TS << '\n';
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (ByteArray.size()) {
|
||||
OwningPtr<EDInst>
|
||||
inst(disassembler->createInst(byteArrayReader, 0, &ByteArray));
|
||||
|
||||
if (inst == 0) {
|
||||
errs() << "error: Didn't get an instruction\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
ByteArray.erase (ByteArray.begin(), ByteArray.begin() + inst->byteSize());
|
||||
|
||||
unsigned numTokens = inst->numTokens();
|
||||
if ((int)numTokens < 0) {
|
||||
errs() << "error: couldn't count the instruction's tokens\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned tokenIndex = 0; tokenIndex != numTokens; ++tokenIndex) {
|
||||
EDToken *token;
|
||||
|
||||
if (inst->getToken(token, tokenIndex)) {
|
||||
errs() << "error: Couldn't get token\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *buf;
|
||||
if (token->getString(buf)) {
|
||||
errs() << "error: Couldn't get string for token\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
Out << '[';
|
||||
int operandIndex = token->operandID();
|
||||
|
||||
if (operandIndex >= 0)
|
||||
Out << operandIndex << "-";
|
||||
|
||||
switch (token->type()) {
|
||||
default: Out << "?"; break;
|
||||
case EDToken::kTokenWhitespace: Out << "w"; break;
|
||||
case EDToken::kTokenPunctuation: Out << "p"; break;
|
||||
case EDToken::kTokenOpcode: Out << "o"; break;
|
||||
case EDToken::kTokenLiteral: Out << "l"; break;
|
||||
case EDToken::kTokenRegister: Out << "r"; break;
|
||||
}
|
||||
|
||||
Out << ":" << buf;
|
||||
|
||||
if (token->type() == EDToken::kTokenLiteral) {
|
||||
Out << "=";
|
||||
if (token->literalSign())
|
||||
Out << "-";
|
||||
uint64_t absoluteValue;
|
||||
if (token->literalAbsoluteValue(absoluteValue)) {
|
||||
errs() << "error: Couldn't get the value of a literal token\n";
|
||||
return -1;
|
||||
}
|
||||
Out << absoluteValue;
|
||||
} else if (token->type() == EDToken::kTokenRegister) {
|
||||
Out << "=";
|
||||
unsigned regID;
|
||||
if (token->registerID(regID)) {
|
||||
errs() << "error: Couldn't get the ID of a register token\n";
|
||||
return -1;
|
||||
}
|
||||
Out << "r" << regID;
|
||||
}
|
||||
|
||||
Out << "]";
|
||||
}
|
||||
|
||||
Out << " ";
|
||||
|
||||
if (inst->isBranch())
|
||||
Out << "<br> ";
|
||||
if (inst->isMove())
|
||||
Out << "<mov> ";
|
||||
|
||||
unsigned numOperands = inst->numOperands();
|
||||
|
||||
if ((int)numOperands < 0) {
|
||||
errs() << "error: Couldn't count operands\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned operandIndex = 0; operandIndex != numOperands;
|
||||
++operandIndex) {
|
||||
Out << operandIndex << ":";
|
||||
|
||||
EDOperand *operand;
|
||||
if (inst->getOperand(operand, operandIndex)) {
|
||||
errs() << "error: couldn't get operand\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t evaluatedResult;
|
||||
void *Arg[] = { disassembler.get(), &Out };
|
||||
if (operand->evaluate(evaluatedResult, verboseEvaluator, Arg)) {
|
||||
errs() << "error: Couldn't evaluate an operand\n";
|
||||
return -1;
|
||||
}
|
||||
Out << "=" << evaluatedResult << " ";
|
||||
}
|
||||
|
||||
Out << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
42
contrib/llvm/tools/llvm-mc/Disassembler.h
Normal file
42
contrib/llvm/tools/llvm-mc/Disassembler.h
Normal file
@ -0,0 +1,42 @@
|
||||
//===- Disassembler.h - Text File Disassembler ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This class implements the disassembler of strings of bytes written in
|
||||
// hexadecimal, from standard input or from a file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DISASSEMBLER_H
|
||||
#define DISASSEMBLER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MemoryBuffer;
|
||||
class Target;
|
||||
class raw_ostream;
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
static int disassemble(const Target &target,
|
||||
const std::string &tripleString,
|
||||
const std::string &Cpu,
|
||||
const std::string &FeaturesStr,
|
||||
MemoryBuffer &buffer,
|
||||
raw_ostream &Out);
|
||||
|
||||
static int disassembleEnhanced(const std::string &tripleString,
|
||||
MemoryBuffer &buffer,
|
||||
raw_ostream &Out);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
24
contrib/llvm/tools/llvm-mc/Makefile
Normal file
24
contrib/llvm/tools/llvm-mc/Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
##===- tools/llvm-mc/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llvm-mc
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
# Include this here so we can get the configuration of the targets
|
||||
# that have been configured for construction. We have to do this
|
||||
# early so we can set up LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) MCDisassembler MCParser MC support
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
||||
|
517
contrib/llvm/tools/llvm-mc/llvm-mc.cpp
Normal file
517
contrib/llvm/tools/llvm-mc/llvm-mc.cpp
Normal file
@ -0,0 +1,517 @@
|
||||
//===-- llvm-mc.cpp - Machine Code Hacking Driver -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This utility is a simple driver that allows command line hacking on machine
|
||||
// code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/MC/MCParser/AsmLexer.h"
|
||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCObjectFileInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSectionMachO.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCTargetAsmParser.h"
|
||||
#include "llvm/MC/SubtargetFeature.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileUtilities.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include "Disassembler.h"
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Output filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowEncoding("show-encoding", cl::desc("Show instruction encodings"));
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowInst("show-inst", cl::desc("Show internal instruction representation"));
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowInstOperands("show-inst-operands",
|
||||
cl::desc("Show instructions operands as parsed"));
|
||||
|
||||
static cl::opt<unsigned>
|
||||
OutputAsmVariant("output-asm-variant",
|
||||
cl::desc("Syntax variant to use for output printing"));
|
||||
|
||||
static cl::opt<bool>
|
||||
RelaxAll("mc-relax-all", cl::desc("Relax all fixups"));
|
||||
|
||||
static cl::opt<bool>
|
||||
NoExecStack("mc-no-exec-stack", cl::desc("File doesn't need an exec stack"));
|
||||
|
||||
static cl::opt<bool>
|
||||
EnableLogging("enable-api-logging", cl::desc("Enable MC API logging"));
|
||||
|
||||
enum OutputFileType {
|
||||
OFT_Null,
|
||||
OFT_AssemblyFile,
|
||||
OFT_ObjectFile
|
||||
};
|
||||
static cl::opt<OutputFileType>
|
||||
FileType("filetype", cl::init(OFT_AssemblyFile),
|
||||
cl::desc("Choose an output file type:"),
|
||||
cl::values(
|
||||
clEnumValN(OFT_AssemblyFile, "asm",
|
||||
"Emit an assembly ('.s') file"),
|
||||
clEnumValN(OFT_Null, "null",
|
||||
"Don't emit anything (for timing purposes)"),
|
||||
clEnumValN(OFT_ObjectFile, "obj",
|
||||
"Emit a native object ('.o') file"),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::list<std::string>
|
||||
IncludeDirs("I", cl::desc("Directory of include files"),
|
||||
cl::value_desc("directory"), cl::Prefix);
|
||||
|
||||
static cl::opt<std::string>
|
||||
ArchName("arch", cl::desc("Target arch to assemble for, "
|
||||
"see -version for available targets"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
TripleName("triple", cl::desc("Target triple to assemble for, "
|
||||
"see -version for available targets"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
MCPU("mcpu",
|
||||
cl::desc("Target a specific cpu type (-mcpu=help for details)"),
|
||||
cl::value_desc("cpu-name"),
|
||||
cl::init(""));
|
||||
|
||||
static cl::list<std::string>
|
||||
MAttrs("mattr",
|
||||
cl::CommaSeparated,
|
||||
cl::desc("Target specific attributes (-mattr=help for details)"),
|
||||
cl::value_desc("a1,+a2,-a3,..."));
|
||||
|
||||
static cl::opt<Reloc::Model>
|
||||
RelocModel("relocation-model",
|
||||
cl::desc("Choose relocation model"),
|
||||
cl::init(Reloc::Default),
|
||||
cl::values(
|
||||
clEnumValN(Reloc::Default, "default",
|
||||
"Target default relocation model"),
|
||||
clEnumValN(Reloc::Static, "static",
|
||||
"Non-relocatable code"),
|
||||
clEnumValN(Reloc::PIC_, "pic",
|
||||
"Fully relocatable, position independent code"),
|
||||
clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
|
||||
"Relocatable external references, non-relocatable code"),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::opt<llvm::CodeModel::Model>
|
||||
CMModel("code-model",
|
||||
cl::desc("Choose code model"),
|
||||
cl::init(CodeModel::Default),
|
||||
cl::values(clEnumValN(CodeModel::Default, "default",
|
||||
"Target default code model"),
|
||||
clEnumValN(CodeModel::Small, "small",
|
||||
"Small code model"),
|
||||
clEnumValN(CodeModel::Kernel, "kernel",
|
||||
"Kernel code model"),
|
||||
clEnumValN(CodeModel::Medium, "medium",
|
||||
"Medium code model"),
|
||||
clEnumValN(CodeModel::Large, "large",
|
||||
"Large code model"),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::opt<bool>
|
||||
NoInitialTextSection("n", cl::desc("Don't assume assembly file starts "
|
||||
"in the text section"));
|
||||
|
||||
static cl::opt<bool>
|
||||
SaveTempLabels("L", cl::desc("Don't discard temporary labels"));
|
||||
|
||||
enum ActionType {
|
||||
AC_AsLex,
|
||||
AC_Assemble,
|
||||
AC_Disassemble,
|
||||
AC_EDisassemble
|
||||
};
|
||||
|
||||
static cl::opt<ActionType>
|
||||
Action(cl::desc("Action to perform:"),
|
||||
cl::init(AC_Assemble),
|
||||
cl::values(clEnumValN(AC_AsLex, "as-lex",
|
||||
"Lex tokens from a .s file"),
|
||||
clEnumValN(AC_Assemble, "assemble",
|
||||
"Assemble a .s file (default)"),
|
||||
clEnumValN(AC_Disassemble, "disassemble",
|
||||
"Disassemble strings of hex bytes"),
|
||||
clEnumValN(AC_EDisassemble, "edis",
|
||||
"Enhanced disassembly of strings of hex bytes"),
|
||||
clEnumValEnd));
|
||||
|
||||
static const Target *GetTarget(const char *ProgName) {
|
||||
// Figure out the target triple.
|
||||
if (TripleName.empty())
|
||||
TripleName = sys::getHostTriple();
|
||||
Triple TheTriple(Triple::normalize(TripleName));
|
||||
|
||||
const Target *TheTarget = 0;
|
||||
if (!ArchName.empty()) {
|
||||
for (TargetRegistry::iterator it = TargetRegistry::begin(),
|
||||
ie = TargetRegistry::end(); it != ie; ++it) {
|
||||
if (ArchName == it->getName()) {
|
||||
TheTarget = &*it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!TheTarget) {
|
||||
errs() << ProgName << ": error: invalid target '" << ArchName << "'.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Adjust the triple to match (if known), otherwise stick with the
|
||||
// module/host triple.
|
||||
Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName);
|
||||
if (Type != Triple::UnknownArch)
|
||||
TheTriple.setArch(Type);
|
||||
} else {
|
||||
// Get the target specific parser.
|
||||
std::string Error;
|
||||
TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
|
||||
if (TheTarget == 0) {
|
||||
errs() << ProgName << ": error: unable to get target for '"
|
||||
<< TheTriple.getTriple()
|
||||
<< "', see --version and --triple.\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
TripleName = TheTriple.getTriple();
|
||||
return TheTarget;
|
||||
}
|
||||
|
||||
static tool_output_file *GetOutputStream() {
|
||||
if (OutputFilename == "")
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string Err;
|
||||
tool_output_file *Out = new tool_output_file(OutputFilename.c_str(), Err,
|
||||
raw_fd_ostream::F_Binary);
|
||||
if (!Err.empty()) {
|
||||
errs() << Err << '\n';
|
||||
delete Out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Out;
|
||||
}
|
||||
|
||||
static int AsLexInput(const char *ProgName) {
|
||||
OwningPtr<MemoryBuffer> BufferPtr;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
|
||||
errs() << ProgName << ": " << ec.message() << '\n';
|
||||
return 1;
|
||||
}
|
||||
MemoryBuffer *Buffer = BufferPtr.take();
|
||||
|
||||
SourceMgr SrcMgr;
|
||||
|
||||
// Tell SrcMgr about this buffer, which is what TGParser will pick up.
|
||||
SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
|
||||
|
||||
// Record the location of the include directories so that the lexer can find
|
||||
// it later.
|
||||
SrcMgr.setIncludeDirs(IncludeDirs);
|
||||
|
||||
const Target *TheTarget = GetTarget(ProgName);
|
||||
if (!TheTarget)
|
||||
return 1;
|
||||
|
||||
llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
|
||||
assert(MAI && "Unable to create target asm info!");
|
||||
|
||||
AsmLexer Lexer(*MAI);
|
||||
Lexer.setBuffer(SrcMgr.getMemoryBuffer(0));
|
||||
|
||||
OwningPtr<tool_output_file> Out(GetOutputStream());
|
||||
if (!Out)
|
||||
return 1;
|
||||
|
||||
bool Error = false;
|
||||
while (Lexer.Lex().isNot(AsmToken::Eof)) {
|
||||
AsmToken Tok = Lexer.getTok();
|
||||
|
||||
switch (Tok.getKind()) {
|
||||
default:
|
||||
SrcMgr.PrintMessage(Lexer.getLoc(), "unknown token", "warning");
|
||||
Error = true;
|
||||
break;
|
||||
case AsmToken::Error:
|
||||
Error = true; // error already printed.
|
||||
break;
|
||||
case AsmToken::Identifier:
|
||||
Out->os() << "identifier: " << Lexer.getTok().getString();
|
||||
break;
|
||||
case AsmToken::Integer:
|
||||
Out->os() << "int: " << Lexer.getTok().getString();
|
||||
break;
|
||||
case AsmToken::Real:
|
||||
Out->os() << "real: " << Lexer.getTok().getString();
|
||||
break;
|
||||
case AsmToken::Register:
|
||||
Out->os() << "register: " << Lexer.getTok().getRegVal();
|
||||
break;
|
||||
case AsmToken::String:
|
||||
Out->os() << "string: " << Lexer.getTok().getString();
|
||||
break;
|
||||
|
||||
case AsmToken::Amp: Out->os() << "Amp"; break;
|
||||
case AsmToken::AmpAmp: Out->os() << "AmpAmp"; break;
|
||||
case AsmToken::At: Out->os() << "At"; break;
|
||||
case AsmToken::Caret: Out->os() << "Caret"; break;
|
||||
case AsmToken::Colon: Out->os() << "Colon"; break;
|
||||
case AsmToken::Comma: Out->os() << "Comma"; break;
|
||||
case AsmToken::Dollar: Out->os() << "Dollar"; break;
|
||||
case AsmToken::Dot: Out->os() << "Dot"; break;
|
||||
case AsmToken::EndOfStatement: Out->os() << "EndOfStatement"; break;
|
||||
case AsmToken::Eof: Out->os() << "Eof"; break;
|
||||
case AsmToken::Equal: Out->os() << "Equal"; break;
|
||||
case AsmToken::EqualEqual: Out->os() << "EqualEqual"; break;
|
||||
case AsmToken::Exclaim: Out->os() << "Exclaim"; break;
|
||||
case AsmToken::ExclaimEqual: Out->os() << "ExclaimEqual"; break;
|
||||
case AsmToken::Greater: Out->os() << "Greater"; break;
|
||||
case AsmToken::GreaterEqual: Out->os() << "GreaterEqual"; break;
|
||||
case AsmToken::GreaterGreater: Out->os() << "GreaterGreater"; break;
|
||||
case AsmToken::Hash: Out->os() << "Hash"; break;
|
||||
case AsmToken::LBrac: Out->os() << "LBrac"; break;
|
||||
case AsmToken::LCurly: Out->os() << "LCurly"; break;
|
||||
case AsmToken::LParen: Out->os() << "LParen"; break;
|
||||
case AsmToken::Less: Out->os() << "Less"; break;
|
||||
case AsmToken::LessEqual: Out->os() << "LessEqual"; break;
|
||||
case AsmToken::LessGreater: Out->os() << "LessGreater"; break;
|
||||
case AsmToken::LessLess: Out->os() << "LessLess"; break;
|
||||
case AsmToken::Minus: Out->os() << "Minus"; break;
|
||||
case AsmToken::Percent: Out->os() << "Percent"; break;
|
||||
case AsmToken::Pipe: Out->os() << "Pipe"; break;
|
||||
case AsmToken::PipePipe: Out->os() << "PipePipe"; break;
|
||||
case AsmToken::Plus: Out->os() << "Plus"; break;
|
||||
case AsmToken::RBrac: Out->os() << "RBrac"; break;
|
||||
case AsmToken::RCurly: Out->os() << "RCurly"; break;
|
||||
case AsmToken::RParen: Out->os() << "RParen"; break;
|
||||
case AsmToken::Slash: Out->os() << "Slash"; break;
|
||||
case AsmToken::Star: Out->os() << "Star"; break;
|
||||
case AsmToken::Tilde: Out->os() << "Tilde"; break;
|
||||
}
|
||||
|
||||
// Print the token string.
|
||||
Out->os() << " (\"";
|
||||
Out->os().write_escaped(Tok.getString());
|
||||
Out->os() << "\")\n";
|
||||
}
|
||||
|
||||
// Keep output if no errors.
|
||||
if (Error == 0) Out->keep();
|
||||
|
||||
return Error;
|
||||
}
|
||||
|
||||
static int AssembleInput(const char *ProgName) {
|
||||
const Target *TheTarget = GetTarget(ProgName);
|
||||
if (!TheTarget)
|
||||
return 1;
|
||||
|
||||
OwningPtr<MemoryBuffer> BufferPtr;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) {
|
||||
errs() << ProgName << ": " << ec.message() << '\n';
|
||||
return 1;
|
||||
}
|
||||
MemoryBuffer *Buffer = BufferPtr.take();
|
||||
|
||||
SourceMgr SrcMgr;
|
||||
|
||||
// Tell SrcMgr about this buffer, which is what the parser will pick up.
|
||||
SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
|
||||
|
||||
// Record the location of the include directories so that the lexer can find
|
||||
// it later.
|
||||
SrcMgr.setIncludeDirs(IncludeDirs);
|
||||
|
||||
|
||||
llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName));
|
||||
assert(MAI && "Unable to create target asm info!");
|
||||
|
||||
llvm::OwningPtr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName));
|
||||
assert(MRI && "Unable to create target register info!");
|
||||
|
||||
// FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
|
||||
// MCObjectFileInfo needs a MCContext reference in order to initialize itself.
|
||||
OwningPtr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
|
||||
MCContext Ctx(*MAI, *MRI, MOFI.get());
|
||||
MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx);
|
||||
|
||||
if (SaveTempLabels)
|
||||
Ctx.setAllowTemporaryLabels(false);
|
||||
|
||||
// Package up features to be passed to target/subtarget
|
||||
std::string FeaturesStr;
|
||||
if (MAttrs.size()) {
|
||||
SubtargetFeatures Features;
|
||||
for (unsigned i = 0; i != MAttrs.size(); ++i)
|
||||
Features.AddFeature(MAttrs[i]);
|
||||
FeaturesStr = Features.getString();
|
||||
}
|
||||
|
||||
OwningPtr<tool_output_file> Out(GetOutputStream());
|
||||
if (!Out)
|
||||
return 1;
|
||||
|
||||
formatted_raw_ostream FOS(Out->os());
|
||||
OwningPtr<MCStreamer> Str;
|
||||
|
||||
OwningPtr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
|
||||
OwningPtr<MCSubtargetInfo>
|
||||
STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
|
||||
|
||||
// FIXME: There is a bit of code duplication with addPassesToEmitFile.
|
||||
if (FileType == OFT_AssemblyFile) {
|
||||
MCInstPrinter *IP =
|
||||
TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *STI);
|
||||
MCCodeEmitter *CE = 0;
|
||||
MCAsmBackend *MAB = 0;
|
||||
if (ShowEncoding) {
|
||||
CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
|
||||
MAB = TheTarget->createMCAsmBackend(TripleName);
|
||||
}
|
||||
Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true,
|
||||
/*useLoc*/ true,
|
||||
/*useCFI*/ true, IP, CE, MAB,
|
||||
ShowInst));
|
||||
} else if (FileType == OFT_Null) {
|
||||
Str.reset(createNullStreamer(Ctx));
|
||||
} else {
|
||||
assert(FileType == OFT_ObjectFile && "Invalid file type!");
|
||||
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *STI, Ctx);
|
||||
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName);
|
||||
Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB,
|
||||
FOS, CE, RelaxAll,
|
||||
NoExecStack));
|
||||
}
|
||||
|
||||
if (EnableLogging) {
|
||||
Str.reset(createLoggingStreamer(Str.take(), errs()));
|
||||
}
|
||||
|
||||
OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx,
|
||||
*Str.get(), *MAI));
|
||||
OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(*STI, *Parser));
|
||||
if (!TAP) {
|
||||
errs() << ProgName
|
||||
<< ": error: this target does not support assembly parsing.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Parser->setShowParsedOperands(ShowInstOperands);
|
||||
Parser->setTargetParser(*TAP.get());
|
||||
|
||||
int Res = Parser->Run(NoInitialTextSection);
|
||||
|
||||
// Keep output if no errors.
|
||||
if (Res == 0) Out->keep();
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
static int DisassembleInput(const char *ProgName, bool Enhanced) {
|
||||
const Target *TheTarget = GetTarget(ProgName);
|
||||
if (!TheTarget)
|
||||
return 0;
|
||||
|
||||
OwningPtr<MemoryBuffer> Buffer;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, Buffer)) {
|
||||
errs() << ProgName << ": " << ec.message() << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
OwningPtr<tool_output_file> Out(GetOutputStream());
|
||||
if (!Out)
|
||||
return 1;
|
||||
|
||||
int Res;
|
||||
if (Enhanced) {
|
||||
Res =
|
||||
Disassembler::disassembleEnhanced(TripleName, *Buffer.take(), Out->os());
|
||||
} else {
|
||||
// Package up features to be passed to target/subtarget
|
||||
std::string FeaturesStr;
|
||||
if (MAttrs.size()) {
|
||||
SubtargetFeatures Features;
|
||||
for (unsigned i = 0; i != MAttrs.size(); ++i)
|
||||
Features.AddFeature(MAttrs[i]);
|
||||
FeaturesStr = Features.getString();
|
||||
}
|
||||
|
||||
Res = Disassembler::disassemble(*TheTarget, TripleName, MCPU, FeaturesStr,
|
||||
*Buffer.take(), Out->os());
|
||||
}
|
||||
|
||||
// Keep output if no errors.
|
||||
if (Res == 0) Out->keep();
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
// Initialize targets and assembly printers/parsers.
|
||||
llvm::InitializeAllTargetInfos();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
llvm::InitializeAllDisassemblers();
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
|
||||
TripleName = Triple::normalize(TripleName);
|
||||
|
||||
switch (Action) {
|
||||
default:
|
||||
case AC_AsLex:
|
||||
return AsLexInput(argv[0]);
|
||||
case AC_Assemble:
|
||||
return AssembleInput(argv[0]);
|
||||
case AC_Disassemble:
|
||||
return DisassembleInput(argv[0], false);
|
||||
case AC_EDisassemble:
|
||||
return DisassembleInput(argv[0], true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
5
contrib/llvm/tools/llvm-nm/CMakeLists.txt
Normal file
5
contrib/llvm/tools/llvm-nm/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS archive bitreader object)
|
||||
|
||||
add_llvm_tool(llvm-nm
|
||||
llvm-nm.cpp
|
||||
)
|
17
contrib/llvm/tools/llvm-nm/Makefile
Normal file
17
contrib/llvm/tools/llvm-nm/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-nm/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-nm
|
||||
LINK_COMPONENTS = archive bitreader object
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
392
contrib/llvm/tools/llvm-nm/llvm-nm.cpp
Normal file
392
contrib/llvm/tools/llvm-nm/llvm-nm.cpp
Normal file
@ -0,0 +1,392 @@
|
||||
//===-- llvm-nm.cpp - Symbol table dumping utility for llvm ---------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This program is a utility that works like traditional Unix "nm",
|
||||
// that is, it prints out the names of symbols in a bitcode file,
|
||||
// along with some information about each symbol.
|
||||
//
|
||||
// This "nm" does not print symbols' addresses. It supports many of
|
||||
// the features of GNU "nm", including its different output formats.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Bitcode/Archive.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
using namespace llvm;
|
||||
using namespace object;
|
||||
|
||||
namespace {
|
||||
enum OutputFormatTy { bsd, sysv, posix };
|
||||
cl::opt<OutputFormatTy>
|
||||
OutputFormat("format",
|
||||
cl::desc("Specify output format"),
|
||||
cl::values(clEnumVal(bsd, "BSD format"),
|
||||
clEnumVal(sysv, "System V format"),
|
||||
clEnumVal(posix, "POSIX.2 format"),
|
||||
clEnumValEnd), cl::init(bsd));
|
||||
cl::alias OutputFormat2("f", cl::desc("Alias for --format"),
|
||||
cl::aliasopt(OutputFormat));
|
||||
|
||||
cl::list<std::string>
|
||||
InputFilenames(cl::Positional, cl::desc("<input bitcode files>"),
|
||||
cl::ZeroOrMore);
|
||||
|
||||
cl::opt<bool> UndefinedOnly("undefined-only",
|
||||
cl::desc("Show only undefined symbols"));
|
||||
cl::alias UndefinedOnly2("u", cl::desc("Alias for --undefined-only"),
|
||||
cl::aliasopt(UndefinedOnly));
|
||||
|
||||
cl::opt<bool> DefinedOnly("defined-only",
|
||||
cl::desc("Show only defined symbols"));
|
||||
|
||||
cl::opt<bool> ExternalOnly("extern-only",
|
||||
cl::desc("Show only external symbols"));
|
||||
cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"),
|
||||
cl::aliasopt(ExternalOnly));
|
||||
|
||||
cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd"));
|
||||
cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"));
|
||||
|
||||
cl::opt<bool> PrintFileName("print-file-name",
|
||||
cl::desc("Precede each symbol with the object file it came from"));
|
||||
|
||||
cl::alias PrintFileNameA("A", cl::desc("Alias for --print-file-name"),
|
||||
cl::aliasopt(PrintFileName));
|
||||
cl::alias PrintFileNameo("o", cl::desc("Alias for --print-file-name"),
|
||||
cl::aliasopt(PrintFileName));
|
||||
|
||||
cl::opt<bool> DebugSyms("debug-syms",
|
||||
cl::desc("Show all symbols, even debugger only"));
|
||||
cl::alias DebugSymsa("a", cl::desc("Alias for --debug-syms"),
|
||||
cl::aliasopt(DebugSyms));
|
||||
|
||||
cl::opt<bool> NumericSort("numeric-sort",
|
||||
cl::desc("Sort symbols by address"));
|
||||
cl::alias NumericSortn("n", cl::desc("Alias for --numeric-sort"),
|
||||
cl::aliasopt(NumericSort));
|
||||
cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"),
|
||||
cl::aliasopt(NumericSort));
|
||||
|
||||
cl::opt<bool> NoSort("no-sort",
|
||||
cl::desc("Show symbols in order encountered"));
|
||||
cl::alias NoSortp("p", cl::desc("Alias for --no-sort"),
|
||||
cl::aliasopt(NoSort));
|
||||
|
||||
cl::opt<bool> PrintSize("print-size",
|
||||
cl::desc("Show symbol size instead of address"));
|
||||
cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"),
|
||||
cl::aliasopt(PrintSize));
|
||||
|
||||
cl::opt<bool> SizeSort("size-sort", cl::desc("Sort symbols by size"));
|
||||
|
||||
bool PrintAddress = true;
|
||||
|
||||
bool MultipleFiles = false;
|
||||
|
||||
std::string ToolName;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct NMSymbol {
|
||||
uint64_t Address;
|
||||
uint64_t Size;
|
||||
char TypeChar;
|
||||
StringRef Name;
|
||||
};
|
||||
|
||||
static bool CompareSymbolAddress(const NMSymbol &a, const NMSymbol &b) {
|
||||
if (a.Address < b.Address)
|
||||
return true;
|
||||
else if (a.Address == b.Address && a.Name < b.Name)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
static bool CompareSymbolSize(const NMSymbol &a, const NMSymbol &b) {
|
||||
if (a.Size < b.Size)
|
||||
return true;
|
||||
else if (a.Size == b.Size && a.Name < b.Name)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) {
|
||||
return a.Name < b.Name;
|
||||
}
|
||||
|
||||
StringRef CurrentFilename;
|
||||
typedef std::vector<NMSymbol> SymbolListT;
|
||||
SymbolListT SymbolList;
|
||||
|
||||
bool error(error_code ec) {
|
||||
if (!ec) return false;
|
||||
|
||||
outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
|
||||
outs().flush();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void SortAndPrintSymbolList() {
|
||||
if (!NoSort) {
|
||||
if (NumericSort)
|
||||
std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolAddress);
|
||||
else if (SizeSort)
|
||||
std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolSize);
|
||||
else
|
||||
std::sort(SymbolList.begin(), SymbolList.end(), CompareSymbolName);
|
||||
}
|
||||
|
||||
if (OutputFormat == posix && MultipleFiles) {
|
||||
outs() << '\n' << CurrentFilename << ":\n";
|
||||
} else if (OutputFormat == bsd && MultipleFiles) {
|
||||
outs() << "\n" << CurrentFilename << ":\n";
|
||||
} else if (OutputFormat == sysv) {
|
||||
outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"
|
||||
<< "Name Value Class Type"
|
||||
<< " Size Line Section\n";
|
||||
}
|
||||
|
||||
for (SymbolListT::iterator i = SymbolList.begin(),
|
||||
e = SymbolList.end(); i != e; ++i) {
|
||||
if ((i->TypeChar != 'U') && UndefinedOnly)
|
||||
continue;
|
||||
if ((i->TypeChar == 'U') && DefinedOnly)
|
||||
continue;
|
||||
if (SizeSort && !PrintAddress && i->Size == UnknownAddressOrSize)
|
||||
continue;
|
||||
|
||||
char SymbolAddrStr[10] = "";
|
||||
char SymbolSizeStr[10] = "";
|
||||
|
||||
if (OutputFormat == sysv || i->Address == object::UnknownAddressOrSize)
|
||||
strcpy(SymbolAddrStr, " ");
|
||||
if (OutputFormat == sysv)
|
||||
strcpy(SymbolSizeStr, " ");
|
||||
|
||||
if (i->Address != object::UnknownAddressOrSize)
|
||||
format("%08"PRIx64, i->Address).print(SymbolAddrStr, sizeof(SymbolAddrStr));
|
||||
if (i->Size != object::UnknownAddressOrSize)
|
||||
format("%08"PRIx64, i->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
|
||||
|
||||
if (OutputFormat == posix) {
|
||||
outs() << i->Name << " " << i->TypeChar << " "
|
||||
<< SymbolAddrStr << SymbolSizeStr << "\n";
|
||||
} else if (OutputFormat == bsd) {
|
||||
if (PrintAddress)
|
||||
outs() << SymbolAddrStr << ' ';
|
||||
if (PrintSize) {
|
||||
outs() << SymbolSizeStr;
|
||||
if (i->Size != object::UnknownAddressOrSize)
|
||||
outs() << ' ';
|
||||
}
|
||||
outs() << i->TypeChar << " " << i->Name << "\n";
|
||||
} else if (OutputFormat == sysv) {
|
||||
std::string PaddedName (i->Name);
|
||||
while (PaddedName.length () < 20)
|
||||
PaddedName += " ";
|
||||
outs() << PaddedName << "|" << SymbolAddrStr << "| "
|
||||
<< i->TypeChar
|
||||
<< " | |" << SymbolSizeStr << "| |\n";
|
||||
}
|
||||
}
|
||||
|
||||
SymbolList.clear();
|
||||
}
|
||||
|
||||
static char TypeCharForSymbol(GlobalValue &GV) {
|
||||
if (GV.isDeclaration()) return 'U';
|
||||
if (GV.hasLinkOnceLinkage()) return 'C';
|
||||
if (GV.hasCommonLinkage()) return 'C';
|
||||
if (GV.hasWeakLinkage()) return 'W';
|
||||
if (isa<Function>(GV) && GV.hasInternalLinkage()) return 't';
|
||||
if (isa<Function>(GV)) return 'T';
|
||||
if (isa<GlobalVariable>(GV) && GV.hasInternalLinkage()) return 'd';
|
||||
if (isa<GlobalVariable>(GV)) return 'D';
|
||||
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(&GV)) {
|
||||
const GlobalValue *AliasedGV = GA->getAliasedGlobal();
|
||||
if (isa<Function>(AliasedGV)) return 'T';
|
||||
if (isa<GlobalVariable>(AliasedGV)) return 'D';
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
|
||||
static void DumpSymbolNameForGlobalValue(GlobalValue &GV) {
|
||||
// Private linkage and available_externally linkage don't exist in symtab.
|
||||
if (GV.hasPrivateLinkage() ||
|
||||
GV.hasLinkerPrivateLinkage() ||
|
||||
GV.hasLinkerPrivateWeakLinkage() ||
|
||||
GV.hasLinkerPrivateWeakDefAutoLinkage() ||
|
||||
GV.hasAvailableExternallyLinkage())
|
||||
return;
|
||||
char TypeChar = TypeCharForSymbol(GV);
|
||||
if (GV.hasLocalLinkage () && ExternalOnly)
|
||||
return;
|
||||
|
||||
NMSymbol s;
|
||||
s.Address = object::UnknownAddressOrSize;
|
||||
s.Size = object::UnknownAddressOrSize;
|
||||
s.TypeChar = TypeChar;
|
||||
s.Name = GV.getName();
|
||||
SymbolList.push_back(s);
|
||||
}
|
||||
|
||||
static void DumpSymbolNamesFromModule(Module *M) {
|
||||
CurrentFilename = M->getModuleIdentifier();
|
||||
std::for_each (M->begin(), M->end(), DumpSymbolNameForGlobalValue);
|
||||
std::for_each (M->global_begin(), M->global_end(),
|
||||
DumpSymbolNameForGlobalValue);
|
||||
std::for_each (M->alias_begin(), M->alias_end(),
|
||||
DumpSymbolNameForGlobalValue);
|
||||
|
||||
SortAndPrintSymbolList();
|
||||
}
|
||||
|
||||
static void DumpSymbolNamesFromObject(ObjectFile *obj) {
|
||||
error_code ec;
|
||||
for (symbol_iterator i = obj->begin_symbols(),
|
||||
e = obj->end_symbols();
|
||||
i != e; i.increment(ec)) {
|
||||
if (error(ec)) break;
|
||||
bool internal;
|
||||
if (error(i->isInternal(internal))) break;
|
||||
if (!DebugSyms && internal)
|
||||
continue;
|
||||
NMSymbol s;
|
||||
s.Size = object::UnknownAddressOrSize;
|
||||
s.Address = object::UnknownAddressOrSize;
|
||||
if (PrintSize || SizeSort) {
|
||||
if (error(i->getSize(s.Size))) break;
|
||||
}
|
||||
if (PrintAddress)
|
||||
if (error(i->getOffset(s.Address))) break;
|
||||
if (error(i->getNMTypeChar(s.TypeChar))) break;
|
||||
if (error(i->getName(s.Name))) break;
|
||||
SymbolList.push_back(s);
|
||||
}
|
||||
|
||||
CurrentFilename = obj->getFileName();
|
||||
SortAndPrintSymbolList();
|
||||
}
|
||||
|
||||
static void DumpSymbolNamesFromFile(std::string &Filename) {
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
std::string ErrorMessage;
|
||||
sys::Path aPath(Filename);
|
||||
bool exists;
|
||||
if (sys::fs::exists(aPath.str(), exists) || !exists)
|
||||
errs() << ToolName << ": '" << Filename << "': " << "No such file\n";
|
||||
// Note: Currently we do not support reading an archive from stdin.
|
||||
if (Filename == "-" || aPath.isBitcodeFile()) {
|
||||
OwningPtr<MemoryBuffer> Buffer;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buffer))
|
||||
ErrorMessage = ec.message();
|
||||
Module *Result = 0;
|
||||
if (Buffer.get())
|
||||
Result = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
|
||||
|
||||
if (Result) {
|
||||
DumpSymbolNamesFromModule(Result);
|
||||
delete Result;
|
||||
} else
|
||||
errs() << ToolName << ": " << Filename << ": " << ErrorMessage << "\n";
|
||||
|
||||
} else if (aPath.isArchive()) {
|
||||
OwningPtr<Binary> arch;
|
||||
if (error_code ec = object::createBinary(aPath.str(), arch)) {
|
||||
errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n";
|
||||
return;
|
||||
}
|
||||
if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) {
|
||||
for (object::Archive::child_iterator i = a->begin_children(),
|
||||
e = a->end_children(); i != e; ++i) {
|
||||
OwningPtr<Binary> child;
|
||||
if (error_code ec = i->getAsBinary(child)) {
|
||||
// Try opening it as a bitcode file.
|
||||
OwningPtr<MemoryBuffer> buff(i->getBuffer());
|
||||
Module *Result = 0;
|
||||
if (buff)
|
||||
Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage);
|
||||
|
||||
if (Result) {
|
||||
DumpSymbolNamesFromModule(Result);
|
||||
delete Result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (object::ObjectFile *o = dyn_cast<ObjectFile>(child.get())) {
|
||||
outs() << o->getFileName() << ":\n";
|
||||
DumpSymbolNamesFromObject(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (aPath.isObjectFile()) {
|
||||
OwningPtr<Binary> obj;
|
||||
if (error_code ec = object::createBinary(aPath.str(), obj)) {
|
||||
errs() << ToolName << ": " << Filename << ": " << ec.message() << ".\n";
|
||||
return;
|
||||
}
|
||||
if (object::ObjectFile *o = dyn_cast<ObjectFile>(obj.get()))
|
||||
DumpSymbolNamesFromObject(o);
|
||||
} else {
|
||||
errs() << ToolName << ": " << Filename << ": "
|
||||
<< "unrecognizable file type\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm symbol table dumper\n");
|
||||
|
||||
ToolName = argv[0];
|
||||
if (BSDFormat) OutputFormat = bsd;
|
||||
if (POSIXFormat) OutputFormat = posix;
|
||||
|
||||
// The relative order of these is important. If you pass --size-sort it should
|
||||
// only print out the size. However, if you pass -S --size-sort, it should
|
||||
// print out both the size and address.
|
||||
if (SizeSort && !PrintSize) PrintAddress = false;
|
||||
if (OutputFormat == sysv || SizeSort) PrintSize = true;
|
||||
|
||||
switch (InputFilenames.size()) {
|
||||
case 0: InputFilenames.push_back("-");
|
||||
case 1: break;
|
||||
default: MultipleFiles = true;
|
||||
}
|
||||
|
||||
std::for_each(InputFilenames.begin(), InputFilenames.end(),
|
||||
DumpSymbolNamesFromFile);
|
||||
return 0;
|
||||
}
|
14
contrib/llvm/tools/llvm-objdump/CMakeLists.txt
Normal file
14
contrib/llvm/tools/llvm-objdump/CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
||||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
DebugInfo
|
||||
MC
|
||||
MCParser
|
||||
MCDisassembler
|
||||
Object
|
||||
)
|
||||
|
||||
add_llvm_tool(llvm-objdump
|
||||
llvm-objdump.cpp
|
||||
MachODump.cpp
|
||||
MCFunction.cpp
|
||||
)
|
138
contrib/llvm/tools/llvm-objdump/MCFunction.cpp
Normal file
138
contrib/llvm/tools/llvm-objdump/MCFunction.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
//===-- MCFunction.cpp ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the algorithm to break down a region of machine code
|
||||
// into basic blocks and try to reconstruct a CFG from it.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCFunction.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
#include "llvm/MC/MCInstrAnalysis.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/Support/MemoryObject.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <set>
|
||||
using namespace llvm;
|
||||
|
||||
MCFunction
|
||||
MCFunction::createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm,
|
||||
const MemoryObject &Region, uint64_t Start,
|
||||
uint64_t End, const MCInstrAnalysis *Ana,
|
||||
raw_ostream &DebugOut,
|
||||
SmallVectorImpl<uint64_t> &Calls) {
|
||||
std::vector<MCDecodedInst> Instructions;
|
||||
std::set<uint64_t> Splits;
|
||||
Splits.insert(Start);
|
||||
uint64_t Size;
|
||||
|
||||
MCFunction f(Name);
|
||||
|
||||
{
|
||||
DenseSet<uint64_t> VisitedInsts;
|
||||
SmallVector<uint64_t, 16> WorkList;
|
||||
WorkList.push_back(Start);
|
||||
// Disassemble code and gather basic block split points.
|
||||
while (!WorkList.empty()) {
|
||||
uint64_t Index = WorkList.pop_back_val();
|
||||
if (VisitedInsts.find(Index) != VisitedInsts.end())
|
||||
continue; // Already visited this location.
|
||||
|
||||
for (;Index < End; Index += Size) {
|
||||
VisitedInsts.insert(Index);
|
||||
|
||||
MCInst Inst;
|
||||
if (DisAsm->getInstruction(Inst, Size, Region, Index, DebugOut, nulls())){
|
||||
Instructions.push_back(MCDecodedInst(Index, Size, Inst));
|
||||
if (Ana->isBranch(Inst)) {
|
||||
uint64_t targ = Ana->evaluateBranch(Inst, Index, Size);
|
||||
if (targ != -1ULL && targ == Index+Size)
|
||||
continue; // Skip nop jumps.
|
||||
|
||||
// If we could determine the branch target, make a note to start a
|
||||
// new basic block there and add the target to the worklist.
|
||||
if (targ != -1ULL) {
|
||||
Splits.insert(targ);
|
||||
WorkList.push_back(targ);
|
||||
WorkList.push_back(Index+Size);
|
||||
}
|
||||
Splits.insert(Index+Size);
|
||||
break;
|
||||
} else if (Ana->isReturn(Inst)) {
|
||||
// Return instruction. This basic block ends here.
|
||||
Splits.insert(Index+Size);
|
||||
break;
|
||||
} else if (Ana->isCall(Inst)) {
|
||||
uint64_t targ = Ana->evaluateBranch(Inst, Index, Size);
|
||||
// Add the call to the call list if the destination is known.
|
||||
if (targ != -1ULL && targ != Index+Size)
|
||||
Calls.push_back(targ);
|
||||
}
|
||||
} else {
|
||||
errs().write_hex(Index) << ": warning: invalid instruction encoding\n";
|
||||
if (Size == 0)
|
||||
Size = 1; // skip illegible bytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the instruction list is sorted.
|
||||
std::sort(Instructions.begin(), Instructions.end());
|
||||
|
||||
// Create basic blocks.
|
||||
unsigned ii = 0, ie = Instructions.size();
|
||||
for (std::set<uint64_t>::iterator spi = Splits.begin(),
|
||||
spe = llvm::prior(Splits.end()); spi != spe; ++spi) {
|
||||
MCBasicBlock BB;
|
||||
uint64_t BlockEnd = *llvm::next(spi);
|
||||
// Add instructions to the BB.
|
||||
for (; ii != ie; ++ii) {
|
||||
if (Instructions[ii].Address < *spi ||
|
||||
Instructions[ii].Address >= BlockEnd)
|
||||
break;
|
||||
BB.addInst(Instructions[ii]);
|
||||
}
|
||||
f.addBlock(*spi, BB);
|
||||
}
|
||||
|
||||
std::sort(f.Blocks.begin(), f.Blocks.end());
|
||||
|
||||
// Calculate successors of each block.
|
||||
for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) {
|
||||
MCBasicBlock &BB = const_cast<MCBasicBlock&>(i->second);
|
||||
if (BB.getInsts().empty()) continue;
|
||||
const MCDecodedInst &Inst = BB.getInsts().back();
|
||||
|
||||
if (Ana->isBranch(Inst.Inst)) {
|
||||
uint64_t targ = Ana->evaluateBranch(Inst.Inst, Inst.Address, Inst.Size);
|
||||
if (targ == -1ULL) {
|
||||
// Indirect branch. Bail and add all blocks of the function as a
|
||||
// successor.
|
||||
for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i)
|
||||
BB.addSucc(i->first);
|
||||
} else if (targ != Inst.Address+Inst.Size)
|
||||
BB.addSucc(targ);
|
||||
// Conditional branches can also fall through to the next block.
|
||||
if (Ana->isConditionalBranch(Inst.Inst) && llvm::next(i) != e)
|
||||
BB.addSucc(llvm::next(i)->first);
|
||||
} else {
|
||||
// No branch. Fall through to the next block.
|
||||
if (!Ana->isReturn(Inst.Inst) && llvm::next(i) != e)
|
||||
BB.addSucc(llvm::next(i)->first);
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
100
contrib/llvm/tools/llvm-objdump/MCFunction.h
Normal file
100
contrib/llvm/tools/llvm-objdump/MCFunction.h
Normal file
@ -0,0 +1,100 @@
|
||||
//===-- MCFunction.h ------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the data structures to hold a CFG reconstructed from
|
||||
// machine code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_OBJECTDUMP_MCFUNCTION_H
|
||||
#define LLVM_OBJECTDUMP_MCFUNCTION_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include <map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCDisassembler;
|
||||
class MCInstrAnalysis;
|
||||
class MemoryObject;
|
||||
class raw_ostream;
|
||||
|
||||
/// MCDecodedInst - Small container to hold an MCInst and associated info like
|
||||
/// address and size.
|
||||
struct MCDecodedInst {
|
||||
uint64_t Address;
|
||||
uint64_t Size;
|
||||
MCInst Inst;
|
||||
|
||||
MCDecodedInst() {}
|
||||
MCDecodedInst(uint64_t Address, uint64_t Size, MCInst Inst)
|
||||
: Address(Address), Size(Size), Inst(Inst) {}
|
||||
|
||||
bool operator<(const MCDecodedInst &RHS) const {
|
||||
return Address < RHS.Address;
|
||||
}
|
||||
};
|
||||
|
||||
/// MCBasicBlock - Consists of multiple MCDecodedInsts and a list of successing
|
||||
/// MCBasicBlocks.
|
||||
class MCBasicBlock {
|
||||
std::vector<MCDecodedInst> Insts;
|
||||
typedef DenseSet<uint64_t> SetTy;
|
||||
SetTy Succs;
|
||||
public:
|
||||
ArrayRef<MCDecodedInst> getInsts() const { return Insts; }
|
||||
|
||||
typedef SetTy::const_iterator succ_iterator;
|
||||
succ_iterator succ_begin() const { return Succs.begin(); }
|
||||
succ_iterator succ_end() const { return Succs.end(); }
|
||||
|
||||
bool contains(uint64_t Addr) const { return Succs.count(Addr); }
|
||||
|
||||
void addInst(const MCDecodedInst &Inst) { Insts.push_back(Inst); }
|
||||
void addSucc(uint64_t Addr) { Succs.insert(Addr); }
|
||||
|
||||
bool operator<(const MCBasicBlock &RHS) const {
|
||||
return Insts.size() < RHS.Insts.size();
|
||||
}
|
||||
};
|
||||
|
||||
/// MCFunction - Represents a named function in machine code, containing
|
||||
/// multiple MCBasicBlocks.
|
||||
class MCFunction {
|
||||
const StringRef Name;
|
||||
// Keep BBs sorted by address.
|
||||
typedef std::vector<std::pair<uint64_t, MCBasicBlock> > MapTy;
|
||||
MapTy Blocks;
|
||||
public:
|
||||
MCFunction(StringRef Name) : Name(Name) {}
|
||||
|
||||
// Create an MCFunction from a region of binary machine code.
|
||||
static MCFunction
|
||||
createFunctionFromMC(StringRef Name, const MCDisassembler *DisAsm,
|
||||
const MemoryObject &Region, uint64_t Start, uint64_t End,
|
||||
const MCInstrAnalysis *Ana, raw_ostream &DebugOut,
|
||||
SmallVectorImpl<uint64_t> &Calls);
|
||||
|
||||
typedef MapTy::const_iterator iterator;
|
||||
iterator begin() const { return Blocks.begin(); }
|
||||
iterator end() const { return Blocks.end(); }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
|
||||
MCBasicBlock &addBlock(uint64_t Address, const MCBasicBlock &BB) {
|
||||
Blocks.push_back(std::make_pair(Address, BB));
|
||||
return Blocks.back().second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
617
contrib/llvm/tools/llvm-objdump/MachODump.cpp
Normal file
617
contrib/llvm/tools/llvm-objdump/MachODump.cpp
Normal file
@ -0,0 +1,617 @@
|
||||
//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MachO-specific dumper for llvm-objdump.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-objdump.h"
|
||||
#include "MCFunction.h"
|
||||
#include "llvm/Support/MachO.h"
|
||||
#include "llvm/Object/MachOObject.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/DebugInfo/DIContext.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
#include "llvm/MC/MCInstrAnalysis.h"
|
||||
#include "llvm/MC/MCInstrDesc.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
using namespace llvm;
|
||||
using namespace object;
|
||||
|
||||
static cl::opt<bool>
|
||||
CFG("cfg", cl::desc("Create a CFG for every symbol in the object file and"
|
||||
"write it to a graphviz file (MachO-only)"));
|
||||
|
||||
static cl::opt<bool>
|
||||
UseDbg("g", cl::desc("Print line information from debug info if available"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
DSYMFile("dsym", cl::desc("Use .dSYM file for debug info"));
|
||||
|
||||
static const Target *GetTarget(const MachOObject *MachOObj) {
|
||||
// Figure out the target triple.
|
||||
llvm::Triple TT("unknown-unknown-unknown");
|
||||
switch (MachOObj->getHeader().CPUType) {
|
||||
case llvm::MachO::CPUTypeI386:
|
||||
TT.setArch(Triple::ArchType(Triple::x86));
|
||||
break;
|
||||
case llvm::MachO::CPUTypeX86_64:
|
||||
TT.setArch(Triple::ArchType(Triple::x86_64));
|
||||
break;
|
||||
case llvm::MachO::CPUTypeARM:
|
||||
TT.setArch(Triple::ArchType(Triple::arm));
|
||||
break;
|
||||
case llvm::MachO::CPUTypePowerPC:
|
||||
TT.setArch(Triple::ArchType(Triple::ppc));
|
||||
break;
|
||||
case llvm::MachO::CPUTypePowerPC64:
|
||||
TT.setArch(Triple::ArchType(Triple::ppc64));
|
||||
break;
|
||||
}
|
||||
|
||||
TripleName = TT.str();
|
||||
|
||||
// Get the target specific parser.
|
||||
std::string Error;
|
||||
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
|
||||
if (TheTarget)
|
||||
return TheTarget;
|
||||
|
||||
errs() << "llvm-objdump: error: unable to get target for '" << TripleName
|
||||
<< "', see --version and --triple.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Section {
|
||||
char Name[16];
|
||||
uint64_t Address;
|
||||
uint64_t Size;
|
||||
uint32_t Offset;
|
||||
uint32_t NumRelocs;
|
||||
uint64_t RelocTableOffset;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
uint64_t Value;
|
||||
uint32_t StringIndex;
|
||||
uint8_t SectionIndex;
|
||||
bool operator<(const Symbol &RHS) const { return Value < RHS.Value; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static Section copySection(const T &Sect) {
|
||||
Section S;
|
||||
memcpy(S.Name, Sect->Name, 16);
|
||||
S.Address = Sect->Address;
|
||||
S.Size = Sect->Size;
|
||||
S.Offset = Sect->Offset;
|
||||
S.NumRelocs = Sect->NumRelocationTableEntries;
|
||||
S.RelocTableOffset = Sect->RelocationTableOffset;
|
||||
return S;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static Symbol copySymbol(const T &STE) {
|
||||
Symbol S;
|
||||
S.StringIndex = STE->StringIndex;
|
||||
S.SectionIndex = STE->SectionIndex;
|
||||
S.Value = STE->Value;
|
||||
return S;
|
||||
}
|
||||
|
||||
// Print additional information about an address, if available.
|
||||
static void DumpAddress(uint64_t Address, ArrayRef<Section> Sections,
|
||||
MachOObject *MachOObj, raw_ostream &OS) {
|
||||
for (unsigned i = 0; i != Sections.size(); ++i) {
|
||||
uint64_t addr = Address-Sections[i].Address;
|
||||
if (Sections[i].Address <= Address &&
|
||||
Sections[i].Address + Sections[i].Size > Address) {
|
||||
StringRef bytes = MachOObj->getData(Sections[i].Offset,
|
||||
Sections[i].Size);
|
||||
// Print constant strings.
|
||||
if (!strcmp(Sections[i].Name, "__cstring"))
|
||||
OS << '"' << bytes.substr(addr, bytes.find('\0', addr)) << '"';
|
||||
// Print constant CFStrings.
|
||||
if (!strcmp(Sections[i].Name, "__cfstring"))
|
||||
OS << "@\"" << bytes.substr(addr, bytes.find('\0', addr)) << '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::map<uint64_t, MCFunction*> FunctionMapTy;
|
||||
typedef SmallVector<MCFunction, 16> FunctionListTy;
|
||||
static void createMCFunctionAndSaveCalls(StringRef Name,
|
||||
const MCDisassembler *DisAsm,
|
||||
MemoryObject &Object, uint64_t Start,
|
||||
uint64_t End,
|
||||
MCInstrAnalysis *InstrAnalysis,
|
||||
uint64_t Address,
|
||||
raw_ostream &DebugOut,
|
||||
FunctionMapTy &FunctionMap,
|
||||
FunctionListTy &Functions) {
|
||||
SmallVector<uint64_t, 16> Calls;
|
||||
MCFunction f =
|
||||
MCFunction::createFunctionFromMC(Name, DisAsm, Object, Start, End,
|
||||
InstrAnalysis, DebugOut, Calls);
|
||||
Functions.push_back(f);
|
||||
FunctionMap[Address] = &Functions.back();
|
||||
|
||||
// Add the gathered callees to the map.
|
||||
for (unsigned i = 0, e = Calls.size(); i != e; ++i)
|
||||
FunctionMap.insert(std::make_pair(Calls[i], (MCFunction*)0));
|
||||
}
|
||||
|
||||
// Write a graphviz file for the CFG inside an MCFunction.
|
||||
static void emitDOTFile(const char *FileName, const MCFunction &f,
|
||||
MCInstPrinter *IP) {
|
||||
// Start a new dot file.
|
||||
std::string Error;
|
||||
raw_fd_ostream Out(FileName, Error);
|
||||
if (!Error.empty()) {
|
||||
errs() << "llvm-objdump: warning: " << Error << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
Out << "digraph " << f.getName() << " {\n";
|
||||
Out << "graph [ rankdir = \"LR\" ];\n";
|
||||
for (MCFunction::iterator i = f.begin(), e = f.end(); i != e; ++i) {
|
||||
bool hasPreds = false;
|
||||
// Only print blocks that have predecessors.
|
||||
// FIXME: Slow.
|
||||
for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe;
|
||||
++pi)
|
||||
if (pi->second.contains(i->first)) {
|
||||
hasPreds = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hasPreds && i != f.begin())
|
||||
continue;
|
||||
|
||||
Out << '"' << i->first << "\" [ label=\"<a>";
|
||||
// Print instructions.
|
||||
for (unsigned ii = 0, ie = i->second.getInsts().size(); ii != ie;
|
||||
++ii) {
|
||||
// Escape special chars and print the instruction in mnemonic form.
|
||||
std::string Str;
|
||||
raw_string_ostream OS(Str);
|
||||
IP->printInst(&i->second.getInsts()[ii].Inst, OS, "");
|
||||
Out << DOT::EscapeString(OS.str()) << '|';
|
||||
}
|
||||
Out << "<o>\" shape=\"record\" ];\n";
|
||||
|
||||
// Add edges.
|
||||
for (MCBasicBlock::succ_iterator si = i->second.succ_begin(),
|
||||
se = i->second.succ_end(); si != se; ++si)
|
||||
Out << i->first << ":o -> " << *si <<":a\n";
|
||||
}
|
||||
Out << "}\n";
|
||||
}
|
||||
|
||||
static void getSectionsAndSymbols(const macho::Header &Header,
|
||||
MachOObject *MachOObj,
|
||||
InMemoryStruct<macho::SymtabLoadCommand> *SymtabLC,
|
||||
std::vector<Section> &Sections,
|
||||
std::vector<Symbol> &Symbols,
|
||||
SmallVectorImpl<uint64_t> &FoundFns) {
|
||||
// Make a list of all symbols in the object file.
|
||||
for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
|
||||
const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i);
|
||||
if (LCI.Command.Type == macho::LCT_Segment) {
|
||||
InMemoryStruct<macho::SegmentLoadCommand> SegmentLC;
|
||||
MachOObj->ReadSegmentLoadCommand(LCI, SegmentLC);
|
||||
|
||||
// Store the sections in this segment.
|
||||
for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
|
||||
InMemoryStruct<macho::Section> Sect;
|
||||
MachOObj->ReadSection(LCI, SectNum, Sect);
|
||||
Sections.push_back(copySection(Sect));
|
||||
|
||||
}
|
||||
} else if (LCI.Command.Type == macho::LCT_Segment64) {
|
||||
InMemoryStruct<macho::Segment64LoadCommand> Segment64LC;
|
||||
MachOObj->ReadSegment64LoadCommand(LCI, Segment64LC);
|
||||
|
||||
// Store the sections in this segment.
|
||||
for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections;
|
||||
++SectNum) {
|
||||
InMemoryStruct<macho::Section64> Sect64;
|
||||
MachOObj->ReadSection64(LCI, SectNum, Sect64);
|
||||
Sections.push_back(copySection(Sect64));
|
||||
}
|
||||
} else if (LCI.Command.Type == macho::LCT_FunctionStarts) {
|
||||
// We found a function starts segment, parse the addresses for later
|
||||
// consumption.
|
||||
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
|
||||
MachOObj->ReadLinkeditDataLoadCommand(LCI, LLC);
|
||||
|
||||
MachOObj->ReadULEB128s(LLC->DataOffset, FoundFns);
|
||||
}
|
||||
}
|
||||
// Store the symbols.
|
||||
if (SymtabLC) {
|
||||
for (unsigned i = 0; i != (*SymtabLC)->NumSymbolTableEntries; ++i) {
|
||||
if (MachOObj->is64Bit()) {
|
||||
InMemoryStruct<macho::Symbol64TableEntry> STE;
|
||||
MachOObj->ReadSymbol64TableEntry((*SymtabLC)->SymbolTableOffset, i,
|
||||
STE);
|
||||
Symbols.push_back(copySymbol(STE));
|
||||
} else {
|
||||
InMemoryStruct<macho::SymbolTableEntry> STE;
|
||||
MachOObj->ReadSymbolTableEntry((*SymtabLC)->SymbolTableOffset, i,
|
||||
STE);
|
||||
Symbols.push_back(copySymbol(STE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void llvm::DisassembleInputMachO(StringRef Filename) {
|
||||
OwningPtr<MemoryBuffer> Buff;
|
||||
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) {
|
||||
errs() << "llvm-objdump: " << Filename << ": " << ec.message() << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OwningPtr<MachOObject> MachOObj(MachOObject::LoadFromBuffer(Buff.take()));
|
||||
|
||||
const Target *TheTarget = GetTarget(MachOObj.get());
|
||||
if (!TheTarget) {
|
||||
// GetTarget prints out stuff.
|
||||
return;
|
||||
}
|
||||
OwningPtr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
|
||||
OwningPtr<MCInstrAnalysis>
|
||||
InstrAnalysis(TheTarget->createMCInstrAnalysis(InstrInfo.get()));
|
||||
|
||||
// Set up disassembler.
|
||||
OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName));
|
||||
OwningPtr<const MCSubtargetInfo>
|
||||
STI(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
||||
OwningPtr<const MCDisassembler> DisAsm(TheTarget->createMCDisassembler(*STI));
|
||||
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
||||
OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
|
||||
AsmPrinterVariant, *AsmInfo, *STI));
|
||||
|
||||
if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) {
|
||||
errs() << "error: couldn't initialize disassembler for target "
|
||||
<< TripleName << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
outs() << '\n' << Filename << ":\n\n";
|
||||
|
||||
const macho::Header &Header = MachOObj->getHeader();
|
||||
|
||||
const MachOObject::LoadCommandInfo *SymtabLCI = 0;
|
||||
// First, find the symbol table segment.
|
||||
for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
|
||||
const MachOObject::LoadCommandInfo &LCI = MachOObj->getLoadCommandInfo(i);
|
||||
if (LCI.Command.Type == macho::LCT_Symtab) {
|
||||
SymtabLCI = &LCI;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read and register the symbol table data.
|
||||
InMemoryStruct<macho::SymtabLoadCommand> SymtabLC;
|
||||
MachOObj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC);
|
||||
MachOObj->RegisterStringTable(*SymtabLC);
|
||||
|
||||
std::vector<Section> Sections;
|
||||
std::vector<Symbol> Symbols;
|
||||
SmallVector<uint64_t, 8> FoundFns;
|
||||
|
||||
getSectionsAndSymbols(Header, MachOObj.get(), &SymtabLC, Sections, Symbols,
|
||||
FoundFns);
|
||||
|
||||
// Make a copy of the unsorted symbol list. FIXME: duplication
|
||||
std::vector<Symbol> UnsortedSymbols(Symbols);
|
||||
// Sort the symbols by address, just in case they didn't come in that way.
|
||||
array_pod_sort(Symbols.begin(), Symbols.end());
|
||||
|
||||
#ifndef NDEBUG
|
||||
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
|
||||
#else
|
||||
raw_ostream &DebugOut = nulls();
|
||||
#endif
|
||||
|
||||
StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection,
|
||||
DebugLineSection, DebugStrSection;
|
||||
OwningPtr<DIContext> diContext;
|
||||
OwningPtr<MachOObject> DSYMObj;
|
||||
MachOObject *DbgInfoObj = MachOObj.get();
|
||||
// Try to find debug info and set up the DIContext for it.
|
||||
if (UseDbg) {
|
||||
ArrayRef<Section> DebugSections = Sections;
|
||||
std::vector<Section> DSYMSections;
|
||||
|
||||
// A separate DSym file path was specified, parse it as a macho file,
|
||||
// get the sections and supply it to the section name parsing machinery.
|
||||
if (!DSYMFile.empty()) {
|
||||
OwningPtr<MemoryBuffer> Buf;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile.c_str(), Buf)) {
|
||||
errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n';
|
||||
return;
|
||||
}
|
||||
DSYMObj.reset(MachOObject::LoadFromBuffer(Buf.take()));
|
||||
const macho::Header &Header = DSYMObj->getHeader();
|
||||
|
||||
std::vector<Symbol> Symbols;
|
||||
SmallVector<uint64_t, 8> FoundFns;
|
||||
getSectionsAndSymbols(Header, DSYMObj.get(), 0, DSYMSections, Symbols,
|
||||
FoundFns);
|
||||
DebugSections = DSYMSections;
|
||||
DbgInfoObj = DSYMObj.get();
|
||||
}
|
||||
|
||||
// Find the named debug info sections.
|
||||
for (unsigned SectIdx = 0; SectIdx != DebugSections.size(); SectIdx++) {
|
||||
if (!strcmp(DebugSections[SectIdx].Name, "__debug_abbrev"))
|
||||
DebugAbbrevSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
|
||||
DebugSections[SectIdx].Size);
|
||||
else if (!strcmp(DebugSections[SectIdx].Name, "__debug_info"))
|
||||
DebugInfoSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
|
||||
DebugSections[SectIdx].Size);
|
||||
else if (!strcmp(DebugSections[SectIdx].Name, "__debug_aranges"))
|
||||
DebugArangesSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
|
||||
DebugSections[SectIdx].Size);
|
||||
else if (!strcmp(DebugSections[SectIdx].Name, "__debug_line"))
|
||||
DebugLineSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
|
||||
DebugSections[SectIdx].Size);
|
||||
else if (!strcmp(DebugSections[SectIdx].Name, "__debug_str"))
|
||||
DebugStrSection = DbgInfoObj->getData(DebugSections[SectIdx].Offset,
|
||||
DebugSections[SectIdx].Size);
|
||||
}
|
||||
|
||||
// Setup the DIContext.
|
||||
diContext.reset(DIContext::getDWARFContext(DbgInfoObj->isLittleEndian(),
|
||||
DebugInfoSection,
|
||||
DebugAbbrevSection,
|
||||
DebugArangesSection,
|
||||
DebugLineSection,
|
||||
DebugStrSection));
|
||||
}
|
||||
|
||||
FunctionMapTy FunctionMap;
|
||||
FunctionListTy Functions;
|
||||
|
||||
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
|
||||
if (strcmp(Sections[SectIdx].Name, "__text"))
|
||||
continue; // Skip non-text sections
|
||||
|
||||
// Insert the functions from the function starts segment into our map.
|
||||
uint64_t VMAddr = Sections[SectIdx].Address - Sections[SectIdx].Offset;
|
||||
for (unsigned i = 0, e = FoundFns.size(); i != e; ++i)
|
||||
FunctionMap.insert(std::make_pair(FoundFns[i]+VMAddr, (MCFunction*)0));
|
||||
|
||||
StringRef Bytes = MachOObj->getData(Sections[SectIdx].Offset,
|
||||
Sections[SectIdx].Size);
|
||||
StringRefMemoryObject memoryObject(Bytes);
|
||||
bool symbolTableWorked = false;
|
||||
|
||||
// Parse relocations.
|
||||
std::vector<std::pair<uint64_t, uint32_t> > Relocs;
|
||||
for (unsigned j = 0; j != Sections[SectIdx].NumRelocs; ++j) {
|
||||
InMemoryStruct<macho::RelocationEntry> RE;
|
||||
MachOObj->ReadRelocationEntry(Sections[SectIdx].RelocTableOffset, j, RE);
|
||||
Relocs.push_back(std::make_pair(RE->Word0, RE->Word1 & 0xffffff));
|
||||
}
|
||||
array_pod_sort(Relocs.begin(), Relocs.end());
|
||||
|
||||
// Disassemble symbol by symbol.
|
||||
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
|
||||
// Make sure the symbol is defined in this section.
|
||||
if ((unsigned)Symbols[SymIdx].SectionIndex - 1 != SectIdx)
|
||||
continue;
|
||||
|
||||
// Start at the address of the symbol relative to the section's address.
|
||||
uint64_t Start = Symbols[SymIdx].Value - Sections[SectIdx].Address;
|
||||
// Stop disassembling either at the beginning of the next symbol or at
|
||||
// the end of the section.
|
||||
uint64_t End = (SymIdx+1 == Symbols.size() ||
|
||||
Symbols[SymIdx].SectionIndex != Symbols[SymIdx+1].SectionIndex) ?
|
||||
Sections[SectIdx].Size :
|
||||
Symbols[SymIdx+1].Value - Sections[SectIdx].Address;
|
||||
uint64_t Size;
|
||||
|
||||
if (Start >= End)
|
||||
continue;
|
||||
|
||||
symbolTableWorked = true;
|
||||
|
||||
if (!CFG) {
|
||||
// Normal disassembly, print addresses, bytes and mnemonic form.
|
||||
outs() << MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex)
|
||||
<< ":\n";
|
||||
DILineInfo lastLine;
|
||||
for (uint64_t Index = Start; Index < End; Index += Size) {
|
||||
MCInst Inst;
|
||||
|
||||
if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
|
||||
DebugOut, nulls())) {
|
||||
outs() << format("%8llx:\t", Sections[SectIdx].Address + Index);
|
||||
DumpBytes(StringRef(Bytes.data() + Index, Size));
|
||||
IP->printInst(&Inst, outs(), "");
|
||||
|
||||
// Print debug info.
|
||||
if (diContext) {
|
||||
DILineInfo dli =
|
||||
diContext->getLineInfoForAddress(Sections[SectIdx].Address +
|
||||
Index);
|
||||
// Print valid line info if it changed.
|
||||
if (dli != lastLine && dli.getLine() != 0)
|
||||
outs() << "\t## " << dli.getFileName() << ':'
|
||||
<< dli.getLine() << ':' << dli.getColumn();
|
||||
lastLine = dli;
|
||||
}
|
||||
outs() << "\n";
|
||||
} else {
|
||||
errs() << "llvm-objdump: warning: invalid instruction encoding\n";
|
||||
if (Size == 0)
|
||||
Size = 1; // skip illegible bytes
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create CFG and use it for disassembly.
|
||||
createMCFunctionAndSaveCalls(
|
||||
MachOObj->getStringAtIndex(Symbols[SymIdx].StringIndex),
|
||||
DisAsm.get(), memoryObject, Start, End, InstrAnalysis.get(),
|
||||
Start, DebugOut, FunctionMap, Functions);
|
||||
}
|
||||
}
|
||||
|
||||
if (CFG) {
|
||||
if (!symbolTableWorked) {
|
||||
// Reading the symbol table didn't work, create a big __TEXT symbol.
|
||||
createMCFunctionAndSaveCalls("__TEXT", DisAsm.get(), memoryObject,
|
||||
0, Sections[SectIdx].Size,
|
||||
InstrAnalysis.get(),
|
||||
Sections[SectIdx].Offset, DebugOut,
|
||||
FunctionMap, Functions);
|
||||
}
|
||||
for (std::map<uint64_t, MCFunction*>::iterator mi = FunctionMap.begin(),
|
||||
me = FunctionMap.end(); mi != me; ++mi)
|
||||
if (mi->second == 0) {
|
||||
// Create functions for the remaining callees we have gathered,
|
||||
// but we didn't find a name for them.
|
||||
SmallVector<uint64_t, 16> Calls;
|
||||
MCFunction f =
|
||||
MCFunction::createFunctionFromMC("unknown", DisAsm.get(),
|
||||
memoryObject, mi->first,
|
||||
Sections[SectIdx].Size,
|
||||
InstrAnalysis.get(), DebugOut,
|
||||
Calls);
|
||||
Functions.push_back(f);
|
||||
mi->second = &Functions.back();
|
||||
for (unsigned i = 0, e = Calls.size(); i != e; ++i) {
|
||||
std::pair<uint64_t, MCFunction*> p(Calls[i], (MCFunction*)0);
|
||||
if (FunctionMap.insert(p).second)
|
||||
mi = FunctionMap.begin();
|
||||
}
|
||||
}
|
||||
|
||||
DenseSet<uint64_t> PrintedBlocks;
|
||||
for (unsigned ffi = 0, ffe = Functions.size(); ffi != ffe; ++ffi) {
|
||||
MCFunction &f = Functions[ffi];
|
||||
for (MCFunction::iterator fi = f.begin(), fe = f.end(); fi != fe; ++fi){
|
||||
if (!PrintedBlocks.insert(fi->first).second)
|
||||
continue; // We already printed this block.
|
||||
|
||||
// We assume a block has predecessors when it's the first block after
|
||||
// a symbol.
|
||||
bool hasPreds = FunctionMap.find(fi->first) != FunctionMap.end();
|
||||
|
||||
// See if this block has predecessors.
|
||||
// FIXME: Slow.
|
||||
for (MCFunction::iterator pi = f.begin(), pe = f.end(); pi != pe;
|
||||
++pi)
|
||||
if (pi->second.contains(fi->first)) {
|
||||
hasPreds = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// No predecessors, this is a data block. Print as .byte directives.
|
||||
if (!hasPreds) {
|
||||
uint64_t End = llvm::next(fi) == fe ? Sections[SectIdx].Size :
|
||||
llvm::next(fi)->first;
|
||||
outs() << "# " << End-fi->first << " bytes of data:\n";
|
||||
for (unsigned pos = fi->first; pos != End; ++pos) {
|
||||
outs() << format("%8x:\t", Sections[SectIdx].Address + pos);
|
||||
DumpBytes(StringRef(Bytes.data() + pos, 1));
|
||||
outs() << format("\t.byte 0x%02x\n", (uint8_t)Bytes[pos]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fi->second.contains(fi->first)) // Print a header for simple loops
|
||||
outs() << "# Loop begin:\n";
|
||||
|
||||
DILineInfo lastLine;
|
||||
// Walk over the instructions and print them.
|
||||
for (unsigned ii = 0, ie = fi->second.getInsts().size(); ii != ie;
|
||||
++ii) {
|
||||
const MCDecodedInst &Inst = fi->second.getInsts()[ii];
|
||||
|
||||
// If there's a symbol at this address, print its name.
|
||||
if (FunctionMap.find(Sections[SectIdx].Address + Inst.Address) !=
|
||||
FunctionMap.end())
|
||||
outs() << FunctionMap[Sections[SectIdx].Address + Inst.Address]->
|
||||
getName() << ":\n";
|
||||
|
||||
outs() << format("%8llx:\t", Sections[SectIdx].Address +
|
||||
Inst.Address);
|
||||
DumpBytes(StringRef(Bytes.data() + Inst.Address, Inst.Size));
|
||||
|
||||
if (fi->second.contains(fi->first)) // Indent simple loops.
|
||||
outs() << '\t';
|
||||
|
||||
IP->printInst(&Inst.Inst, outs(), "");
|
||||
|
||||
// Look for relocations inside this instructions, if there is one
|
||||
// print its target and additional information if available.
|
||||
for (unsigned j = 0; j != Relocs.size(); ++j)
|
||||
if (Relocs[j].first >= Sections[SectIdx].Address + Inst.Address &&
|
||||
Relocs[j].first < Sections[SectIdx].Address + Inst.Address +
|
||||
Inst.Size) {
|
||||
outs() << "\t# "
|
||||
<< MachOObj->getStringAtIndex(
|
||||
UnsortedSymbols[Relocs[j].second].StringIndex)
|
||||
<< ' ';
|
||||
DumpAddress(UnsortedSymbols[Relocs[j].second].Value, Sections,
|
||||
MachOObj.get(), outs());
|
||||
}
|
||||
|
||||
// If this instructions contains an address, see if we can evaluate
|
||||
// it and print additional information.
|
||||
uint64_t targ = InstrAnalysis->evaluateBranch(Inst.Inst,
|
||||
Inst.Address,
|
||||
Inst.Size);
|
||||
if (targ != -1ULL)
|
||||
DumpAddress(targ, Sections, MachOObj.get(), outs());
|
||||
|
||||
// Print debug info.
|
||||
if (diContext) {
|
||||
DILineInfo dli =
|
||||
diContext->getLineInfoForAddress(Sections[SectIdx].Address +
|
||||
Inst.Address);
|
||||
// Print valid line info if it changed.
|
||||
if (dli != lastLine && dli.getLine() != 0)
|
||||
outs() << "\t## " << dli.getFileName() << ':'
|
||||
<< dli.getLine() << ':' << dli.getColumn();
|
||||
lastLine = dli;
|
||||
}
|
||||
|
||||
outs() << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
emitDOTFile((f.getName().str() + ".dot").c_str(), f, IP.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
contrib/llvm/tools/llvm-objdump/Makefile
Normal file
18
contrib/llvm/tools/llvm-objdump/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
##===- tools/llvm-objdump/Makefile -------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-objdump
|
||||
LINK_COMPONENTS = $(TARGETS_TO_BUILD) DebugInfo MC MCParser MCDisassembler \
|
||||
Object
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
459
contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
Normal file
459
contrib/llvm/tools/llvm-objdump/llvm-objdump.cpp
Normal file
@ -0,0 +1,459 @@
|
||||
//===-- llvm-objdump.cpp - Object file dumping utility for llvm -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This program is a utility that works like binutils "objdump", that is, it
|
||||
// dumps out a plethora of information about an object file depending on the
|
||||
// flags.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-objdump.h"
|
||||
#include "MCFunction.h"
|
||||
#include "llvm/Object/Archive.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/MemoryObject.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
using namespace llvm;
|
||||
using namespace object;
|
||||
|
||||
static cl::list<std::string>
|
||||
InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<bool>
|
||||
Disassemble("disassemble",
|
||||
cl::desc("Display assembler mnemonics for the machine instructions"));
|
||||
static cl::alias
|
||||
Disassembled("d", cl::desc("Alias for --disassemble"),
|
||||
cl::aliasopt(Disassemble));
|
||||
|
||||
static cl::opt<bool>
|
||||
Relocations("r", cl::desc("Display the relocation entries in the file"));
|
||||
|
||||
static cl::opt<bool>
|
||||
MachO("macho", cl::desc("Use MachO specific object file parser"));
|
||||
static cl::alias
|
||||
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachO));
|
||||
|
||||
cl::opt<std::string>
|
||||
llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
|
||||
"see -version for available targets"));
|
||||
|
||||
cl::opt<std::string>
|
||||
llvm::ArchName("arch", cl::desc("Target arch to disassemble for, "
|
||||
"see -version for available targets"));
|
||||
|
||||
static cl::opt<bool>
|
||||
SectionHeaders("section-headers", cl::desc("Display summaries of the headers "
|
||||
"for each section."));
|
||||
static cl::alias
|
||||
SectionHeadersShort("headers", cl::desc("Alias for --section-headers"),
|
||||
cl::aliasopt(SectionHeaders));
|
||||
static cl::alias
|
||||
SectionHeadersShorter("h", cl::desc("Alias for --section-headers"),
|
||||
cl::aliasopt(SectionHeaders));
|
||||
|
||||
static StringRef ToolName;
|
||||
|
||||
static bool error(error_code ec) {
|
||||
if (!ec) return false;
|
||||
|
||||
outs() << ToolName << ": error reading file: " << ec.message() << ".\n";
|
||||
outs().flush();
|
||||
return true;
|
||||
}
|
||||
|
||||
static const Target *GetTarget(const ObjectFile *Obj = NULL) {
|
||||
// Figure out the target triple.
|
||||
llvm::Triple TT("unknown-unknown-unknown");
|
||||
if (TripleName.empty()) {
|
||||
if (Obj)
|
||||
TT.setArch(Triple::ArchType(Obj->getArch()));
|
||||
} else
|
||||
TT.setTriple(Triple::normalize(TripleName));
|
||||
|
||||
if (!ArchName.empty())
|
||||
TT.setArchName(ArchName);
|
||||
|
||||
TripleName = TT.str();
|
||||
|
||||
// Get the target specific parser.
|
||||
std::string Error;
|
||||
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
|
||||
if (TheTarget)
|
||||
return TheTarget;
|
||||
|
||||
errs() << ToolName << ": error: unable to get target for '" << TripleName
|
||||
<< "', see --version and --triple.\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
void llvm::DumpBytes(StringRef bytes) {
|
||||
static const char hex_rep[] = "0123456789abcdef";
|
||||
// FIXME: The real way to do this is to figure out the longest instruction
|
||||
// and align to that size before printing. I'll fix this when I get
|
||||
// around to outputting relocations.
|
||||
// 15 is the longest x86 instruction
|
||||
// 3 is for the hex rep of a byte + a space.
|
||||
// 1 is for the null terminator.
|
||||
enum { OutputSize = (15 * 3) + 1 };
|
||||
char output[OutputSize];
|
||||
|
||||
assert(bytes.size() <= 15
|
||||
&& "DumpBytes only supports instructions of up to 15 bytes");
|
||||
memset(output, ' ', sizeof(output));
|
||||
unsigned index = 0;
|
||||
for (StringRef::iterator i = bytes.begin(),
|
||||
e = bytes.end(); i != e; ++i) {
|
||||
output[index] = hex_rep[(*i & 0xF0) >> 4];
|
||||
output[index + 1] = hex_rep[*i & 0xF];
|
||||
index += 3;
|
||||
}
|
||||
|
||||
output[sizeof(output) - 1] = 0;
|
||||
outs() << output;
|
||||
}
|
||||
|
||||
static bool RelocAddressLess(RelocationRef a, RelocationRef b) {
|
||||
uint64_t a_addr, b_addr;
|
||||
if (error(a.getAddress(a_addr))) return false;
|
||||
if (error(b.getAddress(b_addr))) return false;
|
||||
return a_addr < b_addr;
|
||||
}
|
||||
|
||||
static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
|
||||
const Target *TheTarget = GetTarget(Obj);
|
||||
if (!TheTarget) {
|
||||
// GetTarget prints out stuff.
|
||||
return;
|
||||
}
|
||||
|
||||
outs() << '\n';
|
||||
outs() << Obj->getFileName()
|
||||
<< ":\tfile format " << Obj->getFileFormatName() << "\n\n";
|
||||
|
||||
error_code ec;
|
||||
for (section_iterator i = Obj->begin_sections(),
|
||||
e = Obj->end_sections();
|
||||
i != e; i.increment(ec)) {
|
||||
if (error(ec)) break;
|
||||
bool text;
|
||||
if (error(i->isText(text))) break;
|
||||
if (!text) continue;
|
||||
|
||||
uint64_t SectionAddr;
|
||||
if (error(i->getAddress(SectionAddr))) break;
|
||||
|
||||
// Make a list of all the symbols in this section.
|
||||
std::vector<std::pair<uint64_t, StringRef> > Symbols;
|
||||
for (symbol_iterator si = Obj->begin_symbols(),
|
||||
se = Obj->end_symbols();
|
||||
si != se; si.increment(ec)) {
|
||||
bool contains;
|
||||
if (!error(i->containsSymbol(*si, contains)) && contains) {
|
||||
uint64_t Address;
|
||||
if (error(si->getOffset(Address))) break;
|
||||
StringRef Name;
|
||||
if (error(si->getName(Name))) break;
|
||||
Symbols.push_back(std::make_pair(Address, Name));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the symbols by address, just in case they didn't come in that way.
|
||||
array_pod_sort(Symbols.begin(), Symbols.end());
|
||||
|
||||
// Make a list of all the relocations for this section.
|
||||
std::vector<RelocationRef> Rels;
|
||||
if (InlineRelocs) {
|
||||
for (relocation_iterator ri = i->begin_relocations(),
|
||||
re = i->end_relocations();
|
||||
ri != re; ri.increment(ec)) {
|
||||
if (error(ec)) break;
|
||||
Rels.push_back(*ri);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort relocations by address.
|
||||
std::sort(Rels.begin(), Rels.end(), RelocAddressLess);
|
||||
|
||||
StringRef name;
|
||||
if (error(i->getName(name))) break;
|
||||
outs() << "Disassembly of section " << name << ':';
|
||||
|
||||
// If the section has no symbols just insert a dummy one and disassemble
|
||||
// the whole section.
|
||||
if (Symbols.empty())
|
||||
Symbols.push_back(std::make_pair(0, name));
|
||||
|
||||
// Set up disassembler.
|
||||
OwningPtr<const MCAsmInfo> AsmInfo(TheTarget->createMCAsmInfo(TripleName));
|
||||
|
||||
if (!AsmInfo) {
|
||||
errs() << "error: no assembly info for target " << TripleName << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OwningPtr<const MCSubtargetInfo> STI(
|
||||
TheTarget->createMCSubtargetInfo(TripleName, "", ""));
|
||||
|
||||
if (!STI) {
|
||||
errs() << "error: no subtarget info for target " << TripleName << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OwningPtr<const MCDisassembler> DisAsm(
|
||||
TheTarget->createMCDisassembler(*STI));
|
||||
if (!DisAsm) {
|
||||
errs() << "error: no disassembler for target " << TripleName << "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
|
||||
OwningPtr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
|
||||
AsmPrinterVariant, *AsmInfo, *STI));
|
||||
if (!IP) {
|
||||
errs() << "error: no instruction printer for target " << TripleName
|
||||
<< '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef Bytes;
|
||||
if (error(i->getContents(Bytes))) break;
|
||||
StringRefMemoryObject memoryObject(Bytes);
|
||||
uint64_t Size;
|
||||
uint64_t Index;
|
||||
uint64_t SectSize;
|
||||
if (error(i->getSize(SectSize))) break;
|
||||
|
||||
std::vector<RelocationRef>::const_iterator rel_cur = Rels.begin();
|
||||
std::vector<RelocationRef>::const_iterator rel_end = Rels.end();
|
||||
// Disassemble symbol by symbol.
|
||||
for (unsigned si = 0, se = Symbols.size(); si != se; ++si) {
|
||||
uint64_t Start = Symbols[si].first;
|
||||
uint64_t End;
|
||||
// The end is either the size of the section or the beginning of the next
|
||||
// symbol.
|
||||
if (si == se - 1)
|
||||
End = SectSize;
|
||||
// Make sure this symbol takes up space.
|
||||
else if (Symbols[si + 1].first != Start)
|
||||
End = Symbols[si + 1].first - 1;
|
||||
else
|
||||
// This symbol has the same address as the next symbol. Skip it.
|
||||
continue;
|
||||
|
||||
outs() << '\n' << Symbols[si].second << ":\n";
|
||||
|
||||
#ifndef NDEBUG
|
||||
raw_ostream &DebugOut = DebugFlag ? dbgs() : nulls();
|
||||
#else
|
||||
raw_ostream &DebugOut = nulls();
|
||||
#endif
|
||||
|
||||
for (Index = Start; Index < End; Index += Size) {
|
||||
MCInst Inst;
|
||||
|
||||
if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
|
||||
DebugOut, nulls())) {
|
||||
outs() << format("%8"PRIx64":\t", SectionAddr + Index);
|
||||
DumpBytes(StringRef(Bytes.data() + Index, Size));
|
||||
IP->printInst(&Inst, outs(), "");
|
||||
outs() << "\n";
|
||||
} else {
|
||||
errs() << ToolName << ": warning: invalid instruction encoding\n";
|
||||
if (Size == 0)
|
||||
Size = 1; // skip illegible bytes
|
||||
}
|
||||
|
||||
// Print relocation for instruction.
|
||||
while (rel_cur != rel_end) {
|
||||
uint64_t addr;
|
||||
SmallString<16> name;
|
||||
SmallString<32> val;
|
||||
if (error(rel_cur->getAddress(addr))) goto skip_print_rel;
|
||||
// Stop when rel_cur's address is past the current instruction.
|
||||
if (addr > Index + Size) break;
|
||||
if (error(rel_cur->getTypeName(name))) goto skip_print_rel;
|
||||
if (error(rel_cur->getValueString(val))) goto skip_print_rel;
|
||||
|
||||
outs() << format("\t\t\t%8"PRIx64": ", SectionAddr + addr) << name << "\t"
|
||||
<< val << "\n";
|
||||
|
||||
skip_print_rel:
|
||||
++rel_cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintRelocations(const ObjectFile *o) {
|
||||
error_code ec;
|
||||
for (section_iterator si = o->begin_sections(), se = o->end_sections();
|
||||
si != se; si.increment(ec)){
|
||||
if (error(ec)) return;
|
||||
if (si->begin_relocations() == si->end_relocations())
|
||||
continue;
|
||||
StringRef secname;
|
||||
if (error(si->getName(secname))) continue;
|
||||
outs() << "RELOCATION RECORDS FOR [" << secname << "]:\n";
|
||||
for (relocation_iterator ri = si->begin_relocations(),
|
||||
re = si->end_relocations();
|
||||
ri != re; ri.increment(ec)) {
|
||||
if (error(ec)) return;
|
||||
|
||||
uint64_t address;
|
||||
SmallString<32> relocname;
|
||||
SmallString<32> valuestr;
|
||||
if (error(ri->getTypeName(relocname))) continue;
|
||||
if (error(ri->getAddress(address))) continue;
|
||||
if (error(ri->getValueString(valuestr))) continue;
|
||||
outs() << address << " " << relocname << " " << valuestr << "\n";
|
||||
}
|
||||
outs() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintSectionHeaders(const ObjectFile *o) {
|
||||
outs() << "Sections:\n"
|
||||
"Idx Name Size Address Type\n";
|
||||
error_code ec;
|
||||
unsigned i = 0;
|
||||
for (section_iterator si = o->begin_sections(), se = o->end_sections();
|
||||
si != se; si.increment(ec)) {
|
||||
if (error(ec)) return;
|
||||
StringRef Name;
|
||||
if (error(si->getName(Name))) return;
|
||||
uint64_t Address;
|
||||
if (error(si->getAddress(Address))) return;
|
||||
uint64_t Size;
|
||||
if (error(si->getSize(Size))) return;
|
||||
bool Text, Data, BSS;
|
||||
if (error(si->isText(Text))) return;
|
||||
if (error(si->isData(Data))) return;
|
||||
if (error(si->isBSS(BSS))) return;
|
||||
std::string Type = (std::string(Text ? "TEXT " : "") +
|
||||
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
|
||||
outs() << format("%3d %-13s %09"PRIx64" %017"PRIx64" %s\n", i, Name.str().c_str(), Size,
|
||||
Address, Type.c_str());
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpObject(const ObjectFile *o) {
|
||||
if (Disassemble)
|
||||
DisassembleObject(o, Relocations);
|
||||
if (Relocations && !Disassemble)
|
||||
PrintRelocations(o);
|
||||
if (SectionHeaders)
|
||||
PrintSectionHeaders(o);
|
||||
}
|
||||
|
||||
/// @brief Dump each object file in \a a;
|
||||
static void DumpArchive(const Archive *a) {
|
||||
for (Archive::child_iterator i = a->begin_children(),
|
||||
e = a->end_children(); i != e; ++i) {
|
||||
OwningPtr<Binary> child;
|
||||
if (error_code ec = i->getAsBinary(child)) {
|
||||
errs() << ToolName << ": '" << a->getFileName() << "': " << ec.message()
|
||||
<< ".\n";
|
||||
continue;
|
||||
}
|
||||
if (ObjectFile *o = dyn_cast<ObjectFile>(child.get()))
|
||||
DumpObject(o);
|
||||
else
|
||||
errs() << ToolName << ": '" << a->getFileName() << "': "
|
||||
<< "Unrecognized file type.\n";
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Open file and figure out how to dump it.
|
||||
static void DumpInput(StringRef file) {
|
||||
// If file isn't stdin, check that it exists.
|
||||
if (file != "-" && !sys::fs::exists(file)) {
|
||||
errs() << ToolName << ": '" << file << "': " << "No such file\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (MachO && Disassemble) {
|
||||
DisassembleInputMachO(file);
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to open the binary.
|
||||
OwningPtr<Binary> binary;
|
||||
if (error_code ec = createBinary(file, binary)) {
|
||||
errs() << ToolName << ": '" << file << "': " << ec.message() << ".\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Archive *a = dyn_cast<Archive>(binary.get())) {
|
||||
DumpArchive(a);
|
||||
} else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
|
||||
DumpObject(o);
|
||||
} else {
|
||||
errs() << ToolName << ": '" << file << "': " << "Unrecognized file type.\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
// Initialize targets and assembly printers/parsers.
|
||||
llvm::InitializeAllTargetInfos();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
llvm::InitializeAllDisassemblers();
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm object file dumper\n");
|
||||
TripleName = Triple::normalize(TripleName);
|
||||
|
||||
ToolName = argv[0];
|
||||
|
||||
// Defaults to a.out if no filenames specified.
|
||||
if (InputFilenames.size() == 0)
|
||||
InputFilenames.push_back("a.out");
|
||||
|
||||
if (!Disassemble && !Relocations && !SectionHeaders) {
|
||||
cl::PrintHelpMessage();
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::for_each(InputFilenames.begin(), InputFilenames.end(),
|
||||
DumpInput);
|
||||
|
||||
return 0;
|
||||
}
|
46
contrib/llvm/tools/llvm-objdump/llvm-objdump.h
Normal file
46
contrib/llvm/tools/llvm-objdump/llvm-objdump.h
Normal file
@ -0,0 +1,46 @@
|
||||
//===-- llvm-objdump.h ----------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_OBJDUMP_H
|
||||
#define LLVM_OBJDUMP_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/MemoryObject.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern cl::opt<std::string> TripleName;
|
||||
extern cl::opt<std::string> ArchName;
|
||||
|
||||
// Various helper functions.
|
||||
void DumpBytes(StringRef bytes);
|
||||
void DisassembleInputMachO(StringRef Filename);
|
||||
|
||||
class StringRefMemoryObject : public MemoryObject {
|
||||
private:
|
||||
StringRef Bytes;
|
||||
public:
|
||||
StringRefMemoryObject(StringRef bytes) : Bytes(bytes) {}
|
||||
|
||||
uint64_t getBase() const { return 0; }
|
||||
uint64_t getExtent() const { return Bytes.size(); }
|
||||
|
||||
int readByte(uint64_t Addr, uint8_t *Byte) const {
|
||||
if (Addr >= getExtent())
|
||||
return -1;
|
||||
*Byte = Bytes[Addr];
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
5
contrib/llvm/tools/llvm-prof/CMakeLists.txt
Normal file
5
contrib/llvm/tools/llvm-prof/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS bitreader analysis)
|
||||
|
||||
add_llvm_tool(llvm-prof
|
||||
llvm-prof.cpp
|
||||
)
|
17
contrib/llvm/tools/llvm-prof/Makefile
Normal file
17
contrib/llvm/tools/llvm-prof/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
##===- tools/llvm-prof/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
|
||||
TOOLNAME = llvm-prof
|
||||
LINK_COMPONENTS = bitreader analysis
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
293
contrib/llvm/tools/llvm-prof/llvm-prof.cpp
Normal file
293
contrib/llvm/tools/llvm-prof/llvm-prof.cpp
Normal file
@ -0,0 +1,293 @@
|
||||
//===- llvm-prof.cpp - Read in and process llvmprof.out data files --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tools is meant for use with the various LLVM profiling instrumentation
|
||||
// passes. It reads in the data file produced by executing an instrumented
|
||||
// program, and outputs a nice report.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/InstrTypes.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/Assembly/AssemblyAnnotationWriter.h"
|
||||
#include "llvm/Analysis/ProfileInfo.h"
|
||||
#include "llvm/Analysis/ProfileInfoLoader.h"
|
||||
#include "llvm/Analysis/Passes.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
cl::opt<std::string>
|
||||
BitcodeFile(cl::Positional, cl::desc("<program bitcode file>"),
|
||||
cl::Required);
|
||||
|
||||
cl::opt<std::string>
|
||||
ProfileDataFile(cl::Positional, cl::desc("<llvmprof.out file>"),
|
||||
cl::Optional, cl::init("llvmprof.out"));
|
||||
|
||||
cl::opt<bool>
|
||||
PrintAnnotatedLLVM("annotated-llvm",
|
||||
cl::desc("Print LLVM code with frequency annotations"));
|
||||
cl::alias PrintAnnotated2("A", cl::desc("Alias for --annotated-llvm"),
|
||||
cl::aliasopt(PrintAnnotatedLLVM));
|
||||
cl::opt<bool>
|
||||
PrintAllCode("print-all-code",
|
||||
cl::desc("Print annotated code for the entire program"));
|
||||
}
|
||||
|
||||
// PairSecondSort - A sorting predicate to sort by the second element of a pair.
|
||||
template<class T>
|
||||
struct PairSecondSortReverse
|
||||
: public std::binary_function<std::pair<T, double>,
|
||||
std::pair<T, double>, bool> {
|
||||
bool operator()(const std::pair<T, double> &LHS,
|
||||
const std::pair<T, double> &RHS) const {
|
||||
return LHS.second > RHS.second;
|
||||
}
|
||||
};
|
||||
|
||||
static double ignoreMissing(double w) {
|
||||
if (w == ProfileInfo::MissingValue) return 0;
|
||||
return w;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class ProfileAnnotator : public AssemblyAnnotationWriter {
|
||||
ProfileInfo &PI;
|
||||
public:
|
||||
ProfileAnnotator(ProfileInfo &pi) : PI(pi) {}
|
||||
|
||||
virtual void emitFunctionAnnot(const Function *F,
|
||||
formatted_raw_ostream &OS) {
|
||||
double w = PI.getExecutionCount(F);
|
||||
if (w != ProfileInfo::MissingValue) {
|
||||
OS << ";;; %" << F->getName() << " called "<<(unsigned)w
|
||||
<<" times.\n;;;\n";
|
||||
}
|
||||
}
|
||||
virtual void emitBasicBlockStartAnnot(const BasicBlock *BB,
|
||||
formatted_raw_ostream &OS) {
|
||||
double w = PI.getExecutionCount(BB);
|
||||
if (w != ProfileInfo::MissingValue) {
|
||||
if (w != 0) {
|
||||
OS << "\t;;; Basic block executed " << (unsigned)w << " times.\n";
|
||||
} else {
|
||||
OS << "\t;;; Never executed!\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void emitBasicBlockEndAnnot(const BasicBlock *BB,
|
||||
formatted_raw_ostream &OS) {
|
||||
// Figure out how many times each successor executed.
|
||||
std::vector<std::pair<ProfileInfo::Edge, double> > SuccCounts;
|
||||
|
||||
const TerminatorInst *TI = BB->getTerminator();
|
||||
for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) {
|
||||
BasicBlock* Succ = TI->getSuccessor(s);
|
||||
double w = ignoreMissing(PI.getEdgeWeight(std::make_pair(BB, Succ)));
|
||||
if (w != 0)
|
||||
SuccCounts.push_back(std::make_pair(std::make_pair(BB, Succ), w));
|
||||
}
|
||||
if (!SuccCounts.empty()) {
|
||||
OS << "\t;;; Out-edge counts:";
|
||||
for (unsigned i = 0, e = SuccCounts.size(); i != e; ++i)
|
||||
OS << " [" << (SuccCounts[i]).second << " -> "
|
||||
<< (SuccCounts[i]).first.second->getName() << "]";
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// ProfileInfoPrinterPass - Helper pass to dump the profile information for
|
||||
/// a module.
|
||||
//
|
||||
// FIXME: This should move elsewhere.
|
||||
class ProfileInfoPrinterPass : public ModulePass {
|
||||
ProfileInfoLoader &PIL;
|
||||
public:
|
||||
static char ID; // Class identification, replacement for typeinfo.
|
||||
explicit ProfileInfoPrinterPass(ProfileInfoLoader &_PIL)
|
||||
: ModulePass(ID), PIL(_PIL) {}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<ProfileInfo>();
|
||||
}
|
||||
|
||||
bool runOnModule(Module &M);
|
||||
};
|
||||
}
|
||||
|
||||
char ProfileInfoPrinterPass::ID = 0;
|
||||
|
||||
bool ProfileInfoPrinterPass::runOnModule(Module &M) {
|
||||
ProfileInfo &PI = getAnalysis<ProfileInfo>();
|
||||
std::map<const Function *, unsigned> FuncFreqs;
|
||||
std::map<const BasicBlock*, unsigned> BlockFreqs;
|
||||
std::map<ProfileInfo::Edge, unsigned> EdgeFreqs;
|
||||
|
||||
// Output a report. Eventually, there will be multiple reports selectable on
|
||||
// the command line, for now, just keep things simple.
|
||||
|
||||
// Emit the most frequent function table...
|
||||
std::vector<std::pair<Function*, double> > FunctionCounts;
|
||||
std::vector<std::pair<BasicBlock*, double> > Counts;
|
||||
for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) {
|
||||
if (FI->isDeclaration()) continue;
|
||||
double w = ignoreMissing(PI.getExecutionCount(FI));
|
||||
FunctionCounts.push_back(std::make_pair(FI, w));
|
||||
for (Function::iterator BB = FI->begin(), BBE = FI->end();
|
||||
BB != BBE; ++BB) {
|
||||
double w = ignoreMissing(PI.getExecutionCount(BB));
|
||||
Counts.push_back(std::make_pair(BB, w));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by the frequency, backwards.
|
||||
sort(FunctionCounts.begin(), FunctionCounts.end(),
|
||||
PairSecondSortReverse<Function*>());
|
||||
|
||||
double TotalExecutions = 0;
|
||||
for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i)
|
||||
TotalExecutions += FunctionCounts[i].second;
|
||||
|
||||
outs() << "===" << std::string(73, '-') << "===\n"
|
||||
<< "LLVM profiling output for execution";
|
||||
if (PIL.getNumExecutions() != 1) outs() << "s";
|
||||
outs() << ":\n";
|
||||
|
||||
for (unsigned i = 0, e = PIL.getNumExecutions(); i != e; ++i) {
|
||||
outs() << " ";
|
||||
if (e != 1) outs() << i+1 << ". ";
|
||||
outs() << PIL.getExecution(i) << "\n";
|
||||
}
|
||||
|
||||
outs() << "\n===" << std::string(73, '-') << "===\n";
|
||||
outs() << "Function execution frequencies:\n\n";
|
||||
|
||||
// Print out the function frequencies...
|
||||
outs() << " ## Frequency\n";
|
||||
for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) {
|
||||
if (FunctionCounts[i].second == 0) {
|
||||
outs() << "\n NOTE: " << e-i << " function"
|
||||
<< (e-i-1 ? "s were" : " was") << " never executed!\n";
|
||||
break;
|
||||
}
|
||||
|
||||
outs() << format("%3d", i+1) << ". "
|
||||
<< format("%5.2g", FunctionCounts[i].second) << "/"
|
||||
<< format("%g", TotalExecutions) << " "
|
||||
<< FunctionCounts[i].first->getNameStr() << "\n";
|
||||
}
|
||||
|
||||
std::set<Function*> FunctionsToPrint;
|
||||
|
||||
TotalExecutions = 0;
|
||||
for (unsigned i = 0, e = Counts.size(); i != e; ++i)
|
||||
TotalExecutions += Counts[i].second;
|
||||
|
||||
// Sort by the frequency, backwards.
|
||||
sort(Counts.begin(), Counts.end(),
|
||||
PairSecondSortReverse<BasicBlock*>());
|
||||
|
||||
outs() << "\n===" << std::string(73, '-') << "===\n";
|
||||
outs() << "Top 20 most frequently executed basic blocks:\n\n";
|
||||
|
||||
// Print out the function frequencies...
|
||||
outs() <<" ## %% \tFrequency\n";
|
||||
unsigned BlocksToPrint = Counts.size();
|
||||
if (BlocksToPrint > 20) BlocksToPrint = 20;
|
||||
for (unsigned i = 0; i != BlocksToPrint; ++i) {
|
||||
if (Counts[i].second == 0) break;
|
||||
Function *F = Counts[i].first->getParent();
|
||||
outs() << format("%3d", i+1) << ". "
|
||||
<< format("%5g", Counts[i].second/(double)TotalExecutions*100) << "% "
|
||||
<< format("%5.0f", Counts[i].second) << "/"
|
||||
<< format("%g", TotalExecutions) << "\t"
|
||||
<< F->getNameStr() << "() - "
|
||||
<< Counts[i].first->getNameStr() << "\n";
|
||||
FunctionsToPrint.insert(F);
|
||||
}
|
||||
|
||||
if (PrintAnnotatedLLVM || PrintAllCode) {
|
||||
outs() << "\n===" << std::string(73, '-') << "===\n";
|
||||
outs() << "Annotated LLVM code for the module:\n\n";
|
||||
|
||||
ProfileAnnotator PA(PI);
|
||||
|
||||
if (FunctionsToPrint.empty() || PrintAllCode)
|
||||
M.print(outs(), &PA);
|
||||
else
|
||||
// Print just a subset of the functions.
|
||||
for (std::set<Function*>::iterator I = FunctionsToPrint.begin(),
|
||||
E = FunctionsToPrint.end(); I != E; ++I)
|
||||
(*I)->print(outs(), &PA);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n");
|
||||
|
||||
// Read in the bitcode file...
|
||||
std::string ErrorMessage;
|
||||
OwningPtr<MemoryBuffer> Buffer;
|
||||
error_code ec;
|
||||
Module *M = 0;
|
||||
if (!(ec = MemoryBuffer::getFileOrSTDIN(BitcodeFile, Buffer))) {
|
||||
M = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage);
|
||||
} else
|
||||
ErrorMessage = ec.message();
|
||||
if (M == 0) {
|
||||
errs() << argv[0] << ": " << BitcodeFile << ": "
|
||||
<< ErrorMessage << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read the profiling information. This is redundant since we load it again
|
||||
// using the standard profile info provider pass, but for now this gives us
|
||||
// access to additional information not exposed via the ProfileInfo
|
||||
// interface.
|
||||
ProfileInfoLoader PIL(argv[0], ProfileDataFile, *M);
|
||||
|
||||
// Run the printer pass.
|
||||
PassManager PassMgr;
|
||||
PassMgr.add(createProfileLoaderPass(ProfileDataFile));
|
||||
PassMgr.add(new ProfileInfoPrinterPass(PIL));
|
||||
PassMgr.run(*M);
|
||||
|
||||
return 0;
|
||||
}
|
6
contrib/llvm/tools/llvm-ranlib/CMakeLists.txt
Normal file
6
contrib/llvm/tools/llvm-ranlib/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
set(LLVM_LINK_COMPONENTS archive)
|
||||
set(LLVM_REQUIRES_EH 1)
|
||||
|
||||
add_llvm_tool(llvm-ranlib
|
||||
llvm-ranlib.cpp
|
||||
)
|
18
contrib/llvm/tools/llvm-ranlib/Makefile
Normal file
18
contrib/llvm/tools/llvm-ranlib/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
##===- tools/llvm-ranlib/Makefile --------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llvm-ranlib
|
||||
LINK_COMPONENTS = archive
|
||||
REQUIRES_EH := 1
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
101
contrib/llvm/tools/llvm-ranlib/llvm-ranlib.cpp
Normal file
101
contrib/llvm/tools/llvm-ranlib/llvm-ranlib.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
//===-- llvm-ranlib.cpp - LLVM archive index generator --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Adds or updates an index (symbol table) for an LLVM archive file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Bitcode/Archive.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include <memory>
|
||||
using namespace llvm;
|
||||
|
||||
// llvm-ar operation code and modifier flags
|
||||
static cl::opt<std::string>
|
||||
ArchiveName(cl::Positional, cl::Optional, cl::desc("<archive-file>"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Verbose("verbose",cl::Optional,cl::init(false),
|
||||
cl::desc("Print the symbol table"));
|
||||
|
||||
// printSymbolTable - print out the archive's symbol table.
|
||||
void printSymbolTable(Archive* TheArchive) {
|
||||
outs() << "\nArchive Symbol Table:\n";
|
||||
const Archive::SymTabType& symtab = TheArchive->getSymbolTable();
|
||||
for (Archive::SymTabType::const_iterator I=symtab.begin(), E=symtab.end();
|
||||
I != E; ++I ) {
|
||||
unsigned offset = TheArchive->getFirstFileOffset() + I->second;
|
||||
outs() << " " << format("%9u", offset) << "\t" << I->first <<"\n";
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
llvm::sys::PrintStackTraceOnErrorSignal();
|
||||
llvm::PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
// Have the command line options parsed and handle things
|
||||
// like --help and --version.
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"LLVM Archive Index Generator (llvm-ranlib)\n\n"
|
||||
" This program adds or updates an index of bitcode symbols\n"
|
||||
" to an LLVM archive file."
|
||||
);
|
||||
|
||||
int exitCode = 0;
|
||||
|
||||
// Make sure we don't exit with "unhandled exception".
|
||||
try {
|
||||
|
||||
// Check the path name of the archive
|
||||
sys::Path ArchivePath;
|
||||
if (!ArchivePath.set(ArchiveName))
|
||||
throw std::string("Archive name invalid: ") + ArchiveName;
|
||||
|
||||
// Make sure it exists, we don't create empty archives
|
||||
bool Exists;
|
||||
if (llvm::sys::fs::exists(ArchivePath.str(), Exists) || !Exists)
|
||||
throw std::string("Archive file does not exist");
|
||||
|
||||
std::string err_msg;
|
||||
std::auto_ptr<Archive>
|
||||
AutoArchive(Archive::OpenAndLoad(ArchivePath, Context, &err_msg));
|
||||
Archive* TheArchive = AutoArchive.get();
|
||||
if (!TheArchive)
|
||||
throw err_msg;
|
||||
|
||||
if (TheArchive->writeToDisk(true, false, false, &err_msg ))
|
||||
throw err_msg;
|
||||
|
||||
if (Verbose)
|
||||
printSymbolTable(TheArchive);
|
||||
|
||||
} catch (const char* msg) {
|
||||
errs() << argv[0] << ": " << msg << "\n\n";
|
||||
exitCode = 1;
|
||||
} catch (const std::string& msg) {
|
||||
errs() << argv[0] << ": " << msg << "\n";
|
||||
exitCode = 2;
|
||||
} catch (...) {
|
||||
errs() << argv[0] << ": An unexpected unknown exception occurred.\n";
|
||||
exitCode = 3;
|
||||
}
|
||||
return exitCode;
|
||||
}
|
5
contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt
Normal file
5
contrib/llvm/tools/llvm-rtdyld/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT)
|
||||
|
||||
add_llvm_tool(llvm-rtdyld
|
||||
llvm-rtdyld.cpp
|
||||
)
|
23
contrib/llvm/tools/llvm-rtdyld/Makefile
Normal file
23
contrib/llvm/tools/llvm-rtdyld/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
##===- tools/llvm-rtdyld/Makefile --------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llvm-rtdyld
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
# Include this here so we can get the configuration of the targets
|
||||
# that have been configured for construction. We have to do this
|
||||
# early so we can set up LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := $(TARGETS_TO_BUILD) support MC object RuntimeDyld JIT
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
151
contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
Normal file
151
contrib/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
//===-- llvm-rtdyld.cpp - MCJIT Testing Tool ------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a testing tool for use with the MC-JIT LLVM components.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ExecutionEngine/RuntimeDyld.h"
|
||||
#include "llvm/Object/MachOObject.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
||||
static cl::list<std::string>
|
||||
InputFileList(cl::Positional, cl::ZeroOrMore,
|
||||
cl::desc("<input file>"));
|
||||
|
||||
enum ActionType {
|
||||
AC_Execute
|
||||
};
|
||||
|
||||
static cl::opt<ActionType>
|
||||
Action(cl::desc("Action to perform:"),
|
||||
cl::init(AC_Execute),
|
||||
cl::values(clEnumValN(AC_Execute, "execute",
|
||||
"Load, link, and execute the inputs."),
|
||||
clEnumValEnd));
|
||||
|
||||
static cl::opt<std::string>
|
||||
EntryPoint("entry",
|
||||
cl::desc("Function to call as entry point."),
|
||||
cl::init("_main"));
|
||||
|
||||
/* *** */
|
||||
|
||||
// A trivial memory manager that doesn't do anything fancy, just uses the
|
||||
// support library allocation routines directly.
|
||||
class TrivialMemoryManager : public RTDyldMemoryManager {
|
||||
public:
|
||||
SmallVector<sys::MemoryBlock, 16> FunctionMemory;
|
||||
|
||||
uint8_t *startFunctionBody(const char *Name, uintptr_t &Size);
|
||||
void endFunctionBody(const char *Name, uint8_t *FunctionStart,
|
||||
uint8_t *FunctionEnd);
|
||||
};
|
||||
|
||||
uint8_t *TrivialMemoryManager::startFunctionBody(const char *Name,
|
||||
uintptr_t &Size) {
|
||||
return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
|
||||
}
|
||||
|
||||
void TrivialMemoryManager::endFunctionBody(const char *Name,
|
||||
uint8_t *FunctionStart,
|
||||
uint8_t *FunctionEnd) {
|
||||
uintptr_t Size = FunctionEnd - FunctionStart + 1;
|
||||
FunctionMemory.push_back(sys::MemoryBlock(FunctionStart, Size));
|
||||
}
|
||||
|
||||
static const char *ProgramName;
|
||||
|
||||
static void Message(const char *Type, const Twine &Msg) {
|
||||
errs() << ProgramName << ": " << Type << ": " << Msg << "\n";
|
||||
}
|
||||
|
||||
static int Error(const Twine &Msg) {
|
||||
Message("error", Msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* *** */
|
||||
|
||||
static int executeInput() {
|
||||
// Instantiate a dynamic linker.
|
||||
TrivialMemoryManager *MemMgr = new TrivialMemoryManager;
|
||||
RuntimeDyld Dyld(MemMgr);
|
||||
|
||||
// If we don't have any input files, read from stdin.
|
||||
if (!InputFileList.size())
|
||||
InputFileList.push_back("-");
|
||||
for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
|
||||
// Load the input memory buffer.
|
||||
OwningPtr<MemoryBuffer> InputBuffer;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i],
|
||||
InputBuffer))
|
||||
return Error("unable to read input: '" + ec.message() + "'");
|
||||
|
||||
// Load the object file into it.
|
||||
if (Dyld.loadObject(InputBuffer.take())) {
|
||||
return Error(Dyld.getErrorString());
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve all the relocations we can.
|
||||
Dyld.resolveRelocations();
|
||||
|
||||
// FIXME: Error out if there are unresolved relocations.
|
||||
|
||||
// Get the address of the entry point (_main by default).
|
||||
void *MainAddress = Dyld.getSymbolAddress(EntryPoint);
|
||||
if (MainAddress == 0)
|
||||
return Error("no definition for '" + EntryPoint + "'");
|
||||
|
||||
// Invalidate the instruction cache for each loaded function.
|
||||
for (unsigned i = 0, e = MemMgr->FunctionMemory.size(); i != e; ++i) {
|
||||
sys::MemoryBlock &Data = MemMgr->FunctionMemory[i];
|
||||
// Make sure the memory is executable.
|
||||
std::string ErrorStr;
|
||||
sys::Memory::InvalidateInstructionCache(Data.base(), Data.size());
|
||||
if (!sys::Memory::setExecutable(Data, &ErrorStr))
|
||||
return Error("unable to mark function executable: '" + ErrorStr + "'");
|
||||
}
|
||||
|
||||
// Dispatch to _main().
|
||||
errs() << "loaded '" << EntryPoint << "' at: " << (void*)MainAddress << "\n";
|
||||
|
||||
int (*Main)(int, const char**) =
|
||||
(int(*)(int,const char**)) uintptr_t(MainAddress);
|
||||
const char **Argv = new const char*[2];
|
||||
// Use the name of the first input object module as argv[0] for the target.
|
||||
Argv[0] = InputFileList[0].c_str();
|
||||
Argv[1] = 0;
|
||||
return Main(1, Argv);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
ProgramName = argv[0];
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n");
|
||||
|
||||
switch (Action) {
|
||||
default:
|
||||
case AC_Execute:
|
||||
return executeInput();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
3
contrib/llvm/tools/llvm-stub/CMakeLists.txt
Normal file
3
contrib/llvm/tools/llvm-stub/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_llvm_tool(llvm-stub
|
||||
llvm-stub.c
|
||||
)
|
13
contrib/llvm/tools/llvm-stub/Makefile
Normal file
13
contrib/llvm/tools/llvm-stub/Makefile
Normal file
@ -0,0 +1,13 @@
|
||||
##===- tools/llvm-stub/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = llvm-stub
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
77
contrib/llvm/tools/llvm-stub/llvm-stub.c
Normal file
77
contrib/llvm/tools/llvm-stub/llvm-stub.c
Normal file
@ -0,0 +1,77 @@
|
||||
/*===- llvm-stub.c - Stub executable to run llvm bitcode files ------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This tool is used by the gccld program to enable transparent execution of
|
||||
// bitcode files by the user. Specifically, gccld outputs two files when asked
|
||||
// to compile a <program> file:
|
||||
// 1. It outputs the LLVM bitcode file to <program>.bc
|
||||
// 2. It outputs a stub executable that runs lli on <program>.bc
|
||||
//
|
||||
// This allows the end user to just say ./<program> and have the JIT executed
|
||||
// automatically. On unix, the stub executable emitted is actually a bourne
|
||||
// shell script that does the forwarding. Windows does not like #!/bin/sh
|
||||
// programs in .exe files, so we make it an actual program, defined here.
|
||||
//
|
||||
//===----------------------------------------------------------------------===*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
|
||||
#if defined(HAVE_UNISTD_H) && !defined(_MSC_VER)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <process.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const char *Interp = getenv("LLVMINTERP");
|
||||
const char **Args;
|
||||
if (Interp == 0) Interp = "lli";
|
||||
|
||||
/* Set up the command line options to pass to the JIT. */
|
||||
Args = (const char**)malloc(sizeof(char*) * (argc+2));
|
||||
/* argv[0] is the JIT */
|
||||
Args[0] = Interp;
|
||||
|
||||
#ifdef LLVM_ON_WIN32
|
||||
{
|
||||
int len = strlen(argv[0]);
|
||||
if (len < 4 || strcmp(argv[0] + len - 4, ".exe") != 0) {
|
||||
/* .exe suffix is stripped off of argv[0] if the executable was run on the
|
||||
* command line without one. Put it back on.
|
||||
*/
|
||||
argv[0] = strcat(strcpy((char*)malloc(len + 5), argv[0]), ".exe");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* argv[1] is argv[0] + ".bc". */
|
||||
Args[1] = strcat(strcpy((char*)malloc(strlen(argv[0])+4), argv[0]), ".bc");
|
||||
|
||||
/* The rest of the args are as before. */
|
||||
memcpy((char **)Args+2, argv+1, sizeof(char*)*argc);
|
||||
|
||||
/* Run the JIT. */
|
||||
#if !defined(_WIN32) || defined(__MINGW64__)
|
||||
execvp(Interp, (char **)Args); /* POSIX execvp takes a char *const[]. */
|
||||
#else
|
||||
execvp(Interp, Args); /* windows execvp takes a const char *const *. */
|
||||
#endif
|
||||
/* if _execv returns, the JIT could not be started. */
|
||||
fprintf(stderr, "Could not execute the LLVM JIT. Either add 'lli' to your"
|
||||
" path, or set the\ninterpreter you want to use in the LLVMINTERP "
|
||||
"environment variable.\n");
|
||||
return 1;
|
||||
}
|
5
contrib/llvm/tools/macho-dump/CMakeLists.txt
Normal file
5
contrib/llvm/tools/macho-dump/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support object)
|
||||
|
||||
add_llvm_tool(macho-dump
|
||||
macho-dump.cpp
|
||||
)
|
23
contrib/llvm/tools/macho-dump/Makefile
Normal file
23
contrib/llvm/tools/macho-dump/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
##===- tools/macho-dump/Makefile ---------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
TOOLNAME = macho-dump
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
# Include this here so we can get the configuration of the targets
|
||||
# that have been configured for construction. We have to do this
|
||||
# early so we can set up LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := support object
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
400
contrib/llvm/tools/macho-dump/macho-dump.cpp
Normal file
400
contrib/llvm/tools/macho-dump/macho-dump.cpp
Normal file
@ -0,0 +1,400 @@
|
||||
//===-- macho-dump.cpp - Mach Object Dumping Tool -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This is a testing tool for use with the MC/Mach-O LLVM components.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Object/MachOObject.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
using namespace llvm;
|
||||
using namespace llvm::object;
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFile(cl::Positional, cl::desc("<input file>"), cl::init("-"));
|
||||
|
||||
static cl::opt<bool>
|
||||
ShowSectionData("dump-section-data", cl::desc("Dump the contents of sections"),
|
||||
cl::init(false));
|
||||
|
||||
///
|
||||
|
||||
static const char *ProgramName;
|
||||
|
||||
static void Message(const char *Type, const Twine &Msg) {
|
||||
errs() << ProgramName << ": " << Type << ": " << Msg << "\n";
|
||||
}
|
||||
|
||||
static int Error(const Twine &Msg) {
|
||||
Message("error", Msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void Warning(const Twine &Msg) {
|
||||
Message("warning", Msg);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
static void DumpSegmentCommandData(StringRef Name,
|
||||
uint64_t VMAddr, uint64_t VMSize,
|
||||
uint64_t FileOffset, uint64_t FileSize,
|
||||
uint32_t MaxProt, uint32_t InitProt,
|
||||
uint32_t NumSections, uint32_t Flags) {
|
||||
outs() << " ('segment_name', '";
|
||||
outs().write_escaped(Name, /*UseHexEscapes=*/true) << "')\n";
|
||||
outs() << " ('vm_addr', " << VMAddr << ")\n";
|
||||
outs() << " ('vm_size', " << VMSize << ")\n";
|
||||
outs() << " ('file_offset', " << FileOffset << ")\n";
|
||||
outs() << " ('file_size', " << FileSize << ")\n";
|
||||
outs() << " ('maxprot', " << MaxProt << ")\n";
|
||||
outs() << " ('initprot', " << InitProt << ")\n";
|
||||
outs() << " ('num_sections', " << NumSections << ")\n";
|
||||
outs() << " ('flags', " << Flags << ")\n";
|
||||
}
|
||||
|
||||
static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name,
|
||||
StringRef SegmentName, uint64_t Address,
|
||||
uint64_t Size, uint32_t Offset,
|
||||
uint32_t Align, uint32_t RelocationTableOffset,
|
||||
uint32_t NumRelocationTableEntries,
|
||||
uint32_t Flags, uint32_t Reserved1,
|
||||
uint32_t Reserved2, uint64_t Reserved3 = ~0ULL) {
|
||||
outs() << " # Section " << Index << "\n";
|
||||
outs() << " (('section_name', '";
|
||||
outs().write_escaped(Name, /*UseHexEscapes=*/true) << "')\n";
|
||||
outs() << " ('segment_name', '";
|
||||
outs().write_escaped(SegmentName, /*UseHexEscapes=*/true) << "')\n";
|
||||
outs() << " ('address', " << Address << ")\n";
|
||||
outs() << " ('size', " << Size << ")\n";
|
||||
outs() << " ('offset', " << Offset << ")\n";
|
||||
outs() << " ('alignment', " << Align << ")\n";
|
||||
outs() << " ('reloc_offset', " << RelocationTableOffset << ")\n";
|
||||
outs() << " ('num_reloc', " << NumRelocationTableEntries << ")\n";
|
||||
outs() << " ('flags', " << format("0x%x", Flags) << ")\n";
|
||||
outs() << " ('reserved1', " << Reserved1 << ")\n";
|
||||
outs() << " ('reserved2', " << Reserved2 << ")\n";
|
||||
if (Reserved3 != ~0ULL)
|
||||
outs() << " ('reserved3', " << Reserved3 << ")\n";
|
||||
outs() << " ),\n";
|
||||
|
||||
// Dump the relocation entries.
|
||||
int Res = 0;
|
||||
outs() << " ('_relocations', [\n";
|
||||
for (unsigned i = 0; i != NumRelocationTableEntries; ++i) {
|
||||
InMemoryStruct<macho::RelocationEntry> RE;
|
||||
Obj.ReadRelocationEntry(RelocationTableOffset, i, RE);
|
||||
if (!RE) {
|
||||
Res = Error("unable to read relocation table entry '" + Twine(i) + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
outs() << " # Relocation " << i << "\n";
|
||||
outs() << " (('word-0', " << format("0x%x", RE->Word0) << "),\n";
|
||||
outs() << " ('word-1', " << format("0x%x", RE->Word1) << ")),\n";
|
||||
}
|
||||
outs() << " ])\n";
|
||||
|
||||
// Dump the section data, if requested.
|
||||
if (ShowSectionData) {
|
||||
outs() << " ('_section_data', '";
|
||||
StringRef Data = Obj.getData(Offset, Size);
|
||||
for (unsigned i = 0; i != Data.size(); ++i) {
|
||||
if (i && (i % 4) == 0)
|
||||
outs() << ' ';
|
||||
outs() << hexdigit((Data[i] >> 4) & 0xF, /*LowerCase=*/true);
|
||||
outs() << hexdigit((Data[i] >> 0) & 0xF, /*LowerCase=*/true);
|
||||
}
|
||||
outs() << "')\n";
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
static int DumpSegmentCommand(MachOObject &Obj,
|
||||
const MachOObject::LoadCommandInfo &LCI) {
|
||||
InMemoryStruct<macho::SegmentLoadCommand> SLC;
|
||||
Obj.ReadSegmentLoadCommand(LCI, SLC);
|
||||
if (!SLC)
|
||||
return Error("unable to read segment load command");
|
||||
|
||||
DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress,
|
||||
SLC->VMSize, SLC->FileOffset, SLC->FileSize,
|
||||
SLC->MaxVMProtection, SLC->InitialVMProtection,
|
||||
SLC->NumSections, SLC->Flags);
|
||||
|
||||
// Dump the sections.
|
||||
int Res = 0;
|
||||
outs() << " ('sections', [\n";
|
||||
for (unsigned i = 0; i != SLC->NumSections; ++i) {
|
||||
InMemoryStruct<macho::Section> Sect;
|
||||
Obj.ReadSection(LCI, i, Sect);
|
||||
if (!SLC) {
|
||||
Res = Error("unable to read section '" + Twine(i) + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16),
|
||||
StringRef(Sect->SegmentName, 16), Sect->Address,
|
||||
Sect->Size, Sect->Offset, Sect->Align,
|
||||
Sect->RelocationTableOffset,
|
||||
Sect->NumRelocationTableEntries, Sect->Flags,
|
||||
Sect->Reserved1, Sect->Reserved2)))
|
||||
break;
|
||||
}
|
||||
outs() << " ])\n";
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
static int DumpSegment64Command(MachOObject &Obj,
|
||||
const MachOObject::LoadCommandInfo &LCI) {
|
||||
InMemoryStruct<macho::Segment64LoadCommand> SLC;
|
||||
Obj.ReadSegment64LoadCommand(LCI, SLC);
|
||||
if (!SLC)
|
||||
return Error("unable to read segment load command");
|
||||
|
||||
DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress,
|
||||
SLC->VMSize, SLC->FileOffset, SLC->FileSize,
|
||||
SLC->MaxVMProtection, SLC->InitialVMProtection,
|
||||
SLC->NumSections, SLC->Flags);
|
||||
|
||||
// Dump the sections.
|
||||
int Res = 0;
|
||||
outs() << " ('sections', [\n";
|
||||
for (unsigned i = 0; i != SLC->NumSections; ++i) {
|
||||
InMemoryStruct<macho::Section64> Sect;
|
||||
Obj.ReadSection64(LCI, i, Sect);
|
||||
if (!SLC) {
|
||||
Res = Error("unable to read section '" + Twine(i) + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16),
|
||||
StringRef(Sect->SegmentName, 16), Sect->Address,
|
||||
Sect->Size, Sect->Offset, Sect->Align,
|
||||
Sect->RelocationTableOffset,
|
||||
Sect->NumRelocationTableEntries, Sect->Flags,
|
||||
Sect->Reserved1, Sect->Reserved2,
|
||||
Sect->Reserved3)))
|
||||
break;
|
||||
}
|
||||
outs() << " ])\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DumpSymbolTableEntryData(MachOObject &Obj,
|
||||
unsigned Index, uint32_t StringIndex,
|
||||
uint8_t Type, uint8_t SectionIndex,
|
||||
uint16_t Flags, uint64_t Value) {
|
||||
outs() << " # Symbol " << Index << "\n";
|
||||
outs() << " (('n_strx', " << StringIndex << ")\n";
|
||||
outs() << " ('n_type', " << format("0x%x", Type) << ")\n";
|
||||
outs() << " ('n_sect', " << uint32_t(SectionIndex) << ")\n";
|
||||
outs() << " ('n_desc', " << Flags << ")\n";
|
||||
outs() << " ('n_value', " << Value << ")\n";
|
||||
outs() << " ('_string', '" << Obj.getStringAtIndex(StringIndex) << "')\n";
|
||||
outs() << " ),\n";
|
||||
}
|
||||
|
||||
static int DumpSymtabCommand(MachOObject &Obj,
|
||||
const MachOObject::LoadCommandInfo &LCI) {
|
||||
InMemoryStruct<macho::SymtabLoadCommand> SLC;
|
||||
Obj.ReadSymtabLoadCommand(LCI, SLC);
|
||||
if (!SLC)
|
||||
return Error("unable to read segment load command");
|
||||
|
||||
outs() << " ('symoff', " << SLC->SymbolTableOffset << ")\n";
|
||||
outs() << " ('nsyms', " << SLC->NumSymbolTableEntries << ")\n";
|
||||
outs() << " ('stroff', " << SLC->StringTableOffset << ")\n";
|
||||
outs() << " ('strsize', " << SLC->StringTableSize << ")\n";
|
||||
|
||||
// Cache the string table data.
|
||||
Obj.RegisterStringTable(*SLC);
|
||||
|
||||
// Dump the string data.
|
||||
outs() << " ('_string_data', '";
|
||||
outs().write_escaped(Obj.getStringTableData(),
|
||||
/*UseHexEscapes=*/true) << "')\n";
|
||||
|
||||
// Dump the symbol table.
|
||||
int Res = 0;
|
||||
outs() << " ('_symbols', [\n";
|
||||
for (unsigned i = 0; i != SLC->NumSymbolTableEntries; ++i) {
|
||||
if (Obj.is64Bit()) {
|
||||
InMemoryStruct<macho::Symbol64TableEntry> STE;
|
||||
Obj.ReadSymbol64TableEntry(SLC->SymbolTableOffset, i, STE);
|
||||
if (!STE) {
|
||||
Res = Error("unable to read symbol: '" + Twine(i) + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type,
|
||||
STE->SectionIndex, STE->Flags, STE->Value);
|
||||
} else {
|
||||
InMemoryStruct<macho::SymbolTableEntry> STE;
|
||||
Obj.ReadSymbolTableEntry(SLC->SymbolTableOffset, i, STE);
|
||||
if (!SLC) {
|
||||
Res = Error("unable to read symbol: '" + Twine(i) + "'");
|
||||
break;
|
||||
}
|
||||
|
||||
DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type,
|
||||
STE->SectionIndex, STE->Flags, STE->Value);
|
||||
}
|
||||
}
|
||||
outs() << " ])\n";
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
static int DumpDysymtabCommand(MachOObject &Obj,
|
||||
const MachOObject::LoadCommandInfo &LCI) {
|
||||
InMemoryStruct<macho::DysymtabLoadCommand> DLC;
|
||||
Obj.ReadDysymtabLoadCommand(LCI, DLC);
|
||||
if (!DLC)
|
||||
return Error("unable to read segment load command");
|
||||
|
||||
outs() << " ('ilocalsym', " << DLC->LocalSymbolsIndex << ")\n";
|
||||
outs() << " ('nlocalsym', " << DLC->NumLocalSymbols << ")\n";
|
||||
outs() << " ('iextdefsym', " << DLC->ExternalSymbolsIndex << ")\n";
|
||||
outs() << " ('nextdefsym', " << DLC->NumExternalSymbols << ")\n";
|
||||
outs() << " ('iundefsym', " << DLC->UndefinedSymbolsIndex << ")\n";
|
||||
outs() << " ('nundefsym', " << DLC->NumUndefinedSymbols << ")\n";
|
||||
outs() << " ('tocoff', " << DLC->TOCOffset << ")\n";
|
||||
outs() << " ('ntoc', " << DLC->NumTOCEntries << ")\n";
|
||||
outs() << " ('modtaboff', " << DLC->ModuleTableOffset << ")\n";
|
||||
outs() << " ('nmodtab', " << DLC->NumModuleTableEntries << ")\n";
|
||||
outs() << " ('extrefsymoff', " << DLC->ReferenceSymbolTableOffset << ")\n";
|
||||
outs() << " ('nextrefsyms', "
|
||||
<< DLC->NumReferencedSymbolTableEntries << ")\n";
|
||||
outs() << " ('indirectsymoff', " << DLC->IndirectSymbolTableOffset << ")\n";
|
||||
outs() << " ('nindirectsyms', "
|
||||
<< DLC->NumIndirectSymbolTableEntries << ")\n";
|
||||
outs() << " ('extreloff', " << DLC->ExternalRelocationTableOffset << ")\n";
|
||||
outs() << " ('nextrel', " << DLC->NumExternalRelocationTableEntries << ")\n";
|
||||
outs() << " ('locreloff', " << DLC->LocalRelocationTableOffset << ")\n";
|
||||
outs() << " ('nlocrel', " << DLC->NumLocalRelocationTableEntries << ")\n";
|
||||
|
||||
// Dump the indirect symbol table.
|
||||
int Res = 0;
|
||||
outs() << " ('_indirect_symbols', [\n";
|
||||
for (unsigned i = 0; i != DLC->NumIndirectSymbolTableEntries; ++i) {
|
||||
InMemoryStruct<macho::IndirectSymbolTableEntry> ISTE;
|
||||
Obj.ReadIndirectSymbolTableEntry(*DLC, i, ISTE);
|
||||
if (!ISTE) {
|
||||
Res = Error("unable to read segment load command");
|
||||
break;
|
||||
}
|
||||
|
||||
outs() << " # Indirect Symbol " << i << "\n";
|
||||
outs() << " (('symbol_index', "
|
||||
<< format("0x%x", ISTE->Index) << "),),\n";
|
||||
}
|
||||
outs() << " ])\n";
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
static int DumpLinkeditDataCommand(MachOObject &Obj,
|
||||
const MachOObject::LoadCommandInfo &LCI) {
|
||||
InMemoryStruct<macho::LinkeditDataLoadCommand> LLC;
|
||||
Obj.ReadLinkeditDataLoadCommand(LCI, LLC);
|
||||
if (!LLC)
|
||||
return Error("unable to read segment load command");
|
||||
|
||||
outs() << " ('dataoff', " << LLC->DataOffset << ")\n"
|
||||
<< " ('datasize', " << LLC->DataSize << ")\n"
|
||||
<< " ('_addresses', [\n";
|
||||
|
||||
SmallVector<uint64_t, 8> Addresses;
|
||||
Obj.ReadULEB128s(LLC->DataOffset, Addresses);
|
||||
for (unsigned i = 0, e = Addresses.size(); i != e; ++i)
|
||||
outs() << " # Address " << i << '\n'
|
||||
<< " ('address', " << format("0x%x", Addresses[i]) << "),\n";
|
||||
|
||||
outs() << " ])\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int DumpLoadCommand(MachOObject &Obj, unsigned Index) {
|
||||
const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index);
|
||||
int Res = 0;
|
||||
|
||||
outs() << " # Load Command " << Index << "\n"
|
||||
<< " (('command', " << LCI.Command.Type << ")\n"
|
||||
<< " ('size', " << LCI.Command.Size << ")\n";
|
||||
switch (LCI.Command.Type) {
|
||||
case macho::LCT_Segment:
|
||||
Res = DumpSegmentCommand(Obj, LCI);
|
||||
break;
|
||||
case macho::LCT_Segment64:
|
||||
Res = DumpSegment64Command(Obj, LCI);
|
||||
break;
|
||||
case macho::LCT_Symtab:
|
||||
Res = DumpSymtabCommand(Obj, LCI);
|
||||
break;
|
||||
case macho::LCT_Dysymtab:
|
||||
Res = DumpDysymtabCommand(Obj, LCI);
|
||||
break;
|
||||
case macho::LCT_CodeSignature:
|
||||
case macho::LCT_SegmentSplitInfo:
|
||||
case macho::LCT_FunctionStarts:
|
||||
Res = DumpLinkeditDataCommand(Obj, LCI);
|
||||
break;
|
||||
default:
|
||||
Warning("unknown load command: " + Twine(LCI.Command.Type));
|
||||
break;
|
||||
}
|
||||
outs() << " ),\n";
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
ProgramName = argv[0];
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n");
|
||||
|
||||
// Load the input file.
|
||||
std::string ErrorStr;
|
||||
OwningPtr<MemoryBuffer> InputBuffer;
|
||||
if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFile, InputBuffer))
|
||||
return Error("unable to read input: '" + ec.message() + "'");
|
||||
|
||||
// Construct the Mach-O wrapper object.
|
||||
OwningPtr<MachOObject> InputObject(
|
||||
MachOObject::LoadFromBuffer(InputBuffer.take(), &ErrorStr));
|
||||
if (!InputObject)
|
||||
return Error("unable to load object: '" + ErrorStr + "'");
|
||||
|
||||
// Print the header
|
||||
InputObject->printHeader(outs());
|
||||
|
||||
// Print the load commands.
|
||||
int Res = 0;
|
||||
outs() << "('load_commands', [\n";
|
||||
for (unsigned i = 0; i != InputObject->getHeader().NumLoadCommands; ++i)
|
||||
if ((Res = DumpLoadCommand(*InputObject, i)))
|
||||
break;
|
||||
outs() << "])\n";
|
||||
|
||||
return Res;
|
||||
}
|
94
contrib/llvm/tools/opt/AnalysisWrappers.cpp
Normal file
94
contrib/llvm/tools/opt/AnalysisWrappers.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
//===- AnalysisWrappers.cpp - Wrappers around non-pass analyses -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines pass wrappers around LLVM analyses that don't make sense to
|
||||
// be passes. It provides a nice standard pass interface to these classes so
|
||||
// that they can be printed out by analyze.
|
||||
//
|
||||
// These classes are separated out of analyze.cpp so that it is more clear which
|
||||
// code is the integral part of the analyze tool, and which part of the code is
|
||||
// just making it so more passes are available.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
/// ExternalFunctionsPassedConstants - This pass prints out call sites to
|
||||
/// external functions that are called with constant arguments. This can be
|
||||
/// useful when looking for standard library functions we should constant fold
|
||||
/// or handle in alias analyses.
|
||||
struct ExternalFunctionsPassedConstants : public ModulePass {
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
ExternalFunctionsPassedConstants() : ModulePass(ID) {}
|
||||
virtual bool runOnModule(Module &M) {
|
||||
for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
|
||||
if (!I->isDeclaration()) continue;
|
||||
|
||||
bool PrintedFn = false;
|
||||
for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
|
||||
UI != E; ++UI) {
|
||||
Instruction *User = dyn_cast<Instruction>(*UI);
|
||||
if (!User) continue;
|
||||
|
||||
CallSite CS(cast<Value>(User));
|
||||
if (!CS) continue;
|
||||
|
||||
for (CallSite::arg_iterator AI = CS.arg_begin(),
|
||||
E = CS.arg_end(); AI != E; ++AI) {
|
||||
if (!isa<Constant>(*AI)) continue;
|
||||
|
||||
if (!PrintedFn) {
|
||||
errs() << "Function '" << I->getName() << "':\n";
|
||||
PrintedFn = true;
|
||||
}
|
||||
errs() << *User;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char ExternalFunctionsPassedConstants::ID = 0;
|
||||
static RegisterPass<ExternalFunctionsPassedConstants>
|
||||
P1("print-externalfnconstants",
|
||||
"Print external fn callsites passed constants");
|
||||
|
||||
namespace {
|
||||
struct CallGraphPrinter : public ModulePass {
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
CallGraphPrinter() : ModulePass(ID) {}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequiredTransitive<CallGraph>();
|
||||
}
|
||||
virtual bool runOnModule(Module &M) {
|
||||
getAnalysis<CallGraph>().print(errs(), &M);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CallGraphPrinter::ID = 0;
|
||||
static RegisterPass<CallGraphPrinter>
|
||||
P2("print-callgraph", "Print a call graph");
|
8
contrib/llvm/tools/opt/CMakeLists.txt
Normal file
8
contrib/llvm/tools/opt/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
set(LLVM_LINK_COMPONENTS bitreader asmparser bitwriter instrumentation scalaropts ipo)
|
||||
|
||||
add_llvm_tool(opt
|
||||
AnalysisWrappers.cpp
|
||||
GraphPrinters.cpp
|
||||
PrintSCC.cpp
|
||||
opt.cpp
|
||||
)
|
118
contrib/llvm/tools/opt/GraphPrinters.cpp
Normal file
118
contrib/llvm/tools/opt/GraphPrinters.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
//===- GraphPrinters.cpp - DOT printers for various graph types -----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines several printers for various different types of graphs used
|
||||
// by the LLVM infrastructure. It uses the generic graph interface to convert
|
||||
// the graph into a .dot graph. These graphs can then be processed with the
|
||||
// "dot" tool to convert them to postscript or some other suitable format.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Value.h"
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/Analysis/Dominators.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
using namespace llvm;
|
||||
|
||||
template<typename GraphType>
|
||||
static void WriteGraphToFile(raw_ostream &O, const std::string &GraphName,
|
||||
const GraphType >) {
|
||||
std::string Filename = GraphName + ".dot";
|
||||
O << "Writing '" << Filename << "'...";
|
||||
std::string ErrInfo;
|
||||
tool_output_file F(Filename.c_str(), ErrInfo);
|
||||
|
||||
if (ErrInfo.empty()) {
|
||||
WriteGraph(F.os(), GT);
|
||||
F.os().close();
|
||||
if (!F.os().has_error()) {
|
||||
O << "\n";
|
||||
F.keep();
|
||||
return;
|
||||
}
|
||||
}
|
||||
O << " error opening file for writing!\n";
|
||||
F.os().clear_error();
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Call Graph Printer
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace llvm {
|
||||
template<>
|
||||
struct DOTGraphTraits<CallGraph*> : public DefaultDOTGraphTraits {
|
||||
|
||||
DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
|
||||
|
||||
static std::string getGraphName(CallGraph *F) {
|
||||
return "Call Graph";
|
||||
}
|
||||
|
||||
static std::string getNodeLabel(CallGraphNode *Node, CallGraph *Graph) {
|
||||
if (Node->getFunction())
|
||||
return ((Value*)Node->getFunction())->getName();
|
||||
return "external node";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
struct CallGraphPrinter : public ModulePass {
|
||||
static char ID; // Pass ID, replacement for typeid
|
||||
CallGraphPrinter() : ModulePass(ID) {}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
WriteGraphToFile(llvm::errs(), "callgraph", &getAnalysis<CallGraph>());
|
||||
return false;
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS, const llvm::Module*) const {}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequired<CallGraph>();
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CallGraphPrinter::ID = 0;
|
||||
static RegisterPass<CallGraphPrinter> P2("dot-callgraph",
|
||||
"Print Call Graph to 'dot' file");
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DomInfoPrinter Pass
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class DomInfoPrinter : public FunctionPass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
DomInfoPrinter() : FunctionPass(ID) {}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<DominatorTree>();
|
||||
|
||||
}
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
getAnalysis<DominatorTree>().dump();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char DomInfoPrinter::ID = 0;
|
||||
static RegisterPass<DomInfoPrinter>
|
||||
DIP("print-dom-info", "Dominator Info Printer", true, true);
|
14
contrib/llvm/tools/opt/Makefile
Normal file
14
contrib/llvm/tools/opt/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
##===- tools/opt/Makefile ----------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
LEVEL = ../..
|
||||
TOOLNAME = opt
|
||||
|
||||
LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
112
contrib/llvm/tools/opt/PrintSCC.cpp
Normal file
112
contrib/llvm/tools/opt/PrintSCC.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
//===- PrintSCC.cpp - Enumerate SCCs in some key graphs -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides passes to print out SCCs in a CFG or a CallGraph.
|
||||
// Normally, you would not use these passes; instead, you would use the
|
||||
// scc_iterator directly to enumerate SCCs and process them in some way. These
|
||||
// passes serve three purposes:
|
||||
//
|
||||
// (1) As a reference for how to use the scc_iterator.
|
||||
// (2) To print out the SCCs for a CFG or a CallGraph:
|
||||
// analyze -print-cfg-sccs to print the SCCs in each CFG of a module.
|
||||
// analyze -print-cfg-sccs -stats to print the #SCCs and the maximum SCC size.
|
||||
// analyze -print-cfg-sccs -debug > /dev/null to watch the algorithm in action.
|
||||
//
|
||||
// and similarly:
|
||||
// analyze -print-callgraph-sccs [-stats] [-debug] to print SCCs in the CallGraph
|
||||
//
|
||||
// (3) To test the scc_iterator.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/Support/CFG.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/SCCIterator.h"
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
struct CFGSCC : public FunctionPass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
CFGSCC() : FunctionPass(ID) {}
|
||||
bool runOnFunction(Function& func);
|
||||
|
||||
void print(raw_ostream &O, const Module* = 0) const { }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
struct CallGraphSCC : public ModulePass {
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
CallGraphSCC() : ModulePass(ID) {}
|
||||
|
||||
// run - Print out SCCs in the call graph for the specified module.
|
||||
bool runOnModule(Module &M);
|
||||
|
||||
void print(raw_ostream &O, const Module* = 0) const { }
|
||||
|
||||
// getAnalysisUsage - This pass requires the CallGraph.
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<CallGraph>();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
char CFGSCC::ID = 0;
|
||||
static RegisterPass<CFGSCC>
|
||||
Y("print-cfg-sccs", "Print SCCs of each function CFG");
|
||||
|
||||
char CallGraphSCC::ID = 0;
|
||||
static RegisterPass<CallGraphSCC>
|
||||
Z("print-callgraph-sccs", "Print SCCs of the Call Graph");
|
||||
|
||||
bool CFGSCC::runOnFunction(Function &F) {
|
||||
unsigned sccNum = 0;
|
||||
errs() << "SCCs for Function " << F.getName() << " in PostOrder:";
|
||||
for (scc_iterator<Function*> SCCI = scc_begin(&F),
|
||||
E = scc_end(&F); SCCI != E; ++SCCI) {
|
||||
std::vector<BasicBlock*> &nextSCC = *SCCI;
|
||||
errs() << "\nSCC #" << ++sccNum << " : ";
|
||||
for (std::vector<BasicBlock*>::const_iterator I = nextSCC.begin(),
|
||||
E = nextSCC.end(); I != E; ++I)
|
||||
errs() << (*I)->getName() << ", ";
|
||||
if (nextSCC.size() == 1 && SCCI.hasLoop())
|
||||
errs() << " (Has self-loop).";
|
||||
}
|
||||
errs() << "\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// run - Print out SCCs in the call graph for the specified module.
|
||||
bool CallGraphSCC::runOnModule(Module &M) {
|
||||
CallGraphNode* rootNode = getAnalysis<CallGraph>().getRoot();
|
||||
unsigned sccNum = 0;
|
||||
errs() << "SCCs for the program in PostOrder:";
|
||||
for (scc_iterator<CallGraphNode*> SCCI = scc_begin(rootNode),
|
||||
E = scc_end(rootNode); SCCI != E; ++SCCI) {
|
||||
const std::vector<CallGraphNode*> &nextSCC = *SCCI;
|
||||
errs() << "\nSCC #" << ++sccNum << " : ";
|
||||
for (std::vector<CallGraphNode*>::const_iterator I = nextSCC.begin(),
|
||||
E = nextSCC.end(); I != E; ++I)
|
||||
errs() << ((*I)->getFunction() ? (*I)->getFunction()->getNameStr()
|
||||
: std::string("external node")) << ", ";
|
||||
if (nextSCC.size() == 1 && SCCI.hasLoop())
|
||||
errs() << " (Has self-loop).";
|
||||
}
|
||||
errs() << "\n";
|
||||
|
||||
return true;
|
||||
}
|
713
contrib/llvm/tools/opt/opt.cpp
Normal file
713
contrib/llvm/tools/opt/opt.cpp
Normal file
@ -0,0 +1,713 @@
|
||||
//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Optimizations may be specified an arbitrary number of times on the command
|
||||
// line, They are run in the order specified.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/PassManager.h"
|
||||
#include "llvm/CallGraphSCCPass.h"
|
||||
#include "llvm/Bitcode/ReaderWriter.h"
|
||||
#include "llvm/Assembly/PrintModulePass.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/Analysis/Verifier.h"
|
||||
#include "llvm/Analysis/LoopPass.h"
|
||||
#include "llvm/Analysis/RegionPass.h"
|
||||
#include "llvm/Analysis/CallGraph.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Target/TargetLibraryInfo.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/PassNameParser.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/IRReader.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/PluginLoader.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
#include "llvm/Support/SystemUtils.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/LinkAllPasses.h"
|
||||
#include "llvm/LinkAllVMCore.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
using namespace llvm;
|
||||
|
||||
// The OptimizationList is automatically populated with registered Passes by the
|
||||
// PassNameParser.
|
||||
//
|
||||
static cl::list<const PassInfo*, bool, PassNameParser>
|
||||
PassList(cl::desc("Optimizations available:"));
|
||||
|
||||
// Other command line options...
|
||||
//
|
||||
static cl::opt<std::string>
|
||||
InputFilename(cl::Positional, cl::desc("<input bitcode file>"),
|
||||
cl::init("-"), cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("o", cl::desc("Override output filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Force("f", cl::desc("Enable binary output on terminals"));
|
||||
|
||||
static cl::opt<bool>
|
||||
PrintEachXForm("p", cl::desc("Print module after each transformation"));
|
||||
|
||||
static cl::opt<bool>
|
||||
NoOutput("disable-output",
|
||||
cl::desc("Do not write result bitcode file"), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
OutputAssembly("S", cl::desc("Write output as LLVM assembly"));
|
||||
|
||||
static cl::opt<bool>
|
||||
NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden);
|
||||
|
||||
static cl::opt<bool>
|
||||
VerifyEach("verify-each", cl::desc("Verify after each transform"));
|
||||
|
||||
static cl::opt<bool>
|
||||
StripDebug("strip-debug",
|
||||
cl::desc("Strip debugger symbol info from translation unit"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableInline("disable-inlining", cl::desc("Do not run the inliner pass"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableOptimizations("disable-opt",
|
||||
cl::desc("Do not run any optimization passes"));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableInternalize("disable-internalize",
|
||||
cl::desc("Do not mark all symbols as internal"));
|
||||
|
||||
static cl::opt<bool>
|
||||
StandardCompileOpts("std-compile-opts",
|
||||
cl::desc("Include the standard compile time optimizations"));
|
||||
|
||||
static cl::opt<bool>
|
||||
StandardLinkOpts("std-link-opts",
|
||||
cl::desc("Include the standard link time optimizations"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OptLevelO1("O1",
|
||||
cl::desc("Optimization level 1. Similar to llvm-gcc -O1"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OptLevelO2("O2",
|
||||
cl::desc("Optimization level 2. Similar to llvm-gcc -O2"));
|
||||
|
||||
static cl::opt<bool>
|
||||
OptLevelO3("O3",
|
||||
cl::desc("Optimization level 3. Similar to llvm-gcc -O3"));
|
||||
|
||||
static cl::opt<bool>
|
||||
UnitAtATime("funit-at-a-time",
|
||||
cl::desc("Enable IPO. This is same as llvm-gcc's -funit-at-a-time"),
|
||||
cl::init(true));
|
||||
|
||||
static cl::opt<bool>
|
||||
DisableSimplifyLibCalls("disable-simplify-libcalls",
|
||||
cl::desc("Disable simplify-libcalls"));
|
||||
|
||||
static cl::opt<bool>
|
||||
Quiet("q", cl::desc("Obsolete option"), cl::Hidden);
|
||||
|
||||
static cl::alias
|
||||
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));
|
||||
|
||||
static cl::opt<bool>
|
||||
AnalyzeOnly("analyze", cl::desc("Only perform analysis, no optimization"));
|
||||
|
||||
static cl::opt<bool>
|
||||
PrintBreakpoints("print-breakpoints-for-testing",
|
||||
cl::desc("Print select breakpoints location for testing"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
DefaultDataLayout("default-data-layout",
|
||||
cl::desc("data layout string to use if not specified by module"),
|
||||
cl::value_desc("layout-string"), cl::init(""));
|
||||
|
||||
// ---------- Define Printers for module and function passes ------------
|
||||
namespace {
|
||||
|
||||
struct CallGraphSCCPassPrinter : public CallGraphSCCPass {
|
||||
static char ID;
|
||||
const PassInfo *PassToPrint;
|
||||
raw_ostream &Out;
|
||||
std::string PassName;
|
||||
|
||||
CallGraphSCCPassPrinter(const PassInfo *PI, raw_ostream &out) :
|
||||
CallGraphSCCPass(ID), PassToPrint(PI), Out(out) {
|
||||
std::string PassToPrintName = PassToPrint->getPassName();
|
||||
PassName = "CallGraphSCCPass Printer: " + PassToPrintName;
|
||||
}
|
||||
|
||||
virtual bool runOnSCC(CallGraphSCC &SCC) {
|
||||
if (!Quiet)
|
||||
Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n";
|
||||
|
||||
// Get and print pass...
|
||||
for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); I != E; ++I) {
|
||||
Function *F = (*I)->getFunction();
|
||||
if (F)
|
||||
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out,
|
||||
F->getParent());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const { return PassName.c_str(); }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PassToPrint->getTypeInfo());
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
char CallGraphSCCPassPrinter::ID = 0;
|
||||
|
||||
struct ModulePassPrinter : public ModulePass {
|
||||
static char ID;
|
||||
const PassInfo *PassToPrint;
|
||||
raw_ostream &Out;
|
||||
std::string PassName;
|
||||
|
||||
ModulePassPrinter(const PassInfo *PI, raw_ostream &out)
|
||||
: ModulePass(ID), PassToPrint(PI), Out(out) {
|
||||
std::string PassToPrintName = PassToPrint->getPassName();
|
||||
PassName = "ModulePass Printer: " + PassToPrintName;
|
||||
}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
if (!Quiet)
|
||||
Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n";
|
||||
|
||||
// Get and print pass...
|
||||
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out, &M);
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const { return PassName.c_str(); }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PassToPrint->getTypeInfo());
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
char ModulePassPrinter::ID = 0;
|
||||
struct FunctionPassPrinter : public FunctionPass {
|
||||
const PassInfo *PassToPrint;
|
||||
raw_ostream &Out;
|
||||
static char ID;
|
||||
std::string PassName;
|
||||
|
||||
FunctionPassPrinter(const PassInfo *PI, raw_ostream &out)
|
||||
: FunctionPass(ID), PassToPrint(PI), Out(out) {
|
||||
std::string PassToPrintName = PassToPrint->getPassName();
|
||||
PassName = "FunctionPass Printer: " + PassToPrintName;
|
||||
}
|
||||
|
||||
virtual bool runOnFunction(Function &F) {
|
||||
if (!Quiet)
|
||||
Out << "Printing analysis '" << PassToPrint->getPassName()
|
||||
<< "' for function '" << F.getName() << "':\n";
|
||||
|
||||
// Get and print pass...
|
||||
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out,
|
||||
F.getParent());
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const { return PassName.c_str(); }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PassToPrint->getTypeInfo());
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
char FunctionPassPrinter::ID = 0;
|
||||
|
||||
struct LoopPassPrinter : public LoopPass {
|
||||
static char ID;
|
||||
const PassInfo *PassToPrint;
|
||||
raw_ostream &Out;
|
||||
std::string PassName;
|
||||
|
||||
LoopPassPrinter(const PassInfo *PI, raw_ostream &out) :
|
||||
LoopPass(ID), PassToPrint(PI), Out(out) {
|
||||
std::string PassToPrintName = PassToPrint->getPassName();
|
||||
PassName = "LoopPass Printer: " + PassToPrintName;
|
||||
}
|
||||
|
||||
|
||||
virtual bool runOnLoop(Loop *L, LPPassManager &LPM) {
|
||||
if (!Quiet)
|
||||
Out << "Printing analysis '" << PassToPrint->getPassName() << "':\n";
|
||||
|
||||
// Get and print pass...
|
||||
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out,
|
||||
L->getHeader()->getParent()->getParent());
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const { return PassName.c_str(); }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PassToPrint->getTypeInfo());
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
char LoopPassPrinter::ID = 0;
|
||||
|
||||
struct RegionPassPrinter : public RegionPass {
|
||||
static char ID;
|
||||
const PassInfo *PassToPrint;
|
||||
raw_ostream &Out;
|
||||
std::string PassName;
|
||||
|
||||
RegionPassPrinter(const PassInfo *PI, raw_ostream &out) : RegionPass(ID),
|
||||
PassToPrint(PI), Out(out) {
|
||||
std::string PassToPrintName = PassToPrint->getPassName();
|
||||
PassName = "RegionPass Printer: " + PassToPrintName;
|
||||
}
|
||||
|
||||
virtual bool runOnRegion(Region *R, RGPassManager &RGM) {
|
||||
if (!Quiet) {
|
||||
Out << "Printing analysis '" << PassToPrint->getPassName() << "' for "
|
||||
<< "region: '" << R->getNameStr() << "' in function '"
|
||||
<< R->getEntry()->getParent()->getNameStr() << "':\n";
|
||||
}
|
||||
// Get and print pass...
|
||||
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out,
|
||||
R->getEntry()->getParent()->getParent());
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const { return PassName.c_str(); }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PassToPrint->getTypeInfo());
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
char RegionPassPrinter::ID = 0;
|
||||
|
||||
struct BasicBlockPassPrinter : public BasicBlockPass {
|
||||
const PassInfo *PassToPrint;
|
||||
raw_ostream &Out;
|
||||
static char ID;
|
||||
std::string PassName;
|
||||
|
||||
BasicBlockPassPrinter(const PassInfo *PI, raw_ostream &out)
|
||||
: BasicBlockPass(ID), PassToPrint(PI), Out(out) {
|
||||
std::string PassToPrintName = PassToPrint->getPassName();
|
||||
PassName = "BasicBlockPass Printer: " + PassToPrintName;
|
||||
}
|
||||
|
||||
virtual bool runOnBasicBlock(BasicBlock &BB) {
|
||||
if (!Quiet)
|
||||
Out << "Printing Analysis info for BasicBlock '" << BB.getName()
|
||||
<< "': Pass " << PassToPrint->getPassName() << ":\n";
|
||||
|
||||
// Get and print pass...
|
||||
getAnalysisID<Pass>(PassToPrint->getTypeInfo()).print(Out,
|
||||
BB.getParent()->getParent());
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual const char *getPassName() const { return PassName.c_str(); }
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.addRequiredID(PassToPrint->getTypeInfo());
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
char BasicBlockPassPrinter::ID = 0;
|
||||
|
||||
struct BreakpointPrinter : public ModulePass {
|
||||
raw_ostream &Out;
|
||||
static char ID;
|
||||
|
||||
BreakpointPrinter(raw_ostream &out)
|
||||
: ModulePass(ID), Out(out) {
|
||||
}
|
||||
|
||||
void getContextName(DIDescriptor Context, std::string &N) {
|
||||
if (Context.isNameSpace()) {
|
||||
DINameSpace NS(Context);
|
||||
if (!NS.getName().empty()) {
|
||||
getContextName(NS.getContext(), N);
|
||||
N = N + NS.getName().str() + "::";
|
||||
}
|
||||
} else if (Context.isType()) {
|
||||
DIType TY(Context);
|
||||
if (!TY.getName().empty()) {
|
||||
getContextName(TY.getContext(), N);
|
||||
N = N + TY.getName().str() + "::";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool runOnModule(Module &M) {
|
||||
StringSet<> Processed;
|
||||
if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp"))
|
||||
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
|
||||
std::string Name;
|
||||
DISubprogram SP(NMD->getOperand(i));
|
||||
if (SP.Verify())
|
||||
getContextName(SP.getContext(), Name);
|
||||
Name = Name + SP.getDisplayName().str();
|
||||
if (!Name.empty() && Processed.insert(Name)) {
|
||||
Out << Name << "\n";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
char BreakpointPrinter::ID = 0;
|
||||
|
||||
static inline void addPass(PassManagerBase &PM, Pass *P) {
|
||||
// Add the pass to the pass manager...
|
||||
PM.add(P);
|
||||
|
||||
// If we are verifying all of the intermediate steps, add the verifier...
|
||||
if (VerifyEach) PM.add(createVerifierPass());
|
||||
}
|
||||
|
||||
/// AddOptimizationPasses - This routine adds optimization passes
|
||||
/// based on selected optimization level, OptLevel. This routine
|
||||
/// duplicates llvm-gcc behaviour.
|
||||
///
|
||||
/// OptLevel - Optimization Level
|
||||
static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
|
||||
unsigned OptLevel) {
|
||||
PassManagerBuilder Builder;
|
||||
Builder.OptLevel = OptLevel;
|
||||
|
||||
if (DisableInline) {
|
||||
// No inlining pass
|
||||
} else if (OptLevel > 1) {
|
||||
unsigned Threshold = 225;
|
||||
if (OptLevel > 2)
|
||||
Threshold = 275;
|
||||
Builder.Inliner = createFunctionInliningPass(Threshold);
|
||||
} else {
|
||||
Builder.Inliner = createAlwaysInlinerPass();
|
||||
}
|
||||
Builder.DisableUnitAtATime = !UnitAtATime;
|
||||
Builder.DisableUnrollLoops = OptLevel == 0;
|
||||
Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls;
|
||||
|
||||
Builder.populateFunctionPassManager(FPM);
|
||||
Builder.populateModulePassManager(MPM);
|
||||
}
|
||||
|
||||
static void AddStandardCompilePasses(PassManagerBase &PM) {
|
||||
PM.add(createVerifierPass()); // Verify that input is correct
|
||||
|
||||
// If the -strip-debug command line option was specified, do it.
|
||||
if (StripDebug)
|
||||
addPass(PM, createStripSymbolsPass(true));
|
||||
|
||||
if (DisableOptimizations) return;
|
||||
|
||||
// -std-compile-opts adds the same module passes as -O3.
|
||||
PassManagerBuilder Builder;
|
||||
if (!DisableInline)
|
||||
Builder.Inliner = createFunctionInliningPass();
|
||||
Builder.OptLevel = 3;
|
||||
Builder.DisableSimplifyLibCalls = DisableSimplifyLibCalls;
|
||||
Builder.populateModulePassManager(PM);
|
||||
}
|
||||
|
||||
static void AddStandardLinkPasses(PassManagerBase &PM) {
|
||||
PM.add(createVerifierPass()); // Verify that input is correct
|
||||
|
||||
// If the -strip-debug command line option was specified, do it.
|
||||
if (StripDebug)
|
||||
addPass(PM, createStripSymbolsPass(true));
|
||||
|
||||
if (DisableOptimizations) return;
|
||||
|
||||
PassManagerBuilder Builder;
|
||||
Builder.populateLTOPassManager(PM, /*Internalize=*/ !DisableInternalize,
|
||||
/*RunInliner=*/ !DisableInline);
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// main for opt
|
||||
//
|
||||
int main(int argc, char **argv) {
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
llvm::PrettyStackTraceProgram X(argc, argv);
|
||||
|
||||
// Enable debug stream buffering.
|
||||
EnableDebugBuffering = true;
|
||||
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
LLVMContext &Context = getGlobalContext();
|
||||
|
||||
// Initialize passes
|
||||
PassRegistry &Registry = *PassRegistry::getPassRegistry();
|
||||
initializeCore(Registry);
|
||||
initializeScalarOpts(Registry);
|
||||
initializeIPO(Registry);
|
||||
initializeAnalysis(Registry);
|
||||
initializeIPA(Registry);
|
||||
initializeTransformUtils(Registry);
|
||||
initializeInstCombine(Registry);
|
||||
initializeInstrumentation(Registry);
|
||||
initializeTarget(Registry);
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv,
|
||||
"llvm .bc -> .bc modular optimizer and analysis printer\n");
|
||||
|
||||
if (AnalyzeOnly && NoOutput) {
|
||||
errs() << argv[0] << ": analyze mode conflicts with no-output mode.\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate a full target machine description only if necessary.
|
||||
// FIXME: The choice of target should be controllable on the command line.
|
||||
std::auto_ptr<TargetMachine> target;
|
||||
|
||||
SMDiagnostic Err;
|
||||
|
||||
// Load the input module...
|
||||
std::auto_ptr<Module> M;
|
||||
M.reset(ParseIRFile(InputFilename, Err, Context));
|
||||
|
||||
if (M.get() == 0) {
|
||||
Err.Print(argv[0], errs());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Figure out what stream we are supposed to write to...
|
||||
OwningPtr<tool_output_file> Out;
|
||||
if (NoOutput) {
|
||||
if (!OutputFilename.empty())
|
||||
errs() << "WARNING: The -o (output filename) option is ignored when\n"
|
||||
"the --disable-output option is used.\n";
|
||||
} else {
|
||||
// Default to standard output.
|
||||
if (OutputFilename.empty())
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string ErrorInfo;
|
||||
Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary));
|
||||
if (!ErrorInfo.empty()) {
|
||||
errs() << ErrorInfo << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If the output is set to be emitted to standard out, and standard out is a
|
||||
// console, print out a warning message and refuse to do it. We don't
|
||||
// impress anyone by spewing tons of binary goo to a terminal.
|
||||
if (!Force && !NoOutput && !AnalyzeOnly && !OutputAssembly)
|
||||
if (CheckBitcodeOutputToConsole(Out->os(), !Quiet))
|
||||
NoOutput = true;
|
||||
|
||||
// Create a PassManager to hold and optimize the collection of passes we are
|
||||
// about to build.
|
||||
//
|
||||
PassManager Passes;
|
||||
|
||||
// Add an appropriate TargetLibraryInfo pass for the module's triple.
|
||||
TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple()));
|
||||
|
||||
// The -disable-simplify-libcalls flag actually disables all builtin optzns.
|
||||
if (DisableSimplifyLibCalls)
|
||||
TLI->disableAllFunctions();
|
||||
Passes.add(TLI);
|
||||
|
||||
// Add an appropriate TargetData instance for this module.
|
||||
TargetData *TD = 0;
|
||||
const std::string &ModuleDataLayout = M.get()->getDataLayout();
|
||||
if (!ModuleDataLayout.empty())
|
||||
TD = new TargetData(ModuleDataLayout);
|
||||
else if (!DefaultDataLayout.empty())
|
||||
TD = new TargetData(DefaultDataLayout);
|
||||
|
||||
if (TD)
|
||||
Passes.add(TD);
|
||||
|
||||
OwningPtr<FunctionPassManager> FPasses;
|
||||
if (OptLevelO1 || OptLevelO2 || OptLevelO3) {
|
||||
FPasses.reset(new FunctionPassManager(M.get()));
|
||||
if (TD)
|
||||
FPasses->add(new TargetData(*TD));
|
||||
}
|
||||
|
||||
if (PrintBreakpoints) {
|
||||
// Default to standard output.
|
||||
if (!Out) {
|
||||
if (OutputFilename.empty())
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string ErrorInfo;
|
||||
Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
|
||||
raw_fd_ostream::F_Binary));
|
||||
if (!ErrorInfo.empty()) {
|
||||
errs() << ErrorInfo << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Passes.add(new BreakpointPrinter(Out->os()));
|
||||
NoOutput = true;
|
||||
}
|
||||
|
||||
// If the -strip-debug command line option was specified, add it. If
|
||||
// -std-compile-opts was also specified, it will handle StripDebug.
|
||||
if (StripDebug && !StandardCompileOpts)
|
||||
addPass(Passes, createStripSymbolsPass(true));
|
||||
|
||||
// Create a new optimization pass for each one specified on the command line
|
||||
for (unsigned i = 0; i < PassList.size(); ++i) {
|
||||
// Check to see if -std-compile-opts was specified before this option. If
|
||||
// so, handle it.
|
||||
if (StandardCompileOpts &&
|
||||
StandardCompileOpts.getPosition() < PassList.getPosition(i)) {
|
||||
AddStandardCompilePasses(Passes);
|
||||
StandardCompileOpts = false;
|
||||
}
|
||||
|
||||
if (StandardLinkOpts &&
|
||||
StandardLinkOpts.getPosition() < PassList.getPosition(i)) {
|
||||
AddStandardLinkPasses(Passes);
|
||||
StandardLinkOpts = false;
|
||||
}
|
||||
|
||||
if (OptLevelO1 && OptLevelO1.getPosition() < PassList.getPosition(i)) {
|
||||
AddOptimizationPasses(Passes, *FPasses, 1);
|
||||
OptLevelO1 = false;
|
||||
}
|
||||
|
||||
if (OptLevelO2 && OptLevelO2.getPosition() < PassList.getPosition(i)) {
|
||||
AddOptimizationPasses(Passes, *FPasses, 2);
|
||||
OptLevelO2 = false;
|
||||
}
|
||||
|
||||
if (OptLevelO3 && OptLevelO3.getPosition() < PassList.getPosition(i)) {
|
||||
AddOptimizationPasses(Passes, *FPasses, 3);
|
||||
OptLevelO3 = false;
|
||||
}
|
||||
|
||||
const PassInfo *PassInf = PassList[i];
|
||||
Pass *P = 0;
|
||||
if (PassInf->getNormalCtor())
|
||||
P = PassInf->getNormalCtor()();
|
||||
else
|
||||
errs() << argv[0] << ": cannot create pass: "
|
||||
<< PassInf->getPassName() << "\n";
|
||||
if (P) {
|
||||
PassKind Kind = P->getPassKind();
|
||||
addPass(Passes, P);
|
||||
|
||||
if (AnalyzeOnly) {
|
||||
switch (Kind) {
|
||||
case PT_BasicBlock:
|
||||
Passes.add(new BasicBlockPassPrinter(PassInf, Out->os()));
|
||||
break;
|
||||
case PT_Region:
|
||||
Passes.add(new RegionPassPrinter(PassInf, Out->os()));
|
||||
break;
|
||||
case PT_Loop:
|
||||
Passes.add(new LoopPassPrinter(PassInf, Out->os()));
|
||||
break;
|
||||
case PT_Function:
|
||||
Passes.add(new FunctionPassPrinter(PassInf, Out->os()));
|
||||
break;
|
||||
case PT_CallGraphSCC:
|
||||
Passes.add(new CallGraphSCCPassPrinter(PassInf, Out->os()));
|
||||
break;
|
||||
default:
|
||||
Passes.add(new ModulePassPrinter(PassInf, Out->os()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (PrintEachXForm)
|
||||
Passes.add(createPrintModulePass(&errs()));
|
||||
}
|
||||
|
||||
// If -std-compile-opts was specified at the end of the pass list, add them.
|
||||
if (StandardCompileOpts) {
|
||||
AddStandardCompilePasses(Passes);
|
||||
StandardCompileOpts = false;
|
||||
}
|
||||
|
||||
if (StandardLinkOpts) {
|
||||
AddStandardLinkPasses(Passes);
|
||||
StandardLinkOpts = false;
|
||||
}
|
||||
|
||||
if (OptLevelO1)
|
||||
AddOptimizationPasses(Passes, *FPasses, 1);
|
||||
|
||||
if (OptLevelO2)
|
||||
AddOptimizationPasses(Passes, *FPasses, 2);
|
||||
|
||||
if (OptLevelO3)
|
||||
AddOptimizationPasses(Passes, *FPasses, 3);
|
||||
|
||||
if (OptLevelO1 || OptLevelO2 || OptLevelO3) {
|
||||
FPasses->doInitialization();
|
||||
for (Module::iterator F = M->begin(), E = M->end(); F != E; ++F)
|
||||
FPasses->run(*F);
|
||||
FPasses->doFinalization();
|
||||
}
|
||||
|
||||
// Check that the module is well formed on completion of optimization
|
||||
if (!NoVerify && !VerifyEach)
|
||||
Passes.add(createVerifierPass());
|
||||
|
||||
// Write bitcode or assembly to the output as the last step...
|
||||
if (!NoOutput && !AnalyzeOnly) {
|
||||
if (OutputAssembly)
|
||||
Passes.add(createPrintModulePass(&Out->os()));
|
||||
else
|
||||
Passes.add(createBitcodeWriterPass(Out->os()));
|
||||
}
|
||||
|
||||
// Before executing passes, print the final values of the LLVM options.
|
||||
cl::PrintOptionValues();
|
||||
|
||||
// Now that we have all of the passes ready, run them.
|
||||
Passes.run(*M.get());
|
||||
|
||||
// Declare success.
|
||||
if (!NoOutput || PrintBreakpoints)
|
||||
Out->keep();
|
||||
|
||||
return 0;
|
||||
}
|
@ -223,8 +223,8 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
login_cap_t *lc;
|
||||
const char *from_host, *from_ip;
|
||||
|
||||
from_host = get_canonical_hostname(options.use_dns);
|
||||
from_ip = get_remote_ipaddr();
|
||||
from_host = get_canonical_hostname(options.use_dns);
|
||||
from_ip = get_remote_ipaddr();
|
||||
#endif
|
||||
|
||||
if (authctxt == NULL)
|
||||
@ -272,23 +272,23 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOGIN_CAP
|
||||
if (authctxt->pw != NULL) {
|
||||
lc = login_getpwclass(authctxt->pw);
|
||||
if (lc == NULL)
|
||||
lc = login_getclassbyname(NULL, authctxt->pw);
|
||||
if (!auth_hostok(lc, from_host, from_ip)) {
|
||||
logit("Denied connection for %.200s from %.200s [%.200s].",
|
||||
authctxt->pw->pw_name, from_host, from_ip);
|
||||
packet_disconnect("Sorry, you are not allowed to connect.");
|
||||
}
|
||||
if (!auth_timeok(lc, time(NULL))) {
|
||||
logit("LOGIN %.200s REFUSED (TIME) FROM %.200s",
|
||||
authctxt->pw->pw_name, from_host);
|
||||
packet_disconnect("Logins not available right now.");
|
||||
}
|
||||
login_close(lc);
|
||||
lc = NULL;
|
||||
}
|
||||
if (authctxt->pw != NULL) {
|
||||
lc = login_getpwclass(authctxt->pw);
|
||||
if (lc == NULL)
|
||||
lc = login_getclassbyname(NULL, authctxt->pw);
|
||||
if (!auth_hostok(lc, from_host, from_ip)) {
|
||||
logit("Denied connection for %.200s from %.200s [%.200s].",
|
||||
authctxt->pw->pw_name, from_host, from_ip);
|
||||
packet_disconnect("Sorry, you are not allowed to connect.");
|
||||
}
|
||||
if (!auth_timeok(lc, time(NULL))) {
|
||||
logit("LOGIN %.200s REFUSED (TIME) FROM %.200s",
|
||||
authctxt->pw->pw_name, from_host);
|
||||
packet_disconnect("Logins not available right now.");
|
||||
}
|
||||
login_close(lc);
|
||||
lc = NULL;
|
||||
}
|
||||
#endif /* HAVE_LOGIN_CAP */
|
||||
|
||||
/* reset state */
|
||||
|
@ -2690,7 +2690,7 @@ channel_set_af(int af)
|
||||
void
|
||||
channel_set_hpn(int disabled, u_int buf_size)
|
||||
{
|
||||
hpn_disabled = disabled;
|
||||
hpn_disabled = disabled;
|
||||
buffer_size = buf_size;
|
||||
debug("HPN Disabled: %d, HPN Buffer Size: %d",
|
||||
hpn_disabled, buffer_size);
|
||||
@ -2856,10 +2856,10 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
|
||||
c = channel_new("port listener", type, sock, sock, -1,
|
||||
CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
|
||||
0, "port listener", 1);
|
||||
else
|
||||
c = channel_new("port listener", type, sock, sock, -1,
|
||||
buffer_size, CHAN_TCP_PACKET_DEFAULT,
|
||||
0, "port listener", 1);
|
||||
else
|
||||
c = channel_new("port listener", type, sock, sock, -1,
|
||||
buffer_size, CHAN_TCP_PACKET_DEFAULT,
|
||||
0, "port listener", 1);
|
||||
c->path = xstrdup(host);
|
||||
c->host_port = port_to_connect;
|
||||
c->listening_port = listen_port;
|
||||
|
@ -126,7 +126,7 @@ struct Channel {
|
||||
u_int local_window_max;
|
||||
u_int local_consumed;
|
||||
u_int local_maxpacket;
|
||||
u_int tcpwinsz;
|
||||
u_int tcpwinsz;
|
||||
int dynamic_window;
|
||||
int extended_usage;
|
||||
int single_connection;
|
||||
@ -165,13 +165,10 @@ struct Channel {
|
||||
/* default window/packet sizes for tcp/x11-fwd-channel */
|
||||
#define CHAN_SES_PACKET_DEFAULT (32*1024)
|
||||
#define CHAN_SES_WINDOW_DEFAULT (64*CHAN_SES_PACKET_DEFAULT)
|
||||
|
||||
#define CHAN_TCP_PACKET_DEFAULT (32*1024)
|
||||
#define CHAN_TCP_WINDOW_DEFAULT (64*CHAN_TCP_PACKET_DEFAULT)
|
||||
|
||||
#define CHAN_X11_PACKET_DEFAULT (16*1024)
|
||||
#define CHAN_X11_WINDOW_DEFAULT (4*CHAN_X11_PACKET_DEFAULT)
|
||||
|
||||
#define CHAN_HPN_MIN_WINDOW_DEFAULT (2*1024*1024)
|
||||
|
||||
/* possible input states */
|
||||
@ -302,6 +299,7 @@ void chan_write_failed(Channel *);
|
||||
void chan_obuf_empty(Channel *);
|
||||
|
||||
/* hpn handler */
|
||||
void channel_set_hpn(int, u_int);
|
||||
|
||||
void channel_set_hpn(int, u_int);
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user