This commit integrates support for the LLVM MCJIT

into the mainline LLDB codebase.  MCJIT introduces
API improvements and better architectural support.

This commit adds a new subsystem, the
ProcessDataAllocator, which is responsible for
performing static data allocations on behalf of the
IR transformer.  MCJIT currently does not support
the relocations required to store the constant pool
in the same allocation as the function body, so we
allocate a heap region separately and redirect
static data references from the expression to that
heap region in a new IR modification pass.

This patch also fixes bugs in the IR
transformations that were exposed by the transition
to the MCJIT.  Finally, the patch also pulls in a
more recent revision of LLVM so that the MCJIT is
available for use.

llvm-svn: 131923
This commit is contained in:
Sean Callanan 2011-05-23 21:40:23 +00:00
parent 9dbb45b596
commit 79763a42ab
14 changed files with 730 additions and 188 deletions

View File

@ -14,6 +14,7 @@
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/ClangForward.h"
#include "lldb/Core/Error.h"
#include "lldb/Expression/IRForTarget.h"
#include <string>
#include <vector>
@ -102,6 +103,9 @@ public:
/// @param[in] exe_ctx
/// The execution context to write the function into.
///
/// @param[in] data_allocator
/// If non-NULL, he static data allocator to use for literal strings.
///
/// @param[out] const_result
/// If the result of the expression is constant, and the
/// expression has no side effects, this is set to the result of the
@ -120,6 +124,7 @@ public:
lldb::addr_t &func_addr,
lldb::addr_t &func_end,
ExecutionContext &exe_ctx,
IRForTarget::StaticDataAllocator *data_allocator,
lldb::ClangExpressionVariableSP &const_result,
bool jit_only_if_needed = false);

View File

@ -25,6 +25,8 @@
#include "lldb/Core/ClangForward.h"
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangExpressionVariable.h"
#include "lldb/Expression/IRForTarget.h"
#include "lldb/Expression/ProcessDataAllocator.h"
#include "lldb/Symbol/TaggedASTType.h"
#include "lldb/Target/Process.h"
@ -285,6 +287,7 @@ private:
//------------------------------------------------------------------
/// Populate m_cplusplus and m_objetivec based on the environment.
//------------------------------------------------------------------
void
ScanContext(ExecutionContext &exe_ctx);
@ -303,6 +306,7 @@ private:
std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.
std::auto_ptr<ClangExpressionVariableList> m_local_variables; ///< The local expression variables, if the expression is DWARF.
std::auto_ptr<StreamString> m_dwarf_opcodes; ///< The DWARF opcodes for the expression. May be NULL.
std::auto_ptr<ProcessDataAllocator> m_data_allocator; ///< The allocator that the parser uses to place strings for use by JIT-compiled code.
bool m_cplusplus; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method).
bool m_objectivec; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method).

View File

