mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-11-12 21:56:54 +00:00
clang-format: disable bin packing
Bin packing often makes code hard to read. Disable it entirely. Test plan: - CI
This commit is contained in:
parent
c207972af6
commit
393f8aab42
@ -9,3 +9,4 @@ AllowShortLoopsOnASingleLine: false
|
||||
DerivePointerAlignment: false
|
||||
PointerAlignment: Left
|
||||
BinPackParameters: false
|
||||
BinPackArguments: false
|
||||
|
@ -39,10 +39,17 @@ class CSV {
|
||||
static constexpr std::string_view kEscapedQuote = "\\\"";
|
||||
static constexpr std::string_view kListDelimiter = ";";
|
||||
|
||||
static constexpr std::string_view kColumns[] = {
|
||||
"id", "name", "typePath", "typeNames",
|
||||
"staticSize", "exclusiveSize", "pointer", "length",
|
||||
"capacity", "is_set", "parent_id"};
|
||||
static constexpr std::string_view kColumns[] = {"id",
|
||||
"name",
|
||||
"typePath",
|
||||
"typeNames",
|
||||
"staticSize",
|
||||
"exclusiveSize",
|
||||
"pointer",
|
||||
"length",
|
||||
"capacity",
|
||||
"is_set",
|
||||
"parent_id"};
|
||||
|
||||
size_t id_ = 0;
|
||||
std::vector<size_t> parentIdStack_ = {0};
|
||||
|
@ -194,12 +194,12 @@ namespace {
|
||||
|
||||
size_t calculateExclusiveSize(const Type& t) {
|
||||
if (const auto* c = dynamic_cast<const Class*>(&t)) {
|
||||
return std::accumulate(c->members.cbegin(), c->members.cend(), 0,
|
||||
[](size_t a, const auto& m) {
|
||||
if (m.name.starts_with(AddPadding::MemberPrefix))
|
||||
return a + m.type().size();
|
||||
return a;
|
||||
});
|
||||
return std::accumulate(
|
||||
c->members.cbegin(), c->members.cend(), 0, [](size_t a, const auto& m) {
|
||||
if (m.name.starts_with(AddPadding::MemberPrefix))
|
||||
return a + m.type().size();
|
||||
return a;
|
||||
});
|
||||
}
|
||||
return t.size();
|
||||
}
|
||||
@ -1087,8 +1087,8 @@ constexpr inst::Field make_field(std::string_view name) {
|
||||
TemplateParam{typeGraph.makeType<Primitive>(Primitive::Kind::UInt64),
|
||||
"0"},
|
||||
};
|
||||
genContainerTypeHandler(features, used, FuncGen::GetOiArrayContainerInfo(),
|
||||
arrayParams, code);
|
||||
genContainerTypeHandler(
|
||||
features, used, FuncGen::GetOiArrayContainerInfo(), arrayParams, code);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -1098,12 +1098,17 @@ void CodeGen::addTypeHandlers(const TypeGraph& typeGraph, std::string& code) {
|
||||
if (const auto* c = dynamic_cast<const Class*>(&t)) {
|
||||
genClassTypeHandler(*c, code);
|
||||
} else if (const auto* con = dynamic_cast<const Container*>(&t)) {
|
||||
genContainerTypeHandler(config_.features, definedContainers_,
|
||||
con->containerInfo_, con->templateParams, code);
|
||||
genContainerTypeHandler(config_.features,
|
||||
definedContainers_,
|
||||
con->containerInfo_,
|
||||
con->templateParams,
|
||||
code);
|
||||
} else if (const auto* cap = dynamic_cast<const CaptureKeys*>(&t)) {
|
||||
genContainerTypeHandler(config_.features, definedContainers_,
|
||||
genContainerTypeHandler(config_.features,
|
||||
definedContainers_,
|
||||
cap->containerInfo(),
|
||||
cap->container().templateParams, code);
|
||||
cap->container().templateParams,
|
||||
code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1301,7 +1306,8 @@ void CodeGen::generate(
|
||||
}
|
||||
|
||||
if (config_.features[Feature::TreeBuilderV2]) {
|
||||
FuncGen::DefineTreeBuilderInstructions(code, typeName,
|
||||
FuncGen::DefineTreeBuilderInstructions(code,
|
||||
typeName,
|
||||
calculateExclusiveSize(rootType),
|
||||
enumerateTypeNames(rootType));
|
||||
} else if (config_.features[Feature::TreeBuilderTypeChecking]) {
|
||||
|
@ -215,8 +215,8 @@ std::optional<FeatureSet> processConfigFile(
|
||||
auto* members = (*captureKeys)["members"].as_array();
|
||||
if (!members) {
|
||||
generatorConfig.keysToCapture.push_back(
|
||||
OICodeGen::Config::KeyToCapture{type->value_or(""), "*",
|
||||
false});
|
||||
OICodeGen::Config::KeyToCapture{
|
||||
type->value_or(""), "*", false});
|
||||
} else {
|
||||
for (auto&& member : *members) {
|
||||
generatorConfig.keysToCapture.push_back(
|
||||
@ -226,8 +226,8 @@ std::optional<FeatureSet> processConfigFile(
|
||||
}
|
||||
} else if (topLevel) {
|
||||
generatorConfig.keysToCapture.push_back(
|
||||
OICodeGen::Config::KeyToCapture{std::nullopt, std::nullopt,
|
||||
true});
|
||||
OICodeGen::Config::KeyToCapture{
|
||||
std::nullopt, std::nullopt, true});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,6 +323,8 @@ ContainerInfo::ContainerInfo(std::string typeName_,
|
||||
matcher(getMatcher(typeName)),
|
||||
ctype(ctype_),
|
||||
header(std::move(header_)),
|
||||
codegen(Codegen{"// DummyDecl %1%\n", "// DummyFunc %1%\n",
|
||||
"// DummyHandler %1%\n", "// DummyFunc\n"}) {
|
||||
codegen(Codegen{"// DummyDecl %1%\n",
|
||||
"// DummyFunc %1%\n",
|
||||
"// DummyHandler %1%\n",
|
||||
"// DummyFunc\n"}) {
|
||||
}
|
||||
|
@ -800,7 +800,8 @@ void FuncGen::DefineBasicTypeHandlers(std::string& code, FeatureSet features) {
|
||||
}
|
||||
|
||||
ContainerInfo FuncGen::GetOiArrayContainerInfo() {
|
||||
ContainerInfo oiArray{"OIArray", UNKNOWN_TYPE,
|
||||
ContainerInfo oiArray{"OIArray",
|
||||
UNKNOWN_TYPE,
|
||||
"cstdint"}; // TODO: remove the need for a dummy header
|
||||
|
||||
oiArray.codegen.handler = R"(
|
||||
|
@ -130,8 +130,11 @@ void Tracing::stop() {
|
||||
|
||||
std::lock_guard<std::mutex> guard{static_.mutex};
|
||||
// Can't use emplace_back() because of old clang++ on CI
|
||||
static_.traces.push_back({getNextIndex(), std::move(traceName),
|
||||
duration.count(), rssBeforeBytes, rssAfterBytes});
|
||||
static_.traces.push_back({getNextIndex(),
|
||||
std::move(traceName),
|
||||
duration.count(),
|
||||
rssBeforeBytes,
|
||||
rssAfterBytes});
|
||||
}
|
||||
|
||||
void Tracing::saveTraces(const std::filesystem::path& output) {
|
||||
|
@ -204,8 +204,8 @@ std::string OICodeGen::preProcessUniquePtr(drgn_type* type, std::string name) {
|
||||
} else if (typeSize == cFunctionDeleterSize) {
|
||||
name.replace(begin, end - begin + 1, "void(*)(" + typeName + "*)");
|
||||
} else if (typeSize == stdFunctionDeleterSize) {
|
||||
name.replace(begin, end - begin + 1,
|
||||
"std::function<void (" + typeName + "*)>");
|
||||
name.replace(
|
||||
begin, end - begin + 1, "std::function<void (" + typeName + "*)>");
|
||||
} else {
|
||||
LOG(ERROR) << "Unhandled case, unique_ptr size: " << typeSize;
|
||||
}
|
||||
@ -540,8 +540,8 @@ bool OICodeGen::buildNameInt(drgn_type* type,
|
||||
templateParamsStrings.push_back(templateParamName);
|
||||
}
|
||||
|
||||
replaceTemplateParameters(type, templateParams, templateParamsStrings,
|
||||
nameWithoutTemplate);
|
||||
replaceTemplateParameters(
|
||||
type, templateParams, templateParamsStrings, nameWithoutTemplate);
|
||||
|
||||
outName = nameWithoutTemplate;
|
||||
for (size_t i = 0; i < templateParamsStrings.size(); ++i) {
|
||||
@ -765,8 +765,9 @@ bool OICodeGen::enumerateTemplateParamIdxs(drgn_type* type,
|
||||
|
||||
auto& templateTypes =
|
||||
containerTypeMapDrgn
|
||||
.emplace(type, std::pair(std::ref(containerInfo),
|
||||
std::vector<drgn_qualified_type>()))
|
||||
.emplace(type,
|
||||
std::pair(std::ref(containerInfo),
|
||||
std::vector<drgn_qualified_type>()))
|
||||
.first->second.second;
|
||||
|
||||
for (auto i : paramIdxs) {
|
||||
@ -1721,8 +1722,8 @@ void OICodeGen::enumerateDescendants(drgn_type* type, drgn_type* baseType) {
|
||||
|
||||
// TODO this list may end up containing duplicates
|
||||
const auto& children = it->second;
|
||||
descendantClasses[baseType].insert(descendantClasses[baseType].end(),
|
||||
children.begin(), children.end());
|
||||
descendantClasses[baseType].insert(
|
||||
descendantClasses[baseType].end(), children.begin(), children.end());
|
||||
|
||||
for (const auto& child : children) {
|
||||
enumerateDescendants(child, baseType);
|
||||
@ -1878,7 +1879,8 @@ void OICodeGen::memberTransformName(
|
||||
sortedTypes.push_back(e.first);
|
||||
}
|
||||
|
||||
std::sort(sortedTypes.begin(), sortedTypes.end(),
|
||||
std::sort(sortedTypes.begin(),
|
||||
sortedTypes.end(),
|
||||
[](const std::string& first, const std::string& second) {
|
||||
return first.size() > second.size();
|
||||
});
|
||||
@ -2212,8 +2214,13 @@ bool OICodeGen::generateStructDef(drgn_type* e, std::string& code) {
|
||||
|
||||
uint64_t offsetBits = 0;
|
||||
std::unordered_map<std::string, int> memberNames;
|
||||
if (!generateStructMembers(e, memberNames, generatedMembers, offsetBits,
|
||||
paddingInfo, violatesAlignmentRequirement, 0)) {
|
||||
if (!generateStructMembers(e,
|
||||
memberNames,
|
||||
generatedMembers,
|
||||
offsetBits,
|
||||
paddingInfo,
|
||||
violatesAlignmentRequirement,
|
||||
0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2471,8 +2478,8 @@ std::optional<uint64_t> OICodeGen::generateMember(
|
||||
currOffsetBits = 0;
|
||||
VLOG(1) << "Member size: " << memberSize;
|
||||
} else {
|
||||
addSizeComment(feature(Feature::GenPaddingStats), code, currOffsetBits,
|
||||
memberSize);
|
||||
addSizeComment(
|
||||
feature(Feature::GenPaddingStats), code, currOffsetBits, memberSize);
|
||||
currOffsetBits = currOffsetBits + memberSize;
|
||||
}
|
||||
|
||||
@ -2499,8 +2506,12 @@ bool OICodeGen::generateParent(
|
||||
auto* underlyingType = drgn_utils::underlyingType(p);
|
||||
uint64_t offsetBits = 0;
|
||||
|
||||
if (!generateStructMembers(underlyingType, memberNames, code, offsetBits,
|
||||
paddingInfo, violatesAlignmentRequirement,
|
||||
if (!generateStructMembers(underlyingType,
|
||||
memberNames,
|
||||
code,
|
||||
offsetBits,
|
||||
paddingInfo,
|
||||
violatesAlignmentRequirement,
|
||||
offsetToNextMember)) {
|
||||
return false;
|
||||
}
|
||||
@ -2657,8 +2668,11 @@ bool OICodeGen::generateStructMembers(
|
||||
size_t prevOffsetBits = currOffsetBits;
|
||||
|
||||
auto newCurrOffsetBits =
|
||||
generateMember(members[memberIndex], memberNames, currOffsetBits,
|
||||
code, drgn_type_kind(e) == DRGN_TYPE_UNION);
|
||||
generateMember(members[memberIndex],
|
||||
memberNames,
|
||||
currOffsetBits,
|
||||
code,
|
||||
drgn_type_kind(e) == DRGN_TYPE_UNION);
|
||||
|
||||
if (!newCurrOffsetBits.has_value()) {
|
||||
return false;
|
||||
@ -2770,8 +2784,11 @@ bool OICodeGen::generateStructMembers(
|
||||
}
|
||||
}
|
||||
|
||||
if (!generateParent(parentClasses[e][parentIndex].type, memberNames,
|
||||
currOffsetBits, code, offsetToNextMember)) {
|
||||
if (!generateParent(parentClasses[e][parentIndex].type,
|
||||
memberNames,
|
||||
currOffsetBits,
|
||||
code,
|
||||
offsetToNextMember)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2869,8 +2886,8 @@ bool OICodeGen::generateStructDefs(std::string& code) {
|
||||
if (parentClassesCopy.find(e) != parentClassesCopy.end()) {
|
||||
auto& parents = parentClassesCopy[e];
|
||||
for (auto& p : parents) {
|
||||
auto it2 = std::find(structDefTypeCopy.begin(),
|
||||
structDefTypeCopy.end(), p.type);
|
||||
auto it2 = std::find(
|
||||
structDefTypeCopy.begin(), structDefTypeCopy.end(), p.type);
|
||||
if (it2 != structDefTypeCopy.cend()) {
|
||||
skip = true;
|
||||
break;
|
||||
@ -2886,7 +2903,8 @@ bool OICodeGen::generateStructDefs(std::string& code) {
|
||||
|
||||
if (underlyingType != e) {
|
||||
auto it2 = std::find(structDefTypeCopy.begin(),
|
||||
structDefTypeCopy.end(), underlyingType);
|
||||
structDefTypeCopy.end(),
|
||||
underlyingType);
|
||||
if (it2 != structDefTypeCopy.cend()) {
|
||||
skip = true;
|
||||
break;
|
||||
@ -3204,8 +3222,8 @@ bool OICodeGen::generateJitCode(std::string& code) {
|
||||
std::string functionsCode;
|
||||
functionsCode.append("namespace OIInternal {\nnamespace {\n");
|
||||
functionsCode.append("// functions -----\n");
|
||||
if (!funcGen.DeclareGetSizeFuncs(functionsCode, containerTypesFuncDef,
|
||||
config.features)) {
|
||||
if (!funcGen.DeclareGetSizeFuncs(
|
||||
functionsCode, containerTypesFuncDef, config.features)) {
|
||||
LOG(ERROR) << "declaring get size for containers failed";
|
||||
return false;
|
||||
}
|
||||
@ -3235,8 +3253,8 @@ bool OICodeGen::generateJitCode(std::string& code) {
|
||||
funcGen.DeclareEncodeData(functionsCode);
|
||||
funcGen.DeclareEncodeDataSize(functionsCode);
|
||||
|
||||
if (!funcGen.DefineGetSizeFuncs(functionsCode, containerTypesFuncDef,
|
||||
config.features)) {
|
||||
if (!funcGen.DefineGetSizeFuncs(
|
||||
functionsCode, containerTypesFuncDef, config.features)) {
|
||||
LOG(ERROR) << "defining get size for containers failed";
|
||||
return false;
|
||||
}
|
||||
@ -3289,8 +3307,8 @@ bool OICodeGen::generateJitCode(std::string& code) {
|
||||
bool generateOffsetAsserts =
|
||||
(drgn_type_kind(structType) != DRGN_TYPE_UNION);
|
||||
|
||||
if (!addStaticAssertsForType(structType, generateOffsetAsserts,
|
||||
functionsCode)) {
|
||||
if (!addStaticAssertsForType(
|
||||
structType, generateOffsetAsserts, functionsCode)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -3328,11 +3346,11 @@ bool OICodeGen::generateJitCode(std::string& code) {
|
||||
if (rootTypeStr.starts_with("unique_ptr") ||
|
||||
rootTypeStr.starts_with("LowPtr") ||
|
||||
rootTypeStr.starts_with("shared_ptr")) {
|
||||
funcGen.DefineTopLevelGetSizeSmartPtr(functionsCode, rawTypeName,
|
||||
config.features);
|
||||
funcGen.DefineTopLevelGetSizeSmartPtr(
|
||||
functionsCode, rawTypeName, config.features);
|
||||
} else {
|
||||
funcGen.DefineTopLevelGetSizeRef(functionsCode, rawTypeName,
|
||||
config.features);
|
||||
funcGen.DefineTopLevelGetSizeRef(
|
||||
functionsCode, rawTypeName, config.features);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3593,7 +3611,9 @@ bool OICodeGen::staticAssertMemberOffsets(
|
||||
// Operate on the underlying type for typedefs
|
||||
return staticAssertMemberOffsets(struct_name,
|
||||
drgn_utils::underlyingType(struct_type),
|
||||
assert_str, memberNames, base_offset);
|
||||
assert_str,
|
||||
memberNames,
|
||||
base_offset);
|
||||
}
|
||||
|
||||
const auto* tag = drgn_type_tag(struct_type);
|
||||
@ -3606,8 +3626,11 @@ bool OICodeGen::staticAssertMemberOffsets(
|
||||
// Recurse into parents to find inherited members
|
||||
for (const auto& parent : parentClasses[struct_type]) {
|
||||
auto parentOffset = base_offset + parent.bit_offset / CHAR_BIT;
|
||||
if (!staticAssertMemberOffsets(struct_name, parent.type, assert_str,
|
||||
memberNames, parentOffset)) {
|
||||
if (!staticAssertMemberOffsets(struct_name,
|
||||
parent.type,
|
||||
assert_str,
|
||||
memberNames,
|
||||
parentOffset)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -79,8 +79,8 @@ static struct LLVMInitializer {
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
llvm::InitializeNativeTargetDisassembler();
|
||||
|
||||
disassemblerContext = LLVMCreateDisasm("x86_64-pc-linux", nullptr, 0,
|
||||
nullptr, symbolLookupCallback);
|
||||
disassemblerContext = LLVMCreateDisasm(
|
||||
"x86_64-pc-linux", nullptr, 0, nullptr, symbolLookupCallback);
|
||||
if (!disassemblerContext) {
|
||||
throw std::runtime_error("Failed to initialize disassemblerContext");
|
||||
}
|
||||
@ -106,10 +106,13 @@ OICompiler::Disassembler::operator()() {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t instSize = LLVMDisasmInstruction(
|
||||
disassemblerContext, const_cast<uint8_t*>(std::data(funcText)),
|
||||
std::size(funcText), 0, std::data(disassemblyBuffer),
|
||||
std::size(disassemblyBuffer));
|
||||
size_t instSize =
|
||||
LLVMDisasmInstruction(disassemblerContext,
|
||||
const_cast<uint8_t*>(std::data(funcText)),
|
||||
std::size(funcText),
|
||||
0,
|
||||
std::data(disassemblyBuffer),
|
||||
std::size(disassemblyBuffer));
|
||||
if (instSize == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
@ -150,7 +153,9 @@ class OIMemoryManager : public RTDyldMemoryManager {
|
||||
std::error_code errorCode;
|
||||
auto mem = sys::Memory::allocateMappedMemory(
|
||||
alignTo(totalSize + 256, 256), // Extra to fit paddings added below
|
||||
nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, errorCode);
|
||||
nullptr,
|
||||
sys::Memory::MF_READ | sys::Memory::MF_WRITE,
|
||||
errorCode);
|
||||
|
||||
/*
|
||||
* It looks like report_fatal_error() calls exit() by default. If it's
|
||||
@ -509,7 +514,9 @@ bool OICompiler::compile(const std::string& code,
|
||||
|
||||
for (const auto& path : config.userHeaderPaths) {
|
||||
headerSearchOptions.AddPath(
|
||||
path.c_str(), clang::frontend::IncludeDirGroup::IndexHeaderMap, false,
|
||||
path.c_str(),
|
||||
clang::frontend::IncludeDirGroup::IndexHeaderMap,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
@ -518,22 +525,25 @@ bool OICompiler::compile(const std::string& code,
|
||||
path.c_str(), clang::frontend::IncludeDirGroup::System, false, false);
|
||||
}
|
||||
|
||||
static const auto syntheticHeaders = std::array<
|
||||
std::pair<Feature, std::pair<std::string_view, std::string>>, 7>{{
|
||||
{Feature::TypedDataSegment, {headers::oi_types_st_h, "oi/types/st.h"}},
|
||||
{Feature::TreeBuilderTypeChecking,
|
||||
{headers::oi_types_dy_h, "oi/types/dy.h"}},
|
||||
{Feature::TreeBuilderV2,
|
||||
{headers::oi_exporters_inst_h, "oi/exporters/inst.h"}},
|
||||
{Feature::TreeBuilderV2,
|
||||
{headers::oi_exporters_ParsedData_h, "oi/exporters/ParsedData.h"}},
|
||||
{Feature::TreeBuilderV2,
|
||||
{headers::oi_result_Element_h, "oi/result/Element.h"}},
|
||||
{Feature::Library,
|
||||
{headers::oi_IntrospectionResult_h, "oi/IntrospectionResult.h"}},
|
||||
{Feature::Library,
|
||||
{headers::oi_IntrospectionResult_inl_h, "oi/IntrospectionResult-inl.h"}},
|
||||
}};
|
||||
static const auto syntheticHeaders =
|
||||
std::array<std::pair<Feature, std::pair<std::string_view, std::string>>,
|
||||
7>{{
|
||||
{Feature::TypedDataSegment,
|
||||
{headers::oi_types_st_h, "oi/types/st.h"}},
|
||||
{Feature::TreeBuilderTypeChecking,
|
||||
{headers::oi_types_dy_h, "oi/types/dy.h"}},
|
||||
{Feature::TreeBuilderV2,
|
||||
{headers::oi_exporters_inst_h, "oi/exporters/inst.h"}},
|
||||
{Feature::TreeBuilderV2,
|
||||
{headers::oi_exporters_ParsedData_h, "oi/exporters/ParsedData.h"}},
|
||||
{Feature::TreeBuilderV2,
|
||||
{headers::oi_result_Element_h, "oi/result/Element.h"}},
|
||||
{Feature::Library,
|
||||
{headers::oi_IntrospectionResult_h, "oi/IntrospectionResult.h"}},
|
||||
{Feature::Library,
|
||||
{headers::oi_IntrospectionResult_inl_h,
|
||||
"oi/IntrospectionResult-inl.h"}},
|
||||
}};
|
||||
for (const auto& [k, v] : syntheticHeaders) {
|
||||
if (!config.features[k])
|
||||
continue;
|
||||
@ -546,7 +556,9 @@ bool OICompiler::compile(const std::string& code,
|
||||
if (config.features[k]) {
|
||||
headerSearchOptions.AddPath(
|
||||
"/synthetic/headers",
|
||||
clang::frontend::IncludeDirGroup::IndexHeaderMap, false, false);
|
||||
clang::frontend::IncludeDirGroup::IndexHeaderMap,
|
||||
false,
|
||||
false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -657,9 +669,10 @@ std::optional<OICompiler::RelocResult> OICompiler::applyRelocs(
|
||||
<< currentRelocAddress + offset;
|
||||
}
|
||||
|
||||
res.relocInfos.push_back(RelocResult::RelocInfo{
|
||||
(uintptr_t)slab.memBlock.base(), currentRelocAddress,
|
||||
slab.memBlock.allocatedSize()});
|
||||
res.relocInfos.push_back(
|
||||
RelocResult::RelocInfo{(uintptr_t)slab.memBlock.base(),
|
||||
currentRelocAddress,
|
||||
slab.memBlock.allocatedSize()});
|
||||
currentRelocAddress =
|
||||
alignTo(currentRelocAddress + slab.memBlock.allocatedSize(), 128);
|
||||
res.newBaseRelocAddr = currentRelocAddress;
|
||||
|
101
oi/OID.cpp
101
oi/OID.cpp
@ -108,51 +108,90 @@ enum ExitStatus {
|
||||
|
||||
constexpr static OIOpts opts{
|
||||
OIOpt{'h', "help", no_argument, nullptr, "Print this message and exit"},
|
||||
OIOpt{'p', "pid", required_argument, "<pid>",
|
||||
"Target process to attach to"},
|
||||
OIOpt{'c', "config-file", required_argument, nullptr,
|
||||
"</path/to/oid.toml>"},
|
||||
OIOpt{'x', "data-buf-size", required_argument, "<bytes>",
|
||||
OIOpt{
|
||||
'p', "pid", required_argument, "<pid>", "Target process to attach to"},
|
||||
OIOpt{
|
||||
'c', "config-file", required_argument, nullptr, "</path/to/oid.toml>"},
|
||||
OIOpt{'x',
|
||||
"data-buf-size",
|
||||
required_argument,
|
||||
"<bytes>",
|
||||
"Size of data segment (default:1MB)\n"
|
||||
"Accepts multiplicative suffix: K, M, G, T, P, E"},
|
||||
OIOpt{'d', "debug-level", required_argument, "<level>",
|
||||
OIOpt{'d',
|
||||
"debug-level",
|
||||
required_argument,
|
||||
"<level>",
|
||||
"Verbose level for logging"},
|
||||
OIOpt{'r', "remove-mappings", no_argument, nullptr,
|
||||
OIOpt{'r',
|
||||
"remove-mappings",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Remove oid mappings from target process"},
|
||||
OIOpt{'s', "script", required_argument, nullptr, "</path/to/script.oid>"},
|
||||
OIOpt{'S', "script-source", required_argument, nullptr, "type:symbol:arg"},
|
||||
OIOpt{'t', "timeout", required_argument, "<seconds>",
|
||||
OIOpt{'t',
|
||||
"timeout",
|
||||
required_argument,
|
||||
"<seconds>",
|
||||
"How long to probe the target process for"},
|
||||
OIOpt{'k', "custom-code-file", required_argument, nullptr,
|
||||
OIOpt{'k',
|
||||
"custom-code-file",
|
||||
required_argument,
|
||||
nullptr,
|
||||
"</path/to/code.cpp>\n"
|
||||
"Use your own CPP file instead of CodeGen"},
|
||||
OIOpt{'e', "compile-and-exit", no_argument, nullptr,
|
||||
OIOpt{'e',
|
||||
"compile-and-exit",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Compile only then exit"},
|
||||
OIOpt{'o', "cache-path", required_argument, "<path>",
|
||||
OIOpt{'o',
|
||||
"cache-path",
|
||||
required_argument,
|
||||
"<path>",
|
||||
"Enable caching using the provided directory"},
|
||||
OIOpt{'u', "cache-remote", required_argument, nullptr,
|
||||
OIOpt{'u',
|
||||
"cache-remote",
|
||||
required_argument,
|
||||
nullptr,
|
||||
"Enable upload/download of cache files\n"
|
||||
"Pick from {both,upload,download}"},
|
||||
OIOpt{'i', "debug-path", required_argument, nullptr,
|
||||
OIOpt{'i',
|
||||
"debug-path",
|
||||
required_argument,
|
||||
nullptr,
|
||||
"</path/to/binary>\n"
|
||||
"Run oid on a executable with debug infos instead of a running "
|
||||
"process"},
|
||||
// Optional arguments are pretty nasty - it will only work as
|
||||
// "--dump-json=PATH" and not "--dump-json PATH". Try and make this take a
|
||||
// required argument at a later point
|
||||
OIOpt{'J', "dump-json", optional_argument, "[oid_out.json]",
|
||||
OIOpt{'J',
|
||||
"dump-json",
|
||||
optional_argument,
|
||||
"[oid_out.json]",
|
||||
"File to dump the results to, as JSON\n"
|
||||
"(in addition to the default RocksDB output)"},
|
||||
OIOpt{
|
||||
'B', "dump-data-segment", no_argument, nullptr,
|
||||
'B',
|
||||
"dump-data-segment",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Dump the data segment's content, before TreeBuilder processes it\n"
|
||||
"Each argument gets its own dump file: 'dataseg.<oid-pid>.<arg>.dump'"},
|
||||
OIOpt{'a', "log-all-structs", no_argument, nullptr, "Log all structures"},
|
||||
OIOpt{'m', "mode", required_argument, "MODE",
|
||||
OIOpt{'m',
|
||||
"mode",
|
||||
required_argument,
|
||||
"MODE",
|
||||
"Allows to specify a mode of operation/group of settings"},
|
||||
OIOpt{'f', "enable-feature", required_argument, "FEATURE",
|
||||
"Enable feature"},
|
||||
OIOpt{'F', "disable-feature", required_argument, "FEATURE",
|
||||
OIOpt{
|
||||
'f', "enable-feature", required_argument, "FEATURE", "Enable feature"},
|
||||
OIOpt{'F',
|
||||
"disable-feature",
|
||||
required_argument,
|
||||
"FEATURE",
|
||||
"Disable feature"},
|
||||
};
|
||||
|
||||
@ -287,11 +326,11 @@ static ExitStatus::ExitStatus runScript(
|
||||
|
||||
std::shared_ptr<OIDebugger> oid; // share oid with the global signal handler
|
||||
if (oidConfig.pid != 0) {
|
||||
oid = std::make_shared<OIDebugger>(oidConfig.pid, codeGenConfig,
|
||||
compilerConfig, tbConfig);
|
||||
oid = std::make_shared<OIDebugger>(
|
||||
oidConfig.pid, codeGenConfig, compilerConfig, tbConfig);
|
||||
} else {
|
||||
oid = std::make_shared<OIDebugger>(oidConfig.debugInfoFile, codeGenConfig,
|
||||
compilerConfig, tbConfig);
|
||||
oid = std::make_shared<OIDebugger>(
|
||||
oidConfig.debugInfoFile, codeGenConfig, compilerConfig, tbConfig);
|
||||
}
|
||||
weak_oid = oid; // set the weak_ptr for signal handlers
|
||||
|
||||
@ -496,8 +535,8 @@ int main(int argc, char* argv[]) {
|
||||
google::SetStderrLogging(google::WARNING);
|
||||
|
||||
int c = 0;
|
||||
while ((c = getopt_long(argc, argv, opts.shortOpts(), opts.longOpts(),
|
||||
nullptr)) != -1) {
|
||||
while ((c = getopt_long(
|
||||
argc, argv, opts.shortOpts(), opts.longOpts(), nullptr)) != -1) {
|
||||
switch (c) {
|
||||
case 'F':
|
||||
[[fallthrough]];
|
||||
@ -675,8 +714,8 @@ int main(int argc, char* argv[]) {
|
||||
.jsonPath = jsonPath,
|
||||
};
|
||||
|
||||
auto featureSet = config::processConfigFiles(oidConfig.configFiles, features,
|
||||
compilerConfig, codeGenConfig);
|
||||
auto featureSet = config::processConfigFiles(
|
||||
oidConfig.configFiles, features, compilerConfig, codeGenConfig);
|
||||
if (!featureSet) {
|
||||
return ExitStatus::UsageError;
|
||||
}
|
||||
@ -690,15 +729,15 @@ int main(int argc, char* argv[]) {
|
||||
return ExitStatus::FileNotFoundError;
|
||||
}
|
||||
std::ifstream script(scriptFile);
|
||||
auto status = runScript(scriptFile, script, oidConfig, codeGenConfig,
|
||||
compilerConfig, tbConfig);
|
||||
auto status = runScript(
|
||||
scriptFile, script, oidConfig, codeGenConfig, compilerConfig, tbConfig);
|
||||
if (status != ExitStatus::Success) {
|
||||
return status;
|
||||
}
|
||||
} else if (!scriptSource.empty()) {
|
||||
std::istringstream script(scriptSource);
|
||||
auto status = runScript(scriptFile, script, oidConfig, codeGenConfig,
|
||||
compilerConfig, tbConfig);
|
||||
auto status = runScript(
|
||||
scriptFile, script, oidConfig, codeGenConfig, compilerConfig, tbConfig);
|
||||
if (status != ExitStatus::Success) {
|
||||
return status;
|
||||
}
|
||||
|
@ -67,8 +67,9 @@ namespace oi::detail {
|
||||
constexpr int oidMagicId = 0x01DE8;
|
||||
|
||||
bool OIDebugger::isGlobalDataProbeEnabled(void) const {
|
||||
return std::any_of(cbegin(pdata), cend(pdata),
|
||||
[](const auto& r) { return r.type == "global"; });
|
||||
return std::any_of(cbegin(pdata), cend(pdata), [](const auto& r) {
|
||||
return r.type == "global";
|
||||
});
|
||||
}
|
||||
|
||||
bool OIDebugger::parseScript(std::istream& script) {
|
||||
@ -214,7 +215,8 @@ bool OIDebugger::setupLogFile(void) {
|
||||
* The memory will be re-used anyway and the path will get overwritten.
|
||||
*/
|
||||
if (!writeTargetMemory((void*)logFilePath.c_str(),
|
||||
(void*)segConfig.textSegBase, logFilePathLen)) {
|
||||
(void*)segConfig.textSegBase,
|
||||
logFilePathLen)) {
|
||||
LOG(ERROR) << "Failed to write Log File's path into target process";
|
||||
return false;
|
||||
}
|
||||
@ -381,9 +383,15 @@ void OIDebugger::deleteSegmentConfig(bool deleteSegConfigFile) {
|
||||
*/
|
||||
std::string OIDebugger::taskStateToString(OIDebugger::StatusType status) {
|
||||
/* Must reflect the order of OIDebugger::StatusType enum */
|
||||
static const std::array enumMapping{"SLEEP", "TRACED", "RUNNING",
|
||||
"ZOMBIE", "DEAD", "DISK SLEEP",
|
||||
"STOPPED", "OTHER", "BAD"};
|
||||
static const std::array enumMapping{"SLEEP",
|
||||
"TRACED",
|
||||
"RUNNING",
|
||||
"ZOMBIE",
|
||||
"DEAD",
|
||||
"DISK SLEEP",
|
||||
"STOPPED",
|
||||
"OTHER",
|
||||
"BAD"};
|
||||
|
||||
return enumMapping[static_cast<int>(status)];
|
||||
}
|
||||
@ -583,7 +591,8 @@ bool OIDebugger::locateObjectsAddresses(const trapInfo& tInfo,
|
||||
}
|
||||
|
||||
VLOG(4) << "Entry: arg addr: " << std::hex << *addr;
|
||||
if (!writeTargetMemory((void*)(&addr.value()), (void*)remoteObjAddr->second,
|
||||
if (!writeTargetMemory((void*)(&addr.value()),
|
||||
(void*)remoteObjAddr->second,
|
||||
sizeof(*addr))) {
|
||||
LOG(ERROR) << "Entry: writeTargetMemory remoteObjAddr failed!";
|
||||
ret = false;
|
||||
@ -882,8 +891,8 @@ bool OIDebugger::processGlobal(const std::string& varName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!writeTargetMemory((void*)&addr, (void*)remoteObjAddr->second,
|
||||
sizeof(addr))) {
|
||||
if (!writeTargetMemory(
|
||||
(void*)&addr, (void*)remoteObjAddr->second, sizeof(addr))) {
|
||||
LOG(ERROR) << "processGlobal: writeTargetMemory remoteObjAddr failed!";
|
||||
}
|
||||
|
||||
@ -1023,7 +1032,9 @@ OIDebugger::processTrapRet OIDebugger::processTrap(pid_t pid,
|
||||
VLOG(4) << "child was stopped with: " << WSTOPSIG(tstatus);
|
||||
}
|
||||
|
||||
ptrace(PTRACE_SETOPTIONS, childPid, NULL,
|
||||
ptrace(PTRACE_SETOPTIONS,
|
||||
childPid,
|
||||
NULL,
|
||||
PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE |
|
||||
PTRACE_O_TRACEVFORK);
|
||||
|
||||
@ -1230,8 +1241,9 @@ OIDebugger::processTrapRet OIDebugger::processTrap(pid_t pid,
|
||||
|
||||
std::optional<std::vector<uintptr_t>> OIDebugger::findRetLocs(FuncDesc& fd) {
|
||||
size_t maxSize = std::accumulate(
|
||||
fd.ranges.begin(), fd.ranges.end(), size_t(0),
|
||||
[](auto currMax, auto& r) { return std::max(currMax, r.size()); });
|
||||
fd.ranges.begin(), fd.ranges.end(), size_t(0), [](auto currMax, auto& r) {
|
||||
return std::max(currMax, r.size());
|
||||
});
|
||||
|
||||
std::vector<uintptr_t> retLocs;
|
||||
std::vector<std::byte> text(maxSize);
|
||||
@ -1384,8 +1396,9 @@ bool OIDebugger::functionPatch(const prequest& req) {
|
||||
|
||||
/* 1. Locate all TRAP points and create a corresponding empty trapInfo in
|
||||
* tiVec */
|
||||
bool hasArg = std::any_of(begin(req.args), end(req.args),
|
||||
[](auto& arg) { return arg != "retval"; });
|
||||
bool hasArg = std::any_of(begin(req.args), end(req.args), [](auto& arg) {
|
||||
return arg != "retval";
|
||||
});
|
||||
|
||||
if (req.type == "entry" || hasArg) {
|
||||
trapType tType =
|
||||
@ -1414,8 +1427,8 @@ bool OIDebugger::functionPatch(const prequest& req) {
|
||||
}
|
||||
|
||||
for (auto addr : *retLocs) {
|
||||
tiVec.push_back(std::make_shared<trapInfo>(OID_TRAP_VECT_RET, addr,
|
||||
segConfig.textSegBase));
|
||||
tiVec.push_back(std::make_shared<trapInfo>(
|
||||
OID_TRAP_VECT_RET, addr, segConfig.textSegBase));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1433,8 +1446,12 @@ bool OIDebugger::functionPatch(const prequest& req) {
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
auto readBytes = process_vm_readv(traceePid, localIov.data(), localIov.size(),
|
||||
remoteIov.data(), remoteIov.size(), 0);
|
||||
auto readBytes = process_vm_readv(traceePid,
|
||||
localIov.data(),
|
||||
localIov.size(),
|
||||
remoteIov.data(),
|
||||
remoteIov.size(),
|
||||
0);
|
||||
if (readBytes < 0) {
|
||||
LOG(ERROR) << "Failed to get original instructions: " << strerror(errno);
|
||||
return false;
|
||||
@ -1489,9 +1506,12 @@ bool OIDebugger::functionPatch(const prequest& req) {
|
||||
|
||||
/* 4. Save the original instructions in our Replay Instruction buffer */
|
||||
errno = 0;
|
||||
auto writtenBytes =
|
||||
process_vm_writev(traceePid, localIov.data(), localIov.size(),
|
||||
remoteIov.data(), remoteIov.size(), 0);
|
||||
auto writtenBytes = process_vm_writev(traceePid,
|
||||
localIov.data(),
|
||||
localIov.size(),
|
||||
remoteIov.data(),
|
||||
remoteIov.size(),
|
||||
0);
|
||||
if (writtenBytes < 0) {
|
||||
LOG(ERROR) << "Failed to save original instructions: " << strerror(errno);
|
||||
return false;
|
||||
@ -1588,8 +1608,12 @@ std::optional<typename Sys::RetType> OIDebugger::remoteSyscall(Args... _args) {
|
||||
* x86-64 rdi rsi rdx r10 r8 r9 -
|
||||
*/
|
||||
const std::array<unsigned long long*, 6> argToReg = {
|
||||
&newregs.rdi, &newregs.rsi, &newregs.rdx,
|
||||
&newregs.r10, &newregs.r8, &newregs.r9,
|
||||
&newregs.rdi,
|
||||
&newregs.rsi,
|
||||
&newregs.rdx,
|
||||
&newregs.r10,
|
||||
&newregs.r8,
|
||||
&newregs.r9,
|
||||
};
|
||||
|
||||
unsigned long long args[] = {(unsigned long long)_args...};
|
||||
@ -1682,15 +1706,19 @@ bool OIDebugger::setupSegment(SegType seg) {
|
||||
std::optional<void*> segAddr;
|
||||
if (seg == SegType::text) {
|
||||
segAddr =
|
||||
remoteSyscall<SysMmap>(nullptr, textSegSize, // addr & size
|
||||
remoteSyscall<SysMmap>(nullptr,
|
||||
textSegSize, // addr & size
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC, // prot
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, // flags
|
||||
-1, 0); // fd & offset
|
||||
-1,
|
||||
0); // fd & offset
|
||||
} else {
|
||||
segAddr = remoteSyscall<SysMmap>(nullptr, dataSegSize, // addr & size
|
||||
segAddr = remoteSyscall<SysMmap>(nullptr,
|
||||
dataSegSize, // addr & size
|
||||
PROT_READ | PROT_WRITE, // prot
|
||||
MAP_SHARED | MAP_ANONYMOUS, // flags
|
||||
-1, 0); // fd & offset
|
||||
-1,
|
||||
0); // fd & offset
|
||||
}
|
||||
|
||||
if (!segAddr.has_value()) {
|
||||
@ -1835,13 +1863,16 @@ bool OIDebugger::removeTrap(pid_t pid, const trapInfo& t) {
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(repatchedBytes.data() + off, it->second->patchedTextBytes,
|
||||
memcpy(repatchedBytes.data() + off,
|
||||
it->second->patchedTextBytes,
|
||||
windowSize - off);
|
||||
}
|
||||
}
|
||||
|
||||
VLOG(4) << "removeTrap removing int3 at " << std::hex << t.trapAddr;
|
||||
if (ptrace(PTRACE_POKETEXT, (!pid ? traceePid : pid), t.trapAddr,
|
||||
if (ptrace(PTRACE_POKETEXT,
|
||||
(!pid ? traceePid : pid),
|
||||
t.trapAddr,
|
||||
*reinterpret_cast<uintptr_t*>(repatchedBytes.data())) < 0) {
|
||||
LOG(ERROR) << "Execute: Couldn't poke text: " << strerror(errno);
|
||||
return false;
|
||||
@ -2120,8 +2151,8 @@ bool OIDebugger::writePrologue(
|
||||
|
||||
assert(off <= prologueLength);
|
||||
|
||||
return writeTargetMemory(&newInsts, (void*)segConfig.textSegBase,
|
||||
prologueLength);
|
||||
return writeTargetMemory(
|
||||
&newInsts, (void*)segConfig.textSegBase, prologueLength);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2161,7 +2192,9 @@ bool OIDebugger::compileCode() {
|
||||
} else {
|
||||
LOG(INFO) << "Attempting to get cache request from gobs";
|
||||
ObjectIntrospection::GobsService::requestCache(
|
||||
procpath, std::string(buf, buf_size), req.toString(),
|
||||
procpath,
|
||||
std::string(buf, buf_size),
|
||||
req.toString(),
|
||||
generatorConfig.toOptions());
|
||||
}
|
||||
#endif
|
||||
@ -2236,7 +2269,8 @@ bool OIDebugger::compileCode() {
|
||||
}
|
||||
|
||||
const auto& [rootType, typeHierarchy, paddingInfo] = typeInfos.at(req);
|
||||
cache.store(req, OICache::Entity::TypeHierarchy,
|
||||
cache.store(req,
|
||||
OICache::Entity::TypeHierarchy,
|
||||
std::make_pair(rootType, typeHierarchy));
|
||||
cache.store(req, OICache::Entity::PaddingInfo, paddingInfo);
|
||||
}
|
||||
@ -2256,8 +2290,8 @@ bool OIDebugger::compileCode() {
|
||||
for (const auto& o : objectFiles) {
|
||||
VLOG(2) << " * " << o;
|
||||
}
|
||||
auto relocRes = compiler.applyRelocs(segConfig.jitCodeStart, objectFiles,
|
||||
syntheticSymbols);
|
||||
auto relocRes = compiler.applyRelocs(
|
||||
segConfig.jitCodeStart, objectFiles, syntheticSymbols);
|
||||
if (!relocRes.has_value()) {
|
||||
LOG(ERROR) << "Failed to relocate object code";
|
||||
return false;
|
||||
@ -2292,7 +2326,8 @@ bool OIDebugger::compileCode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!writeTargetMemory(&dataSegSize, (void*)syntheticSymbols["dataSize"],
|
||||
if (!writeTargetMemory(&dataSegSize,
|
||||
(void*)syntheticSymbols["dataSize"],
|
||||
sizeof(dataSegSize))) {
|
||||
LOG(ERROR) << "Failed to write dataSegSize in probe's dataSize";
|
||||
return false;
|
||||
@ -2307,8 +2342,8 @@ bool OIDebugger::compileCode() {
|
||||
|
||||
int logFile =
|
||||
generatorConfig.features[Feature::JitLogging] ? segConfig.logFile : 0;
|
||||
if (!writeTargetMemory(&logFile, (void*)syntheticSymbols["logFile"],
|
||||
sizeof(logFile))) {
|
||||
if (!writeTargetMemory(
|
||||
&logFile, (void*)syntheticSymbols["logFile"], sizeof(logFile))) {
|
||||
LOG(ERROR) << "Failed to write logFile in probe's cookieValue";
|
||||
return false;
|
||||
}
|
||||
@ -2329,8 +2364,9 @@ void OIDebugger::restoreState(void) {
|
||||
* Ensure we don't have any trap in the target process still active.
|
||||
*/
|
||||
const size_t activeTrapsCount = std::count_if(
|
||||
activeTraps.cbegin(), activeTraps.cend(),
|
||||
[](const auto& t) { return t.second->trapKind != OID_TRAP_JITCODERET; });
|
||||
activeTraps.cbegin(), activeTraps.cend(), [](const auto& t) {
|
||||
return t.second->trapKind != OID_TRAP_JITCODERET;
|
||||
});
|
||||
VLOG(1) << "Active traps still within the target process: "
|
||||
<< activeTrapsCount;
|
||||
assert(activeTrapsCount == 0);
|
||||
@ -2562,7 +2598,9 @@ bool OIDebugger::targetAttach() {
|
||||
* here (note: ptrace(2) overloads the ESRCH return but with a seize
|
||||
* I think it can only mean one thing).
|
||||
*/
|
||||
if (ptrace(PTRACE_SEIZE, pid, NULL,
|
||||
if (ptrace(PTRACE_SEIZE,
|
||||
pid,
|
||||
NULL,
|
||||
PTRACE_O_TRACECLONE | PTRACE_O_TRACEFORK |
|
||||
PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXIT) < 0) {
|
||||
LOG(ERROR) << "Couldn't seize thread " << pid
|
||||
@ -2750,9 +2788,11 @@ bool OIDebugger::decodeTargetData(const DataHeader& dataHeader,
|
||||
static bool dumpDataSegment(const irequest& req,
|
||||
const std::vector<uint64_t>& dataSeg) {
|
||||
char dumpPath[PATH_MAX] = {0};
|
||||
auto dumpPathSize =
|
||||
snprintf(dumpPath, sizeof(dumpPath), "/tmp/dataseg.%d.%s.dump", getpid(),
|
||||
req.arg.c_str());
|
||||
auto dumpPathSize = snprintf(dumpPath,
|
||||
sizeof(dumpPath),
|
||||
"/tmp/dataseg.%d.%s.dump",
|
||||
getpid(),
|
||||
req.arg.c_str());
|
||||
if (dumpPathSize < 0 || (size_t)dumpPathSize > sizeof(dumpPath)) {
|
||||
LOG(ERROR) << "Failed to generate data-segment path";
|
||||
return false;
|
||||
@ -2781,7 +2821,8 @@ bool OIDebugger::processTargetData() {
|
||||
|
||||
std::vector<std::byte> buf{dataSegSize};
|
||||
if (!readTargetMemory(reinterpret_cast<void*>(segConfig.dataSegBase),
|
||||
buf.data(), dataSegSize)) {
|
||||
buf.data(),
|
||||
dataSegSize)) {
|
||||
LOG(ERROR) << "Failed to read data segment from target process";
|
||||
return false;
|
||||
}
|
||||
@ -2838,8 +2879,8 @@ bool OIDebugger::processTargetData() {
|
||||
}
|
||||
|
||||
try {
|
||||
typeTree.build(outVec, rootType.varName, rootType.type.type,
|
||||
typeHierarchy);
|
||||
typeTree.build(
|
||||
outVec, rootType.varName, rootType.type.type, typeHierarchy);
|
||||
} catch (std::exception& e) {
|
||||
LOG(ERROR) << "Failed to run TreeBuilder for " << req.arg;
|
||||
LOG(ERROR) << e.what();
|
||||
@ -2901,7 +2942,8 @@ std::optional<std::string> OIDebugger::generateCode(const irequest& req) {
|
||||
typeInfos.emplace(
|
||||
req,
|
||||
std::make_tuple(RootInfo{rootInfo.varName, codegen->getRootType()},
|
||||
codegen->getTypeHierarchy(), codegen->getPaddingInfo()));
|
||||
codegen->getTypeHierarchy(),
|
||||
codegen->getPaddingInfo()));
|
||||
|
||||
if (generatorConfig.features[Feature::TypeGraph]) {
|
||||
CodeGen codegen2{generatorConfig, *symbols};
|
||||
|
@ -113,7 +113,8 @@ class OIDebugger {
|
||||
return std::all_of(
|
||||
std::begin(pdata), std::end(pdata), [this](const auto& req) {
|
||||
return std::all_of(
|
||||
std::begin(req.args), std::end(req.args),
|
||||
std::begin(req.args),
|
||||
std::end(req.args),
|
||||
[this, &req](const auto& arg) {
|
||||
return cache.upload(irequest{req.type, req.func, arg});
|
||||
});
|
||||
@ -123,7 +124,8 @@ class OIDebugger {
|
||||
return std::all_of(
|
||||
std::begin(pdata), std::end(pdata), [this](const auto& req) {
|
||||
return std::all_of(
|
||||
std::begin(req.args), std::end(req.args),
|
||||
std::begin(req.args),
|
||||
std::end(req.args),
|
||||
[this, &req](const auto& arg) {
|
||||
return cache.download(irequest{req.type, req.func, arg});
|
||||
});
|
||||
|
@ -169,9 +169,12 @@ int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
|
||||
|
||||
{
|
||||
std::array<const char*, 1> objectPaths = {{primaryObject.c_str()}};
|
||||
if (auto err = drgnplusplus::error(drgn_program_load_debug_info(
|
||||
prog.get(), std::data(objectPaths), std::size(objectPaths), false,
|
||||
false))) {
|
||||
if (auto err = drgnplusplus::error(
|
||||
drgn_program_load_debug_info(prog.get(),
|
||||
std::data(objectPaths),
|
||||
std::size(objectPaths),
|
||||
false,
|
||||
false))) {
|
||||
LOG(ERROR) << "error loading debug info program: " << err;
|
||||
throw err;
|
||||
}
|
||||
@ -193,8 +196,8 @@ int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
|
||||
OICompiler::Config compilerConfig{};
|
||||
compilerConfig.usePIC = pic;
|
||||
|
||||
auto features = config::processConfigFiles(configFilePaths, featuresMap,
|
||||
compilerConfig, generatorConfig);
|
||||
auto features = config::processConfigFiles(
|
||||
configFilePaths, featuresMap, compilerConfig, generatorConfig);
|
||||
if (!features) {
|
||||
LOG(ERROR) << "failed to process config file";
|
||||
return -1;
|
||||
@ -204,8 +207,8 @@ int OIGenerator::generate(fs::path& primaryObject, SymbolService& symbols) {
|
||||
|
||||
size_t failures = 0;
|
||||
for (const auto& [linkageName, type] : oilTypes) {
|
||||
if (auto obj = generateForType(generatorConfig, compilerConfig, type,
|
||||
linkageName, symbols);
|
||||
if (auto obj = generateForType(
|
||||
generatorConfig, compilerConfig, type, linkageName, symbols);
|
||||
!obj.empty()) {
|
||||
std::cout << obj.string() << std::endl;
|
||||
} else {
|
||||
|
@ -40,8 +40,12 @@ drgn_qualified_type getTypeFromAtomicHole(drgn_program* prog, void* hole);
|
||||
} // namespace
|
||||
|
||||
OILibraryImpl::LocalTextSegment::LocalTextSegment(size_t size) {
|
||||
void* base = mmap(NULL, size, PROT_EXEC | PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
void* base = mmap(NULL,
|
||||
size,
|
||||
PROT_EXEC | PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1,
|
||||
0);
|
||||
if (base == MAP_FAILED)
|
||||
throw std::runtime_error(std::string("segment map failed: ") +
|
||||
std::strerror(errno));
|
||||
@ -93,9 +97,10 @@ std::pair<void*, const exporters::inst::Inst&> OILibraryImpl::init() {
|
||||
}
|
||||
|
||||
void OILibraryImpl::processConfigFile() {
|
||||
auto features =
|
||||
config::processConfigFiles(opts_.configFilePaths, requestedFeatures_,
|
||||
compilerConfig_, generatorConfig_);
|
||||
auto features = config::processConfigFiles(opts_.configFilePaths,
|
||||
requestedFeatures_,
|
||||
compilerConfig_,
|
||||
generatorConfig_);
|
||||
if (!features)
|
||||
throw std::runtime_error("failed to process configuration");
|
||||
|
||||
@ -164,7 +169,8 @@ std::pair<void*, const exporters::inst::Inst&> OILibraryImpl::compileCode() {
|
||||
|
||||
for (const auto& [baseAddr, relocAddr, size] : segments)
|
||||
std::memcpy(reinterpret_cast<void*>(relocAddr),
|
||||
reinterpret_cast<void*>(baseAddr), size);
|
||||
reinterpret_cast<void*>(baseAddr),
|
||||
size);
|
||||
|
||||
textSeg.release(); // don't munmap() the region containing the code
|
||||
return {fp, *ty};
|
||||
|
@ -80,7 +80,8 @@ class ParseData {
|
||||
public:
|
||||
void addReq(std::string type, std::string func, std::list<std::string> args) {
|
||||
// Convert the args std::list into a more efficient std::vector
|
||||
reqs.emplace_back(std::move(type), std::move(func),
|
||||
reqs.emplace_back(std::move(type),
|
||||
std::move(func),
|
||||
std::vector(std::make_move_iterator(args.begin()),
|
||||
std::make_move_iterator(args.end())));
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ void PaddingHunter::outputPaddingInfo() {
|
||||
|
||||
paddingStatsFile << "Total Saving Opportunity: " << sum << "\n\n\n";
|
||||
|
||||
std::sort(paddedStructsVec.begin(), paddedStructsVec.end(),
|
||||
std::sort(paddedStructsVec.begin(),
|
||||
paddedStructsVec.end(),
|
||||
[](const std::pair<std::string, PaddingInfo>& left,
|
||||
const std::pair<std::string, PaddingInfo>& right) {
|
||||
return left.second.instancesCnt * left.second.savingSize >
|
||||
|
@ -66,7 +66,13 @@ static bool LoadExecutableAddressRange(
|
||||
while (std::getline(f, line)) {
|
||||
if (sscanf(line.c_str(),
|
||||
"%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %" PRIu64 " %n",
|
||||
&start, &end, perm, &offset, &dmajor, &dminor, &inode,
|
||||
&start,
|
||||
&end,
|
||||
perm,
|
||||
&offset,
|
||||
&dmajor,
|
||||
&dminor,
|
||||
&inode,
|
||||
&nread) < 7 ||
|
||||
nread <= 0) {
|
||||
return false;
|
||||
@ -92,7 +98,9 @@ static bool isExecutableAddr(
|
||||
|
||||
// Find the smallest exeAddrs range where addr < range.end
|
||||
auto it = std::upper_bound(
|
||||
begin(exeAddrs), end(exeAddrs), std::make_pair(addr, addr),
|
||||
begin(exeAddrs),
|
||||
end(exeAddrs),
|
||||
std::make_pair(addr, addr),
|
||||
[](const auto& r1, const auto& r2) { return r1.second < r2.second; });
|
||||
|
||||
return it != end(exeAddrs) && addr >= it->first;
|
||||
@ -246,8 +254,9 @@ bool SymbolService::loadModulesFromPath(const fs::path& targetPath) {
|
||||
|
||||
Dwarf_Addr start = 0;
|
||||
Dwarf_Addr end = 0;
|
||||
if (dwfl_module_info(mod, nullptr, &start, &end, nullptr, nullptr, nullptr,
|
||||
nullptr) == nullptr) {
|
||||
if (dwfl_module_info(
|
||||
mod, nullptr, &start, &end, nullptr, nullptr, nullptr, nullptr) ==
|
||||
nullptr) {
|
||||
LOG(ERROR) << "dwfl_module_info: " << dwfl_errmsg(dwfl_errno());
|
||||
return false;
|
||||
}
|
||||
@ -442,8 +451,8 @@ struct drgn_program* SymbolService::getDrgnProgram() {
|
||||
auto executable = fs::read_symlink(
|
||||
"/proc/" + std::to_string(std::get<pid_t>(target)) + "/exe");
|
||||
const auto* executableCStr = executable.c_str();
|
||||
if (auto* err = drgn_program_load_debug_info(prog, &executableCStr, 1,
|
||||
false, false)) {
|
||||
if (auto* err = drgn_program_load_debug_info(
|
||||
prog, &executableCStr, 1, false, false)) {
|
||||
LOG(ERROR) << "Error loading debug info: " << err->message;
|
||||
return nullptr;
|
||||
}
|
||||
@ -769,8 +778,11 @@ std::shared_ptr<GlobalDesc> SymbolService::findGlobalDesc(
|
||||
drgn_object_deinit(&globalObj);
|
||||
};
|
||||
|
||||
if (auto* err = drgn_program_find_object(drgnProg, global.c_str(), nullptr,
|
||||
DRGN_FIND_OBJECT_ANY, &globalObj)) {
|
||||
if (auto* err = drgn_program_find_object(drgnProg,
|
||||
global.c_str(),
|
||||
nullptr,
|
||||
DRGN_FIND_OBJECT_ANY,
|
||||
&globalObj)) {
|
||||
LOG(ERROR) << "Failed to lookup global variable '" << global
|
||||
<< "': " << err->code << " " << err->message;
|
||||
|
||||
|
@ -455,7 +455,8 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
|
||||
auto childID = nextNodeID++;
|
||||
auto child = process(childID, Variable{entry->second, "", ""});
|
||||
node.children = {childID, childID + 1};
|
||||
setSize(node, child.staticSize + child.dynamicSize,
|
||||
setSize(node,
|
||||
child.staticSize + child.dynamicSize,
|
||||
child.staticSize + child.dynamicSize);
|
||||
}
|
||||
}
|
||||
@ -477,8 +478,8 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
|
||||
auto childID = nextNodeID++;
|
||||
auto child = process(childID, Variable{entry->second, "", ""});
|
||||
node.children = {childID, childID + 1};
|
||||
setSize(node, child.dynamicSize,
|
||||
child.dynamicSize + child.staticSize);
|
||||
setSize(
|
||||
node, child.dynamicSize, child.dynamicSize + child.staticSize);
|
||||
}
|
||||
} break;
|
||||
case DRGN_TYPE_CLASS:
|
||||
@ -532,10 +533,12 @@ TreeBuilder::Node TreeBuilder::process(NodeID id, Variable variable) {
|
||||
}
|
||||
}
|
||||
const auto& member = members[i];
|
||||
auto child =
|
||||
process(childID++,
|
||||
Variable{member.type, member.member_name,
|
||||
member.member_name, isset, member.isStubbed});
|
||||
auto child = process(childID++,
|
||||
Variable{member.type,
|
||||
member.member_name,
|
||||
member.member_name,
|
||||
isset,
|
||||
member.isStubbed});
|
||||
node.dynamicSize += child.dynamicSize;
|
||||
memberSizes += child.dynamicSize + child.staticSize;
|
||||
}
|
||||
@ -582,8 +585,8 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
|
||||
arrayElementType = drgn_type_type(variable.type).type;
|
||||
numElems = drgn_type_length(variable.type);
|
||||
} else {
|
||||
drgn_utils::getDrgnArrayElementType(variable.type, &arrayElementType,
|
||||
numElems);
|
||||
drgn_utils::getDrgnArrayElementType(
|
||||
variable.type, &arrayElementType, numElems);
|
||||
}
|
||||
assert(numElems > 0);
|
||||
elementTypes.push_back(
|
||||
@ -675,10 +678,11 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
|
||||
// elementTypes is only populated with the underlying container type for
|
||||
// container adapters
|
||||
auto containerType = elementTypes[0];
|
||||
auto child = process(
|
||||
childID++, {.type = containerType.type,
|
||||
.name = "",
|
||||
.typePath = drgnTypeToName(containerType.type) + "[]"});
|
||||
auto child =
|
||||
process(childID++,
|
||||
{.type = containerType.type,
|
||||
.name = "",
|
||||
.typePath = drgnTypeToName(containerType.type) + "[]"});
|
||||
|
||||
setSize(node, child.dynamicSize, child.dynamicSize + child.staticSize);
|
||||
node.containerStats = child.containerStats;
|
||||
@ -715,10 +719,11 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
|
||||
auto childID = node.children->first;
|
||||
|
||||
auto elementType = elementTypes[index];
|
||||
auto child = process(
|
||||
childID++, {.type = elementType.type,
|
||||
.name = "",
|
||||
.typePath = drgnTypeToName(elementType.type) + "[]"});
|
||||
auto child =
|
||||
process(childID++,
|
||||
{.type = elementType.type,
|
||||
.name = "",
|
||||
.typePath = drgnTypeToName(elementType.type) + "[]"});
|
||||
|
||||
setSize(node, child.dynamicSize, child.dynamicSize + child.staticSize);
|
||||
}
|
||||
@ -879,8 +884,9 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
|
||||
"uninitialized data in the target process");
|
||||
}
|
||||
if (std::ranges::all_of(
|
||||
elementTypes.cbegin(), elementTypes.cend(),
|
||||
[this](auto& type) { return isPrimitive(type.type); })) {
|
||||
elementTypes.cbegin(), elementTypes.cend(), [this](auto& type) {
|
||||
return isPrimitive(type.type);
|
||||
})) {
|
||||
VLOG(1)
|
||||
<< "Container [" << node.id
|
||||
<< "] contains only primitive types, skipping processing its members";
|
||||
@ -900,10 +906,10 @@ void TreeBuilder::processContainer(const Variable& variable, Node& node) {
|
||||
uint64_t memberSizes = 0;
|
||||
for (size_t i = 0; i < containerStats.length; i++) {
|
||||
for (auto& type : elementTypes) {
|
||||
auto child =
|
||||
process(childID++, {.type = type.type,
|
||||
.name = "",
|
||||
.typePath = drgnTypeToName(type.type) + "[]"});
|
||||
auto child = process(childID++,
|
||||
{.type = type.type,
|
||||
.name = "",
|
||||
.typePath = drgnTypeToName(type.type) + "[]"});
|
||||
node.dynamicSize += child.dynamicSize;
|
||||
memberSizes += child.dynamicSize + child.staticSize;
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ void Json::print(IntrospectionResult::const_iterator& it,
|
||||
out_ << (pretty_ ? ",\n" : ",") << indent;
|
||||
|
||||
out_ << tab << "\"typeNames\"" << space << ':' << space;
|
||||
printStringList(out_, it->type_names.begin(), it->type_names.end(),
|
||||
pretty_);
|
||||
printStringList(
|
||||
out_, it->type_names.begin(), it->type_names.end(), pretty_);
|
||||
out_ << ',' << endl << indent;
|
||||
|
||||
out_ << tab << "\"staticSize\":" << space << it->static_size << ',' << endl
|
||||
|
@ -145,8 +145,8 @@ TEST(TypeCheckingWalker, TestListEmpty) {
|
||||
TEST(TypeCheckingWalker, TestListSome) {
|
||||
// ASSIGN
|
||||
std::array<uint64_t, 3> listElements{59942, 44126, 64525};
|
||||
std::vector<uint64_t> data{listElements.size(), listElements[0],
|
||||
listElements[1], listElements[2]};
|
||||
std::vector<uint64_t> data{
|
||||
listElements.size(), listElements[0], listElements[1], listElements[2]};
|
||||
|
||||
types::dy::VarInt varint;
|
||||
types::dy::List rootType{varint};
|
||||
|
@ -123,8 +123,8 @@ void AddPadding::addPadding(uint64_t paddingStartBits,
|
||||
|
||||
if (paddingBits % 8 != 0) {
|
||||
// Pad with a bitfield up to the next byte
|
||||
paddedMembers.emplace_back(primitive, MemberPrefix, paddingStartBits,
|
||||
paddingBits % 8);
|
||||
paddedMembers.emplace_back(
|
||||
primitive, MemberPrefix, paddingStartBits, paddingBits % 8);
|
||||
}
|
||||
|
||||
uint64_t paddingBytes = paddingBits / 8;
|
||||
|
@ -180,8 +180,8 @@ Class& DrgnParser::enumerateClass(struct drgn_type* type) {
|
||||
std::to_string(drgn_type_kind(type))};
|
||||
}
|
||||
|
||||
auto& c = makeType<Class>(type, kind, std::move(name), std::move(fqName),
|
||||
size, virtuality);
|
||||
auto& c = makeType<Class>(
|
||||
type, kind, std::move(name), std::move(fqName), size, virtuality);
|
||||
|
||||
enumerateClassTemplateParams(type, c.templateParams);
|
||||
enumerateClassParents(type, c.parents);
|
||||
@ -402,7 +402,8 @@ void DrgnParser::enumerateClassFunctions(struct drgn_type* type,
|
||||
drgn_qualified_type t{};
|
||||
if (auto* err = drgn_member_function_type(&drgn_functions[i], &t)) {
|
||||
warnForDrgnError(
|
||||
type, "Error looking up member function (" + std::to_string(i) + ")",
|
||||
type,
|
||||
"Error looking up member function (" + std::to_string(i) + ")",
|
||||
err);
|
||||
continue;
|
||||
}
|
||||
|
@ -54,8 +54,8 @@ void flattenParent(const Parent& parent,
|
||||
}
|
||||
} else if (auto* parentContainer = dynamic_cast<Container*>(&parentType)) {
|
||||
// Create a new member to represent this parent container
|
||||
flattenedMembers.emplace_back(*parentContainer, Flattener::ParentPrefix,
|
||||
parent.bitOffset);
|
||||
flattenedMembers.emplace_back(
|
||||
*parentContainer, Flattener::ParentPrefix, parent.bitOffset);
|
||||
} else if (auto* parentPrimitive = dynamic_cast<Incomplete*>(&parentType)) {
|
||||
// Bad DWARF can lead to us seeing incomplete parent types. Just ignore
|
||||
// these as there is nothing we can do to recover the missing info.
|
||||
@ -151,7 +151,8 @@ void Flattener::visit(Class& c) {
|
||||
for (const auto& parent : c.parents) {
|
||||
Type& parentType = stripTypedefs(parent.type());
|
||||
if (Class* parentClass = dynamic_cast<Class*>(&parentType)) {
|
||||
c.functions.insert(c.functions.end(), parentClass->functions.begin(),
|
||||
c.functions.insert(c.functions.end(),
|
||||
parentClass->functions.begin(),
|
||||
parentClass->functions.end());
|
||||
}
|
||||
}
|
||||
@ -201,8 +202,8 @@ void Flattener::visit(Class& c) {
|
||||
// Pull in children from flattened children
|
||||
// This may result in duplicates, but that shouldn't be a big deal
|
||||
for (const Class& child : c.children) {
|
||||
c.children.insert(c.children.end(), child.children.begin(),
|
||||
child.children.end());
|
||||
c.children.insert(
|
||||
c.children.end(), child.children.begin(), child.children.end());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,8 +112,8 @@ void TypeIdentifier::visit(Container& c) {
|
||||
typeToAllocate, size, param.type().align(), allocator->name());
|
||||
c.templateParams[i] = dummy;
|
||||
} else {
|
||||
auto& dummy = typeGraph_.makeType<Dummy>(size, param.type().align(),
|
||||
param.type().name());
|
||||
auto& dummy = typeGraph_.makeType<Dummy>(
|
||||
size, param.type().align(), param.type().name());
|
||||
c.templateParams[i] = dummy;
|
||||
}
|
||||
}
|
||||
|
@ -310,8 +310,8 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
|
||||
auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
|
||||
std::string inputName{*tryParseInputName(line)};
|
||||
auto& typeToAlloc = parseType(input, indent + 2);
|
||||
type = &typeGraph_.makeType<DummyAllocator>(id, typeToAlloc, size, 0,
|
||||
inputName);
|
||||
type = &typeGraph_.makeType<DummyAllocator>(
|
||||
id, typeToAlloc, size, 0, inputName);
|
||||
} else {
|
||||
throw TypeGraphParserError{"Unsupported node type: " +
|
||||
std::string{nodeTypeName}};
|
||||
|
@ -35,17 +35,35 @@ std::vector<std::string> global_oid_args{};
|
||||
|
||||
constexpr static OIOpts cliOpts{
|
||||
OIOpt{'h', "help", no_argument, nullptr, "Print this message and exit"},
|
||||
OIOpt{'p', "preserve", no_argument, nullptr,
|
||||
OIOpt{'p',
|
||||
"preserve",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Do not clean up files generated by OID after tests are finished"},
|
||||
OIOpt{'P', "preserve-on-failure", no_argument, nullptr,
|
||||
OIOpt{'P',
|
||||
"preserve-on-failure",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Do not clean up files generated by OID for failed tests"},
|
||||
OIOpt{'v', "verbose", no_argument, nullptr,
|
||||
OIOpt{'v',
|
||||
"verbose",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Verbose output. Show OID's stdout and stderr on test failure"},
|
||||
OIOpt{'f', "force", no_argument, nullptr,
|
||||
OIOpt{'f',
|
||||
"force",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Force running tests, even if they are marked as skipped"},
|
||||
OIOpt{'x', "oid", required_argument, nullptr,
|
||||
OIOpt{'x',
|
||||
"oid",
|
||||
required_argument,
|
||||
nullptr,
|
||||
"Path to OID executable to test"},
|
||||
OIOpt{'\0', "enable-feature", required_argument, nullptr,
|
||||
OIOpt{'\0',
|
||||
"enable-feature",
|
||||
required_argument,
|
||||
nullptr,
|
||||
"Enable extra OID feature."},
|
||||
};
|
||||
|
||||
@ -64,8 +82,9 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, cliOpts.shortOpts(), cliOpts.longOpts(),
|
||||
nullptr)) != -1) {
|
||||
while ((c = getopt_long(
|
||||
argc, argv, cliOpts.shortOpts(), cliOpts.longOpts(), nullptr)) !=
|
||||
-1) {
|
||||
switch (c) {
|
||||
case 'p':
|
||||
preserve = true;
|
||||
@ -193,8 +212,8 @@ OidProc OidIntegration::runOidOnProcess(OidOpts opts,
|
||||
|
||||
// The arguments are appended in ascending order of precedence (low -> high)
|
||||
std::vector<std::string> oid_args;
|
||||
oid_args.insert(oid_args.end(), global_oid_args.begin(),
|
||||
global_oid_args.end());
|
||||
oid_args.insert(
|
||||
oid_args.end(), global_oid_args.begin(), global_oid_args.end());
|
||||
oid_args.insert(oid_args.end(), extra_args.begin(), extra_args.end());
|
||||
oid_args.insert(oid_args.end(), default_args.begin(), default_args.end());
|
||||
|
||||
@ -269,7 +288,9 @@ OidProc OidIntegration::runOidOnProcess(OidOpts opts,
|
||||
|
||||
return OidProc{
|
||||
.target = Proc{opts.ctx, std::move(targetProcess), {}, {}},
|
||||
.oid = Proc{opts.ctx, std::move(oidProcess), std::move(std_out),
|
||||
.oid = Proc{opts.ctx,
|
||||
std::move(oidProcess),
|
||||
std::move(std_out),
|
||||
std::move(std_err)},
|
||||
};
|
||||
}
|
||||
@ -298,8 +319,10 @@ void IntegrationBase::compare_json(const bpt::ptree& expected_json,
|
||||
for (auto e_it = expected_json.begin(), a_it = actual_json.begin();
|
||||
e_it != expected_json.end() && a_it != actual_json.end();
|
||||
e_it++, a_it++) {
|
||||
compare_json(e_it->second, a_it->second,
|
||||
full_key + "[" + std::to_string(i) + "]", expect_eq);
|
||||
compare_json(e_it->second,
|
||||
a_it->second,
|
||||
full_key + "[" + std::to_string(i) + "]",
|
||||
expect_eq);
|
||||
i++;
|
||||
}
|
||||
return;
|
||||
@ -417,6 +440,8 @@ Proc OilIntegration::runOilTarget(OilOpts opts,
|
||||
opts.ctx);
|
||||
// clang-format on
|
||||
|
||||
return Proc{opts.ctx, std::move(targetProcess), std::move(std_out),
|
||||
return Proc{opts.ctx,
|
||||
std::move(targetProcess),
|
||||
std::move(std_out),
|
||||
std::move(std_err)};
|
||||
}
|
||||
|
@ -66,7 +66,8 @@ TEST_F(AddChildrenTest, InheritanceStatic) {
|
||||
}
|
||||
|
||||
TEST_F(AddChildrenTest, InheritancePolymorphic) {
|
||||
testMultiCompilerGlob("oid_test_case_inheritance_polymorphic_a_as_a", R"(
|
||||
testMultiCompilerGlob("oid_test_case_inheritance_polymorphic_a_as_a",
|
||||
R"(
|
||||
[1] Pointer
|
||||
[0] Class: A (size: 16)
|
||||
Member: _vptr$A (offset: 0)
|
||||
|
@ -7,7 +7,8 @@
|
||||
using namespace type_graph;
|
||||
|
||||
TEST(AddPaddingTest, BetweenMembers) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 16)
|
||||
Member: n1 (offset: 0)
|
||||
Primitive: int8_t
|
||||
@ -27,7 +28,8 @@ TEST(AddPaddingTest, BetweenMembers) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, AtBeginning) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Struct: MyStruct (size: 16)
|
||||
Member: n1 (offset: 8)
|
||||
Primitive: int64_t
|
||||
@ -43,7 +45,8 @@ TEST(AddPaddingTest, AtBeginning) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, AtEnd) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Struct: MyStruct (size: 16)
|
||||
Member: n1 (offset: 0)
|
||||
Primitive: int64_t
|
||||
@ -63,7 +66,8 @@ TEST(AddPaddingTest, AtEnd) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, UnionBetweenMembers) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Union: MyUnion (size: 8)
|
||||
Member: n1 (offset: 0)
|
||||
Primitive: int64_t
|
||||
@ -80,7 +84,8 @@ TEST(AddPaddingTest, UnionBetweenMembers) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, UnionAtEnd) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Union: MyUnion (size: 16)
|
||||
Member: n1 (offset: 0)
|
||||
Primitive: int64_t
|
||||
@ -100,7 +105,8 @@ TEST(AddPaddingTest, UnionAtEnd) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, Bitfields) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 16)
|
||||
Member: b1 (offset: 0, bitsize: 3)
|
||||
Primitive: int64_t
|
||||
@ -148,7 +154,8 @@ TEST(AddPaddingTest, EmptyClass) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, MemberlessClass) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 12)
|
||||
)",
|
||||
R"(
|
||||
@ -160,7 +167,8 @@ TEST(AddPaddingTest, MemberlessClass) {
|
||||
}
|
||||
|
||||
TEST(AddPaddingTest, MemberlessUnion) {
|
||||
test(AddPadding::createPass(), R"(
|
||||
test(AddPadding::createPass(),
|
||||
R"(
|
||||
[0] Union: MyUnion (size: 16)
|
||||
)",
|
||||
R"(
|
||||
|
@ -6,7 +6,8 @@
|
||||
using namespace type_graph;
|
||||
|
||||
TEST(AlignmentCalcTest, PrimitiveMembers) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 16)
|
||||
Member: n (offset: 0)
|
||||
Primitive: int8_t
|
||||
@ -23,7 +24,8 @@ TEST(AlignmentCalcTest, PrimitiveMembers) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, StructMembers) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 12)
|
||||
Member: n (offset: 0)
|
||||
Primitive: int8_t
|
||||
@ -48,7 +50,8 @@ TEST(AlignmentCalcTest, StructMembers) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, StructInContainer) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 8)
|
||||
Param
|
||||
[1] Class: MyClass (size: 16)
|
||||
@ -69,7 +72,8 @@ TEST(AlignmentCalcTest, StructInContainer) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, PackedMembers) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Struct: MyStruct (size: 8)
|
||||
Member: n1 (offset: 0)
|
||||
Primitive: int8_t
|
||||
@ -98,7 +102,8 @@ TEST(AlignmentCalcTest, PackedMembers) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, PackedTailPadding) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Struct: MyStruct (size: 5)
|
||||
Member: n1 (offset: 0)
|
||||
Primitive: int32_t
|
||||
@ -115,7 +120,8 @@ TEST(AlignmentCalcTest, PackedTailPadding) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, RecurseClassParam) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Param
|
||||
[1] Class: ClassA (size: 16)
|
||||
@ -136,7 +142,8 @@ TEST(AlignmentCalcTest, RecurseClassParam) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, RecurseClassParent) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassA (size: 16)
|
||||
@ -157,7 +164,8 @@ TEST(AlignmentCalcTest, RecurseClassParent) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, RecurseClassMember) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Member: xxx (offset: 0)
|
||||
[1] Class: ClassA (size: 16)
|
||||
@ -178,7 +186,8 @@ TEST(AlignmentCalcTest, RecurseClassMember) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, RecurseClassChild) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Child
|
||||
[1] Class: ClassA (size: 16)
|
||||
@ -199,7 +208,8 @@ TEST(AlignmentCalcTest, RecurseClassChild) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, Bitfields) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 8)
|
||||
Member: a (offset: 0, bitsize: 2)
|
||||
Primitive: int8_t
|
||||
@ -216,7 +226,8 @@ TEST(AlignmentCalcTest, Bitfields) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, Array) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 1)
|
||||
Member: a (offset: 0)
|
||||
[1] Array: (length: 1)
|
||||
@ -235,7 +246,8 @@ TEST(AlignmentCalcTest, Array) {
|
||||
}
|
||||
|
||||
TEST(AlignmentCalcTest, Typedef) {
|
||||
test(AlignmentCalc::createPass(), R"(
|
||||
test(AlignmentCalc::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 1)
|
||||
Member: a (offset: 0)
|
||||
[1] Typedef: MyTypedef
|
||||
|
@ -114,7 +114,8 @@ TEST(CodeGenTest, TransformContainerAllocatorParamInParent) {
|
||||
TEST(CodeGenTest, RemovedMemberAlignment) {
|
||||
OICodeGen::Config config;
|
||||
config.membersToStub = {{"MyClass", "b"}};
|
||||
testTransform(config, R"(
|
||||
testTransform(config,
|
||||
R"(
|
||||
[0] Class: MyClass (size: 24)
|
||||
Member: a (offset: 0)
|
||||
Primitive: int8_t
|
||||
|
@ -50,9 +50,12 @@ TEST(CompilerTest, CompileAndRelocate) {
|
||||
EXPECT_TRUE(compiler.compile(code, sourcePath, objectPath));
|
||||
|
||||
const size_t relocSlabSize = 4096;
|
||||
void* relocSlab =
|
||||
mmap(nullptr, relocSlabSize, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
void* relocSlab = mmap(nullptr,
|
||||
relocSlabSize,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1,
|
||||
0);
|
||||
EXPECT_NE(relocSlab, nullptr);
|
||||
|
||||
auto relocResult =
|
||||
@ -128,13 +131,16 @@ TEST(CompilerTest, CompileAndRelocateMultipleObjs) {
|
||||
EXPECT_TRUE(compiler.compile(codeY, sourceYPath, objectYPath));
|
||||
|
||||
const size_t relocSlabSize = 8192;
|
||||
void* relocSlab =
|
||||
mmap(nullptr, relocSlabSize, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
void* relocSlab = mmap(nullptr,
|
||||
relocSlabSize,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1,
|
||||
0);
|
||||
EXPECT_NE(relocSlab, nullptr);
|
||||
|
||||
auto relocResult = compiler.applyRelocs((uintptr_t)relocSlab,
|
||||
{objectXPath, objectYPath}, {});
|
||||
auto relocResult = compiler.applyRelocs(
|
||||
(uintptr_t)relocSlab, {objectXPath, objectYPath}, {});
|
||||
EXPECT_TRUE(relocResult.has_value());
|
||||
|
||||
auto& [_, segs, jitSymbols] = relocResult.value();
|
||||
@ -254,10 +260,10 @@ TEST(CompilerTest, LocateOpcodes) {
|
||||
{ /* Large range of differently sized needles */
|
||||
const std::array needles = {
|
||||
std::vector{0x41_b, 0x54_b}, /* push r12: 1 instance */
|
||||
std::vector{0x48_b, 0x83_b, 0xec_b,
|
||||
0x18_b}, /* sub rsp,0x18: 1 instance */
|
||||
std::vector(1, 0xe8_b), /* call: 4 instances */
|
||||
std::vector{0x41_b, 0x5c_b}, /* pop r12: 1 instance */
|
||||
std::vector{
|
||||
0x48_b, 0x83_b, 0xec_b, 0x18_b}, /* sub rsp,0x18: 1 instance */
|
||||
std::vector(1, 0xe8_b), /* call: 4 instances */
|
||||
std::vector{0x41_b, 0x5c_b}, /* pop r12: 1 instance */
|
||||
};
|
||||
auto locs = OICompiler::locateOpcodes(insts, needles);
|
||||
ASSERT_TRUE(locs.has_value());
|
||||
|
@ -253,7 +253,8 @@ TEST_F(DrgnParserTest, InheritanceMultiple) {
|
||||
}
|
||||
|
||||
TEST_F(DrgnParserTest, Container) {
|
||||
testMultiCompilerGlob("oid_test_case_std_vector_int_empty", R"(
|
||||
testMultiCompilerGlob("oid_test_case_std_vector_int_empty",
|
||||
R"(
|
||||
[13] Pointer
|
||||
[0] Class: vector<int, std::allocator<int> > (size: 24)
|
||||
Param
|
||||
@ -340,7 +341,8 @@ TEST_F(DrgnParserTest, EnumNoValues) {
|
||||
DrgnParserOptions options{
|
||||
.readEnumValues = false,
|
||||
};
|
||||
test("oid_test_case_enums_scoped", R"(
|
||||
test("oid_test_case_enums_scoped",
|
||||
R"(
|
||||
Enum: ScopedEnum (size: 4)
|
||||
)",
|
||||
options);
|
||||
@ -408,7 +410,8 @@ TEST_F(DrgnParserTest, PointerNoFollow) {
|
||||
DrgnParserOptions options{
|
||||
.chaseRawPointers = false,
|
||||
};
|
||||
test("oid_test_case_pointers_struct_primitive_ptrs", R"(
|
||||
test("oid_test_case_pointers_struct_primitive_ptrs",
|
||||
R"(
|
||||
[1] Pointer
|
||||
[0] Struct: PrimitivePtrs (size: 24)
|
||||
Member: a (offset: 0)
|
||||
@ -582,7 +585,8 @@ TEST_F(DrgnParserTest, MemberAlignment) {
|
||||
}
|
||||
|
||||
TEST_F(DrgnParserTest, VirtualFunctions) {
|
||||
testMultiCompiler("oid_test_case_inheritance_polymorphic_a_as_a", R"(
|
||||
testMultiCompiler("oid_test_case_inheritance_polymorphic_a_as_a",
|
||||
R"(
|
||||
[1] Pointer
|
||||
[0] Class: A (size: 16)
|
||||
Member: _vptr$A (offset: 0)
|
||||
|
@ -6,7 +6,8 @@
|
||||
using namespace type_graph;
|
||||
|
||||
TEST(EnforceCompatibilityTest, ParentContainers) {
|
||||
test(EnforceCompatibility::createPass(), R"(
|
||||
test(EnforceCompatibility::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 24)
|
||||
Member: __oi_parent (offset: 0)
|
||||
[1] Container: std::vector (size: 24)
|
||||
@ -19,7 +20,8 @@ TEST(EnforceCompatibilityTest, ParentContainers) {
|
||||
}
|
||||
|
||||
TEST(EnforceCompatibilityTest, TypesToStub) {
|
||||
test(EnforceCompatibility::createPass(), R"(
|
||||
test(EnforceCompatibility::createPass(),
|
||||
R"(
|
||||
[0] Class: EnumMap (size: 8)
|
||||
Member: a (offset: 0)
|
||||
Primitive: int32_t
|
||||
@ -32,7 +34,8 @@ TEST(EnforceCompatibilityTest, TypesToStub) {
|
||||
}
|
||||
|
||||
TEST(EnforceCompatibilityTest, VoidPointer) {
|
||||
test(EnforceCompatibility::createPass(), R"(
|
||||
test(EnforceCompatibility::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 8)
|
||||
Member: p (offset: 0)
|
||||
[1] Pointer
|
||||
|
@ -39,7 +39,8 @@ TEST(FlattenerTest, OnlyParents) {
|
||||
// int b;
|
||||
// int c;
|
||||
// };
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 8)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -72,7 +73,8 @@ TEST(FlattenerTest, ParentsFirst) {
|
||||
// int a;
|
||||
// };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -109,7 +111,8 @@ TEST(FlattenerTest, MembersFirst) {
|
||||
// int c;
|
||||
// };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Parent (offset: 4)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -147,7 +150,8 @@ TEST(FlattenerTest, MixedMembersAndParents) {
|
||||
// int c;
|
||||
// };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 16)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -188,7 +192,8 @@ TEST(FlattenerTest, EmptyParent) {
|
||||
// int a2;
|
||||
// };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 0)
|
||||
@ -227,7 +232,8 @@ TEST(FlattenerTest, TwoDeep) {
|
||||
// int a;
|
||||
// };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 16)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 8)
|
||||
@ -271,7 +277,8 @@ TEST(FlattenerTest, DiamondInheritance) {
|
||||
// int a;
|
||||
// };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 16)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 8)
|
||||
@ -309,7 +316,8 @@ TEST(FlattenerTest, Member) {
|
||||
// class B { int c; int b; };
|
||||
// Class A { int a; B b; };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Member: a (offset: 0)
|
||||
Primitive: int32_t
|
||||
@ -345,7 +353,8 @@ TEST(FlattenerTest, MemberOfParent) {
|
||||
// class C { int c; };
|
||||
// class A { int b; C c; int a; };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 8)
|
||||
@ -381,7 +390,8 @@ TEST(FlattenerTest, ContainerParam) {
|
||||
// class A { int b; int a; };
|
||||
// std::vector<A, int>
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
[1] Class: ClassA (size: 8)
|
||||
@ -413,7 +423,8 @@ TEST(FlattenerTest, Array) {
|
||||
// class A : B { int a; };
|
||||
// A[5]
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Array: (length: 5)
|
||||
[1] Class: ClassA (size: 8)
|
||||
Parent (offset: 0)
|
||||
@ -439,7 +450,8 @@ TEST(FlattenerTest, Typedef) {
|
||||
// class A : B { int a; };
|
||||
// using aliasA = A;
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Typedef: aliasA
|
||||
[1] Class: ClassA (size: 8)
|
||||
Parent (offset: 0)
|
||||
@ -465,7 +477,8 @@ TEST(FlattenerTest, TypedefParent) {
|
||||
// using aliasB = B;
|
||||
// class A : aliasB { int a; };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 8)
|
||||
Parent (offset: 0)
|
||||
[1] Typedef: aliasB
|
||||
@ -502,7 +515,8 @@ TEST(FlattenerTest, Pointer) {
|
||||
auto classC = Class{0, Class::Kind::Class, "ClassC", 8};
|
||||
classC.members.push_back(Member{ptrA, "a", 0});
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassC (size: 8)
|
||||
Member: a (offset: 0)
|
||||
[1] Pointer
|
||||
@ -539,7 +553,8 @@ TEST(FlattenerTest, PointerCycle) {
|
||||
classA.members.push_back(Member{classB, "b", 0});
|
||||
classB.members.push_back(Member{ptrA, "a", 0});
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 69)
|
||||
Member: b (offset: 0)
|
||||
[1] Class: ClassB (size: 69)
|
||||
@ -565,7 +580,8 @@ TEST(FlattenerTest, Alignment) {
|
||||
// class B { alignas(8) int b; };
|
||||
// class A : B, C { int a; };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -605,7 +621,8 @@ TEST(FlattenerTest, Functions) {
|
||||
classB.functions.push_back(Function{"funcB"});
|
||||
classC.functions.push_back(Function{"funcC"});
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 0)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 0)
|
||||
@ -629,7 +646,8 @@ TEST(FlattenerTest, Children) {
|
||||
// class B { int b; };
|
||||
// class A : B, C { };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassB (size: 4)
|
||||
Member: b (offset: 0)
|
||||
Primitive: int32_t
|
||||
@ -664,7 +682,8 @@ TEST(FlattenerTest, ChildrenTwoDeep) {
|
||||
// class B : D { int b; };
|
||||
// class A : B, C { int a; };
|
||||
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassD (size: 4)
|
||||
Member: d (offset: 0)
|
||||
Primitive: int32_t
|
||||
@ -713,7 +732,8 @@ TEST(FlattenerTest, ChildrenTwoDeep) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, ParentContainer) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 32)
|
||||
Parent (offset: 0)
|
||||
[1] Container: std::vector (size: 24)
|
||||
@ -734,7 +754,8 @@ TEST(FlattenerTest, ParentContainer) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, ParentTwoContainers) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 48)
|
||||
Parent (offset: 0)
|
||||
[1] Container: std::vector (size: 24)
|
||||
@ -755,7 +776,8 @@ TEST(FlattenerTest, ParentTwoContainers) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, ParentClassAndContainer) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 32)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -778,7 +800,8 @@ TEST(FlattenerTest, ParentClassAndContainer) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, AllocatorParamInParent) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Container: std::map (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -836,7 +859,8 @@ TEST(FlattenerTest, AllocatorUnfixableNoParent) {
|
||||
|
||||
TEST(FlattenerTest, AllocatorUnfixableParentNotClass) {
|
||||
// This could be supported if need-be, we just don't do it yet
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -875,7 +899,8 @@ TEST(FlattenerTest, AllocatorUnfixableParentNotClass) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, AllocatorUnfixableParentNoParams) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -902,7 +927,8 @@ TEST(FlattenerTest, AllocatorUnfixableParentNoParams) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, AllocatorUnfixableParentParamIsValue) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Container: std::map (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -936,7 +962,8 @@ TEST(FlattenerTest, AllocatorUnfixableParentParamIsValue) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, ClassParam) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 4)
|
||||
Param
|
||||
[1] Class: MyChild (size: 4)
|
||||
@ -955,7 +982,8 @@ TEST(FlattenerTest, ClassParam) {
|
||||
}
|
||||
|
||||
TEST(FlattenerTest, IncompleteParent) {
|
||||
test(Flattener::createPass(), R"(
|
||||
test(Flattener::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 4)
|
||||
Parent (offset: 0)
|
||||
Incomplete: [IncompleteParent]
|
||||
|
@ -9,7 +9,8 @@ using namespace type_graph;
|
||||
|
||||
namespace {
|
||||
void test(std::string_view input, std::string_view expectedAfter) {
|
||||
::test(IdentifyContainers::createPass(getContainerInfos()), input,
|
||||
::test(IdentifyContainers::createPass(getContainerInfos()),
|
||||
input,
|
||||
expectedAfter);
|
||||
}
|
||||
}; // namespace
|
||||
|
@ -11,7 +11,8 @@ TEST(KeyCaptureTest, InClass) {
|
||||
{"MyClass", "b"},
|
||||
};
|
||||
std::vector<std::unique_ptr<ContainerInfo>> containerInfos;
|
||||
test(KeyCapture::createPass(keysToCapture, containerInfos), R"(
|
||||
test(KeyCapture::createPass(keysToCapture, containerInfos),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 12)
|
||||
Member: a (offset: 0)
|
||||
Primitive: int32_t
|
||||
@ -45,7 +46,8 @@ TEST(KeyCaptureTest, MapInMap) {
|
||||
{"MyClass", "a"},
|
||||
};
|
||||
std::vector<std::unique_ptr<ContainerInfo>> containerInfos;
|
||||
test(KeyCapture::createPass(keysToCapture, containerInfos), R"(
|
||||
test(KeyCapture::createPass(keysToCapture, containerInfos),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 12)
|
||||
Member: a (offset: 8)
|
||||
[1] Container: std::map (size: 24)
|
||||
@ -79,7 +81,8 @@ TEST(KeyCaptureTest, TopLevel) {
|
||||
{{}, {}, true},
|
||||
};
|
||||
std::vector<std::unique_ptr<ContainerInfo>> containerInfos;
|
||||
test(KeyCapture::createPass(keysToCapture, containerInfos), R"(
|
||||
test(KeyCapture::createPass(keysToCapture, containerInfos),
|
||||
R"(
|
||||
[0] Container: std::map (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
|
@ -92,7 +92,8 @@ TEST(ParserTest, MangledFunc) {
|
||||
"EEESaISF_EERS1_IS8_SaIS8_EERS1_ISB_IS8_dESaISM_EE:arg9");
|
||||
EXPECT_EQ(pdata.numReqs(), 1);
|
||||
EXPECT_REQ_EQ(
|
||||
pdata.getReq(0), "entry",
|
||||
pdata.getReq(0),
|
||||
"entry",
|
||||
"_Z7doStuffR3FooRSt6vectorISt3mapINSt7__cxx1112basic_stringIcSt11char_"
|
||||
"traitsIcESaIcEEES8_St4lessIS8_ESaISt4pairIKS8_S8_EEESaISF_EERS1_IS8_"
|
||||
"SaIS8_EERS1_ISB_IS8_dESaISM_EE",
|
||||
|
@ -6,7 +6,8 @@
|
||||
using type_graph::Prune;
|
||||
|
||||
TEST(PruneTest, PruneClass) {
|
||||
test(Prune::createPass(), R"(
|
||||
test(Prune::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 8)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -34,7 +35,8 @@ TEST(PruneTest, PruneClass) {
|
||||
}
|
||||
|
||||
TEST(PruneTest, RecurseClassMember) {
|
||||
test(Prune::createPass(), R"(
|
||||
test(Prune::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Member: xxx (offset: 0)
|
||||
[1] Class: ClassA (size: 12)
|
||||
@ -48,7 +50,8 @@ TEST(PruneTest, RecurseClassMember) {
|
||||
}
|
||||
|
||||
TEST(PruneTest, RecurseClassChild) {
|
||||
test(Prune::createPass(), R"(
|
||||
test(Prune::createPass(),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Child
|
||||
[1] Class: ClassA (size: 12)
|
||||
|
@ -11,7 +11,8 @@ TEST(RemoveMembersTest, Match) {
|
||||
{"ClassA", "b"},
|
||||
};
|
||||
|
||||
test(RemoveMembers::createPass(membersToIgnore), R"(
|
||||
test(RemoveMembers::createPass(membersToIgnore),
|
||||
R"(
|
||||
[0] Class: ClassA (size: 12)
|
||||
Member: a (offset: 0)
|
||||
[1] Class: ClassB (size: 4)
|
||||
@ -65,7 +66,8 @@ TEST(RemoveMembersTest, RecurseClassParam) {
|
||||
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
|
||||
{"ClassA", "b"},
|
||||
};
|
||||
test(RemoveMembers::createPass(membersToIgnore), R"(
|
||||
test(RemoveMembers::createPass(membersToIgnore),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Param
|
||||
[1] Class: ClassA (size: 12)
|
||||
@ -91,7 +93,8 @@ TEST(RemoveMembersTest, RecurseClassParent) {
|
||||
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
|
||||
{"ClassA", "b"},
|
||||
};
|
||||
test(RemoveMembers::createPass(membersToIgnore), R"(
|
||||
test(RemoveMembers::createPass(membersToIgnore),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Parent (offset: 0)
|
||||
[1] Class: ClassA (size: 12)
|
||||
@ -117,7 +120,8 @@ TEST(RemoveMembersTest, RecurseClassMember) {
|
||||
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
|
||||
{"ClassA", "b"},
|
||||
};
|
||||
test(RemoveMembers::createPass(membersToIgnore), R"(
|
||||
test(RemoveMembers::createPass(membersToIgnore),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Member: xxx (offset: 0)
|
||||
[1] Class: ClassA (size: 12)
|
||||
@ -143,7 +147,8 @@ TEST(RemoveMembersTest, RecurseClassChild) {
|
||||
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
|
||||
{"ClassA", "b"},
|
||||
};
|
||||
test(RemoveMembers::createPass(membersToIgnore), R"(
|
||||
test(RemoveMembers::createPass(membersToIgnore),
|
||||
R"(
|
||||
[0] Class: MyClass (size: 0)
|
||||
Child
|
||||
[1] Class: ClassA (size: 12)
|
||||
@ -166,7 +171,8 @@ TEST(RemoveMembersTest, RecurseClassChild) {
|
||||
}
|
||||
|
||||
TEST(RemoveMembersTest, Union) {
|
||||
test(RemoveMembers::createPass({}), R"(
|
||||
test(RemoveMembers::createPass({}),
|
||||
R"(
|
||||
[0] Union: MyUnion (size: 4)
|
||||
Member: a (offset: 0)
|
||||
Primitive: int32_t
|
||||
|
@ -7,7 +7,8 @@
|
||||
using namespace type_graph;
|
||||
|
||||
TEST(RemoveTopLevelPointerTest, TopLevelPointerRemoved) {
|
||||
test(RemoveTopLevelPointer::createPass(), R"(
|
||||
test(RemoveTopLevelPointer::createPass(),
|
||||
R"(
|
||||
[0] Pointer
|
||||
[1] Class: MyClass (size: 4)
|
||||
Member: n (offset: 0)
|
||||
|
@ -7,7 +7,8 @@
|
||||
using namespace type_graph;
|
||||
|
||||
TEST(TypeIdentifierTest, StubbedParam) {
|
||||
test(TypeIdentifier::createPass({}), R"(
|
||||
test(TypeIdentifier::createPass({}),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -30,7 +31,8 @@ TEST(TypeIdentifierTest, StubbedParam) {
|
||||
}
|
||||
|
||||
TEST(TypeIdentifierTest, Allocator) {
|
||||
test(TypeIdentifier::createPass({}), R"(
|
||||
test(TypeIdentifier::createPass({}),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -56,7 +58,8 @@ TEST(TypeIdentifierTest, Allocator) {
|
||||
}
|
||||
|
||||
TEST(TypeIdentifierTest, AllocatorSize1) {
|
||||
test(TypeIdentifier::createPass({}), R"(
|
||||
test(TypeIdentifier::createPass({}),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -85,7 +88,8 @@ TEST(TypeIdentifierTest, PassThroughTypes) {
|
||||
std::vector<ContainerInfo> passThroughTypes;
|
||||
passThroughTypes.emplace_back("std::allocator", DUMMY_TYPE, "memory");
|
||||
|
||||
test(TypeIdentifier::createPass(passThroughTypes), R"(
|
||||
test(TypeIdentifier::createPass(passThroughTypes),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -111,7 +115,8 @@ TEST(TypeIdentifierTest, PassThroughSameType) {
|
||||
std::vector<ContainerInfo> passThroughTypes;
|
||||
passThroughTypes.emplace_back("std::allocator", DUMMY_TYPE, "memory");
|
||||
|
||||
test(TypeIdentifier::createPass(passThroughTypes), R"(
|
||||
test(TypeIdentifier::createPass(passThroughTypes),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
@ -138,7 +143,8 @@ TEST(TypeIdentifierTest, PassThroughSameType) {
|
||||
}
|
||||
|
||||
TEST(TypeIdentifierTest, ContainerNotReplaced) {
|
||||
test(TypeIdentifier::createPass({}), R"(
|
||||
test(TypeIdentifier::createPass({}),
|
||||
R"(
|
||||
[0] Container: std::vector (size: 24)
|
||||
Param
|
||||
Primitive: int32_t
|
||||
|
@ -31,17 +31,35 @@ using namespace oi::detail;
|
||||
|
||||
constexpr static OIOpts opts{
|
||||
OIOpt{'h', "help", no_argument, nullptr, "Print this message and exit."},
|
||||
OIOpt{'o', "output", required_argument, "<file>",
|
||||
OIOpt{'o',
|
||||
"output",
|
||||
required_argument,
|
||||
"<file>",
|
||||
"Write output(s) to file(s) with this prefix."},
|
||||
OIOpt{'c', "config-file", required_argument, "<oid.toml>",
|
||||
OIOpt{'c',
|
||||
"config-file",
|
||||
required_argument,
|
||||
"<oid.toml>",
|
||||
"Path to OI configuration file."},
|
||||
OIOpt{'d', "debug-level", required_argument, "<level>",
|
||||
OIOpt{'d',
|
||||
"debug-level",
|
||||
required_argument,
|
||||
"<level>",
|
||||
"Verbose level for logging"},
|
||||
OIOpt{'j', "dump-jit", optional_argument, "<jit.cpp>",
|
||||
OIOpt{'j',
|
||||
"dump-jit",
|
||||
optional_argument,
|
||||
"<jit.cpp>",
|
||||
"Write generated code to a file (for debugging)."},
|
||||
OIOpt{'e', "exit-code", no_argument, nullptr,
|
||||
OIOpt{'e',
|
||||
"exit-code",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Return a bad exit code if nothing is generated."},
|
||||
OIOpt{'p', "pic", no_argument, nullptr,
|
||||
OIOpt{'p',
|
||||
"pic",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Generate position independent code."},
|
||||
};
|
||||
|
||||
@ -68,8 +86,8 @@ int main(int argc, char* argv[]) {
|
||||
bool pic = false;
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, opts.shortOpts(), opts.longOpts(),
|
||||
nullptr)) != -1) {
|
||||
while ((c = getopt_long(
|
||||
argc, argv, opts.shortOpts(), opts.longOpts(), nullptr)) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
|
@ -208,7 +208,9 @@ void printFuncArg(const std::shared_ptr<FuncDesc::TargetObject>& funcObj) {
|
||||
const auto& location = funcArg->locator.locations[i];
|
||||
printf(
|
||||
"{\"start\":\"0x%zx\",\"end\":\"0x%zx\",\"expr_size\":%zu,\"expr\":[",
|
||||
location.start, location.end, location.expr_size);
|
||||
location.start,
|
||||
location.end,
|
||||
location.expr_size);
|
||||
for (size_t j = 0; j < location.expr_size; j++) {
|
||||
if (j > 0) {
|
||||
printf(",");
|
||||
@ -232,8 +234,8 @@ void printFuncDesc(const std::shared_ptr<FuncDesc>& funcDesc) {
|
||||
if (!isFirstRange) {
|
||||
printf(",");
|
||||
}
|
||||
printf("{\"start\": \"0x%zx\", \"end\": \"0x%zx\"}", range.start,
|
||||
range.end);
|
||||
printf(
|
||||
"{\"start\": \"0x%zx\", \"end\": \"0x%zx\"}", range.start, range.end);
|
||||
isFirstRange = false;
|
||||
}
|
||||
printf("],");
|
||||
|
@ -227,8 +227,10 @@ int main(int argc, const char** argv) {
|
||||
rocksdb::DB* _db = nullptr;
|
||||
if (auto status = rocksdb::DB::Open(options, dbpath.string(), &_db);
|
||||
!status.ok()) {
|
||||
fprintf(stderr, "Failed to open DB '%s' with error %s\n",
|
||||
dbpath.string().c_str(), status.ToString().c_str());
|
||||
fprintf(stderr,
|
||||
"Failed to open DB '%s' with error %s\n",
|
||||
dbpath.string().c_str(),
|
||||
status.ToString().c_str());
|
||||
return 1;
|
||||
}
|
||||
db.reset(_db);
|
||||
|
@ -36,15 +36,24 @@ using namespace oi::detail;
|
||||
|
||||
constexpr static OIOpts opts{
|
||||
OIOpt{'h', "help", no_argument, nullptr, "Print this message and exit"},
|
||||
OIOpt{'a', "log-all-structs", no_argument, nullptr,
|
||||
OIOpt{'a',
|
||||
"log-all-structs",
|
||||
no_argument,
|
||||
nullptr,
|
||||
"Enable TreeBuilder::Config::logAllStructs (=true)\n"
|
||||
"Note: this option is already enabled, this is a no-op"},
|
||||
OIOpt{'J', "dump-json", optional_argument, "[oid_out.json]",
|
||||
OIOpt{'J',
|
||||
"dump-json",
|
||||
optional_argument,
|
||||
"[oid_out.json]",
|
||||
"File to dump the results to, as JSON\n"
|
||||
"(in addition to the default RocksDB output)"},
|
||||
OIOpt{'f', "enable-feature", required_argument, "FEATURE",
|
||||
"Enable feature"},
|
||||
OIOpt{'F', "disable-feature", required_argument, "FEATURE",
|
||||
OIOpt{
|
||||
'f', "enable-feature", required_argument, "FEATURE", "Enable feature"},
|
||||
OIOpt{'F',
|
||||
"disable-feature",
|
||||
required_argument,
|
||||
"FEATURE",
|
||||
"Disable feature"},
|
||||
};
|
||||
|
||||
@ -146,8 +155,8 @@ int main(int argc, char* argv[]) {
|
||||
};
|
||||
|
||||
int c = '\0';
|
||||
while ((c = getopt_long(argc, argv, opts.shortOpts(), opts.longOpts(),
|
||||
nullptr)) != -1) {
|
||||
while ((c = getopt_long(
|
||||
argc, argv, opts.shortOpts(), opts.longOpts(), nullptr)) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage(std::cout);
|
||||
|
Loading…
Reference in New Issue
Block a user