Added a setting that enables saving all .o files from a given JIT expression.

This allows debugging of the JIT and other analyses of the internals of the
expression parser.  I've also added a testcase that verifies that the setting
works correctly when off and on.

llvm-svn: 282434
This commit is contained in:
Sean Callanan 2016-09-26 20:18:51 +00:00
parent d543def210
commit 5deb06eb43
7 changed files with 116 additions and 0 deletions

View File

@ -33,6 +33,7 @@ namespace llvm {
class Module;
class ExecutionEngine;
class ObjectCache;
} // namespace llvm
@ -398,6 +399,7 @@ private:
std::unique_ptr<llvm::LLVMContext> m_context_ap;
std::unique_ptr<llvm::ExecutionEngine> m_execution_engine_ap;
std::unique_ptr<llvm::ObjectCache> m_object_cache_ap;
std::unique_ptr<llvm::Module>
m_module_ap; ///< Holder for the module until it's been handed off
llvm::Module *m_module; ///< Owned by the execution engine

View File

@ -128,6 +128,8 @@ public:
bool GetEnableNotifyAboutFixIts() const;
bool GetEnableSaveObjects() const;
bool GetEnableSyntheticValue() const;
uint32_t GetMaximumNumberOfChildrenToDisplay() const;

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,57 @@
"""
Test that LLDB can emit JIT objects when the appropriate setting is enabled
"""
from __future__ import print_function
import os
import time
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
def enumerateJITFiles():
return [f for f in os.listdir(os.getcwd()) if f.startswith("jit")]
def countJITFiles():
return len(enumerateJITFiles())
def cleanJITFiles():
for j in enumerateJITFiles():
os.remove(j)
return
class SaveJITObjectsTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
def test_save_jit_objects(self):
self.build()
src_file = "main.c"
src_file_spec = lldb.SBFileSpec(src_file)
exe_path = os.path.join(os.getcwd(), "a.out")
target = self.dbg.CreateTarget(exe_path)
breakpoint = target.BreakpointCreateBySourceRegex(
"break", src_file_spec)
process = target.LaunchSimple(None, None,
self.get_process_working_directory())
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
cleanJITFiles()
frame.EvaluateExpression("(void*)malloc(0x1)")
self.assertTrue(countJITFiles() == 0,
"No files emitted with save-jit-objects=false")
self.runCmd("settings set target.save-jit-objects true")
frame.EvaluateExpression("(void*)malloc(0x1)")
jit_files_count = countJITFiles()
cleanJITFiles()
self.assertTrue(jit_files_count != 0,
"At least one file emitted with save-jit-objects=true")
process.Kill()

View File

@ -0,0 +1,14 @@
//===-- main.c --------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
int main (int argc, char const *argv[])
{
const char* foo = "Hello world"; // break here
return 0;
}

View File

@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
@ -306,6 +307,32 @@ void IRExecutionUnit::GetRunnableInfo(Error &error, lldb::addr_t &func_addr,
return;
}
class ObjectDumper : public llvm::ObjectCache {
public:
void notifyObjectCompiled(const llvm::Module *module,
llvm::MemoryBufferRef object) override {
int fd = 0;
llvm::SmallVector<char, 256> result_path;
std::string object_name_model =
"jit-object-" + module->getModuleIdentifier() + "-%%%.o";
(void)llvm::sys::fs::createUniqueFile(object_name_model, fd, result_path);
llvm::raw_fd_ostream fds(fd, true);
fds.write(object.getBufferStart(), object.getBufferSize());
}
std::unique_ptr<llvm::MemoryBuffer>
getObject(const llvm::Module *module) override {
// Return nothing - we're just abusing the object-cache mechanism to dump
// objects.
return nullptr;
}
};
if (process_sp->GetTarget().GetEnableSaveObjects()) {
m_object_cache_ap = llvm::make_unique<ObjectDumper>();
m_execution_engine_ap->setObjectCache(m_object_cache_ap.get());
}
// Make sure we see all sections, including ones that don't have
// relocations...
m_execution_engine_ap->setProcessAllSections(true);

View File

@ -3246,6 +3246,8 @@ static PropertyDefinition g_properties[] = {
nullptr, "Automatically apply fix-it hints to expressions."},
{"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr,
nullptr, "Print the fixed expression text."},
{"save-jit-objects", OptionValue::eTypeBoolean, false, false, nullptr,
nullptr, "Save intermediate object files generated by the LLVM JIT"},
{"max-children-count", OptionValue::eTypeSInt64, false, 256, nullptr,
nullptr, "Maximum number of children to expand in any level of depth."},
{"max-string-summary-length", OptionValue::eTypeSInt64, false, 1024,
@ -3370,6 +3372,7 @@ enum {
ePropertyAutoImportClangModules,
ePropertyAutoApplyFixIts,
ePropertyNotifyAboutFixIts,
ePropertySaveObjects,
ePropertyMaxChildrenCount,
ePropertyMaxSummaryLength,
ePropertyMaxMemReadSize,
@ -3788,6 +3791,12 @@ bool TargetProperties::GetEnableNotifyAboutFixIts() const {
nullptr, idx, g_properties[idx].default_uint_value != 0);
}
bool TargetProperties::GetEnableSaveObjects() const {
const uint32_t idx = ePropertySaveObjects;
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, idx, g_properties[idx].default_uint_value != 0);
}
bool TargetProperties::GetEnableSyntheticValue() const {
const uint32_t idx = ePropertyEnableSynthetic;
return m_collection_sp->GetPropertyAtIndexAsBoolean(