@ -24,6 +24,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Core/ClangForward.h"
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ProcessDataAllocator.h"
namespace lldb_private
{
@ -179,6 +180,7 @@ public:
private:
std::auto_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.
std::auto_ptr<ProcessDataAllocator> m_data_allocator; ///< The allocator for static data used in the expression.
std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit.
std::string m_function_name; ///< The name of the function.

View File

@ -20,12 +20,14 @@ namespace llvm {
class BasicBlock;
class CallInst;
class Constant;
class ConstantInt;
class Function;
class GlobalValue;
class GlobalVariable;
class Instruction;
class Module;
class StoreInst;
class Type;
class Value;
}
@ -50,6 +52,14 @@ namespace lldb_private {
class IRForTarget : public llvm::ModulePass
{
public:
class StaticDataAllocator {
public:
StaticDataAllocator();
virtual ~StaticDataAllocator();
virtual lldb_private::StreamString &GetStream() = 0;
virtual lldb::addr_t Allocate() = 0;
};
//------------------------------------------------------------------
/// Constructor
///
@ -68,6 +78,9 @@ public:
/// of the function, if it has no side-effects and the result can
/// be computed statically.
///
/// @param[in] data_allocator
/// If non-NULL, the static data allocator to use for literal strings.
///
/// @param[in] error_stream
/// If non-NULL, a stream on which errors can be printed.
///
@ -77,6 +90,7 @@ public:
IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map,
bool resolve_vars,
lldb::ClangExpressionVariableSP &const_result,
StaticDataAllocator *data_allocator,
lldb_private::Stream *error_stream,
const char* func_name = "$__lldb_expr");
@ -121,6 +135,19 @@ public:
getPotentialPassManagerType() const;
private:
//------------------------------------------------------------------
/// Ensures that the current function's linkage is set to external.
/// Otherwise the JIT may not return an address for it.
///
/// @param[in] llvm_function
/// The function whose linkage is to be fixed.
///
/// @return
/// True on success; false otherwise.
//------------------------------------------------------------------
bool
FixFunctionLinkage (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A function-level pass to check whether the function has side
/// effects.
@ -129,9 +156,6 @@ private:
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] llvm_function
/// The function currently being processed.
///
@ -140,8 +164,7 @@ private:
/// be determined); false otherwise.
//------------------------------------------------------------------
bool
HasSideEffects (llvm::Module &llvm_module,
llvm::Function &llvm_function);
HasSideEffects (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A function-level pass to take the generated global value
@ -154,9 +177,6 @@ private:
/// constant, assuming it can be evaluated. The result variable
/// will be reset to NULL later if the expression has side effects.
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] global
/// The global entity to search for
///
@ -164,8 +184,7 @@ private:
/// The corresponding variable declaration
//------------------------------------------------------------------
clang::NamedDecl *
DeclForGlobal (llvm::Module &llvm_module,
llvm::GlobalValue *global);
DeclForGlobal (llvm::GlobalValue *global);
//------------------------------------------------------------------
/// Set the constant result variable m_const_result to the provided
@ -191,22 +210,15 @@ private:
/// to the result of the cast. The result variable will be reset to
/// NULL latger if the expression has side effects.
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] type
/// The Clang type of the result variable.
//------------------------------------------------------------------
void
MaybeSetCastResult (llvm::Module &llvm_module,
lldb_private::TypeFromParser type);
MaybeSetCastResult (lldb_private::TypeFromParser type);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] llvm_function
/// The function currently being processed.
///
@ -214,8 +226,7 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
CreateResultVariable (llvm::Module &llvm_module,
llvm::Function &llvm_function);
CreateResultVariable (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A function-level pass to find Objective-C constant strings and
@ -225,9 +236,6 @@ private:
//------------------------------------------------------------------
/// Rewrite a single Objective-C constant string.
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] NSStr
/// The constant NSString to be transformed
///
@ -246,17 +254,13 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewriteObjCConstString (llvm::Module &llvm_module,
llvm::GlobalVariable *NSStr,
RewriteObjCConstString (llvm::GlobalVariable *NSStr,
llvm::GlobalVariable *CStr,
llvm::Instruction *FirstEntryInstruction);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] llvm_function
/// The function currently being processed.
///
@ -264,8 +268,7 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewriteObjCConstStrings (llvm::Module &llvm_module,
llvm::Function &llvm_function);
RewriteObjCConstStrings (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A basic block-level pass to find all Objective-C method calls and
@ -284,22 +287,15 @@ private:
/// @param[in] selector_load
/// The load of the statically-allocated selector.
///
/// @param[in] llvm_module
/// The module containing the load.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewriteObjCSelector (llvm::Instruction* selector_load,
llvm::Module &llvm_module);
RewriteObjCSelector (llvm::Instruction* selector_load);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] basic_block
/// The basic block currently being processed.
///
@ -307,8 +303,7 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewriteObjCSelectors (llvm::Module &llvm_module,
llvm::BasicBlock &basic_block);
RewriteObjCSelectors (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// A basic block-level pass to find all newly-declared persistent
@ -327,28 +322,20 @@ private:
/// @param[in] persistent_alloc
/// The allocation of the persistent variable.
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RewritePersistentAlloc (llvm::Instruction *persistent_alloc,
llvm::Module &llvm_module);
RewritePersistentAlloc (llvm::Instruction *persistent_alloc);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] basic_block
/// The basic block currently being processed.
//------------------------------------------------------------------
bool
RewritePersistentAllocs (llvm::Module &llvm_module,
llvm::BasicBlock &basic_block);
RewritePersistentAllocs (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// A function-level pass to find all external variables and functions
@ -361,9 +348,6 @@ private:
//------------------------------------------------------------------
/// Handle a single externally-defined variable
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] value
/// The variable.
///
@ -371,15 +355,11 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
MaybeHandleVariable (llvm::Module &llvm_module,
llvm::Value *value);
MaybeHandleVariable (llvm::Value *value);
//------------------------------------------------------------------
/// Handle a single externally-defined symbol
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] symbol
/// The symbol.
///
@ -387,15 +367,11 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
HandleSymbol (llvm::Module &llvm_module,
llvm::Value *symbol);
HandleSymbol (llvm::Value *symbol);
//------------------------------------------------------------------
/// Handle all the arguments to a function call
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] C
/// The call instruction.
///
@ -403,15 +379,11 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
MaybeHandleCallArguments (llvm::Module &llvm_module,
llvm::CallInst *call_inst);
MaybeHandleCallArguments (llvm::CallInst *call_inst);
//------------------------------------------------------------------
/// Handle a single external function call
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] C
/// The call instruction.
///
@ -419,15 +391,11 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
MaybeHandleCall (llvm::Module &llvm_module,
llvm::CallInst *C);
MaybeHandleCall (llvm::CallInst *C);
//------------------------------------------------------------------
/// Resolve calls to external functions
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] basic_block
/// The basic block currently being processed.
///
@ -435,15 +403,11 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ResolveCalls (llvm::Module &llvm_module,
llvm::BasicBlock &basic_block);
ResolveCalls (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] basic_block
/// The function currently being processed.
///
@ -451,8 +415,7 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ResolveExternals (llvm::Module &llvm_module,
llvm::Function &llvm_function);
ResolveExternals (llvm::Function &llvm_function);
//------------------------------------------------------------------
/// A basic block-level pass to excise guard variables from the code.
@ -462,10 +425,16 @@ private:
//------------------------------------------------------------------
//------------------------------------------------------------------
/// The top-level pass implementation
/// Rewrite a load to a guard variable to return constant 0.
///
/// @param[in] llvm_module
/// The module currently being processed.
/// @param[in] guard_load
/// The load instruction to zero out.
//------------------------------------------------------------------
void
TurnGuardLoadIntoZero(llvm::Instruction* guard_load);
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] basic_block
/// The basic block currently being processed.
@ -474,8 +443,39 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
RemoveGuards (llvm::Module &llvm_module,
llvm::BasicBlock &basic_block);
RemoveGuards (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// A module-level pass to allocate all string literals in a separate
/// allocation and redirect references to them.
//------------------------------------------------------------------
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ReplaceStrings ();
//------------------------------------------------------------------
/// A basick block-level pass to find all literals that will be
/// allocated as statics by the JIT (in contrast to the Strings,
/// which already are statics) and synthesize loads for them.
//------------------------------------------------------------------
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] basic_block
/// The basic block currently being processed.
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ReplaceStaticLiterals (llvm::BasicBlock &basic_block);
//------------------------------------------------------------------
/// A function-level pass to make all external variable references
@ -487,9 +487,6 @@ private:
//------------------------------------------------------------------
/// The top-level pass implementation
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] llvm_function
/// The function currently being processed.
///
@ -497,14 +494,15 @@ private:
/// True on success; false otherwise
//------------------------------------------------------------------
bool
ReplaceVariables (llvm::Module &llvm_module,
llvm::Function &llvm_function);
ReplaceVariables (llvm::Function &llvm_function);
/// Flags
bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved
std::string m_func_name; ///< The name of the function to translate
lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...)
llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet.
lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls
StaticDataAllocator *m_data_allocator; ///< If non-NULL, the allocator to use for constant strings
llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type
llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type
lldb::ClangExpressionVariableSP &m_const_result; ///< This value should be set to the return value of the expression if it is constant and the expression has no side effects
@ -514,7 +512,8 @@ private:
llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL.
bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult)
private:
llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final location of the static allocation.
//------------------------------------------------------------------
/// UnfoldConstant operates on a constant [Old] which has just been
/// replaced with a value [New]. We assume that new_value has
@ -529,9 +528,6 @@ private:
/// FirstEntryInstruction. These instructions replace the constant
/// uses, so UnfoldConstant calls itself recursively for those.
///
/// @param[in] llvm_module
/// The module currently being processed.
///
/// @param[in] llvm_function
/// The function currently being processed.
///
@ -542,6 +538,38 @@ private:
UnfoldConstant (llvm::Constant *old_constant,
llvm::Value *new_constant,
llvm::Instruction *first_entry_inst);
//------------------------------------------------------------------
/// Construct a reference to m_reloc_placeholder with a given type
/// and offset. This typically happens after inserting data into
/// m_data_allocator.
///
/// @param[in] type
/// The type of the value being loaded.
///
/// @param[in] offset
/// The offset of the value from the base of m_data_allocator.
///
/// @return
/// The Constant for the reference, usually a ConstantExpr.
//------------------------------------------------------------------
llvm::Constant *
BuildRelocation(const llvm::Type *type,
uint64_t offset);
//------------------------------------------------------------------
/// Commit the allocation in m_data_allocator and use its final
/// location to replace m_reloc_placeholder.
///
/// @param[in] module
/// The module that m_data_allocator resides in
///
/// @return
/// True on success; false otherwise
//------------------------------------------------------------------
bool
CompleteDataAllocation ();
};
#endif

View File

