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