@ -0,0 +1,74 @@
//===-- ProcessDataAllocator.h ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ProcessDataAllocator_h_
#define liblldb_ProcessDataAllocator_h_
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private.h"
#include "lldb/Expression/IRForTarget.h"
#include "lldb/Target/Process.h"
namespace lldb_private
{
class ProcessDataAllocator : public IRForTarget::StaticDataAllocator {
public:
ProcessDataAllocator(Process &process) :
IRForTarget::StaticDataAllocator(),
m_process(process),
m_stream_string(StreamString::eBinary, process.GetAddressByteSize(), process.GetByteOrder()),
m_allocation(NULL)
{
}
~ProcessDataAllocator()
{
if (m_allocation)
m_process.DeallocateMemory(m_allocation);
}
lldb_private::StreamString &GetStream()
{
return m_stream_string;
}
lldb::addr_t Allocate()
{
Error err;
if (m_allocation)
m_process.DeallocateMemory(m_allocation);
m_allocation = NULL;
m_allocation = m_process.AllocateMemory(m_stream_string.GetSize(), lldb::ePermissionsReadable | lldb::ePermissionsWritable, err);
if (!err.Success())
return NULL;
if (m_allocation)
m_process.WriteMemory(m_allocation, m_stream_string.GetData(), m_stream_string.GetSize(), err);
if (!err.Success())
return NULL;
return m_allocation;
}
void Dump(lldb_private::Stream &stream);
private:
Process &m_process;
StreamString m_stream_string;
lldb::addr_t m_allocation;
};
} // namespace lldb_private
#endif

View File

@ -393,6 +393,8 @@
26F5C32D10F3DFDD009D5894 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32B10F3DFDD009D5894 /* libtermcap.dylib */; };
26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
49C850771384A02F007DB519 /* ProcessDataAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 49C850761384A02F007DB519 /* ProcessDataAllocator.h */; };
49C8507C1384A786007DB519 /* ProcessDataAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */; };
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; };
4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */; };
4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
@ -1073,6 +1075,8 @@
49A8A39F11D568A300AD3B68 /* ASTResultSynthesizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ASTResultSynthesizer.cpp; path = source/Expression/ASTResultSynthesizer.cpp; sourceTree = "<group>"; };
49A8A3A311D568BF00AD3B68 /* ASTResultSynthesizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTResultSynthesizer.h; path = include/lldb/Expression/ASTResultSynthesizer.h; sourceTree = "<group>"; };
49BB309511F79450001A4197 /* TaggedASTType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TaggedASTType.h; path = include/lldb/Symbol/TaggedASTType.h; sourceTree = "<group>"; };
49C850761384A02F007DB519 /* ProcessDataAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProcessDataAllocator.h; path = include/lldb/Expression/ProcessDataAllocator.h; sourceTree = "<group>"; };
49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProcessDataAllocator.cpp; path = source/Expression/ProcessDataAllocator.cpp; sourceTree = "<group>"; };
49CF9829122C70BD007A0B96 /* IRDynamicChecks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IRDynamicChecks.cpp; path = source/Expression/IRDynamicChecks.cpp; sourceTree = "<group>"; };
49CF9833122C718B007A0B96 /* IRDynamicChecks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IRDynamicChecks.h; path = include/lldb/Expression/IRDynamicChecks.h; sourceTree = "<group>"; };
49D4FE821210B5FB00CDB854 /* ClangPersistentVariables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangPersistentVariables.h; path = include/lldb/Expression/ClangPersistentVariables.h; sourceTree = "<group>"; };
@ -2155,6 +2159,8 @@
49DA742F11DE6A5A006AEF7E /* IRToDWARF.cpp */,
4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */,
4C98D3DB118FB96F00E575D0 /* RecordingMemoryManager.cpp */,
49C850761384A02F007DB519 /* ProcessDataAllocator.h */,
49C850781384A0CA007DB519 /* ProcessDataAllocator.cpp */,
);
name = Expression;
sourceTree = "<group>";
@ -2605,6 +2611,7 @@
9A357583116CFDEE00E8ED2F /* SBValueList.h in Headers */,
26D265A2136B40EE002EEE45 /* SharingPtr.h in Headers */,
26D265BC136B4269002EEE45 /* lldb-public.h in Headers */,
49C850771384A02F007DB519 /* ProcessDataAllocator.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2894,6 +2901,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
49C8507C1384A786007DB519 /* ProcessDataAllocator.cpp in Sources */,
2689FFDA13353D9D00698AC0 /* lldb.cpp in Sources */,
2689FFDB13353DA300698AC0 /* lldb-log.cpp in Sources */,
2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */,

View File

@ -26,7 +26,7 @@ our @llvm_clang_slices; # paths to the single architecture static libraries (arc
our $llvm_configuration = $ENV{LLVM_CONFIGURATION};
our $llvm_revision = "131389";
our $llvm_revision = "131657";
our $llvm_source_dir = "$ENV{SRCROOT}";
our @archs = split (/\s+/, $ENV{ARCHS});
@ -70,6 +70,9 @@ our @archive_files = (
"$llvm_configuration/lib/libLLVMMC.a",
"$llvm_configuration/lib/libLLVMMCParser.a",
"$llvm_configuration/lib/libLLVMMCDisassembler.a",
"$llvm_configuration/lib/libLLVMMCJIT.a",
"$llvm_configuration/lib/libLLVMObject.a",
"$llvm_configuration/lib/libLLVMRuntimeDyld.a",
"$llvm_configuration/lib/libLLVMScalarOpts.a",
"$llvm_configuration/lib/libLLVMSelectionDAG.a",
"$llvm_configuration/lib/libLLVMSupport.a",

View File

@ -97,5 +97,5 @@ if (@ARGV == 4)
else
{
print "USAGE\n\tcheckpoint-llvm.pl <llvm-sources> <llvm-build> <lldb-build> <llvm-zip>\n\n";
print "EXAMPLE\n\tcd lldb\n\t./scripts/checkpoint-llvm.pl llvm build/lldb.build/BuildAndIntegration/lldb-core.build/DerivedSources/llvm.build build/BuildAndIntegration llvm.zip\n";
print "EXAMPLE\n\tcd lldb\n\t./scripts/checkpoint-llvm.pl llvm build/llvm build/BuildAndIntegration llvm.zip\n";
}

View File

@ -19,7 +19,6 @@
#include "lldb/Expression/ClangExpression.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Expression/IRForTarget.h"
#include "lldb/Expression/IRToDWARF.h"
#include "lldb/Expression/RecordingMemoryManager.h"
#include "lldb/Target/ExecutionContext.h"
@ -53,7 +52,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#define USE_STANDARD_JIT
//#define USE_STANDARD_JIT
#if defined (USE_STANDARD_JIT)
#include "llvm/ExecutionEngine/JIT.h"
#else
@ -472,6 +471,7 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_allocation_addr,
lldb::addr_t &func_addr,
lldb::addr_t &func_end,
ExecutionContext &exe_ctx,
IRForTarget::StaticDataAllocator *data_allocator,
lldb::ClangExpressionVariableSP &const_result,
bool jit_only_if_needed)
{
@ -519,6 +519,7 @@ ClangExpressionParser::MakeJIT (lldb::addr_t &func_allocation_addr,
IRForTarget ir_for_target(decl_map,
m_expr.NeedsVariableResolution(),
const_result,
data_allocator,
error_stream,
function_name.c_str());

View File

@ -253,7 +253,7 @@ ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
lldb::ClangExpressionVariableSP const_result;
Error jit_error (m_parser->MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, const_result));
Error jit_error (m_parser->MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, NULL, const_result));
if (!jit_error.Success())
return false;

View File

@ -1,4 +1,4 @@
//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===//
//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -284,7 +284,17 @@ ClangUserExpression::Parse (Stream &error_stream,
m_dwarf_opcodes.reset();
Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_const_result, true);
m_data_allocator.reset(new ProcessDataAllocator(*exe_ctx.process));
Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_data_allocator.get(), m_const_result, true);
if (log)
{
StreamString dump_string;
m_data_allocator->Dump(dump_string);
log->Printf("Data buffer contents:\n%s", dump_string.GetString().c_str());
}
m_expr_decl_map->DidParse();

View File

@ -16,6 +16,7 @@
// C++ Includes
#include "lldb/Core/ConstString.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
@ -64,6 +65,8 @@ bool
ClangUtilityFunction::Install (Stream &error_stream,
ExecutionContext &exe_ctx)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
{
error_stream.PutCString("error: already installed\n");
@ -81,6 +84,14 @@ ClangUtilityFunction::Install (Stream &error_stream,
error_stream.PutCString ("error: invalid target\n");
return false;
}
Process *process = exe_ctx.process;
if (!process)
{
error_stream.PutCString ("error: invalid process\n");
return false;
}
//////////////////////////
// Parse the expression
@ -90,6 +101,8 @@ ClangUtilityFunction::Install (Stream &error_stream,
m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory));
m_data_allocator.reset(new ProcessDataAllocator(*exe_ctx.process));
m_expr_decl_map->WillParse(exe_ctx);
ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this);
@ -110,8 +123,17 @@ ClangUtilityFunction::Install (Stream &error_stream,
//
lldb::ClangExpressionVariableSP const_result;
Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, const_result);
Error jit_error = parser.MakeJIT (m_jit_alloc, m_jit_start_addr, m_jit_end_addr, exe_ctx, m_data_allocator.get(), const_result);
if (log)
{
StreamString dump_string;
m_data_allocator->Dump(dump_string);
log->Printf("Data buffer contents:\n%s", dump_string.GetString().c_str());
}
if (exe_ctx.process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
m_jit_process_sp = exe_ctx.process->GetSP();

View File

@ -26,6 +26,7 @@
#include "lldb/Core/Scalar.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Host/Endian.h"
#include "lldb/Symbol/ClangASTContext.h"
#include <map>
@ -34,22 +35,34 @@ using namespace llvm;
static char ID;
IRForTarget::StaticDataAllocator::StaticDataAllocator()
{
}
IRForTarget::StaticDataAllocator::~StaticDataAllocator()
{
}
IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
bool resolve_vars,
lldb::ClangExpressionVariableSP &const_result,
StaticDataAllocator *data_allocator,
lldb_private::Stream *error_stream,
const char *func_name) :
ModulePass(ID),
m_resolve_vars(resolve_vars),
m_func_name(func_name),
m_decl_map(decl_map),
m_module(NULL),
m_CFStringCreateWithBytes(NULL),
m_sel_registerName(NULL),
m_error_stream(error_stream),
m_has_side_effects(false),
m_result_store(NULL),
m_result_is_pointer(false),
m_const_result(const_result)
m_const_result(const_result),
m_data_allocator(data_allocator),
m_reloc_placeholder(NULL)
{
}
@ -83,9 +96,20 @@ IRForTarget::~IRForTarget()
{
}
bool
IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
llvm_function.setLinkage(GlobalValue::ExternalLinkage);
std::string name = llvm_function.getNameStr();
return true;
}
bool
IRForTarget::HasSideEffects (llvm::Module &llvm_module,
llvm::Function &llvm_function)
IRForTarget::HasSideEffects (llvm::Function &llvm_function)
{
llvm::Function::iterator bbi;
BasicBlock::iterator ii;
@ -146,11 +170,11 @@ IRForTarget::HasSideEffects (llvm::Module &llvm_module,
}
clang::NamedDecl *
IRForTarget::DeclForGlobal (llvm::Module &module, GlobalValue *global_val)
IRForTarget::DeclForGlobal (GlobalValue *global_val)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
NamedMDNode *named_metadata = module.getNamedMetadata("clang.global.decl.ptrs");
NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
if (!named_metadata)
return NULL;
@ -209,7 +233,7 @@ IRForTarget::MaybeSetConstantResult (llvm::Constant *initializer,
}
void
IRForTarget::MaybeSetCastResult (llvm::Module &llvm_module, lldb_private::TypeFromParser type)
IRForTarget::MaybeSetCastResult (lldb_private::TypeFromParser type)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -253,7 +277,7 @@ IRForTarget::MaybeSetCastResult (llvm::Module &llvm_module, lldb_private::TypeFr
if (!loaded_global)
return;
clang::NamedDecl *loaded_decl = DeclForGlobal(llvm_module, loaded_global);
clang::NamedDecl *loaded_decl = DeclForGlobal(loaded_global);
if (!loaded_decl)
return;
@ -275,7 +299,7 @@ IRForTarget::MaybeSetCastResult (llvm::Module &llvm_module, lldb_private::TypeFr
}
bool
IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &llvm_function)
IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -284,7 +308,7 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
// Find the result variable. If it doesn't exist, we can give up right here.
ValueSymbolTable& value_symbol_table = llvm_module.getValueSymbolTable();
ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
const char *result_name = NULL;
@ -320,7 +344,7 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
if (log)
log->Printf("Result name: \"%s\"", result_name);
Value *result_value = llvm_module.getNamedValue(result_name);
Value *result_value = m_module->getNamedValue(result_name);
if (!result_value)
{
@ -349,7 +373,7 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
return false;
}
clang::NamedDecl *result_decl = DeclForGlobal (llvm_module, result_global);
clang::NamedDecl *result_decl = DeclForGlobal (result_global);
if (!result_decl)
{
if (log)
@ -433,7 +457,7 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
// Construct a new result global and set up its metadata
GlobalVariable *new_result_global = new GlobalVariable(llvm_module,
GlobalVariable *new_result_global = new GlobalVariable((*m_module),
result_global->getType()->getElementType(),
false, /* not constant */
GlobalValue::ExternalLinkage,
@ -447,7 +471,7 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
// ClangExpressionDeclMap::DoMaterialize, and the name of the variable is
// fixed up.
ConstantInt *new_constant_int = ConstantInt::get(llvm::Type::getInt64Ty(llvm_module.getContext()),
ConstantInt *new_constant_int = ConstantInt::get(llvm::Type::getInt64Ty(m_module->getContext()),
reinterpret_cast<uint64_t>(result_decl),
false);
@ -457,8 +481,8 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
ArrayRef<Value*> value_ref(values, 2);
MDNode *persistent_global_md = MDNode::get(llvm_module.getContext(), value_ref);
NamedMDNode *named_metadata = llvm_module.getNamedMetadata("clang.global.decl.ptrs");
MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
named_metadata->addOperand(persistent_global_md);
if (log)
@ -511,7 +535,7 @@ IRForTarget::CreateResultVariable (llvm::Module &llvm_module, llvm::Function &ll
{
if (!m_has_side_effects && lldb_private::ClangASTContext::IsPointerType (result_decl_type.GetOpaqueQualType()))
{
MaybeSetCastResult (llvm_module, result_decl_type);
MaybeSetCastResult (result_decl_type);
}
result_global->replaceAllUsesWith(new_result_global);
@ -550,18 +574,19 @@ static void DebugUsers(lldb::LogSP &log, Value *value, uint8_t depth)
}
bool
IRForTarget::RewriteObjCConstString (llvm::Module &llvm_module,
llvm::GlobalVariable *ns_str,
IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
llvm::GlobalVariable *cstr,
Instruction *FirstEntryInstruction)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
const Type *i8_ptr_ty = Type::getInt8PtrTy(llvm_module.getContext());
const IntegerType *intptr_ty = Type::getIntNTy(llvm_module.getContext(),
(llvm_module.getPointerSize() == Module::Pointer64) ? 64 : 32);
const Type *i32_ty = Type::getInt32Ty(llvm_module.getContext());
const Type *i8_ty = Type::getInt8Ty(llvm_module.getContext());
const Type *ns_str_ty = ns_str->getType();
const Type *i8_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
const IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
const Type *i32_ty = Type::getInt32Ty(m_module->getContext());
const Type *i8_ty = Type::getInt8Ty(m_module->getContext());
if (!m_CFStringCreateWithBytes)
{
@ -608,7 +633,7 @@ IRForTarget::RewriteObjCConstString (llvm::Module &llvm_module,
CFSCWB_arg_types.push_back(intptr_ty);
CFSCWB_arg_types.push_back(i32_ty);
CFSCWB_arg_types.push_back(i8_ty);
llvm::Type *CFSCWB_ty = FunctionType::get(i8_ptr_ty, CFSCWB_arg_types, false);
llvm::Type *CFSCWB_ty = FunctionType::get(ns_str_ty, CFSCWB_arg_types, false);
// Build the constant containing the pointer to the function
PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty);
@ -660,11 +685,11 @@ IRForTarget::RewriteObjCConstString (llvm::Module &llvm_module,
}
bool
IRForTarget::RewriteObjCConstStrings(Module &llvm_module, Function &llvm_function)
IRForTarget::RewriteObjCConstStrings(Function &llvm_function)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
ValueSymbolTable& value_symbol_table = llvm_module.getValueSymbolTable();
ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
BasicBlock &entry_block(llvm_function.getEntryBlock());
Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg());
@ -845,7 +870,7 @@ IRForTarget::RewriteObjCConstStrings(Module &llvm_module, Function &llvm_functio
if (!cstr_array)
cstr_global = NULL;
if (!RewriteObjCConstString(llvm_module, nsstring_global, cstr_global, FirstEntryInstruction))
if (!RewriteObjCConstString(nsstring_global, cstr_global, FirstEntryInstruction))
{
if (log)
log->PutCString("Error rewriting the constant string");
@ -897,7 +922,7 @@ static bool IsObjCSelectorRef (Value *value)
// This function does not report errors; its callers are responsible.
bool
IRForTarget::RewriteObjCSelector (Instruction* selector_load, Module &llvm_module)
IRForTarget::RewriteObjCSelector (Instruction* selector_load)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -970,17 +995,17 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load, Module &llvm_modul
// Build the function type: struct objc_selector *sel_registerName(uint8_t*)
// The below code would be "more correct," but in actuality what's required is uint8_t*
//Type *sel_type = StructType::get(llvm_module.getContext());
//Type *sel_type = StructType::get(m_module->getContext());
//Type *sel_ptr_type = PointerType::getUnqual(sel_type);
const Type *sel_ptr_type = Type::getInt8PtrTy(llvm_module.getContext());
const Type *sel_ptr_type = Type::getInt8PtrTy(m_module->getContext());
std::vector <const Type *> srN_arg_types;
srN_arg_types.push_back(Type::getInt8PtrTy(llvm_module.getContext()));
srN_arg_types.push_back(Type::getInt8PtrTy(m_module->getContext()));
llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false);
// Build the constant containing the pointer to the function
const IntegerType *intptr_ty = Type::getIntNTy(llvm_module.getContext(),
(llvm_module.getPointerSize() == Module::Pointer64) ? 64 : 32);
const IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
Constant *srN_addr_int = ConstantInt::get(intptr_ty, sel_registerName_addr, false);
m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty);
@ -988,7 +1013,7 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load, Module &llvm_modul
SmallVector <Value*, 1> srN_arguments;
Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(llvm_module.getContext()));
Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(m_module->getContext()));
srN_arguments.push_back(omvn_pointer);
@ -1008,7 +1033,7 @@ IRForTarget::RewriteObjCSelector (Instruction* selector_load, Module &llvm_modul
}
bool
IRForTarget::RewriteObjCSelectors (Module &llvm_module, BasicBlock &basic_block)
IRForTarget::RewriteObjCSelectors (BasicBlock &basic_block)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -1036,7 +1061,7 @@ IRForTarget::RewriteObjCSelectors (Module &llvm_module, BasicBlock &basic_block)
iter != selector_loads.end();
++iter)
{
if (!RewriteObjCSelector(*iter, llvm_module))
if (!RewriteObjCSelector(*iter))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't change a static reference to an Objective-C selector to a dynamic reference\n");
@ -1053,8 +1078,7 @@ IRForTarget::RewriteObjCSelectors (Module &llvm_module, BasicBlock &basic_block)
// This function does not report errors; its callers are responsible.
bool
IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc,
llvm::Module &llvm_module)
IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -1084,7 +1108,7 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc,
if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type, false, false))
return false;
GlobalVariable *persistent_global = new GlobalVariable(llvm_module,
GlobalVariable *persistent_global = new GlobalVariable((*m_module),
alloc->getType(),
false, /* not constant */
GlobalValue::ExternalLinkage,
@ -1094,7 +1118,7 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc,
// What we're going to do here is make believe this was a regular old external
// variable. That means we need to make the metadata valid.
NamedMDNode *named_metadata = llvm_module.getNamedMetadata("clang.global.decl.ptrs");
NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
llvm::Value* values[2];
values[0] = persistent_global;
@ -1102,7 +1126,7 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc,
ArrayRef<llvm::Value*> value_ref(values, 2);
MDNode *persistent_global_md = MDNode::get(llvm_module.getContext(), value_ref);
MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
named_metadata->addOperand(persistent_global_md);
// Now, since the variable is a pointer variable, we will drop in a load of that
@ -1122,7 +1146,7 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc,
}
bool
IRForTarget::RewritePersistentAllocs(llvm::Module &llvm_module, llvm::BasicBlock &basic_block)
IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block)
{
if (!m_resolve_vars)
return true;
@ -1171,7 +1195,7 @@ IRForTarget::RewritePersistentAllocs(llvm::Module &llvm_module, llvm::BasicBlock
iter != pvar_allocs.end();
++iter)
{
if (!RewritePersistentAlloc(*iter, llvm_module))
if (!RewritePersistentAlloc(*iter))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite the creation of a persistent variable\n");
@ -1188,7 +1212,7 @@ IRForTarget::RewritePersistentAllocs(llvm::Module &llvm_module, llvm::BasicBlock
// This function does not report errors; its callers are responsible.
bool
IRForTarget::MaybeHandleVariable (Module &llvm_module, Value *llvm_value_ptr)
IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -1204,13 +1228,13 @@ IRForTarget::MaybeHandleVariable (Module &llvm_module, Value *llvm_value_ptr)
case Instruction::GetElementPtr:
case Instruction::BitCast:
Value *s = constant_expr->getOperand(0);
if (!MaybeHandleVariable(llvm_module, s))
if (!MaybeHandleVariable(s))
return false;
}
}
else if (GlobalVariable *global_variable = dyn_cast<GlobalVariable>(llvm_value_ptr))
{
clang::NamedDecl *named_decl = DeclForGlobal(llvm_module, global_variable);
clang::NamedDecl *named_decl = DeclForGlobal(global_variable);
if (!named_decl)
{
@ -1297,8 +1321,7 @@ IRForTarget::MaybeHandleVariable (Module &llvm_module, Value *llvm_value_ptr)
// This function does not report errors; its callers are responsible.
bool
IRForTarget::HandleSymbol (Module &llvm_module,
Value *symbol)
IRForTarget::HandleSymbol (Value *symbol)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -1319,8 +1342,8 @@ IRForTarget::HandleSymbol (Module &llvm_module,
const Type *symbol_type = symbol->getType();
const IntegerType *intptr_ty = Type::getIntNTy(llvm_module.getContext(),
(llvm_module.getPointerSize() == Module::Pointer64) ? 64 : 32);
const IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
Constant *symbol_addr_int = ConstantInt::get(intptr_ty, symbol_addr, false);
@ -1335,7 +1358,7 @@ IRForTarget::HandleSymbol (Module &llvm_module,
}
bool
IRForTarget::MaybeHandleCallArguments (Module &llvm_module, CallInst *Old)
IRForTarget::MaybeHandleCallArguments (CallInst *Old)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -1345,7 +1368,7 @@ IRForTarget::MaybeHandleCallArguments (Module &llvm_module, CallInst *Old)
for (unsigned op_index = 0, num_ops = Old->getNumArgOperands();
op_index < num_ops;
++op_index)
if (!MaybeHandleVariable(llvm_module, Old->getArgOperand(op_index))) // conservatively believe that this is a store
if (!MaybeHandleVariable(Old->getArgOperand(op_index))) // conservatively believe that this is a store
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite one of the arguments of a function call.\n");
@ -1357,7 +1380,7 @@ IRForTarget::MaybeHandleCallArguments (Module &llvm_module, CallInst *Old)
}
bool
IRForTarget::MaybeHandleCall (Module &llvm_module, CallInst *llvm_call_inst)
IRForTarget::MaybeHandleCall (CallInst *llvm_call_inst)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
@ -1431,7 +1454,7 @@ IRForTarget::MaybeHandleCall (Module &llvm_module, CallInst *llvm_call_inst)
str.SetCStringWithLength (fun->getName().data(), fun->getName().size());
}
clang::NamedDecl *fun_decl = DeclForGlobal (llvm_module, fun);
clang::NamedDecl *fun_decl = DeclForGlobal (fun);
lldb::addr_t fun_addr = LLDB_INVALID_ADDRESS;
Value **fun_value_ptr = NULL;
@ -1474,8 +1497,8 @@ IRForTarget::MaybeHandleCall (Module &llvm_module, CallInst *llvm_call_inst)
if (!fun_value_ptr || !*fun_value_ptr)
{
const IntegerType *intptr_ty = Type::getIntNTy(llvm_module.getContext(),
(llvm_module.getPointerSize() == Module::Pointer64) ? 64 : 32);
const IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
const FunctionType *fun_ty = fun->getFunctionType();
PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
Constant *fun_addr_int = ConstantInt::get(intptr_ty, fun_addr, false);
@ -1490,13 +1513,13 @@ IRForTarget::MaybeHandleCall (Module &llvm_module, CallInst *llvm_call_inst)
llvm_call_inst->setCalledFunction(fun_addr_ptr);
ConstantArray *func_name = (ConstantArray*)ConstantArray::get(llvm_module.getContext(), str.GetCString());
ConstantArray *func_name = (ConstantArray*)ConstantArray::get(m_module->getContext(), str.GetCString());
Value *values[1];
values[0] = func_name;
ArrayRef<Value*> value_ref(values, 1);
MDNode *func_metadata = MDNode::get(llvm_module.getContext(), value_ref);
MDNode *func_metadata = MDNode::get(m_module->getContext(), value_ref);
llvm_call_inst->setMetadata("lldb.call.realName", func_metadata);
@ -1507,7 +1530,7 @@ IRForTarget::MaybeHandleCall (Module &llvm_module, CallInst *llvm_call_inst)
}
bool
IRForTarget::ResolveCalls(Module &llvm_module, BasicBlock &basic_block)
IRForTarget::ResolveCalls(BasicBlock &basic_block)
{
/////////////////////////////////////////////////////////////////////////
// Prepare the current basic block for execution in the remote process
@ -1524,11 +1547,11 @@ IRForTarget::ResolveCalls(Module &llvm_module, BasicBlock &basic_block)
CallInst *call = dyn_cast<CallInst>(&inst);
// MaybeHandleCall handles error reporting; we are silent here
if (call && !MaybeHandleCall(llvm_module, call))
if (call && !MaybeHandleCall(call))
return false;
// MaybeHandleCallArguments handles error reporting; we are silent here
if (call && !MaybeHandleCallArguments(llvm_module, call))
if (call && !MaybeHandleCallArguments(call))
return false;
}
@ -1536,22 +1559,22 @@ IRForTarget::ResolveCalls(Module &llvm_module, BasicBlock &basic_block)
}
bool
IRForTarget::ResolveExternals (Module &llvm_module, Function &llvm_function)
IRForTarget::ResolveExternals (Function &llvm_function)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
for (Module::global_iterator global = llvm_module.global_begin(), end = llvm_module.global_end();
for (Module::global_iterator global = m_module->global_begin(), end = m_module->global_end();
global != end;
++global)
{
if (log)
log->Printf("Examining %s, DeclForGlobalValue returns %p",
(*global).getName().str().c_str(),
DeclForGlobal(llvm_module, global));
DeclForGlobal(global));
if ((*global).getName().str().find("OBJC_IVAR") == 0)
{
if (!HandleSymbol(llvm_module, global))
if (!HandleSymbol(global))
{
if (m_error_stream)
m_error_stream->Printf("Error [IRForTarget]: Couldn't find Objective-C indirect ivar symbol %s\n", (*global).getName().str().c_str());
@ -1559,9 +1582,9 @@ IRForTarget::ResolveExternals (Module &llvm_module, Function &llvm_function)
return false;
}
}
else if (DeclForGlobal(llvm_module, global))
else if (DeclForGlobal(global))
{
if (!MaybeHandleVariable (llvm_module, global))
if (!MaybeHandleVariable (global))
{
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite external variable %s\n", (*global).getName().str().c_str());
@ -1574,6 +1597,216 @@ IRForTarget::ResolveExternals (Module &llvm_module, Function &llvm_function)
return true;
}
bool
IRForTarget::ReplaceStrings ()
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (!m_data_allocator)
return true; // hope for the best; some clients may not want static allocation!
typedef std::map <GlobalVariable *, size_t> OffsetsTy;
OffsetsTy offsets;
for (Module::global_iterator gi = m_module->global_begin(), ge = m_module->global_end();
gi != ge;
++gi)
{
GlobalVariable *gv = gi;
if (!gv->hasInitializer())
continue;
Constant *gc = gv->getInitializer();
ConstantArray *gc_array = dyn_cast<ConstantArray>(gc);
if (!gc_array)
continue;
if (!gc_array->isCString())
continue;
if (log)
log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str());
std::string str = gc_array->getAsString();
offsets[gv] = m_data_allocator->GetStream().GetSize();
m_data_allocator->GetStream().Write(str.c_str(), str.length() + 1);
}
const Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end();
oi != oe;
++oi)
{
GlobalVariable *gv = oi->first;
size_t offset = oi->second;
Constant *new_initializer = BuildRelocation(char_ptr_ty, offset);
if (log)
log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str());
for (GlobalVariable::use_iterator ui = gv->use_begin(), ue = gv->use_end();
ui != ue;
++ui)
{
if (log)
log->Printf("Found use %s", PrintValue(*ui).c_str());
ConstantExpr *const_expr = dyn_cast<ConstantExpr>(*ui);
StoreInst *store_inst = dyn_cast<StoreInst>(*ui);
if (const_expr)
{
if (const_expr->getOpcode() != Instruction::GetElementPtr)
{
if (log)
log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str());
return false;
}
const_expr->replaceAllUsesWith(new_initializer);
}
else if (store_inst)
{
Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType());
store_inst->setOperand(0, bit_cast);
}
else
{
if (log)
log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str());
return false;
}
}
gv->eraseFromParent();
}
return true;
}
bool
IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (!m_data_allocator)
return true;
typedef SmallVector <Value*, 2> ConstantList;
typedef SmallVector <llvm::Instruction*, 2> UserList;
typedef ConstantList::iterator ConstantIterator;
typedef UserList::iterator UserIterator;
ConstantList static_constants;
UserList static_users;
for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end();
ii != ie;
++ii)
{
llvm::Instruction &inst = *ii;
for (Instruction::op_iterator oi = inst.op_begin(), oe = inst.op_end();
oi != oe;
++oi)
{
Value *operand_val = oi->get();
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
if (operand_constant_fp && operand_constant_fp->getType()->isX86_FP80Ty())
{
static_constants.push_back(operand_val);
static_users.push_back(ii);
}
}
}
ConstantIterator constant_iter;
UserIterator user_iter;
const Type *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
for (constant_iter = static_constants.begin(), user_iter = static_users.begin();
constant_iter != static_constants.end();
++constant_iter, ++user_iter)
{
Value *operand_val = *constant_iter;
llvm::Instruction *inst = *user_iter;
ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
if (operand_constant_fp)
{
APFloat operand_apfloat = operand_constant_fp->getValueAPF();
APInt operand_apint = operand_apfloat.bitcastToAPInt();
const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData();
size_t operand_data_size = operand_apint.getBitWidth() / 8;
if (log)
{
std::string s;
raw_string_ostream ss(s);
for (size_t index = 0;
index < operand_data_size;
++index)
{
ss << (uint32_t)operand_raw_data[index];
ss << " ";
}
ss.flush();
log->Printf("Found ConstantFP with size %d and raw data %s", operand_data_size, s.c_str());
}
lldb_private::DataBufferHeap data(operand_data_size, 0);
if (lldb::endian::InlHostByteOrder() != m_data_allocator->GetStream().GetByteOrder())
{
uint8_t *data_bytes = data.GetBytes();
for (size_t index = 0;
index < operand_data_size;
++index)
{
data_bytes[index] = operand_raw_data[operand_data_size - (1 + index)];
}
}
else
{
memcpy(data.GetBytes(), operand_raw_data, operand_data_size);
}
uint64_t offset = m_data_allocator->GetStream().GetSize();
m_data_allocator->GetStream().Write(data.GetBytes(), operand_data_size);
const llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo();
Constant *new_pointer = BuildRelocation(fp_ptr_ty, offset);
llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst);
operand_constant_fp->replaceAllUsesWith(fp_load);
}
}
return true;
}
static bool isGuardVariableRef(Value *V)
{
Constant *Old;
@ -1599,9 +1832,10 @@ static bool isGuardVariableRef(Value *V)
return true;
}
static void TurnGuardLoadIntoZero(Instruction* guard_load, Module &llvm_module)
void
IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction* guard_load)
{
Constant* zero(ConstantInt::get(Type::getInt8Ty(llvm_module.getContext()), 0, true));
Constant* zero(ConstantInt::get(Type::getInt8Ty(m_module->getContext()), 0, true));
Value::use_iterator ui;
@ -1628,7 +1862,7 @@ static void ExciseGuardStore(Instruction* guard_store)
}
bool
IRForTarget::RemoveGuards(Module &llvm_module, BasicBlock &basic_block)
IRForTarget::RemoveGuards(BasicBlock &basic_block)
{
///////////////////////////////////////////////////////
// Eliminate any reference to guard variables found.
@ -1662,7 +1896,7 @@ IRForTarget::RemoveGuards(Module &llvm_module, BasicBlock &basic_block)
for (iter = guard_loads.begin();
iter != guard_loads.end();
++iter)
TurnGuardLoadIntoZero(*iter, llvm_module);
TurnGuardLoadIntoZero(*iter);
for (iter = guard_stores.begin();
iter != guard_stores.end();
@ -1717,7 +1951,7 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
if (s == old_constant)
s = new_constant;
BitCastInst *bit_cast(new BitCastInst(s, old_constant->getType(), "", first_entry_inst));
BitCastInst *bit_cast(new BitCastInst(s, constant_expr->getType(), "", first_entry_inst));
UnfoldConstant(constant_expr, bit_cast, first_entry_inst);
}
@ -1775,7 +2009,7 @@ IRForTarget::UnfoldConstant(Constant *old_constant, Value *new_constant, Instruc
}
bool
IRForTarget::ReplaceVariables (Module &llvm_module, Function &llvm_function)
IRForTarget::ReplaceVariables (Function &llvm_function)
{
if (!m_resolve_vars)
return true;
@ -1877,7 +2111,7 @@ IRForTarget::ReplaceVariables (Module &llvm_module, Function &llvm_function)
return false;
}
LLVMContext &context(llvm_module.getContext());
LLVMContext &context(m_module->getContext());
const IntegerType *offset_type(Type::getInt32Ty(context));
if (!offset_type)
@ -1948,12 +2182,64 @@ IRForTarget::ReplaceVariables (Module &llvm_module, Function &llvm_function)
return true;
}
llvm::Constant *
IRForTarget::BuildRelocation(const llvm::Type *type,
uint64_t offset)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
const IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
llvm::Constant *offset_int = ConstantInt::get(intptr_ty, offset);
llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(m_reloc_placeholder, &offset_int, 1);
llvm::Constant *reloc_getbitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
return reloc_getbitcast;
}
bool
IRForTarget::CompleteDataAllocation ()
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
if (!m_data_allocator->GetStream().GetSize())
return true;
lldb::addr_t allocation = m_data_allocator->Allocate();
if (log)
{
if (allocation)
log->Printf("Allocated static data at 0x%llx", (unsigned long long)allocation);
else
log->Printf("Failed to allocate static data");
}
if (!allocation)
return false;
const IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
(m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
Constant *relocated_addr = ConstantInt::get(intptr_ty, (uint64_t)allocation);
Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext()));
m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast);
m_reloc_placeholder->eraseFromParent();
return true;
}
bool
IRForTarget::runOnModule (Module &llvm_module)
{
lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
Function* function = llvm_module.getFunction(StringRef(m_func_name.c_str()));
m_module = &llvm_module;
Function* function = m_module->getFunction(StringRef(m_func_name.c_str()));
if (!function)
{
@ -1961,20 +2247,40 @@ IRForTarget::runOnModule (Module &llvm_module)
log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str());
if (m_error_stream)
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the mdoule", m_func_name.c_str());
m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str());
return false;
}
if (!FixFunctionLinkage (*function))
{
if (log)
log->Printf("Couldn't fix the linkage for the function");
return false;
}
const llvm::Type *intptr_ty = Type::getInt8Ty(m_module->getContext());
m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
intptr_ty,
false /* isConstant */,
GlobalVariable::InternalLinkage,
Constant::getNullValue(intptr_ty),
"reloc_placeholder",
NULL /* InsertBefore */,
false /* ThreadLocal */,
0 /* AddressSpace */);
Function::iterator bbi;
m_has_side_effects = HasSideEffects(llvm_module, *function);
m_has_side_effects = HasSideEffects(*function);
////////////////////////////////////////////////////////////
// Replace $__lldb_expr_result with a persistent variable
//
if (!CreateResultVariable(llvm_module, *function))
if (!CreateResultVariable(*function))
{
if (log)
log->Printf("CreateResultVariable() failed");
@ -1987,11 +2293,23 @@ IRForTarget::runOnModule (Module &llvm_module)
if (m_const_result)
return true;
if (log)
{
std::string s;
raw_string_ostream oss(s);
m_module->print(oss, NULL);
oss.flush();
log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
}
///////////////////////////////////////////////////////////////////////////////
// Fix all Objective-C constant strings to use NSStringWithCString:encoding:
//
if (!RewriteObjCConstStrings(llvm_module, *function))
if (!RewriteObjCConstStrings(*function))
{
if (log)
log->Printf("RewriteObjCConstStrings() failed");
@ -2009,7 +2327,7 @@ IRForTarget::runOnModule (Module &llvm_module)
bbi != function->end();
++bbi)
{
if (!RemoveGuards(llvm_module, *bbi))
if (!RemoveGuards(*bbi))
{
if (log)
log->Printf("RemoveGuards() failed");
@ -2019,7 +2337,7 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!RewritePersistentAllocs(llvm_module, *bbi))
if (!RewritePersistentAllocs(*bbi))
{
if (log)
log->Printf("RewritePersistentAllocs() failed");
@ -2029,7 +2347,7 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!RewriteObjCSelectors(llvm_module, *bbi))
if (!RewriteObjCSelectors(*bbi))
{
if (log)
log->Printf("RewriteObjCSelectors() failed");
@ -2039,7 +2357,7 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ResolveCalls(llvm_module, *bbi))
if (!ResolveCalls(*bbi))
{
if (log)
log->Printf("ResolveCalls() failed");
@ -2048,13 +2366,21 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ReplaceStaticLiterals(*bbi))
{
if (log)
log->Printf("ReplaceStaticLiterals() failed");
return false;
}
}
///////////////////////////////
// Run function-level passes
//
if (!ResolveExternals(llvm_module, *function))
if (!ResolveExternals(*function))
{
if (log)
log->Printf("ResolveExternals() failed");
@ -2064,7 +2390,7 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ReplaceVariables(llvm_module, *function))
if (!ReplaceVariables(*function))
{
if (log)
log->Printf("ReplaceVariables() failed");
@ -2074,12 +2400,28 @@ IRForTarget::runOnModule (Module &llvm_module)
return false;
}
if (!ReplaceStrings())
{
if (log)
log->Printf("ReplaceStrings() failed");
return false;
}
if (!CompleteDataAllocation())
{
if (log)
log->Printf("CompleteDataAllocation() failed");
return false;
}
if (log)
{
std::string s;
raw_string_ostream oss(s);
llvm_module.print(oss, NULL);
m_module->print(oss, NULL);
oss.flush();

View File

@ -0,0 +1,43 @@
//===-- ProcessDataAllocator.cpp --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/DataBufferHeap.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Expression/ProcessDataAllocator.h"
using namespace lldb_private;
void
ProcessDataAllocator::Dump(Stream &stream)
{
size_t data_size = m_stream_string.GetSize();
if (!m_allocation)
return;
lldb::DataBufferSP data(new DataBufferHeap(data_size, 0));
Error error;
if (m_process.ReadMemory (m_allocation, data->GetBytes(), data_size, error) != data_size)
return;
DataExtractor extractor(data, m_process.GetByteOrder(), m_process.GetAddressByteSize());
extractor.Dump(&stream, // stream
0, // offset
lldb::eFormatBytesWithASCII, // format
1, // byte size of individual entries
data_size, // number of entries
16, // entries per line
m_allocation, // address to print
0, // bit size (bitfields only; 0 means ignore)
0); // bit alignment (bitfields only; 0 means ignore)
stream.PutChar('\n');
}