Snap for 12199973 from 38ecfff1e1d5978b6f4fb4f56133eeb8723535cd to 24Q4-release
Change-Id: I5b8894a59a3b263c8a4514d7506e38beff0875a6
diff --git a/Android.bp b/Android.bp
index 1d0a4e3..a5cf21c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -75,6 +75,7 @@
"deduplication.cc",
"dwarf_processor.cc",
"dwarf_wrappers.cc",
+ "elf_dwarf_handle.cc",
"elf_loader.cc",
"elf_reader.cc",
"fidelity.cc",
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f28e0d5..3849b1c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -85,6 +85,7 @@
deduplication.cc
dwarf_processor.cc
dwarf_wrappers.cc
+ elf_dwarf_handle.cc
elf_loader.cc
elf_reader.cc
fidelity.cc
@@ -140,6 +141,7 @@
error_test
file_descriptor_test
filter_test
+ hex_test
order_test
reporting_test
runtime_test
diff --git a/abigail_reader.cc b/abigail_reader.cc
index f1deff3..8708fc3 100644
--- a/abigail_reader.cc
+++ b/abigail_reader.cc
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2021-2023 Google LLC
+// Copyright 2021-2024 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -526,10 +526,10 @@
//
// 2. Reanonymise anonymous types that have been given names.
//
-// At some point abidw changed its behaviour given an anonymous with a naming
-// typedef. In addition to linking the typedef and type in both directions, the
-// code now gives (some) anonymous types the same name as the typedef. This
-// misrepresents the original types.
+// At some point abidw changed its behaviour given an anonymous type with a
+// naming typedef. In addition to linking the typedef and type in both
+// directions, the code now gives (some) anonymous types the same name as the
+// typedef. This misrepresents the original types.
//
// Such types should be anonymous. We set is-anonymous and drop the name.
//
@@ -789,25 +789,124 @@
return {};
}
-} // namespace
+// Parser for libabigail's ABI XML format, creating a Symbol-Type Graph.
+//
+// On construction Abigail consumes a libxml node tree and builds a graph.
+//
+// Note that the core parser sees a "clean and tidy" XML document due to
+// preprocessing that simplifies the XML and resolves several issues. One
+// notable exception is that duplicate nodes may still remain.
+//
+// The main producer of ABI XML is abidw. The format has no formal specification
+// and has very limited semantic versioning. This parser makes no attempt to
+// support or correct for deficiencies in older versions of the format.
+//
+// The parser detects and will abort on the presence of unexpected elements.
+//
+// The parser ignores attributes it doesn't care about, including member access
+// specifiers and (meaningless) type ids on array dimensions.
+//
+// The STG IR and libabigail ABI XML models diverge in some ways. The parser has
+// to do extra work for each of these, as follows.
+//
+// 0. XML uses type and symbol ids to link together elements. These become edges
+// in the graph between symbols and types and between types and types. Dangling
+// type references will cause an abort. libabigail is much more relaxed about
+// symbols without type information and these are modelled as such.
+//
+// 1. XML function declarations have in-line types. The parser creates
+// free-standing types on-the-fly. A useful space optimisation might be to
+// prevent duplicate creation of such types.
+//
+// 2. Variadic parameters are currently flagged with an XML attribute. A
+// variadic type node is created on demand and will be shared by all such
+// paramerters.
+//
+// 3. XML symbols and aliases have a rather poor repesentation with aliases
+// represented as comma-separated attribute values. Aliases are resolved in a
+// post-processing phase.
+//
+// 4. XML anonymous types may also have names, these are ignored.
+class Abigail {
+ public:
+ explicit Abigail(Graph& graph);
+ Id ProcessRoot(xmlNodePtr root);
-Abigail::Abigail(Graph& graph) : graph_(graph) {}
+ private:
+ struct SymbolInfo {
+ std::string name;
+ std::optional<ElfSymbol::VersionInfo> version_info;
+ xmlNodePtr node;
+ };
-Id Abigail::GetNode(const std::string& type_id) {
- const auto [it, inserted] = type_ids_.insert({type_id, Id(0)});
- if (inserted) {
- it->second = graph_.Allocate();
- }
- return it->second;
-}
+ // Map from libabigail type ids to STG node ids; except for the type of
+ // variadic parameters.
+ Maker<std::string> maker_;
+ // The STG IR uses a distinct node type for the variadic parameter type; if
+ // allocated, this is its STG node id.
+ std::optional<Id> variadic_;
+
+ // symbol id to symbol information
+ std::unordered_map<std::string, SymbolInfo> symbol_info_map_;
+ // alias symbol id to main symbol id
+ std::unordered_map<std::string, std::string> alias_to_main_;
+ // libabigail decorates certain declarations with symbol ids; this is the
+ // mapping from symbol id to the corresponding type and full name.
+ std::unordered_map<std::string, std::pair<Id, std::string>>
+ symbol_id_and_full_name_;
+
+ // Full name of the current scope.
+ Scope scope_name_;
+
+ Id GetEdge(xmlNodePtr element);
+ Id GetVariadic();
+ Function MakeFunctionType(xmlNodePtr function);
+
+ void ProcessCorpusGroup(xmlNodePtr group);
+ void ProcessCorpus(xmlNodePtr corpus);
+ void ProcessSymbols(xmlNodePtr symbols);
+ void ProcessSymbol(xmlNodePtr symbol);
+
+ bool ProcessUserDefinedType(std::string_view name, const std::string& id,
+ xmlNodePtr decl);
+ void ProcessScope(xmlNodePtr scope);
+
+ void ProcessInstr(xmlNodePtr instr);
+ void ProcessNamespace(xmlNodePtr scope);
+
+ Id ProcessDecl(bool is_variable, xmlNodePtr decl);
+
+ void ProcessFunctionType(const std::string& id, xmlNodePtr function);
+ void ProcessTypedef(const std::string& id, xmlNodePtr type_definition);
+ void ProcessPointer(const std::string& id, bool is_pointer,
+ xmlNodePtr pointer);
+ void ProcessQualified(const std::string& id, xmlNodePtr qualified);
+ void ProcessArray(const std::string& id, xmlNodePtr array);
+ void ProcessTypeDecl(const std::string& id, xmlNodePtr type_decl);
+ void ProcessStructUnion(const std::string& id, bool is_struct,
+ xmlNodePtr struct_union);
+ void ProcessEnum(const std::string& id, xmlNodePtr enumeration);
+
+ Id ProcessBaseClass(xmlNodePtr base_class);
+ std::optional<Id> ProcessDataMember(bool is_struct, xmlNodePtr data_member);
+ void ProcessMemberFunction(std::vector<Id>& methods, xmlNodePtr method);
+ void ProcessMemberType(xmlNodePtr member_type);
+
+ Id BuildSymbol(const SymbolInfo& info,
+ std::optional<Id> type_id,
+ const std::optional<std::string>& name);
+ Id BuildSymbols();
+};
+
+Abigail::Abigail(Graph& graph) : maker_(graph) {}
Id Abigail::GetEdge(xmlNodePtr element) {
- return GetNode(GetAttributeOrDie(element, "type-id"));
+ return maker_.Get(GetAttributeOrDie(element, "type-id"));
}
Id Abigail::GetVariadic() {
if (!variadic_) {
- variadic_ = {graph_.Add<Special>(Special::Kind::VARIADIC)};
+ variadic_ = {maker_.Add<Special>(Special::Kind::VARIADIC)};
}
return *variadic_;
}
@@ -833,7 +932,7 @@
if (!return_type) {
Die() << "missing return-type";
}
- return Function(*return_type, parameters);
+ return {*return_type, parameters};
}
Id Abigail::ProcessRoot(xmlNodePtr root) {
@@ -847,14 +946,7 @@
} else {
Die() << "unrecognised root element '" << name << "'";
}
- for (const auto& [type_id, id] : type_ids_) {
- if (!graph_.Is(id)) {
- Warn() << "no definition found for type '" << type_id << "'";
- }
- }
- const Id id = BuildSymbols();
- RemoveUselessQualifiers(graph_, id);
- return id;
+ return BuildSymbols();
}
void Abigail::ProcessCorpusGroup(xmlNodePtr group) {
@@ -920,8 +1012,8 @@
}
}
-bool Abigail::ProcessUserDefinedType(std::string_view name, Id id,
- xmlNodePtr decl) {
+bool Abigail::ProcessUserDefinedType(
+ std::string_view name, const std::string& id, xmlNodePtr decl) {
if (name == "typedef-decl") {
ProcessTypedef(id, decl);
} else if (name == "class-decl") {
@@ -939,14 +1031,10 @@
void Abigail::ProcessScope(xmlNodePtr scope) {
for (auto* element = Child(scope); element; element = Next(element)) {
const auto name = GetName(element);
- const auto type_id = GetAttribute(element, "id");
+ const auto maybe_id = GetAttribute(element, "id");
// all type elements have "id", all non-types do not
- if (type_id) {
- const auto id = GetNode(*type_id);
- if (graph_.Is(id)) {
- Warn() << "duplicate definition of type '" << *type_id << '\'';
- continue;
- }
+ if (maybe_id) {
+ const auto& id = *maybe_id;
if (name == "function-type") {
ProcessFunctionType(id, element);
} else if (name == "pointer-type-def") {
@@ -990,7 +1078,7 @@
const auto name = scope_name_ + GetAttributeOrDie(decl, "name");
const auto symbol_id = GetAttribute(decl, "elf-symbol-id");
const auto type = is_variable ? GetEdge(decl)
- : graph_.Add<Function>(MakeFunctionType(decl));
+ : maker_.Add<Function>(MakeFunctionType(decl));
if (symbol_id) {
// There's a link to an ELF symbol.
const auto [it, inserted] = symbol_id_and_full_name_.emplace(
@@ -1002,25 +1090,27 @@
return type;
}
-void Abigail::ProcessFunctionType(Id id, xmlNodePtr function) {
- graph_.Set<Function>(id, MakeFunctionType(function));
+void Abigail::ProcessFunctionType(const std::string& id, xmlNodePtr function) {
+ maker_.MaybeSet<Function>(id, MakeFunctionType(function));
}
-void Abigail::ProcessTypedef(Id id, xmlNodePtr type_definition) {
+void Abigail::ProcessTypedef(const std::string& id,
+ xmlNodePtr type_definition) {
const auto name = scope_name_ + GetAttributeOrDie(type_definition, "name");
const auto type = GetEdge(type_definition);
- graph_.Set<Typedef>(id, name, type);
+ maker_.MaybeSet<Typedef>(id, name, type);
}
-void Abigail::ProcessPointer(Id id, bool is_pointer, xmlNodePtr pointer) {
+void Abigail::ProcessPointer(const std::string& id, bool is_pointer,
+ xmlNodePtr pointer) {
const auto type = GetEdge(pointer);
const auto kind = is_pointer ? PointerReference::Kind::POINTER
: ReadAttribute<PointerReference::Kind>(
pointer, "kind", &ParseReferenceKind);
- graph_.Set<PointerReference>(id, kind, type);
+ maker_.MaybeSet<PointerReference>(id, kind, type);
}
-void Abigail::ProcessQualified(Id id, xmlNodePtr qualified) {
+void Abigail::ProcessQualified(const std::string& id, xmlNodePtr qualified) {
std::vector<Qualifier> qualifiers;
// Do these in reverse order so we get CVR ordering.
if (ReadAttribute<bool>(qualified, "restrict", false)) {
@@ -1041,14 +1131,14 @@
--count;
const Qualified node(qualifier, type);
if (count) {
- type = graph_.Add<Qualified>(node);
+ type = maker_.Add<Qualified>(node);
} else {
- graph_.Set<Qualified>(id, node);
+ maker_.MaybeSet<Qualified>(id, node);
}
}
}
-void Abigail::ProcessArray(Id id, xmlNodePtr array) {
+void Abigail::ProcessArray(const std::string& id, xmlNodePtr array) {
std::vector<size_t> dimensions;
for (auto* child = Child(array); child; child = Next(child)) {
CheckName("subrange", child);
@@ -1073,14 +1163,14 @@
const auto size = *it;
const Array node(size, type);
if (count) {
- type = graph_.Add<Array>(node);
+ type = maker_.Add<Array>(node);
} else {
- graph_.Set<Array>(id, node);
+ maker_.MaybeSet<Array>(id, node);
}
}
}
-void Abigail::ProcessTypeDecl(Id id, xmlNodePtr type_decl) {
+void Abigail::ProcessTypeDecl(const std::string& id, xmlNodePtr type_decl) {
const auto name = scope_name_ + GetAttributeOrDie(type_decl, "name");
const auto bits = ReadAttribute<size_t>(type_decl, "size-in-bits", 0);
if (bits % 8) {
@@ -1089,15 +1179,15 @@
const auto bytes = bits / 8;
if (name == "void") {
- graph_.Set<Special>(id, Special::Kind::VOID);
+ maker_.MaybeSet<Special>(id, Special::Kind::VOID);
} else {
// libabigail doesn't model encoding at all and we don't want to parse names
// (which will not always work) in an attempt to reconstruct it.
- graph_.Set<Primitive>(id, name, /* encoding= */ std::nullopt, bytes);
+ maker_.MaybeSet<Primitive>(id, name, /* encoding= */ std::nullopt, bytes);
}
}
-void Abigail::ProcessStructUnion(Id id, bool is_struct,
+void Abigail::ProcessStructUnion(const std::string& id, bool is_struct,
xmlNodePtr struct_union) {
// Libabigail sometimes reports is-declaration-only but still provides some
// child elements. So we check both things.
@@ -1115,7 +1205,7 @@
is_anonymous ? std::string() : scope_name_ + name;
const PushScopeName push_scope_name(scope_name_, kind, name);
if (forward) {
- graph_.Set<StructUnion>(id, kind, full_name);
+ maker_.MaybeSet<StructUnion>(id, kind, full_name);
return;
}
const auto bits = ReadAttribute<size_t>(struct_union, "size-in-bits", 0);
@@ -1142,18 +1232,18 @@
}
}
- graph_.Set<StructUnion>(id, kind, full_name, bytes, base_classes, methods,
- members);
+ maker_.MaybeSet<StructUnion>(id, kind, full_name, bytes, base_classes,
+ methods, members);
}
-void Abigail::ProcessEnum(Id id, xmlNodePtr enumeration) {
+void Abigail::ProcessEnum(const std::string& id, xmlNodePtr enumeration) {
const bool forward =
ReadAttribute<bool>(enumeration, "is-declaration-only", false);
const auto name = ReadAttribute<bool>(enumeration, "is-anonymous", false)
? std::string()
: scope_name_ + GetAttributeOrDie(enumeration, "name");
if (forward) {
- graph_.Set<Enumeration>(id, name);
+ maker_.MaybeSet<Enumeration>(id, name);
return;
}
@@ -1173,7 +1263,7 @@
enumerators.emplace_back(enumerator_name, enumerator_value);
}
- graph_.Set<Enumeration>(id, name, type, enumerators);
+ maker_.MaybeSet<Enumeration>(id, name, type, enumerators);
}
Id Abigail::ProcessBaseClass(xmlNodePtr base_class) {
@@ -1183,7 +1273,7 @@
const auto inheritance = ReadAttribute<bool>(base_class, "is-virtual", false)
? BaseClass::Inheritance::VIRTUAL
: BaseClass::Inheritance::NON_VIRTUAL;
- return graph_.Add<BaseClass>(type, offset, inheritance);
+ return maker_.Add<BaseClass>(type, offset, inheritance);
}
std::optional<Id> Abigail::ProcessDataMember(bool is_struct,
@@ -1203,7 +1293,7 @@
const auto type = GetEdge(decl);
// Note: libabigail does not model member size, yet
- return {graph_.Add<Member>(name, type, offset, 0)};
+ return {maker_.Add<Member>(name, type, offset, 0)};
}
void Abigail::ProcessMemberFunction(std::vector<Id>& methods,
@@ -1218,18 +1308,13 @@
const auto mangled_name = ReadAttribute(decl, "mangled-name", missing);
const auto name = GetAttributeOrDie(decl, "name");
methods.push_back(
- graph_.Add<Method>(mangled_name, name, vtable_offset.value(), type));
+ maker_.Add<Method>(mangled_name, name, vtable_offset.value(), type));
}
}
void Abigail::ProcessMemberType(xmlNodePtr member_type) {
const xmlNodePtr decl = GetOnlyChild(member_type);
- const auto type_id = GetAttributeOrDie(decl, "id");
- const auto id = GetNode(type_id);
- if (graph_.Is(id)) {
- Warn() << "duplicate definition of member type '" << type_id << '\'';
- return;
- }
+ const auto id = GetAttributeOrDie(decl, "id");
const auto name = GetName(decl);
if (!ProcessUserDefinedType(name, id, decl)) {
Die() << "unrecognised member-type child element '" << name << "'";
@@ -1249,7 +1334,7 @@
const auto visibility =
ReadAttributeOrDie<ElfSymbol::Visibility>(symbol, "visibility");
- return graph_.Add<ElfSymbol>(
+ return maker_.Add<ElfSymbol>(
info.name, info.version_info,
is_defined, type, binding, visibility, crc, ns, type_id, name);
}
@@ -1264,7 +1349,7 @@
// symbol / alias -> type
//
for (const auto& [alias, main] : alias_to_main_) {
- Check(!alias_to_main_.count(main))
+ Check(!alias_to_main_.contains(main))
<< "found main symbol and alias with id " << main;
}
// Build final symbol table, tying symbols to their types.
@@ -1282,34 +1367,59 @@
}
symbols.insert({id, BuildSymbol(symbol_info, type_id, name)});
}
- return graph_.Add<Interface>(symbols);
+ return maker_.Add<Interface>(symbols);
}
-Document Read(Runtime& runtime, const std::string& path) {
- // Open input for reading.
- const FileDescriptor fd(path.c_str(), O_RDONLY);
+using Parser = xmlDocPtr(xmlParserCtxtPtr context, const char* url,
+ const char* encoding, int options);
- // Read the XML.
+Document Parse(Runtime& runtime, const std::function<Parser>& parser) {
+ const std::unique_ptr<
+ std::remove_pointer_t<xmlParserCtxtPtr>, void(*)(xmlParserCtxtPtr)>
+ context(xmlNewParserCtxt(), xmlFreeParserCtxt);
Document document(nullptr, xmlFreeDoc);
{
const Time t(runtime, "abigail.libxml_parse");
- const std::unique_ptr<
- std::remove_pointer_t<xmlParserCtxtPtr>, void(*)(xmlParserCtxtPtr)>
- context(xmlNewParserCtxt(), xmlFreeParserCtxt);
- document.reset(
- xmlCtxtReadFd(context.get(), fd.Value(), nullptr, nullptr,
- XML_PARSE_NONET));
+ document.reset(parser(context.get(), nullptr, nullptr, XML_PARSE_NONET));
}
Check(document != nullptr) << "failed to parse input as XML";
-
return document;
}
-Id Read(Runtime& runtime, Graph& graph, const std::string& path) {
- const Document document = Read(runtime, path);
- const xmlNodePtr root = xmlDocGetRootElement(document.get());
+} // namespace
+
+Id ProcessDocument(Graph& graph, xmlDocPtr document) {
+ xmlNodePtr root = xmlDocGetRootElement(document);
Check(root != nullptr) << "XML document has no root element";
- return Abigail(graph).ProcessRoot(root);
+ const Id id = Abigail(graph).ProcessRoot(root);
+ return RemoveUselessQualifiers(graph, id);
+}
+
+Document Read(Runtime& runtime, const std::string& path) {
+ const FileDescriptor fd(path.c_str(), O_RDONLY);
+ return Parse(runtime, [&](xmlParserCtxtPtr context, const char* url,
+ const char* encoding, int options) {
+ return xmlCtxtReadFd(context, fd.Value(), url, encoding, options);
+ });
+}
+
+Id Read(Runtime& runtime, Graph& graph, const std::string& path) {
+ // Read the XML.
+ const Document document = Read(runtime, path);
+ // Process the XML.
+ return ProcessDocument(graph, document.get());
+}
+
+Id ReadFromString(Runtime& runtime, Graph& graph, const std::string_view xml) {
+ // Read the XML.
+ const Document document =
+ Parse(runtime, [&](xmlParserCtxtPtr context, const char* url,
+ const char* encoding, int options) {
+ return xmlCtxtReadMemory(context, xml.data(), static_cast<int>(xml.size()),
+ url, encoding, options);
+ });
+ // Process the XML.
+ return ProcessDocument(graph, document.get());
}
} // namespace abixml
diff --git a/abigail_reader.h b/abigail_reader.h
index 3123f93..3cd5617 100644
--- a/abigail_reader.h
+++ b/abigail_reader.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2021-2023 Google LLC
+// Copyright 2021-2024 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -22,131 +22,20 @@
#define STG_ABIGAIL_READER_H_
#include <memory>
-#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
-#include <unordered_map>
-#include <utility>
-#include <vector>
#include <libxml/tree.h>
#include "graph.h"
#include "runtime.h"
-#include "scope.h"
namespace stg {
namespace abixml {
-// Parser for libabigail's ABI XML format, creating a Symbol-Type Graph.
-//
-// On construction Abigail consumes a libxml node tree and builds a graph.
-//
-// The parser supports C types only, with C++ types to be added later.
-//
-// The main producer of ABI XML is abidw. The format has no formal specification
-// and has very limited semantic versioning. This parser makes no attempt to
-// support or correct for deficiencies in older versions of the format.
-//
-// The parser detects unexpected elements and will abort on the presence of at
-// least: namespace, base class and member function information.
-//
-// The parser ignores attributes it doesn't care about, including member access
-// specifiers and (meaningless) type ids on array dimensions.
-//
-// The STG IR and libabigail ABI XML models diverge in some ways. The parser has
-// to do extra work for each of these, as follows.
-//
-// 0. XML uses type and symbol ids to link together elements. These become edges
-// in the graph between symbols and types and between types and types. Dangling
-// type references will cause an abort. libabigail is much more relaxed about
-// symbols without type information and these are modelled as such.
-//
-// 1. XML function declarations have in-line types. The parser creates
-// free-standing types on-the-fly. A useful space optimisation might be to
-// prevent duplicate creation of such types.
-//
-// 2. Variadic parameters are currently flagged with an XML attribute. A
-// variadic type node is created on demand and will be shared by all such
-// paramerters.
-//
-// 3. XML symbols and aliases have a rather poor repesentation with aliases
-// represented as comma-separated attribute values. Aliases are resolved in a
-// post-processing phase.
-//
-// 4. XML anonymous types also have unhelpful names, these are ignored.
-class Abigail {
- public:
- explicit Abigail(Graph& graph);
- Id ProcessRoot(xmlNodePtr root);
-
- private:
- struct SymbolInfo {
- std::string name;
- std::optional<ElfSymbol::VersionInfo> version_info;
- xmlNodePtr node;
- };
-
- Graph& graph_;
-
- // The STG IR uses a distinct node type for the variadic parameter type; if
- // allocated, this is its STG node id.
- std::optional<Id> variadic_;
- // Map from libabigail type ids to STG node ids; except for the type of
- // variadic parameters.
- std::unordered_map<std::string, Id> type_ids_;
-
- // symbol id to symbol information
- std::unordered_map<std::string, SymbolInfo> symbol_info_map_;
- // alias symbol id to main symbol id
- std::unordered_map<std::string, std::string> alias_to_main_;
- // libabigail decorates certain declarations with symbol ids; this is the
- // mapping from symbol id to the corresponding type and full name.
- std::unordered_map<std::string, std::pair<Id, std::string>>
- symbol_id_and_full_name_;
-
- // Full name of the current scope.
- Scope scope_name_;
-
- Id GetNode(const std::string& type_id);
- Id GetEdge(xmlNodePtr element);
- Id GetVariadic();
- Function MakeFunctionType(xmlNodePtr function);
-
- void ProcessCorpusGroup(xmlNodePtr group);
- void ProcessCorpus(xmlNodePtr corpus);
- void ProcessSymbols(xmlNodePtr symbols);
- void ProcessSymbol(xmlNodePtr symbol);
-
- bool ProcessUserDefinedType(std::string_view name, Id id, xmlNodePtr decl);
- void ProcessScope(xmlNodePtr scope);
-
- void ProcessInstr(xmlNodePtr instr);
- void ProcessNamespace(xmlNodePtr scope);
-
- Id ProcessDecl(bool is_variable, xmlNodePtr decl);
-
- void ProcessFunctionType(Id id, xmlNodePtr function);
- void ProcessTypedef(Id id, xmlNodePtr type_definition);
- void ProcessPointer(Id id, bool is_pointer, xmlNodePtr pointer);
- void ProcessQualified(Id id, xmlNodePtr qualified);
- void ProcessArray(Id id, xmlNodePtr array);
- void ProcessTypeDecl(Id id, xmlNodePtr type_decl);
- void ProcessStructUnion(Id id, bool is_struct, xmlNodePtr struct_union);
- void ProcessEnum(Id id, xmlNodePtr enumeration);
-
- Id ProcessBaseClass(xmlNodePtr base_class);
- std::optional<Id> ProcessDataMember(bool is_struct, xmlNodePtr data_member);
- void ProcessMemberFunction(std::vector<Id>& methods, xmlNodePtr method);
- void ProcessMemberType(xmlNodePtr member_type);
-
- Id BuildSymbol(const SymbolInfo& info,
- std::optional<Id> type_id,
- const std::optional<std::string>& name);
- Id BuildSymbols();
-};
-
+Id ProcessDocument(Graph& graph, xmlDocPtr document);
Id Read(Runtime& runtime, Graph& graph, const std::string& path);
+Id ReadFromString(Runtime& runtime, Graph& graph, std::string_view xml);
// Exposed for testing.
void Clean(xmlNodePtr root);
diff --git a/btf_reader.cc b/btf_reader.cc
index 75ec360..397d996 100644
--- a/btf_reader.cc
+++ b/btf_reader.cc
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2020-2022 Google LLC
+// Copyright 2020-2024 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -30,6 +30,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <map>
#include <memory>
#include <optional>
#include <sstream>
@@ -39,6 +40,7 @@
#include <vector>
#include <linux/btf.h>
+#include "elf_dwarf_handle.h"
#include "elf_loader.h"
#include "error.h"
#include "file_descriptor.h"
@@ -49,6 +51,54 @@
namespace btf {
+namespace {
+
+// BTF Specification: https://www.kernel.org/doc/html/latest/bpf/btf.html
+class Structs {
+ public:
+ explicit Structs(Graph& graph);
+ Id Process(std::string_view data);
+
+ private:
+ struct MemoryRange {
+ const char* start;
+ const char* limit;
+ bool Empty() const;
+ template <typename T> const T* Pull(size_t count = 1);
+ };
+
+ MemoryRange string_section_;
+
+ Maker<uint32_t> maker_;
+ std::optional<Id> void_;
+ std::optional<Id> variadic_;
+ std::map<std::string, Id> btf_symbols_;
+
+ Id ProcessAligned(std::string_view data);
+
+ Id GetVoid();
+ Id GetVariadic();
+ Id GetIdRaw(uint32_t btf_index);
+ Id GetId(uint32_t btf_index);
+ Id GetParameterId(uint32_t btf_index);
+ template <typename Node, typename... Args>
+ void Set(uint32_t id, Args&&... args);
+
+ Id BuildTypes(MemoryRange memory);
+ void BuildOneType(const btf_type* t, uint32_t btf_index,
+ MemoryRange& memory);
+ Id BuildSymbols();
+ std::vector<Id> BuildMembers(
+ bool kflag, const btf_member* members, size_t vlen);
+ Enumeration::Enumerators BuildEnums(
+ bool is_signed, const struct btf_enum* enums, size_t vlen);
+ Enumeration::Enumerators BuildEnums64(
+ bool is_signed, const struct btf_enum64* enums, size_t vlen);
+ std::vector<Id> BuildParams(const struct btf_param* params, size_t vlen);
+ Id BuildEnumUnderlyingType(size_t size, bool is_signed);
+ std::string GetName(uint32_t name_off);
+};
+
bool Structs::MemoryRange::Empty() const {
return start == limit;
}
@@ -62,12 +112,12 @@
}
Structs::Structs(Graph& graph)
- : graph_(graph) {}
+ : maker_(graph) {}
// Get the index of the void type, creating one if needed.
Id Structs::GetVoid() {
if (!void_) {
- void_ = {graph_.Add<Special>(Special::Kind::VOID)};
+ void_ = {maker_.Add<Special>(Special::Kind::VOID)};
}
return *void_;
}
@@ -75,40 +125,61 @@
// Get the index of the variadic parameter type, creating one if needed.
Id Structs::GetVariadic() {
if (!variadic_) {
- variadic_ = {graph_.Add<Special>(Special::Kind::VARIADIC)};
+ variadic_ = {maker_.Add<Special>(Special::Kind::VARIADIC)};
}
return *variadic_;
}
-// Map BTF type index to own index.
-//
-// If there is no existing mapping for a BTF type, create one pointing to a new
-// slot at the end of the array.
+// Map BTF type index to node ID.
Id Structs::GetIdRaw(uint32_t btf_index) {
- auto [it, inserted] = btf_type_ids_.insert({btf_index, Id(0)});
- if (inserted) {
- it->second = graph_.Allocate();
- }
- return it->second;
+ return maker_.Get(btf_index);
}
-// Translate BTF type id to own type id, for non-parameters.
+// Translate BTF type index to node ID, for non-parameters.
Id Structs::GetId(uint32_t btf_index) {
return btf_index ? GetIdRaw(btf_index) : GetVoid();
}
-// Translate BTF type id to own type id, for parameters.
+// Translate BTF type index to node ID, for parameters.
Id Structs::GetParameterId(uint32_t btf_index) {
return btf_index ? GetIdRaw(btf_index) : GetVariadic();
}
+// For a BTF type index, populate the node with the corresponding ID.
+template <typename Node, typename... Args>
+void Structs::Set(uint32_t id, Args&&... args) {
+ maker_.Set<Node>(id, std::forward<Args>(args)...);
+}
+
+bool IsAlignedForBtf(std::string_view btf_data) {
+ return reinterpret_cast<uintptr_t>(btf_data.data()) % alignof(btf_header) ==
+ 0;
+}
+
Id Structs::Process(std::string_view btf_data) {
Check(sizeof(btf_header) <= btf_data.size())
<< "BTF section too small for header";
+ if (IsAlignedForBtf(btf_data)) {
+ return ProcessAligned(btf_data);
+ }
+ // Copy the data to aligned memory.
+ // Check that minimum amount of BTF data containing just btf_header will be
+ // heap allocated and will not fit inside the std::string due to small string
+ // optimization.
+ // TODO: Remove this hack once the upstream binaries have proper
+ // alignment.
+ static_assert(
+ sizeof(btf_header) >= sizeof(std::string),
+ "btf_header may hit small string optimization and be misaligned");
+ const std::string aligned_btf_data(btf_data);
+ Check(IsAlignedForBtf(aligned_btf_data))
+ << "std::string with BTF data is misaligned";
+ return ProcessAligned(aligned_btf_data);
+}
+
+Id Structs::ProcessAligned(std::string_view btf_data) {
const btf_header* header =
reinterpret_cast<const btf_header*>(btf_data.data());
- Check(reinterpret_cast<uintptr_t>(header) % alignof(btf_header) == 0)
- << "misaligned BTF data";
Check(header->magic == 0xEB9F) << "Magic field must be 0xEB9F for BTF";
const char* header_limit = btf_data.begin() + header->hdr_len;
@@ -145,7 +216,7 @@
const auto offset = kflag ? BTF_MEMBER_BIT_OFFSET(raw_offset) : raw_offset;
const auto bitfield_size = kflag ? BTF_MEMBER_BITFIELD_SIZE(raw_offset) : 0;
result.push_back(
- graph_.Add<Member>(name, GetId(raw_member.type),
+ maker_.Add<Member>(name, GetId(raw_member.type),
static_cast<uint64_t>(offset), bitfield_size));
}
return result;
@@ -206,7 +277,7 @@
<< (8 * size);
const auto encoding = is_signed ? Primitive::Encoding::SIGNED_INTEGER
: Primitive::Encoding::UNSIGNED_INTEGER;
- return graph_.Add<Primitive>(os.str(), encoding, size);
+ return maker_.Add<Primitive>(os.str(), encoding, size);
}
Id Structs::BuildTypes(MemoryRange memory) {
@@ -231,11 +302,6 @@
const auto vlen = BTF_INFO_VLEN(t->info);
Check(kind < NR_BTF_KINDS) << "Unknown BTF kind: " << static_cast<int>(kind);
- // delay allocation of node id as some BTF nodes are skipped
- auto id = [&]() {
- return GetIdRaw(btf_index);
- };
-
switch (kind) {
case BTF_KIND_INT: {
const auto info = *memory.Pull<uint32_t>();
@@ -258,23 +324,23 @@
if (bits != 8 * t->size) {
Die() << "BTF INT bits != 8 * size";
}
- graph_.Set<Primitive>(id(), name, encoding, t->size);
+ Set<Primitive>(btf_index, name, encoding, t->size);
break;
}
case BTF_KIND_FLOAT: {
const auto name = GetName(t->name_off);
const auto encoding = Primitive::Encoding::REAL_NUMBER;
- graph_.Set<Primitive>(id(), name, encoding, t->size);
+ Set<Primitive>(btf_index, name, encoding, t->size);
break;
}
case BTF_KIND_PTR: {
- graph_.Set<PointerReference>(id(), PointerReference::Kind::POINTER,
- GetId(t->type));
+ Set<PointerReference>(btf_index, PointerReference::Kind::POINTER,
+ GetId(t->type));
break;
}
case BTF_KIND_TYPEDEF: {
const auto name = GetName(t->name_off);
- graph_.Set<Typedef>(id(), name, GetId(t->type));
+ Set<Typedef>(btf_index, name, GetId(t->type));
break;
}
case BTF_KIND_VOLATILE:
@@ -285,12 +351,12 @@
: kind == BTF_KIND_VOLATILE
? Qualifier::VOLATILE
: Qualifier::RESTRICT;
- graph_.Set<Qualified>(id(), qualifier, GetId(t->type));
+ Set<Qualified>(btf_index, qualifier, GetId(t->type));
break;
}
case BTF_KIND_ARRAY: {
const auto* array = memory.Pull<struct btf_array>();
- graph_.Set<Array>(id(), array->nelems, GetId(array->type));
+ Set<Array>(btf_index, array->nelems, GetId(array->type));
break;
}
case BTF_KIND_STRUCT:
@@ -302,8 +368,8 @@
const bool kflag = BTF_INFO_KFLAG(t->info);
const auto* btf_members = memory.Pull<struct btf_member>(vlen);
const auto members = BuildMembers(kflag, btf_members, vlen);
- graph_.Set<StructUnion>(id(), struct_union_kind, name, t->size,
- std::vector<Id>(), std::vector<Id>(), members);
+ Set<StructUnion>(btf_index, struct_union_kind, name, t->size,
+ std::vector<Id>(), std::vector<Id>(), members);
break;
}
case BTF_KIND_ENUM: {
@@ -317,10 +383,10 @@
if (vlen) {
// create a synthetic underlying type
const Id underlying = BuildEnumUnderlyingType(t->size, is_signed);
- graph_.Set<Enumeration>(id(), name, underlying, enumerators);
+ Set<Enumeration>(btf_index, name, underlying, enumerators);
} else {
// BTF actually provides size (4), but it's meaningless.
- graph_.Set<Enumeration>(id(), name);
+ Set<Enumeration>(btf_index, name);
}
break;
}
@@ -331,7 +397,7 @@
const auto enumerators = BuildEnums64(is_signed, enums, vlen);
// create a synthetic underlying type
const Id underlying = BuildEnumUnderlyingType(t->size, is_signed);
- graph_.Set<Enumeration>(id(), name, underlying, enumerators);
+ Set<Enumeration>(btf_index, name, underlying, enumerators);
break;
}
case BTF_KIND_FWD: {
@@ -339,20 +405,20 @@
const auto struct_union_kind = BTF_INFO_KFLAG(t->info)
? StructUnion::Kind::UNION
: StructUnion::Kind::STRUCT;
- graph_.Set<StructUnion>(id(), struct_union_kind, name);
+ Set<StructUnion>(btf_index, struct_union_kind, name);
break;
}
case BTF_KIND_FUNC: {
const auto name = GetName(t->name_off);
// TODO: map linkage (vlen) to symbol properties
- graph_.Set<ElfSymbol>(id(), name, std::nullopt, true,
- ElfSymbol::SymbolType::FUNCTION,
- ElfSymbol::Binding::GLOBAL,
- ElfSymbol::Visibility::DEFAULT,
- std::nullopt,
- std::nullopt,
- GetId(t->type),
- std::nullopt);
+ Set<ElfSymbol>(btf_index, name, std::nullopt, true,
+ ElfSymbol::SymbolType::FUNCTION,
+ ElfSymbol::Binding::GLOBAL,
+ ElfSymbol::Visibility::DEFAULT,
+ std::nullopt,
+ std::nullopt,
+ GetId(t->type),
+ std::nullopt);
const bool inserted =
btf_symbols_.insert({name, GetIdRaw(btf_index)}).second;
Check(inserted) << "duplicate symbol " << name;
@@ -361,7 +427,7 @@
case BTF_KIND_FUNC_PROTO: {
const auto* params = memory.Pull<struct btf_param>(vlen);
const auto parameters = BuildParams(params, vlen);
- graph_.Set<Function>(id(), GetId(t->type), parameters);
+ Set<Function>(btf_index, GetId(t->type), parameters);
break;
}
case BTF_KIND_VAR: {
@@ -370,14 +436,14 @@
const auto name = GetName(t->name_off);
// TODO: map variable->linkage to symbol properties
(void) variable;
- graph_.Set<ElfSymbol>(id(), name, std::nullopt, true,
- ElfSymbol::SymbolType::OBJECT,
- ElfSymbol::Binding::GLOBAL,
- ElfSymbol::Visibility::DEFAULT,
- std::nullopt,
- std::nullopt,
- GetId(t->type),
- std::nullopt);
+ Set<ElfSymbol>(btf_index, name, std::nullopt, true,
+ ElfSymbol::SymbolType::OBJECT,
+ ElfSymbol::Binding::GLOBAL,
+ ElfSymbol::Visibility::DEFAULT,
+ std::nullopt,
+ std::nullopt,
+ GetId(t->type),
+ std::nullopt);
const bool inserted =
btf_symbols_.insert({name, GetIdRaw(btf_index)}).second;
Check(inserted) << "duplicate symbol " << name;
@@ -406,30 +472,19 @@
}
Id Structs::BuildSymbols() {
- return graph_.Add<Interface>(btf_symbols_);
+ return maker_.Add<Interface>(btf_symbols_);
+}
+
+} // namespace
+
+Id ReadSection(Graph& graph, std::string_view data) {
+ return Structs(graph).Process(data);
}
Id ReadFile(Graph& graph, const std::string& path, ReadOptions) {
- Check(elf_version(EV_CURRENT) != EV_NONE) << "ELF version mismatch";
- struct ElfDeleter {
- void operator()(Elf* elf) {
- elf_end(elf);
- }
- };
- const FileDescriptor fd(path.c_str(), O_RDONLY);
- const std::unique_ptr<Elf, ElfDeleter> elf(
- elf_begin(fd.Value(), ELF_C_READ, nullptr));
- if (!elf) {
- const int error_code = elf_errno();
- const char* error = elf_errmsg(error_code);
- if (error != nullptr) {
- Die() << "elf_begin returned error: " << error;
- } else {
- Die() << "elf_begin returned error: " << error_code;
- }
- }
- const elf::ElfLoader loader(elf.get());
- return Structs(graph).Process(loader.GetBtfRawData());
+ ElfDwarfHandle handle(path);
+ const elf::ElfLoader loader(handle.GetElf());
+ return ReadSection(graph, loader.GetSectionRawData(".BTF"));
}
} // namespace btf
diff --git a/btf_reader.h b/btf_reader.h
index 9f52198..74896cf 100644
--- a/btf_reader.h
+++ b/btf_reader.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2020-2023 Google LLC
+// Copyright 2020-2024 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -21,66 +21,15 @@
#ifndef STG_BTF_READER_H_
#define STG_BTF_READER_H_
-#include <cstddef>
-#include <cstdint>
-#include <map>
-#include <optional>
#include <string>
-#include <string_view>
-#include <unordered_map>
-#include <vector>
-#include <linux/btf.h>
#include "graph.h"
#include "reader_options.h"
namespace stg {
namespace btf {
-// BTF Specification: https://www.kernel.org/doc/html/latest/bpf/btf.html
-class Structs {
- public:
- explicit Structs(Graph& graph);
- Id Process(std::string_view data);
-
- private:
- struct MemoryRange {
- const char* start;
- const char* limit;
- bool Empty() const;
- template <typename T> const T* Pull(size_t count = 1);
- };
-
- Graph& graph_;
-
- MemoryRange string_section_;
-
- std::optional<Id> void_;
- std::optional<Id> variadic_;
- std::unordered_map<uint32_t, Id> btf_type_ids_;
- std::map<std::string, Id> btf_symbols_;
-
- Id GetVoid();
- Id GetVariadic();
- Id GetIdRaw(uint32_t btf_index);
- Id GetId(uint32_t btf_index);
- Id GetParameterId(uint32_t btf_index);
-
- Id BuildTypes(MemoryRange memory);
- void BuildOneType(const btf_type* t, uint32_t btf_index,
- MemoryRange& memory);
- Id BuildSymbols();
- std::vector<Id> BuildMembers(
- bool kflag, const btf_member* members, size_t vlen);
- Enumeration::Enumerators BuildEnums(
- bool is_signed, const struct btf_enum* enums, size_t vlen);
- Enumeration::Enumerators BuildEnums64(
- bool is_signed, const struct btf_enum64* enums, size_t vlen);
- std::vector<Id> BuildParams(const struct btf_param* params, size_t vlen);
- Id BuildEnumUnderlyingType(size_t size, bool is_signed);
- std::string GetName(uint32_t name_off);
-};
-
+Id ReadSection(Graph& graph, std::string_view data);
Id ReadFile(Graph& graph, const std::string& path, ReadOptions options);
} // namespace btf
diff --git a/comparison.cc b/comparison.cc
index 0015fc8..b748de5 100644
--- a/comparison.cc
+++ b/comparison.cc
@@ -38,6 +38,7 @@
#include "order.h"
namespace stg {
+namespace diff {
struct IgnoreDescriptor {
std::string_view name;
@@ -590,7 +591,7 @@
const auto& parameters1 = x1.parameters;
const auto& parameters2 = x2.parameters;
- size_t min = std::min(parameters1.size(), parameters2.size());
+ const size_t min = std::min(parameters1.size(), parameters2.size());
for (size_t i = 0; i < min; ++i) {
const Id p1 = parameters1.at(i);
const Id p2 = parameters2.at(i);
@@ -601,7 +602,7 @@
(*this)(p1, p2));
}
- bool added = parameters1.size() < parameters2.size();
+ const bool added = parameters1.size() < parameters2.size();
const auto& which = added ? x2 : x1;
const auto& parameters = which.parameters;
for (size_t i = min; i < parameters.size(); ++i) {
@@ -807,4 +808,5 @@
return {};
}
+} // namespace diff
} // namespace stg
diff --git a/comparison.h b/comparison.h
index 81eccf5..4ccc613 100644
--- a/comparison.h
+++ b/comparison.h
@@ -42,6 +42,7 @@
#include "scc.h"
namespace stg {
+namespace diff {
struct Ignore {
enum Value {
@@ -308,6 +309,7 @@
Histogram scc_size;
};
+} // namespace diff
} // namespace stg
#endif // STG_COMPARISON_H_
diff --git a/dwarf_processor.cc b/dwarf_processor.cc
index 17fd682..beee31f 100644
--- a/dwarf_processor.cc
+++ b/dwarf_processor.cc
@@ -37,6 +37,7 @@
#include "dwarf_wrappers.h"
#include "error.h"
#include "filter.h"
+#include "hex.h"
#include "graph.h"
#include "scope.h"
@@ -70,14 +71,18 @@
std::string GetNameOrEmpty(Entry& entry) {
auto result = MaybeGetName(entry);
if (!result.has_value()) {
- return std::string();
+ return {};
}
return std::move(*result);
}
-std::optional<std::string> MaybeGetLinkageName(int version, Entry& entry) {
- return entry.MaybeGetString(
+std::string GetLinkageName(int version, Entry& entry) {
+ auto linkage_name = entry.MaybeGetString(
version < 4 ? DW_AT_MIPS_linkage_name : DW_AT_linkage_name);
+ if (linkage_name.has_value()) {
+ return std::move(*linkage_name);
+ }
+ return GetNameOrEmpty(entry);
}
size_t GetBitSize(Entry& entry) {
@@ -260,7 +265,7 @@
Processor(Graph& graph, Id void_id, Id variadic_id,
bool is_little_endian_binary,
const std::unique_ptr<Filter>& file_filter, Types& result)
- : graph_(graph),
+ : maker_(graph),
void_id_(void_id),
variadic_id_(variadic_id),
is_little_endian_binary_(is_little_endian_binary),
@@ -275,14 +280,6 @@
Process(compilation_unit.entry);
}
- void CheckUnresolvedIds() const {
- for (const auto& [offset, id] : id_map_) {
- if (!graph_.Is(id)) {
- Die() << "unresolved id " << id << ", DWARF offset " << Hex(offset);
- }
- }
- }
-
void ResolveSymbolSpecifications() {
std::sort(unresolved_symbol_specifications_.begin(),
unresolved_symbol_specifications_.end());
@@ -298,7 +295,7 @@
names_it->first != symbols_it->first) {
Die() << "Scoped name not found for entry " << Hex(symbols_it->first);
}
- result_.symbols[symbols_it->second].name = names_it->second;
+ result_.symbols[symbols_it->second].scoped_name = names_it->second;
++symbols_it;
}
}
@@ -478,8 +475,7 @@
if (!file) {
// Built in types that do not have DW_AT_decl_file should be preserved.
static constexpr std::string_view kBuiltinPrefix = "__";
- // TODO: use std::string_view::starts_with
- if (name.substr(0, kBuiltinPrefix.size()) == kBuiltinPrefix) {
+ if (name.starts_with(kBuiltinPrefix)) {
return true;
}
Die() << "File filter is provided, but " << name << " ("
@@ -641,17 +637,17 @@
void ProcessMethod(std::vector<Id>& methods, Entry& entry) {
Subprogram subprogram = GetSubprogram(entry);
- auto id = graph_.Add<Function>(std::move(subprogram.node));
+ auto id = maker_.Add<Function>(std::move(subprogram.node));
if (subprogram.external && subprogram.address) {
// Only external functions with address are useful for ABI monitoring
// TODO: cover virtual methods
const auto new_symbol_idx = result_.symbols.size();
result_.symbols.push_back(Types::Symbol{
- .name = GetScopedNameForSymbol(
+ .scoped_name = GetScopedNameForSymbol(
new_symbol_idx, subprogram.name_with_context),
.linkage_name = subprogram.linkage_name,
.address = *subprogram.address,
- .id = id});
+ .type_id = id});
}
const auto virtuality = entry.MaybeGetUnsignedConstant(DW_AT_virtuality)
.value_or(DW_VIRTUALITY_none);
@@ -665,9 +661,8 @@
<< " shouldn't have specification";
}
const auto vtable_offset = entry.MaybeGetVtableOffset().value_or(0);
- // TODO: proper handling of missing linkage name
methods.push_back(AddProcessedNode<Method>(
- entry, subprogram.linkage_name.value_or("{missing}"),
+ entry, subprogram.linkage_name,
*subprogram.name_with_context.unscoped_name, vtable_offset, id));
}
}
@@ -903,10 +898,11 @@
// Only external variables with address are useful for ABI monitoring
const auto new_symbol_idx = result_.symbols.size();
result_.symbols.push_back(Types::Symbol{
- .name = GetScopedNameForSymbol(new_symbol_idx, name_with_context),
- .linkage_name = MaybeGetLinkageName(version_, entry),
+ .scoped_name = GetScopedNameForSymbol(
+ new_symbol_idx, name_with_context),
+ .linkage_name = GetLinkageName(version_, entry),
.address = *address,
- .id = referred_type_id});
+ .type_id = referred_type_id});
}
}
@@ -917,18 +913,18 @@
// Only external functions with address are useful for ABI monitoring
const auto new_symbol_idx = result_.symbols.size();
result_.symbols.push_back(Types::Symbol{
- .name = GetScopedNameForSymbol(
+ .scoped_name = GetScopedNameForSymbol(
new_symbol_idx, subprogram.name_with_context),
.linkage_name = std::move(subprogram.linkage_name),
.address = *subprogram.address,
- .id = id});
+ .type_id = id});
}
}
struct Subprogram {
Function node;
NameWithContext name_with_context;
- std::optional<std::string> linkage_name;
+ std::string linkage_name;
std::optional<Address> address;
bool external;
};
@@ -1011,19 +1007,14 @@
return Subprogram{.node = Function(return_type_id, parameters),
.name_with_context = GetNameWithContext(entry),
- .linkage_name = MaybeGetLinkageName(version_, entry),
+ .linkage_name = GetLinkageName(version_, entry),
.address = entry.MaybeGetAddress(DW_AT_low_pc),
.external = entry.GetFlag(DW_AT_external)};
}
// Allocate or get already allocated STG Id for Entry.
Id GetIdForEntry(Entry& entry) {
- const auto offset = entry.GetOffset();
- const auto [it, emplaced] = id_map_.emplace(offset, Id(-1));
- if (emplaced) {
- it->second = graph_.Allocate();
- }
- return it->second;
+ return maker_.Get(Hex(entry.GetOffset()));
}
// Same as GetIdForEntry, but returns "void_id_" for "unspecified" references,
@@ -1040,22 +1031,20 @@
// Populate Id from method above with processed Node.
template <typename Node, typename... Args>
Id AddProcessedNode(Entry& entry, Args&&... args) {
- const Id id = GetIdForEntry(entry);
- graph_.Set<Node>(id, std::forward<Args>(args)...);
- return id;
+ return maker_.Set<Node>(Hex(entry.GetOffset()),
+ std::forward<Args>(args)...);
}
void AddNamedTypeNode(Id id) {
result_.named_type_ids.push_back(id);
}
- Graph& graph_;
+ Maker<Hex<Dwarf_Off>> maker_;
Id void_id_;
Id variadic_id_;
bool is_little_endian_binary_;
const std::unique_ptr<Filter>& file_filter_;
Types& result_;
- std::unordered_map<Dwarf_Off, Id> id_map_;
std::vector<std::pair<Dwarf_Off, std::string>> scoped_names_;
std::vector<std::pair<Dwarf_Off, size_t>> unresolved_symbol_specifications_;
@@ -1066,19 +1055,23 @@
uint64_t language_;
};
-Types Process(Handler& dwarf, bool is_little_endian_binary,
+Types Process(Dwarf* dwarf, bool is_little_endian_binary,
const std::unique_ptr<Filter>& file_filter, Graph& graph) {
Types result;
+
+ if (dwarf == nullptr) {
+ return result;
+ }
+
const Id void_id = graph.Add<Special>(Special::Kind::VOID);
const Id variadic_id = graph.Add<Special>(Special::Kind::VARIADIC);
// TODO: Scope Processor to compilation units?
Processor processor(graph, void_id, variadic_id, is_little_endian_binary,
file_filter, result);
- for (auto& compilation_unit : dwarf.GetCompilationUnits()) {
+ for (auto& compilation_unit : GetCompilationUnits(*dwarf)) {
// Could fetch top-level attributes like compiler here.
processor.ProcessCompilationUnit(compilation_unit);
}
- processor.CheckUnresolvedIds();
processor.ResolveSymbolSpecifications();
return result;
diff --git a/dwarf_processor.h b/dwarf_processor.h
index 8a26c76..7eaa8ed 100644
--- a/dwarf_processor.h
+++ b/dwarf_processor.h
@@ -20,6 +20,8 @@
#ifndef STG_DWARF_PROCESSOR_H_
#define STG_DWARF_PROCESSOR_H_
+#include <elfutils/libdw.h>
+
#include <cstddef>
#include <optional>
#include <string>
@@ -34,10 +36,10 @@
struct Types {
struct Symbol {
- std::string name;
- std::optional<std::string> linkage_name;
+ std::string scoped_name;
+ std::string linkage_name;
Address address;
- Id id;
+ Id type_id;
};
size_t processed_entries = 0;
@@ -48,7 +50,8 @@
// Process every compilation unit from DWARF and returns processed STG along
// with information needed for matching to ELF symbols.
-Types Process(Handler& dwarf, bool is_little_endian_binary,
+// If DWARF is missing, returns empty result.
+Types Process(Dwarf* dwarf, bool is_little_endian_binary,
const std::unique_ptr<Filter>& file_filter, Graph& graph);
} // namespace dwarf
diff --git a/dwarf_wrappers.cc b/dwarf_wrappers.cc
index 04e5897..9924a43 100644
--- a/dwarf_wrappers.cc
+++ b/dwarf_wrappers.cc
@@ -27,8 +27,6 @@
#include <cstddef>
#include <cstdint>
-#include <ios>
-#include <memory>
#include <optional>
#include <ostream>
#include <string>
@@ -36,6 +34,7 @@
#include <vector>
#include "error.h"
+#include "hex.h"
namespace stg {
namespace dwarf {
@@ -46,12 +45,6 @@
namespace {
-static const Dwfl_Callbacks kDwflCallbacks = {
- .find_elf = nullptr,
- .find_debuginfo = dwfl_standard_find_debuginfo,
- .section_address = dwfl_offline_section_address,
- .debuginfo_path = nullptr};
-
constexpr int kReturnOk = 0;
constexpr int kReturnNoEntry = 1;
@@ -82,18 +75,6 @@
return result;
}
-void CheckOrDwflError(bool condition, const char* caller) {
- if (!condition) {
- int dwfl_error = dwfl_errno();
- const char* errmsg = dwfl_errmsg(dwfl_error);
- if (errmsg == nullptr) {
- // There are some cases when DWFL fails to produce an error message.
- Die() << caller << " returned error code " << Hex(dwfl_error);
- }
- Die() << caller << " returned error: " << errmsg;
- }
-}
-
std::optional<uint64_t> MaybeGetUnsignedOperand(const Dwarf_Op& operand) {
switch (operand.atom) {
case DW_OP_addr:
@@ -147,56 +128,15 @@
} // namespace
-Handler::Handler(const std::string& path) : dwfl_(dwfl_begin(&kDwflCallbacks)) {
- CheckOrDwflError(dwfl_.get(), "dwfl_begin");
- // Add data to process to dwfl
- dwfl_module_ =
- dwfl_report_offline(dwfl_.get(), path.c_str(), path.c_str(), -1);
- InitialiseDwarf();
-}
-
-Handler::Handler(char* data, size_t size) : dwfl_(dwfl_begin(&kDwflCallbacks)) {
- CheckOrDwflError(dwfl_.get(), "dwfl_begin");
-
- // Check if ELF can be opened from input data, because DWFL couldn't handle
- // memory, that is not ELF.
- // TODO: remove this workaround
- Elf* elf = elf_memory(data, size);
- Check(elf != nullptr) << "Input data is not ELF";
- elf_end(elf);
-
- // Add data to process to dwfl
- dwfl_module_ = dwfl_report_offline_memory(dwfl_.get(), "<memory>", "<memory>",
- data, size);
- InitialiseDwarf();
-}
-
-void Handler::InitialiseDwarf() {
- CheckOrDwflError(dwfl_.get(), "dwfl_report_offline");
- // Finish adding files to dwfl and process them
- CheckOrDwflError(dwfl_report_end(dwfl_.get(), nullptr, nullptr) == kReturnOk,
- "dwfl_report_end");
- GElf_Addr loadbase = 0; // output argument for dwfl, unused by us
- dwarf_ = dwfl_module_getdwarf(dwfl_module_, &loadbase);
- CheckOrDwflError(dwarf_, "dwfl_module_getdwarf");
-}
-
-Elf* Handler::GetElf() {
- GElf_Addr loadbase = 0; // output argument for dwfl, unused by us
- Elf* elf = dwfl_module_getelf(dwfl_module_, &loadbase);
- CheckOrDwflError(elf, "dwfl_module_getelf");
- return elf;
-}
-
-std::vector<CompilationUnit> Handler::GetCompilationUnits() {
+std::vector<CompilationUnit> GetCompilationUnits(Dwarf& dwarf) {
std::vector<CompilationUnit> result;
Dwarf_Off offset = 0;
while (true) {
Dwarf_Off next_offset;
size_t header_size = 0;
Dwarf_Half version = 0;
- int return_code =
- dwarf_next_unit(dwarf_, offset, &next_offset, &header_size, &version,
+ const int return_code =
+ dwarf_next_unit(&dwarf, offset, &next_offset, &header_size, &version,
nullptr, nullptr, nullptr, nullptr, nullptr);
Check(return_code == kReturnOk || return_code == kReturnNoEntry)
<< "dwarf_next_unit returned error";
@@ -204,7 +144,8 @@
break;
}
result.push_back({version, {}});
- Check(dwarf_offdie(dwarf_, offset + header_size, &result.back().entry.die))
+ Check(dwarf_offdie(&dwarf, offset + header_size,
+ &result.back().entry.die) != nullptr)
<< "dwarf_offdie returned error";
offset = next_offset;
diff --git a/dwarf_wrappers.h b/dwarf_wrappers.h
index c584345..ad43413 100644
--- a/dwarf_wrappers.h
+++ b/dwarf_wrappers.h
@@ -22,16 +22,12 @@
#include <elf.h>
#include <elfutils/libdw.h>
-#include <elfutils/libdwfl.h>
-#include <compare>
#include <cstddef>
#include <cstdint>
-#include <memory>
#include <optional>
#include <ostream>
#include <string>
-#include <tuple>
#include <vector>
namespace stg {
@@ -88,32 +84,7 @@
Entry entry;
};
-// C++ wrapper over libdw (DWARF library).
-//
-// Creates a "Dwarf" object from an ELF file or a memory and controls the life
-// cycle of the created objects.
-class Handler {
- public:
- explicit Handler(const std::string& path);
- Handler(char* data, size_t size);
-
- Elf* GetElf();
- std::vector<CompilationUnit> GetCompilationUnits();
-
- private:
- struct DwflDeleter {
- void operator()(Dwfl* dwfl) {
- dwfl_end(dwfl);
- }
- };
-
- void InitialiseDwarf();
-
- std::unique_ptr<Dwfl, DwflDeleter> dwfl_;
- // Lifetime of Dwfl_Module and Dwarf is controlled by Dwfl.
- Dwfl_Module* dwfl_module_ = nullptr;
- Dwarf* dwarf_ = nullptr;
-};
+std::vector<CompilationUnit> GetCompilationUnits(Dwarf& dwarf);
class Files {
public:
diff --git a/elf_dwarf_handle.cc b/elf_dwarf_handle.cc
new file mode 100644
index 0000000..b03ad06
--- /dev/null
+++ b/elf_dwarf_handle.cc
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- mode: C++ -*-
+//
+// Copyright 2022-2024 Google LLC
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions (the
+// "License"); you may not use this file except in compliance with the
+// License. You may obtain a copy of the License at
+//
+// https://llvm.org/LICENSE.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Author: Aleksei Vetrov
+
+#include "elf_dwarf_handle.h"
+
+#include <elfutils/libdw.h>
+#include <elfutils/libdwfl.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <libelf.h>
+
+#include <cstddef>
+#include <functional>
+#include <sstream>
+#include <string>
+
+#include "error.h"
+#include "hex.h"
+
+namespace stg {
+
+namespace {
+
+const Dwfl_Callbacks kDwflCallbacks = {
+ .find_elf = nullptr,
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .section_address = dwfl_offline_section_address,
+ .debuginfo_path = nullptr};
+
+constexpr int kReturnOk = 0;
+
+std::string GetDwflError(const char* caller) {
+ std::ostringstream result;
+ const int dwfl_error = dwfl_errno();
+ const char* errmsg = dwfl_errmsg(dwfl_error);
+ if (errmsg == nullptr) {
+ // There are some cases when DWFL fails to produce an error message.
+ result << caller << " returned error code " << Hex(dwfl_error);
+ } else {
+ result << caller << " returned error: " << errmsg;
+ }
+ return result.str();
+}
+
+void CheckOrDwflError(bool condition, const char* caller) {
+ if (!condition) {
+ Die() << GetDwflError(caller);
+ }
+}
+
+} // namespace
+
+ElfDwarfHandle::ElfDwarfHandle(
+ const char* module_name, const std::function<Dwfl_Module*()>& add_module) {
+ dwfl_ = DwflUniquePtr(dwfl_begin(&kDwflCallbacks));
+ CheckOrDwflError(dwfl_ != nullptr, "dwfl_begin");
+ // Add data to process to dwfl
+ dwfl_module_ = add_module();
+ CheckOrDwflError(dwfl_module_ != nullptr, module_name);
+ // Finish adding files to dwfl and process them
+ CheckOrDwflError(dwfl_report_end(dwfl_.get(), nullptr, nullptr) == kReturnOk,
+ "dwfl_report_end");
+}
+
+ElfDwarfHandle::ElfDwarfHandle(const std::string& path)
+ : ElfDwarfHandle("dwfl_report_offline", [&] {
+ return dwfl_report_offline(dwfl_.get(), path.c_str(), path.c_str(), -1);
+ }) {}
+
+ElfDwarfHandle::ElfDwarfHandle(char* data, size_t size)
+ : ElfDwarfHandle("dwfl_report_offline_memory", [&] {
+ return dwfl_report_offline_memory(dwfl_.get(), "<memory>", "<memory>",
+ data, size);
+ }) {}
+
+Elf& ElfDwarfHandle::GetElf() {
+ GElf_Addr loadbase = 0; // output argument for dwfl, unused by us
+ Elf* elf = dwfl_module_getelf(dwfl_module_, &loadbase);
+ CheckOrDwflError(elf != nullptr, "dwfl_module_getelf");
+ return *elf;
+}
+
+Dwarf* ElfDwarfHandle::GetDwarf() {
+ GElf_Addr loadbase = 0; // output argument for dwfl, unused by us
+ Dwarf* dwarf = dwfl_module_getdwarf(dwfl_module_, &loadbase);
+ if (dwarf == nullptr) {
+ Warn() << "No DWARF found: " << GetDwflError("dwfl_module_getdwarf");
+ }
+ return dwarf;
+}
+
+} // namespace stg
diff --git a/elf_dwarf_handle.h b/elf_dwarf_handle.h
new file mode 100644
index 0000000..cca4a0e
--- /dev/null
+++ b/elf_dwarf_handle.h
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- mode: C++ -*-
+//
+// Copyright 2022-2024 Google LLC
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions (the
+// "License"); you may not use this file except in compliance with the
+// License. You may obtain a copy of the License at
+//
+// https://llvm.org/LICENSE.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Author: Aleksei Vetrov
+
+#ifndef STG_ELF_DWARF_HANDLE_H_
+#define STG_ELF_DWARF_HANDLE_H_
+
+#include <elf.h>
+#include <elfutils/libdw.h>
+#include <elfutils/libdwfl.h>
+
+#include <cstddef>
+#include <functional>
+#include <memory>
+#include <string>
+
+namespace stg {
+
+class ElfDwarfHandle {
+ public:
+ explicit ElfDwarfHandle(const std::string& path);
+ ElfDwarfHandle(char* data, size_t size);
+
+ Elf& GetElf();
+ Dwarf* GetDwarf(); // Returns nullptr if DWARF is not available.
+
+ private:
+ struct DwflDeleter {
+ void operator()(Dwfl* dwfl) {
+ dwfl_end(dwfl);
+ }
+ };
+ using DwflUniquePtr = std::unique_ptr<Dwfl, DwflDeleter>;
+
+ ElfDwarfHandle(const char* module_name,
+ const std::function<Dwfl_Module*()>& add_module);
+
+ DwflUniquePtr dwfl_;
+ // Lifetime of Dwfl_Module is controlled by Dwfl.
+ Dwfl_Module* dwfl_module_ = nullptr;
+};
+
+} // namespace stg
+
+
+#endif // STG_ELF_DWARF_HANDLE_H_
diff --git a/elf_loader.cc b/elf_loader.cc
index 82d6b4a..cad551d 100644
--- a/elf_loader.cc
+++ b/elf_loader.cc
@@ -245,6 +245,12 @@
return section_header.sh_size / section_header.sh_entsize;
}
+std::string_view GetRawData(Elf_Scn* section, const char* name) {
+ Elf_Data* data = elf_rawdata(section, nullptr);
+ Check(data != nullptr) << "elf_rawdata failed on section " << name;
+ return {static_cast<char*>(data->d_buf), data->d_size};
+}
+
std::string_view GetString(Elf* elf, uint32_t section, size_t offset) {
const auto name = elf_strptr(elf, section, offset);
@@ -285,17 +291,14 @@
constexpr std::string_view kCFISuffix = ".cfi";
bool IsCFISymbolName(std::string_view name) {
- // Check if symbol name ends with ".cfi"
- // TODO: use std::string_view::ends_with
- return (name.size() >= kCFISuffix.size() &&
- name.substr(name.size() - kCFISuffix.size()) == kCFISuffix);
+ return name.ends_with(kCFISuffix);
}
} // namespace
std::string_view UnwrapCFISymbolName(std::string_view cfi_name) {
Check(IsCFISymbolName(cfi_name))
- << "CFI symbol " << cfi_name << " doesn't end with .cfi";
+ << "CFI symbol " << cfi_name << " doesn't end with " << kCFISuffix;
return cfi_name.substr(0, cfi_name.size() - kCFISuffix.size());
}
@@ -422,9 +425,8 @@
}
}
-ElfLoader::ElfLoader(Elf* elf)
- : elf_(elf) {
- Check(elf_ != nullptr) << "No ELF was provided";
+ElfLoader::ElfLoader(Elf& elf)
+ : elf_(&elf) {
InitializeElfInformation();
}
@@ -434,14 +436,8 @@
is_little_endian_binary_ = elf::IsLittleEndianBinary(elf_);
}
-std::string_view ElfLoader::GetBtfRawData() const {
- Elf_Scn* btf_section = GetSectionByName(elf_, ".BTF");
- Check(btf_section != nullptr) << ".BTF section is invalid";
- Elf_Data* elf_data = elf_rawdata(btf_section, nullptr);
- Check(elf_data != nullptr) << ".BTF section data is invalid";
- const char* btf_start = static_cast<char*>(elf_data->d_buf);
- const size_t btf_size = elf_data->d_size;
- return std::string_view(btf_start, btf_size);
+std::string_view ElfLoader::GetSectionRawData(const char* name) const {
+ return GetRawData(GetSectionByName(elf_, name), name);
}
std::vector<SymbolTableEntry> ElfLoader::GetElfSymbols() const {
@@ -515,7 +511,7 @@
Check(offset + length < data->d_size)
<< "Namespace string should be null-terminated";
- return std::string_view(begin, length);
+ return {begin, length};
}
size_t ElfLoader::GetAbsoluteAddress(const SymbolTableEntry& symbol) const {
diff --git a/elf_loader.h b/elf_loader.h
index 39d9fff..561e1dd 100644
--- a/elf_loader.h
+++ b/elf_loader.h
@@ -75,9 +75,9 @@
class ElfLoader final {
public:
- explicit ElfLoader(Elf* elf);
+ explicit ElfLoader(Elf& elf);
- std::string_view GetBtfRawData() const;
+ std::string_view GetSectionRawData(const char* name) const;
std::vector<SymbolTableEntry> GetElfSymbols() const;
std::vector<SymbolTableEntry> GetCFISymbols() const;
ElfSymbol::CRC GetElfSymbolCRC(const SymbolTableEntry& symbol) const;
diff --git a/elf_reader.cc b/elf_reader.cc
index 31d39cb..b3def7f 100644
--- a/elf_reader.cc
+++ b/elf_reader.cc
@@ -20,7 +20,6 @@
#include "elf_reader.h"
#include <cstddef>
-#include <functional>
#include <map>
#include <memory>
#include <optional>
@@ -30,7 +29,7 @@
#include <vector>
#include "dwarf_processor.h"
-#include "dwarf_wrappers.h"
+#include "elf_dwarf_handle.h"
#include "elf_loader.h"
#include "error.h"
#include "filter.h"
@@ -61,6 +60,8 @@
ElfSymbol::SymbolType ConvertSymbolType(
SymbolTableEntry::SymbolType symbol_type) {
switch (symbol_type) {
+ case SymbolTableEntry::SymbolType::NOTYPE:
+ return ElfSymbol::SymbolType::NOTYPE;
case SymbolTableEntry::SymbolType::OBJECT:
return ElfSymbol::SymbolType::OBJECT;
case SymbolTableEntry::SymbolType::FUNCTION:
@@ -96,7 +97,7 @@
for (const auto& symbol : symbols) {
const std::string_view name = symbol.name;
if (name.substr(0, kCRCPrefix.size()) == kCRCPrefix) {
- std::string_view name_suffix = name.substr(kCRCPrefix.size());
+ const std::string_view name_suffix = name.substr(kCRCPrefix.size());
if (!crc_values.emplace(name_suffix, elf.GetElfSymbolCRC(symbol))
.second) {
Die() << "Multiple CRC values for symbol '" << name_suffix << '\'';
@@ -187,24 +188,27 @@
return true;
}
+bool IsLinuxKernelFunctionOrVariable(const SymbolNameList& ksymtab,
+ const SymbolTableEntry& symbol) {
+ // We use symbol name extracted from __ksymtab_ symbols as a proxy for the
+ // real symbol in the ksymtab. Such names can still be duplicated by LOCAL
+ // symbols so drop them to avoid false matches.
+ if (symbol.binding == SymbolTableEntry::Binding::LOCAL) {
+ return false;
+ }
+ // TODO: handle undefined ksymtab symbols
+ return ksymtab.contains(symbol.name);
+}
+
namespace {
class Reader {
public:
- Reader(Runtime& runtime, Graph& graph, const std::string& path,
+ Reader(Runtime& runtime, Graph& graph, ElfDwarfHandle& elf_dwarf_handle,
ReadOptions options, const std::unique_ptr<Filter>& file_filter)
: graph_(graph),
- dwarf_(path),
- elf_(dwarf_.GetElf()),
- options_(options),
- file_filter_(file_filter),
- runtime_(runtime) {}
-
- Reader(Runtime& runtime, Graph& graph, char* data, size_t size,
- ReadOptions options, const std::unique_ptr<Filter>& file_filter)
- : graph_(graph),
- dwarf_(data, size),
- elf_(dwarf_.GetElf()),
+ elf_dwarf_handle_(elf_dwarf_handle),
+ elf_(elf_dwarf_handle_.GetElf()),
options_(options),
file_filter_(file_filter),
runtime_(runtime) {}
@@ -215,6 +219,13 @@
using SymbolIndex =
std::map<std::pair<dwarf::Address, std::string>, std::vector<size_t>>;
+ void GetLinuxKernelSymbols(
+ const std::vector<SymbolTableEntry>& all_symbols,
+ std::vector<std::pair<ElfSymbol, size_t>>& symbols) const;
+ void GetUserspaceSymbols(
+ const std::vector<SymbolTableEntry>& all_symbols,
+ std::vector<std::pair<ElfSymbol, size_t>>& symbols) const;
+
Id BuildRoot(const std::vector<std::pair<ElfSymbol, size_t>>& symbols) {
// On destruction, the unification object will remove or rewrite each graph
// node for which it has a mapping.
@@ -225,8 +236,9 @@
// the starting node ID to be the current graph limit.
Unification unification(runtime_, graph_, graph_.Limit());
- const dwarf::Types types = dwarf::Process(
- dwarf_, elf_.IsLittleEndianBinary(), file_filter_, graph_);
+ const dwarf::Types types =
+ dwarf::Process(elf_dwarf_handle_.GetDwarf(),
+ elf_.IsLittleEndianBinary(), file_filter_, graph_);
// A less important optimisation is avoiding copying the mapping array as it
// is populated. This is done by reserving space to the new graph limit.
@@ -247,10 +259,7 @@
SymbolIndex address_name_to_index;
for (size_t i = 0; i < types.symbols.size(); ++i) {
const auto& symbol = types.symbols[i];
-
- const auto& name =
- symbol.linkage_name.has_value() ? *symbol.linkage_name : symbol.name;
- address_name_to_index[std::make_pair(symbol.address, name)].push_back(i);
+ address_name_to_index[{symbol.address, symbol.linkage_name}].push_back(i);
}
std::map<std::string, Id> symbols_map;
@@ -282,7 +291,7 @@
std::vector<Id> roots;
roots.reserve(types.named_type_ids.size() + types.symbols.size() + 1);
for (const auto& symbol : types.symbols) {
- roots.push_back(symbol.id);
+ roots.push_back(symbol.type_id);
}
for (const auto id : types.named_type_ids) {
roots.push_back(id);
@@ -298,14 +307,16 @@
static bool IsEqual(Unification& unification,
const dwarf::Types::Symbol& lhs,
const dwarf::Types::Symbol& rhs) {
- return lhs.name == rhs.name && lhs.linkage_name == rhs.linkage_name
- && lhs.address == rhs.address && unification.Unify(lhs.id, rhs.id);
+ return lhs.scoped_name == rhs.scoped_name
+ && lhs.linkage_name == rhs.linkage_name
+ && lhs.address == rhs.address
+ && unification.Unify(lhs.type_id, rhs.type_id);
}
static ElfSymbol SymbolTableEntryToElfSymbol(
const CRCValuesMap& crc_values, const NamespacesMap& namespaces,
const SymbolTableEntry& symbol) {
- return ElfSymbol(
+ return {
/* symbol_name = */ std::string(symbol.name),
/* version_info = */ std::nullopt,
/* is_defined = */
@@ -316,7 +327,7 @@
/* crc = */ MaybeGet(crc_values, std::string(symbol.name)),
/* ns = */ MaybeGet(namespaces, std::string(symbol.name)),
/* type_id = */ std::nullopt,
- /* full_name = */ std::nullopt);
+ /* full_name = */ std::nullopt};
}
static void MaybeAddTypeInfo(
@@ -364,87 +375,91 @@
// "void foo(int bar)" vs "void foo(const int bar)"
if (!IsEqual(unification, best_symbol, other)) {
Die() << "Duplicate DWARF symbol: address="
- << best_symbol.address << ", name=" << best_symbol.name;
+ << best_symbols_it->first.first
+ << ", name=" << best_symbols_it->first.second;
}
}
- if (best_symbol.name.empty()) {
- Die() << "DWARF symbol (address = " << best_symbol.address
- << ", linkage_name = "
- << best_symbol.linkage_name.value_or("{missing}")
- << " should have a name";
+ if (best_symbol.scoped_name.empty()) {
+ Die() << "Anonymous DWARF symbol: address="
+ << best_symbols_it->first.first
+ << ", name=" << best_symbols_it->first.second;
}
// There may be multiple DWARF symbols with same address (zero-length
// arrays), or ELF symbol has different name from DWARF symbol (aliases).
// But if we have both situations at once, we can't match ELF to DWARF and
// it should be fixed in analysed binary source code.
Check(matched_by_name || candidates == 1)
- << "multiple candidates without matching names, best_symbol.name="
- << best_symbol.name;
- node.type_id = best_symbol.id;
- node.full_name = best_symbol.name;
+ << "Multiple candidate symbols without matching name: address="
+ << best_symbols_it->first.first
+ << ", name=" << best_symbols_it->first.second;
+ node.type_id = best_symbol.type_id;
+ node.full_name = best_symbol.scoped_name;
}
}
Graph& graph_;
- // The order of the following two fields is important because ElfLoader uses
- // an Elf* from dwarf::Handler without owning it.
- dwarf::Handler dwarf_;
- elf::ElfLoader elf_;
+ ElfDwarfHandle& elf_dwarf_handle_;
+ ElfLoader elf_;
ReadOptions options_;
const std::unique_ptr<Filter>& file_filter_;
Runtime& runtime_;
};
-Id Reader::Read() {
- const auto all_symbols = elf_.GetElfSymbols();
- const bool is_linux_kernel = elf_.IsLinuxKernelBinary();
- const SymbolNameList ksymtab_symbols =
- is_linux_kernel ? GetKsymtabSymbols(all_symbols) : SymbolNameList();
-
- CRCValuesMap crc_values;
- NamespacesMap namespaces;
- if (is_linux_kernel) {
- crc_values = GetCRCValuesMap(all_symbols, elf_);
- namespaces = GetNamespacesMap(all_symbols, elf_);
- }
-
- const auto cfi_address_map = GetCFIAddressMap(elf_.GetCFISymbols(), elf_);
-
- std::vector<std::pair<ElfSymbol, size_t>> symbols;
- symbols.reserve(all_symbols.size());
+void Reader::GetLinuxKernelSymbols(
+ const std::vector<SymbolTableEntry>& all_symbols,
+ std::vector<std::pair<ElfSymbol, size_t>>& symbols) const {
+ const auto crcs = GetCRCValuesMap(all_symbols, elf_);
+ const auto namespaces = GetNamespacesMap(all_symbols, elf_);
+ const auto ksymtab_symbols = GetKsymtabSymbols(all_symbols);
for (const auto& symbol : all_symbols) {
- if (IsPublicFunctionOrVariable(symbol) &&
- (!is_linux_kernel || ksymtab_symbols.count(symbol.name))) {
+ if (IsLinuxKernelFunctionOrVariable(ksymtab_symbols, symbol)) {
+ const size_t address = elf_.GetAbsoluteAddress(symbol);
+ symbols.emplace_back(
+ SymbolTableEntryToElfSymbol(crcs, namespaces, symbol), address);
+ }
+ }
+}
+
+void Reader::GetUserspaceSymbols(
+ const std::vector<SymbolTableEntry>& all_symbols,
+ std::vector<std::pair<ElfSymbol, size_t>>& symbols) const {
+ const auto cfi_address_map = GetCFIAddressMap(elf_.GetCFISymbols(), elf_);
+ for (const auto& symbol : all_symbols) {
+ if (IsPublicFunctionOrVariable(symbol)) {
const auto cfi_it = cfi_address_map.find(std::string(symbol.name));
const size_t address = cfi_it != cfi_address_map.end()
? cfi_it->second
: elf_.GetAbsoluteAddress(symbol);
symbols.emplace_back(
- SymbolTableEntryToElfSymbol(crc_values, namespaces, symbol), address);
+ SymbolTableEntryToElfSymbol({}, {}, symbol), address);
}
}
+}
+
+Id Reader::Read() {
+ const auto all_symbols = elf_.GetElfSymbols();
+ const auto get_symbols = elf_.IsLinuxKernelBinary()
+ ? &Reader::GetLinuxKernelSymbols
+ : &Reader::GetUserspaceSymbols;
+ std::vector<std::pair<ElfSymbol, size_t>> symbols;
+ symbols.reserve(all_symbols.size());
+ (this->*get_symbols)(all_symbols, symbols);
symbols.shrink_to_fit();
Id root = BuildRoot(symbols);
// Types produced by ELF/DWARF readers may require removing useless
// qualifiers.
- RemoveUselessQualifiers(graph_, root);
-
- return root;
+ return RemoveUselessQualifiers(graph_, root);
}
} // namespace
} // namespace internal
-Id Read(Runtime& runtime, Graph& graph, const std::string& path,
+Id Read(Runtime& runtime, Graph& graph, ElfDwarfHandle& elf_dwarf_handle,
ReadOptions options, const std::unique_ptr<Filter>& file_filter) {
- return internal::Reader(runtime, graph, path, options, file_filter).Read();
-}
-
-Id Read(Runtime& runtime, Graph& graph, char* data, size_t size,
- ReadOptions options, const std::unique_ptr<Filter>& file_filter) {
- return internal::Reader(runtime, graph, data, size, options, file_filter)
+ return internal::Reader(runtime, graph, elf_dwarf_handle, options,
+ file_filter)
.Read();
}
diff --git a/elf_reader.h b/elf_reader.h
index 159096a..ec7562a 100644
--- a/elf_reader.h
+++ b/elf_reader.h
@@ -28,6 +28,7 @@
#include <unordered_set>
#include <vector>
+#include "elf_dwarf_handle.h"
#include "elf_loader.h"
#include "filter.h"
#include "graph.h"
@@ -37,9 +38,7 @@
namespace stg {
namespace elf {
-Id Read(Runtime& runtime, Graph& graph, const std::string& path,
- ReadOptions options, const std::unique_ptr<Filter>& file_filter);
-Id Read(Runtime& runtime, Graph& graph, char* data, size_t size,
+Id Read(Runtime& runtime, Graph& graph, ElfDwarfHandle& elf_dwarf_handle,
ReadOptions options, const std::unique_ptr<Filter>& file_filter);
// For unit tests only
@@ -59,6 +58,8 @@
const ElfLoader& elf);
AddressMap GetCFIAddressMap(const SymbolTable& symbols, const ElfLoader& elf);
bool IsPublicFunctionOrVariable(const SymbolTableEntry& symbol);
+bool IsLinuxKernelFunctionOrVariable(const SymbolNameList& ksymtab,
+ const SymbolTableEntry& symbol);
} // namespace internal
} // namespace elf
diff --git a/equality_cache.h b/equality_cache.h
index 9373aa2..c1aa42b 100644
--- a/equality_cache.h
+++ b/equality_cache.h
@@ -240,7 +240,7 @@
++query_equal_ids;
return {true};
}
- if (known_equalities.count(comparison)) {
+ if (known_equalities.contains(comparison)) {
++query_known_equality;
return {true};
}
diff --git a/error.h b/error.h
index b72faaf..4680cae 100644
--- a/error.h
+++ b/error.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// -*- mode: C++ -*-
//
-// Copyright 2021-2022 Google LLC
+// Copyright 2021-2024 Google LLC
//
// Licensed under the Apache License v2.0 with LLVM Exceptions (the
// "License"); you may not use this file except in compliance with the
@@ -21,7 +21,6 @@
#define STG_ERROR_H_
#include <exception>
-#include <ios>
#include <iostream>
#include <optional>
#include <ostream>
@@ -48,14 +47,17 @@
std::string message_;
};
+// Coded to give compilers a chance of making `Check(ok) << foo;` as efficient
+// as `if (!ok) { Die() << foo; }`.
class Check {
public:
+ // These functions are all small and inlinable.
explicit Check(bool ok)
: os_(ok ? std::optional<std::ostringstream>()
: std::make_optional<std::ostringstream>()) {}
~Check() noexcept(false) {
if (os_) {
- throw Exception(os_->str());
+ Throw(*os_);
}
}
@@ -69,6 +71,11 @@
private:
std::optional<std::ostringstream> os_;
+
+ // This helper is too large to inline.
+ [[noreturn]] static void Throw(const std::ostringstream& os) {
+ throw Exception(os.str());
+ }
};
class Die {
@@ -112,23 +119,6 @@
return os << std::system_error(error.number, std::generic_category()).what();
}
-template <typename T>
-struct Hex {
- explicit Hex(const T& value) : value(value) {}
- const T& value;
-};
-
-template <typename T> Hex(const T&) -> Hex<T>;
-
-template <typename T>
-std::ostream& operator<<(std::ostream& os, const Hex<T>& hex_value) {
- // not quite right if an exception is thrown
- const auto flags = os.flags();
- os << "0x" << std::hex << hex_value.value;
- os.flags(flags);
- return os;
-}
-
} // namespace stg
#endif // STG_ERROR_H_
diff --git a/filter.cc b/filter.cc
index aa6f10a..cff06b3 100644
--- a/filter.cc
+++ b/filter.cc
@@ -71,12 +71,8 @@
}
// See if we are entering a filter list section.
if (line[start] == '[' && line[limit - 1] == ']') {
- std::string_view section(&line[start + 1], limit - start - 2);
- // TODO: use std::string_view::ends_with
- const auto section_size = section.size();
- const auto suffix_size = kSectionSuffix.size();
- in_filter_section = section_size >= suffix_size &&
- section.substr(section_size - suffix_size) == kSectionSuffix;
+ const std::string_view section(&line[start + 1], limit - start - 2);
+ in_filter_section = section.ends_with(kSectionSuffix);
continue;
}
// Add item.
@@ -150,7 +146,7 @@
explicit SetFilter(Items&& items)
: items_(std::move(items)) {}
bool operator()(const std::string& item) const final {
- return items_.count(item) > 0;
+ return items_.contains(item);
};
private:
diff --git a/fuzz/abigail_reader_fuzzer.cc b/fuzz/abigail_reader_fuzzer.cc
index 2e01b94..09b6247 100644
--- a/fuzz/abigail_reader_fuzzer.cc
+++ b/fuzz/abigail_reader_fuzzer.cc
@@ -31,27 +31,24 @@
xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
// Suppress libxml error messages.
xmlSetGenericErrorFunc(ctxt, (xmlGenericErrorFunc) DoNothing);
- xmlDocPtr doc = xmlCtxtReadMemory(
+ xmlDocPtr document = xmlCtxtReadMemory(
ctxt, data, size, nullptr, nullptr,
XML_PARSE_NOERROR | XML_PARSE_NONET | XML_PARSE_NOWARNING);
xmlFreeParserCtxt(ctxt);
- // Bail out if the doc XML is invalid.
- if (!doc) {
+ // Bail out if the document XML is invalid.
+ if (document == nullptr) {
return 0;
}
- xmlNodePtr root = xmlDocGetRootElement(doc);
- if (root) {
- try {
- stg::Graph graph;
- stg::abixml::Abigail(graph).ProcessRoot(root);
- } catch (const stg::Exception&) {
- // Pass as this is us catching invalid XML properly.
- }
+ try {
+ stg::Graph graph;
+ stg::abixml::ProcessDocument(graph, document);
+ } catch (const stg::Exception&) {
+ // Pass as this is us catching invalid XML properly.
}
- xmlFreeDoc(doc);
+ xmlFreeDoc(document);
return 0;
}
diff --git a/fuzz/btf_reader_fuzzer.cc b/fuzz/btf_reader_fuzzer.cc
index 74bbdcc..4ce6de0 100644
--- a/fuzz/btf_reader_fuzzer.cc
+++ b/fuzz/btf_reader_fuzzer.cc
@@ -26,7 +26,7 @@
extern "C" int LLVMFuzzerTestOneInput(char* data, size_t size) {
try {
stg::Graph graph;
- stg::btf::Structs(graph).Process(std::string_view(data, size));
+ stg::btf::ReadSection(graph, std::string_view(data, size));
} catch (const stg::Exception&) {
// Pass as this is us catching invalid BTF properly.
}
diff --git a/fuzz/elf_reader_fuzzer.cc b/fuzz/elf_reader_fuzzer.cc
index d83b012..ea9af18 100644
--- a/fuzz/elf_reader_fuzzer.cc
+++ b/fuzz/elf_reader_fuzzer.cc
@@ -21,6 +21,7 @@
#include <sstream>
#include <vector>
+#include "elf_dwarf_handle.h"
#include "elf_reader.h"
#include "error.h"
#include "graph.h"
@@ -36,7 +37,8 @@
stg::Runtime runtime(os, false);
stg::Graph graph;
std::vector<char> data_copy(data, data + size);
- stg::elf::Read(runtime, graph, data_copy.data(), size, stg::ReadOptions(),
+ stg::ElfDwarfHandle elf_dwarf_handle(data_copy.data(), size);
+ stg::elf::Read(runtime, graph, elf_dwarf_handle, stg::ReadOptions(),
nullptr);
} catch (const stg::Exception&) {
// Pass as this is us catching invalid ELF properly.
diff --git a/fuzz/proto_reader_fuzzer.cc b/fuzz/proto_reader_fuzzer.cc
index da5e8ba..7a102e0 100644
--- a/fuzz/proto_reader_fuzzer.cc
+++ b/fuzz/proto_reader_fuzzer.cc
@@ -17,16 +17,20 @@
//
// Author: Matthias Maennich
+#include <sstream>
#include <string>
#include "error.h"
#include "graph.h"
#include "proto_reader.h"
+#include "runtime.h"
extern "C" int LLVMFuzzerTestOneInput(char* data, size_t size) {
try {
+ std::ostringstream os;
+ stg::Runtime runtime(os, false);
stg::Graph graph;
- stg::proto::ReadFromString(graph, std::string_view(data, size));
+ stg::proto::ReadFromString(runtime, graph, std::string_view(data, size));
} catch (const stg::Exception&) {
// Pass as this is us catching invalid proto properly.
}
diff --git a/graph.cc b/graph.cc
index ad402ca..6c5ca05 100644
--- a/graph.cc
+++ b/graph.cc
@@ -27,6 +27,8 @@
#include <string>
#include <string_view>
+#include "hex.h"
+
namespace stg {
const Id Id::kInvalid(std::numeric_limits<decltype(Id::ix_)>::max());
@@ -80,6 +82,8 @@
std::ostream& operator<<(std::ostream& os, ElfSymbol::SymbolType type) {
switch (type) {
+ case ElfSymbol::SymbolType::NOTYPE:
+ return os << "no-type";
case ElfSymbol::SymbolType::OBJECT:
return os << "variable";
case ElfSymbol::SymbolType::FUNCTION:
diff --git a/graph.h b/graph.h
index 4be5dd0..3a31540 100644
--- a/graph.h
+++ b/graph.h
@@ -266,7 +266,7 @@
};
struct ElfSymbol {
- enum class SymbolType { OBJECT, FUNCTION, COMMON, TLS, GNU_IFUNC };
+ enum class SymbolType { NOTYPE, OBJECT, FUNCTION, COMMON, TLS, GNU_IFUNC };
enum class Binding { GLOBAL, LOCAL, WEAK, GNU_UNIQUE };
enum class Visibility { DEFAULT, PROTECTED, HIDDEN, INTERNAL };
struct VersionInfo {
@@ -728,6 +728,76 @@
std::vector<Id> ids_;
};
+template <typename ExternalId>
+class Maker {
+ public:
+ explicit Maker(Graph& graph) : graph_(graph) {}
+
+ ~Maker() noexcept(false) {
+ if (std::uncaught_exceptions() == 0) {
+ if (undefined_ > 0) {
+ Die die;
+ die << "undefined nodes:";
+ for (const auto& [external_id, id] : map_) {
+ if (!graph_.Is(id)) {
+ die << ' ' << external_id;
+ }
+ }
+ }
+ }
+ }
+
+ Id Get(const ExternalId& external_id) {
+ auto [it, inserted] = map_.emplace(external_id, 0);
+ if (inserted) {
+ it->second = graph_.Allocate();
+ ++undefined_;
+ }
+ return it->second;
+ }
+
+ template <typename Node, typename... Args>
+ Id Set(const ExternalId& external_id, Args&&... args) {
+ return Set<Node>(DieDuplicate, external_id, std::forward<Args>(args)...);
+ }
+
+ template <typename Node, typename... Args>
+ Id MaybeSet(const ExternalId& external_id, Args&&... args) {
+ return Set<Node>(WarnDuplicate, external_id, std::forward<Args>(args)...);
+ }
+
+ template <typename Node, typename... Args>
+ Id Add(Args&&... args) {
+ return graph_.Add<Node>(std::forward<Args>(args)...);
+ }
+
+ private:
+ Graph& graph_;
+ size_t undefined_ = 0;
+ std::unordered_map<ExternalId, Id> map_;
+
+ template <typename Node, typename... Args>
+ Id Set(void(& fail)(const ExternalId&), const ExternalId& external_id,
+ Args&&... args) {
+ const Id id = Get(external_id);
+ if (graph_.Is(id)) {
+ fail(external_id);
+ } else {
+ graph_.Set<Node>(id, std::forward<Args>(args)...);
+ --undefined_;
+ }
+ return id;
+ }
+
+ // These helpers should probably not be inlined.
+ [[noreturn]] static void DieDuplicate(const ExternalId& external_id) {
+ Die() << "duplicate definition of node: " << external_id;
+ }
+ static void WarnDuplicate(const ExternalId& external_id) {
+ Warn() << "ignoring duplicate definition of node: " << external_id;
+ }
+};
+
} // namespace stg
#endif // STG_GRAPH_H_
diff --git a/hex.h b/hex.h
new file mode 100644
index 0000000..0c174f0
--- /dev/null
+++ b/hex.h
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- mode: C++ -*-
+//
+// Copyright 2023-2024 Google LLC
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions (the
+// "License"); you may not use this file except in compliance with the
+// License. You may obtain a copy of the License at
+//
+// https://llvm.org/LICENSE.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Author: Giuliano Procida
+
+#ifndef STG_HEX_H_
+#define STG_HEX_H_
+
+#include <cstddef> // for std::size_t
+#include <functional> // for std::hash
+#include <ios>
+#include <ostream>
+
+namespace stg {
+
+template <typename T>
+struct Hex {
+ explicit Hex(const T& value) : value(value) {}
+ auto operator<=>(const Hex<T>& other) const = default;
+ T value;
+};
+
+template <typename T> Hex(const T&) -> Hex<T>;
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const Hex<T>& hex_value) {
+ // not quite right if an exception is thrown
+ const auto flags = os.flags();
+ os << "0x" << std::hex << hex_value.value;
+ os.flags(flags);
+ return os;
+}
+
+} // namespace stg
+
+template <typename T>
+struct std::hash<stg::Hex<T>> {
+ std::size_t operator()(const stg::Hex<T>& hex) const noexcept {
+ return std::hash<T>{}(hex.value);
+ }
+};
+
+#endif // STG_HEX_H_
diff --git a/hex_test.cc b/hex_test.cc
new file mode 100644
index 0000000..afa7214
--- /dev/null
+++ b/hex_test.cc
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// -*- mode: C++ -*-
+//
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License v2.0 with LLVM Exceptions (the
+// "License"); you may not use this file except in compliance with the
+// License. You may obtain a copy of the License at
+//
+// https://llvm.org/LICENSE.txt
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Author: Giuliano Procida
+
+#include "hex.h"
+
+#include <cstdint>
+#include <sstream>
+#include <string_view>
+
+#include <catch2/catch.hpp>
+
+namespace Test {
+
+struct TestCase {
+ std::string_view name;
+ int value;
+ std::string_view formatted;
+};
+
+TEST_CASE("Hex<uint32_t>") {
+ const auto test = GENERATE(
+ TestCase({"zero", 0, "0x0"}),
+ TestCase({"half width", 0xabcd, "0xabcd"}),
+ TestCase({"full width", 0x12345678, "0x12345678"}));
+
+ INFO("testing with " << test.name << " value");
+ std::ostringstream os;
+ os << stg::Hex<uint32_t>(test.value);
+ CHECK(os.str() == test.formatted);
+}
+
+TEST_CASE("self comparison") {
+ const stg::Hex<uint8_t> a(0);
+ CHECK(a == a);
+ CHECK(!(a != a));
+ CHECK(!(a < a));
+ CHECK(a <= a);
+ CHECK(!(a > a));
+ CHECK(a >= a);
+}
+
+TEST_CASE("distinct comparison") {
+ const stg::Hex<uint8_t> a(0);
+ const stg::Hex<uint8_t> b(1);
+ CHECK(!(a == b));
+ CHECK(a != b);
+ CHECK(a < b);
+ CHECK(a <= b);
+ CHECK(!(a > b));
+ CHECK(!(a >= b));
+}
+
+} // namespace Test
diff --git a/input.cc b/input.cc
index 239cb07..5757379 100644
--- a/input.cc
+++ b/input.cc
@@ -24,6 +24,7 @@
#include "abigail_reader.h"
#include "btf_reader.h"
+#include "elf_dwarf_handle.h"
#include "elf_reader.h"
#include "error.h"
#include "filter.h"
@@ -50,11 +51,12 @@
}
case InputFormat::ELF: {
const Time read(runtime, "read ELF");
- return elf::Read(runtime, graph, input, options, file_filter);
+ ElfDwarfHandle elf_dwarf_handle(input);
+ return elf::Read(runtime, graph, elf_dwarf_handle, options, file_filter);
}
case InputFormat::STG: {
const Time read(runtime, "read STG");
- return proto::Read(graph, input);
+ return proto::Read(runtime, graph, input);
}
}
}
diff --git a/naming.cc b/naming.cc
index 77548c1..ab1507a 100644
--- a/naming.cc
+++ b/naming.cc
@@ -30,7 +30,7 @@
Name Name::Add(Side side, Precedence precedence,
const std::string& text) const {
- bool bracket = precedence < precedence_;
+ const bool bracket = precedence < precedence_;
std::ostringstream left;
std::ostringstream right;
diff --git a/post_processing.cc b/post_processing.cc
index 9aafeb4..aec1b24 100644
--- a/post_processing.cc
+++ b/post_processing.cc
@@ -124,7 +124,7 @@
const size_t indent3 = match3[1].length();
if (indent1 + 2 == indent2 && indent1 >= indent3) {
const auto new_indent = indent1;
- int64_t new_offset =
+ const int64_t new_offset =
std::stoll(match2[3].str()) - std::stoll(match2[2].str());
if (new_indent != indent || new_offset != offset) {
emit_pending();
diff --git a/proto_reader.cc b/proto_reader.cc
index a83fd10..f046458 100644
--- a/proto_reader.cc
+++ b/proto_reader.cc
@@ -28,7 +28,6 @@
#include <optional>
#include <string>
#include <string_view>
-#include <unordered_map>
#include <vector>
#include <google/protobuf/io/zero_copy_stream_impl.h>
@@ -37,6 +36,8 @@
#include <google/protobuf/text_format.h>
#include "error.h"
#include "graph.h"
+#include "hex.h"
+#include "runtime.h"
#include "stg.pb.h"
namespace stg {
@@ -45,7 +46,7 @@
namespace {
struct Transformer {
- explicit Transformer(Graph& graph) : graph(graph) {}
+ explicit Transformer(Graph& graph) : graph(graph), maker(graph) {}
Id Transform(const proto::STG&);
@@ -74,7 +75,7 @@
void AddNode(const Symbols&);
void AddNode(const Interface&);
template <typename STGType, typename... Args>
- void AddNode(Args&&...);
+ void AddNode(uint32_t, Args&&...);
std::vector<Id> Transform(const google::protobuf::RepeatedField<uint32_t>&);
template <typename GetKey>
@@ -97,7 +98,7 @@
Type Transform(const Type&);
Graph& graph;
- std::unordered_map<uint32_t, Id> id_map;
+ Maker<Hex<uint32_t>> maker;
};
Id Transformer::Transform(const proto::STG& x) {
@@ -125,11 +126,7 @@
}
Id Transformer::GetId(uint32_t id) {
- auto [it, inserted] = id_map.emplace(id, 0);
- if (inserted) {
- it->second = graph.Allocate();
- }
- return it->second;
+ return maker.Get(Hex(id));
}
template <typename ProtoType>
@@ -140,59 +137,57 @@
}
void Transformer::AddNode(const Void& x) {
- AddNode<stg::Special>(GetId(x.id()), stg::Special::Kind::VOID);
+ AddNode<stg::Special>(x.id(), stg::Special::Kind::VOID);
}
void Transformer::AddNode(const Variadic& x) {
- AddNode<stg::Special>(GetId(x.id()), stg::Special::Kind::VARIADIC);
+ AddNode<stg::Special>(x.id(), stg::Special::Kind::VARIADIC);
}
void Transformer::AddNode(const Special& x) {
- AddNode<stg::Special>(GetId(x.id()), x.kind());
+ AddNode<stg::Special>(x.id(), x.kind());
}
void Transformer::AddNode(const PointerReference& x) {
- AddNode<stg::PointerReference>(GetId(x.id()), x.kind(),
- GetId(x.pointee_type_id()));
+ AddNode<stg::PointerReference>(x.id(), x.kind(), GetId(x.pointee_type_id()));
}
void Transformer::AddNode(const PointerToMember& x) {
- AddNode<stg::PointerToMember>(GetId(x.id()), GetId(x.containing_type_id()),
+ AddNode<stg::PointerToMember>(x.id(), GetId(x.containing_type_id()),
GetId(x.pointee_type_id()));
}
void Transformer::AddNode(const Typedef& x) {
- AddNode<stg::Typedef>(GetId(x.id()), x.name(), GetId(x.referred_type_id()));
+ AddNode<stg::Typedef>(x.id(), x.name(), GetId(x.referred_type_id()));
}
void Transformer::AddNode(const Qualified& x) {
- AddNode<stg::Qualified>(GetId(x.id()), x.qualifier(),
- GetId(x.qualified_type_id()));
+ AddNode<stg::Qualified>(x.id(), x.qualifier(), GetId(x.qualified_type_id()));
}
void Transformer::AddNode(const Primitive& x) {
const auto& encoding =
Transform<stg::Primitive::Encoding>(x.has_encoding(), x.encoding());
- AddNode<stg::Primitive>(GetId(x.id()), x.name(), encoding, x.bytesize());
+ AddNode<stg::Primitive>(x.id(), x.name(), encoding, x.bytesize());
}
void Transformer::AddNode(const Array& x) {
- AddNode<stg::Array>(GetId(x.id()), x.number_of_elements(),
+ AddNode<stg::Array>(x.id(), x.number_of_elements(),
GetId(x.element_type_id()));
}
void Transformer::AddNode(const BaseClass& x) {
- AddNode<stg::BaseClass>(GetId(x.id()), GetId(x.type_id()), x.offset(),
+ AddNode<stg::BaseClass>(x.id(), GetId(x.type_id()), x.offset(),
x.inheritance());
}
void Transformer::AddNode(const Method& x) {
- AddNode<stg::Method>(GetId(x.id()), x.mangled_name(), x.name(),
- x.vtable_offset(), GetId(x.type_id()));
+ AddNode<stg::Method>(x.id(), x.mangled_name(), x.name(), x.vtable_offset(),
+ GetId(x.type_id()));
}
void Transformer::AddNode(const Member& x) {
- AddNode<stg::Member>(GetId(x.id()), x.name(), GetId(x.type_id()), x.offset(),
+ AddNode<stg::Member>(x.id(), x.name(), GetId(x.type_id()), x.offset(),
x.bitsize());
}
@@ -200,29 +195,29 @@
const auto& discr_value = x.has_discriminant_value()
? std::make_optional(x.discriminant_value())
: std::nullopt;
- AddNode<stg::VariantMember>(GetId(x.id()), x.name(), discr_value,
+ AddNode<stg::VariantMember>(x.id(), x.name(), discr_value,
GetId(x.type_id()));
}
void Transformer::AddNode(const StructUnion& x) {
if (x.has_definition()) {
AddNode<stg::StructUnion>(
- GetId(x.id()), x.kind(), x.name(), x.definition().bytesize(),
+ x.id(), x.kind(), x.name(), x.definition().bytesize(),
x.definition().base_class_id(), x.definition().method_id(),
x.definition().member_id());
} else {
- AddNode<stg::StructUnion>(GetId(x.id()), x.kind(), x.name());
+ AddNode<stg::StructUnion>(x.id(), x.kind(), x.name());
}
}
void Transformer::AddNode(const Enumeration& x) {
if (x.has_definition()) {
- AddNode<stg::Enumeration>(GetId(x.id()), x.name(),
+ AddNode<stg::Enumeration>(x.id(), x.name(),
GetId(x.definition().underlying_type_id()),
x.definition().enumerator());
return;
} else {
- AddNode<stg::Enumeration>(GetId(x.id()), x.name());
+ AddNode<stg::Enumeration>(x.id(), x.name());
}
}
@@ -230,13 +225,12 @@
const auto& discriminant = x.has_discriminant()
? std::make_optional(GetId(x.discriminant()))
: std::nullopt;
- AddNode<stg::Variant>(GetId(x.id()), x.name(), x.bytesize(), discriminant,
+ AddNode<stg::Variant>(x.id(), x.name(), x.bytesize(), discriminant,
x.member_id());
}
void Transformer::AddNode(const Function& x) {
- AddNode<stg::Function>(GetId(x.id()), GetId(x.return_type_id()),
- x.parameter_id());
+ AddNode<stg::Function>(x.id(), GetId(x.return_type_id()), x.parameter_id());
}
void Transformer::AddNode(const ElfSymbol& x) {
@@ -244,7 +238,7 @@
return std::make_optional(
stg::ElfSymbol::VersionInfo{x.is_default(), x.name()});
};
- std::optional<stg::ElfSymbol::VersionInfo> version_info =
+ const std::optional<stg::ElfSymbol::VersionInfo> version_info =
x.has_version_info() ? make_version_info(x.version_info()) : std::nullopt;
const auto& crc = x.has_crc()
? std::make_optional<stg::ElfSymbol::CRC>(x.crc())
@@ -255,7 +249,7 @@
const auto& full_name =
Transform<std::string>(x.has_full_name(), x.full_name());
- AddNode<stg::ElfSymbol>(GetId(x.id()), x.name(), version_info, x.is_defined(),
+ AddNode<stg::ElfSymbol>(x.id(), x.name(), version_info, x.is_defined(),
x.symbol_type(), x.binding(), x.visibility(), crc, ns,
type_id, full_name);
}
@@ -265,25 +259,25 @@
for (const auto& [symbol, id] : x.symbol()) {
symbols.emplace(symbol, GetId(id));
}
- AddNode<stg::Interface>(GetId(x.id()), symbols);
+ AddNode<stg::Interface>(x.id(), symbols);
}
void Transformer::AddNode(const Interface& x) {
const InterfaceKey get_key(graph);
- AddNode<stg::Interface>(GetId(x.id()), Transform(get_key, x.symbol_id()),
+ AddNode<stg::Interface>(x.id(), Transform(get_key, x.symbol_id()),
Transform(get_key, x.type_id()));
}
template <typename STGType, typename... Args>
-void Transformer::AddNode(Args&&... args) {
- graph.Set<STGType>(Transform(args)...);
+void Transformer::AddNode(uint32_t id, Args&&... args) {
+ maker.Set<STGType>(Hex(id), Transform(args)...);
}
std::vector<Id> Transformer::Transform(
const google::protobuf::RepeatedField<uint32_t>& ids) {
std::vector<Id> result;
result.reserve(ids.size());
- for (uint32_t id : ids) {
+ for (const uint32_t id : ids) {
result.push_back(GetId(id));
}
return result;
@@ -391,6 +385,8 @@
stg::ElfSymbol::SymbolType Transformer::Transform(ElfSymbol::SymbolType x) {
switch (x) {
+ case ElfSymbol::NOTYPE:
+ return stg::ElfSymbol::SymbolType::NOTYPE;
case ElfSymbol::OBJECT:
return stg::ElfSymbol::SymbolType::OBJECT;
case ElfSymbol::FUNCTION:
@@ -461,8 +457,8 @@
const std::array<uint32_t, 3> kSupportedFormatVersions = {0, 1, 2};
void CheckFormatVersion(uint32_t version, std::optional<std::string> path) {
- Check(std::count(kSupportedFormatVersions.begin(),
- kSupportedFormatVersions.end(), version) > 0)
+ Check(std::binary_search(kSupportedFormatVersions.begin(),
+ kSupportedFormatVersions.end(), version))
<< "STG format version " << version
<< " is not supported, minimum supported version: "
<< kSupportedFormatVersions.front();
@@ -479,22 +475,35 @@
} // namespace
-Id Read(Graph& graph, const std::string& path) {
- std::ifstream ifs(path);
- Check(ifs.good()) << "error opening file '" << path
- << "' for reading: " << Error(errno);
- google::protobuf::io::IstreamInputStream is(&ifs);
+Id Read(Runtime& runtime, Graph& graph, const std::string& path) {
proto::STG stg;
- google::protobuf::TextFormat::Parse(&is, &stg);
- CheckFormatVersion(stg.version(), path);
- return Transformer(graph).Transform(stg);
+ {
+ const Time t(runtime, "proto.Parse");
+ std::ifstream ifs(path);
+ Check(ifs.good()) << "error opening file '" << path
+ << "' for reading: " << Error(errno);
+ google::protobuf::io::IstreamInputStream is(&ifs);
+ google::protobuf::TextFormat::Parse(&is, &stg);
+ }
+ {
+ const Time t(runtime, "proto.Transform");
+ CheckFormatVersion(stg.version(), path);
+ return Transformer(graph).Transform(stg);
+ }
}
-Id ReadFromString(Graph& graph, const std::string_view input) {
+Id ReadFromString(Runtime& runtime, Graph& graph, std::string_view input) {
proto::STG stg;
- google::protobuf::TextFormat::ParseFromString(std::string(input), &stg);
- CheckFormatVersion(stg.version(), std::nullopt);
- return Transformer(graph).Transform(stg);
+ {
+ const Time t(runtime, "proto.Parse");
+ // TODO: Pass string_view once AOSP Protobuf supports this.
+ google::protobuf::TextFormat::ParseFromString(std::string(input), &stg);
+ }
+ {
+ const Time t(runtime, "proto.Transform");
+ CheckFormatVersion(stg.version(), std::nullopt);
+ return Transformer(graph).Transform(stg);
+ }
}
} // namespace proto
diff --git a/proto_reader.h b/proto_reader.h
index 7639bf1..b57f6e8 100644
--- a/proto_reader.h
+++ b/proto_reader.h
@@ -24,12 +24,13 @@
#include <string_view>
#include "graph.h"
+#include "runtime.h"
namespace stg {
namespace proto {
-Id Read(Graph&, const std::string&);
-Id ReadFromString(Graph&, std::string_view);
+Id Read(Runtime&, Graph&, const std::string&);
+Id ReadFromString(Runtime&, Graph&, std::string_view);
} // namespace proto
} // namespace stg
diff --git a/proto_writer.cc b/proto_writer.cc
index 16b1010..915981f 100644
--- a/proto_writer.cc
+++ b/proto_writer.cc
@@ -27,6 +27,7 @@
#include <ostream>
#include <sstream>
#include <string>
+#include <tuple>
#include <unordered_map>
#include <unordered_set>
@@ -414,6 +415,8 @@
ElfSymbol::SymbolType Transform<MapId>::operator()(
stg::ElfSymbol::SymbolType x) {
switch (x) {
+ case stg::ElfSymbol::SymbolType::NOTYPE:
+ return ElfSymbol::NOTYPE;
case stg::ElfSymbol::SymbolType::OBJECT:
return ElfSymbol::OBJECT;
case stg::ElfSymbol::SymbolType::FUNCTION:
@@ -458,55 +461,44 @@
template <typename ProtoNode>
void SortNodesById(google::protobuf::RepeatedPtrField<ProtoNode>& nodes) {
- std::sort(
- nodes.pointer_begin(), nodes.pointer_end(),
- [](const auto* lhs, const auto* rhs) { return lhs->id() < rhs->id(); });
+ const auto compare = [](const auto* lhs, const auto* rhs) {
+ return lhs->id() < rhs->id();
+ };
+ std::sort(nodes.pointer_begin(), nodes.pointer_end(), compare);
}
template <typename ProtoNode>
void SortNodesByName(google::protobuf::RepeatedPtrField<ProtoNode>& nodes) {
const auto compare = [](const auto* lhs, const auto* rhs) {
- const int comparison = lhs->name().compare(rhs->name());
- return comparison < 0 || (comparison == 0 && lhs->id() < rhs->id());
+ return std::forward_as_tuple(lhs->name(), lhs->id())
+ < std::forward_as_tuple(rhs->name(), rhs->id());
};
std::sort(nodes.pointer_begin(), nodes.pointer_end(), compare);
}
void SortMethodsByMangledName(google::protobuf::RepeatedPtrField<Method>& methods) {
const auto compare = [](const Method* lhs, const Method* rhs) {
- const int comparison = lhs->mangled_name().compare(rhs->mangled_name());
- return comparison < 0 || (comparison == 0 && lhs->id() < rhs->id());
+ return std::forward_as_tuple(lhs->mangled_name(), lhs->id())
+ < std::forward_as_tuple(rhs->mangled_name(), rhs->id());
};
std::sort(methods.pointer_begin(), methods.pointer_end(), compare);
}
void SortElfSymbolsByVersionedName(
google::protobuf::RepeatedPtrField<ElfSymbol>& elf_symbols) {
- // TODO: use spaceship operator <=>
const auto compare = [](const ElfSymbol* lhs, const ElfSymbol* rhs) {
- if (const int c = lhs->name().compare(rhs->name()); c != 0) {
- return c < 0;
- }
-
- // Put symbols with version info after those without version info.
- if (lhs->has_version_info() != rhs->has_version_info()) {
- return rhs->has_version_info();
- }
-
- if (lhs->has_version_info()) {
- const auto& l_version = lhs->version_info();
- const auto& r_version = rhs->version_info();
- if (const int c = l_version.name().compare(r_version.name()); c != 0) {
- return c < 0;
- }
-
- // Put symbols with default version before those with non-default version.
- if (l_version.is_default() != r_version.is_default()) {
- return r_version.is_default();
- }
- }
-
- return lhs->id() < rhs->id();
+ // Sorting by:
+ //
+ // name
+ // version name
+ // ID as tie-breaker
+ //
+ // Note: symbols without version information will be ordered before
+ // versioned symbols of the same name.
+ return std::forward_as_tuple(lhs->name(), lhs->version_info().name(),
+ lhs->id())
+ < std::forward_as_tuple(rhs->name(), rhs->version_info().name(),
+ rhs->id());
};
std::sort(elf_symbols.pointer_begin(), elf_symbols.pointer_end(), compare);
}
diff --git a/reporting.cc b/reporting.cc
index 5c3c02c..66bd998 100644
--- a/reporting.cc
+++ b/reporting.cc
@@ -78,7 +78,7 @@
std::string GetResolvedDescription(
const Graph& graph, NameCache& names, Id id) {
std::ostringstream os;
- const auto [resolved, typedefs] = ResolveTypedefs(graph, id);
+ const auto [resolved, typedefs] = diff::ResolveTypedefs(graph, id);
for (const auto& td : typedefs) {
os << '\'' << td << "' = ";
}
@@ -92,9 +92,9 @@
// empty.
//
// It returns true if the comparison denotes addition or removal of a node.
-bool PrintComparison(const Reporting& reporting, const Comparison& comparison,
- std::ostream& os, size_t indent,
- const std::string& prefix) {
+bool PrintComparison(const Reporting& reporting,
+ const diff::Comparison& comparison, std::ostream& os,
+ size_t indent, const std::string& prefix) {
os << std::string(indent, ' ');
if (!prefix.empty()) {
os << prefix << ' ';
@@ -139,24 +139,24 @@
class Plain {
// unvisited (absent) -> started (false) -> finished (true)
- using Seen = std::unordered_map<Comparison, bool, HashComparison>;
+ using Seen = std::unordered_map<diff::Comparison, bool, diff::HashComparison>;
public:
Plain(const Reporting& reporting, std::ostream& output)
: reporting_(reporting), output_(output) {}
- void Report(const Comparison&);
+ void Report(const diff::Comparison&);
private:
const Reporting& reporting_;
std::ostream& output_;
Seen seen_;
- void Print(const Comparison&, size_t, const std::string&);
+ void Print(const diff::Comparison&, size_t, const std::string&);
};
-void Plain::Print(const Comparison& comparison, size_t indent,
- const std::string& prefix) {
+void Plain::Print(const diff::Comparison& comparison, size_t indent,
+ const std::string& prefix) {
if (PrintComparison(reporting_, comparison, output_, indent, prefix)) {
return;
}
@@ -196,7 +196,7 @@
}
}
-void Plain::Report(const Comparison& comparison) {
+void Plain::Report(const diff::Comparison& comparison) {
// unpack then print - want symbol diff forest rather than symbols diff tree
const auto& diff = reporting_.outcomes.at(comparison);
for (const auto& detail : diff.details) {
@@ -216,21 +216,21 @@
Flat(const Reporting& reporting, bool full, std::ostream& output)
: reporting_(reporting), full_(full), output_(output) {}
- void Report(const Comparison&);
+ void Report(const diff::Comparison&);
private:
const Reporting& reporting_;
const bool full_;
std::ostream& output_;
- std::unordered_set<Comparison, HashComparison> seen_;
- std::deque<Comparison> todo_;
+ std::unordered_set<diff::Comparison, diff::HashComparison> seen_;
+ std::deque<diff::Comparison> todo_;
- bool Print(const Comparison&, bool, std::ostream&, size_t,
+ bool Print(const diff::Comparison&, bool, std::ostream&, size_t,
const std::string&);
};
-bool Flat::Print(const Comparison& comparison, bool stop, std::ostream& os,
- size_t indent, const std::string& prefix) {
+bool Flat::Print(const diff::Comparison& comparison, bool stop,
+ std::ostream& os, size_t indent, const std::string& prefix) {
// Nodes that represent additions or removal are always interesting and no
// recursion is possible.
if (PrintComparison(reporting_, comparison, os, indent, prefix)) {
@@ -269,7 +269,7 @@
// Edge changes are interesting if the target diff node is.
std::ostringstream sub_os;
// Set the stop flag to prevent recursion past diff-holding nodes.
- bool sub_interesting =
+ const bool sub_interesting =
Print(*detail.edge_, true, sub_os, indent, detail.text_);
// If the sub-tree was interesting, add it.
if (sub_interesting || full_) {
@@ -281,7 +281,7 @@
return interesting;
}
-void Flat::Report(const Comparison& comparison) {
+void Flat::Report(const diff::Comparison& comparison) {
// We want a symbol diff forest rather than a symbol table diff tree, so
// unpack the symbol table and then print the symbols specially.
const auto& diff = reporting_.outcomes.at(comparison);
@@ -303,15 +303,17 @@
}
}
-size_t VizId(std::unordered_map<Comparison, size_t, HashComparison>& ids,
- const Comparison& comparison) {
+size_t VizId(
+ std::unordered_map<diff::Comparison, size_t, diff::HashComparison>& ids,
+ const diff::Comparison& comparison) {
return ids.insert({comparison, ids.size()}).first->second;
}
-void VizPrint(const Reporting& reporting, const Comparison& comparison,
- std::unordered_set<Comparison, HashComparison>& seen,
- std::unordered_map<Comparison, size_t, HashComparison>& ids,
- std::ostream& os) {
+void VizPrint(
+ const Reporting& reporting, const diff::Comparison& comparison,
+ std::unordered_set<diff::Comparison, diff::HashComparison>& seen,
+ std::unordered_map<diff::Comparison, size_t, diff::HashComparison>& ids,
+ std::ostream& os) {
if (!seen.insert(comparison).second) {
return;
}
@@ -373,11 +375,11 @@
}
}
-void ReportViz(const Reporting& reporting, const Comparison& comparison,
+void ReportViz(const Reporting& reporting, const diff::Comparison& comparison,
std::ostream& output) {
output << "digraph \"ABI diff\" {\n";
- std::unordered_set<Comparison, HashComparison> seen;
- std::unordered_map<Comparison, size_t, HashComparison> ids;
+ std::unordered_set<diff::Comparison, diff::HashComparison> seen;
+ std::unordered_map<diff::Comparison, size_t, diff::HashComparison> ids;
VizPrint(reporting, comparison, seen, ids, output);
output << "}\n";
}
@@ -395,7 +397,7 @@
} // namespace
-void Report(const Reporting& reporting, const Comparison& comparison,
+void Report(const Reporting& reporting, const diff::Comparison& comparison,
std::ostream& output) {
switch (reporting.options.format) {
case OutputFormat::PLAIN: {
@@ -404,7 +406,7 @@
}
case OutputFormat::FLAT:
case OutputFormat::SMALL: {
- bool full = reporting.options.format == OutputFormat::FLAT;
+ const bool full = reporting.options.format == OutputFormat::FLAT;
Flat(reporting, full, output).Report(comparison);
break;
}
diff --git a/reporting.h b/reporting.h
index edee19e..04c3b98 100644
--- a/reporting.h
+++ b/reporting.h
@@ -47,12 +47,12 @@
struct Reporting {
const Graph& graph;
- const Outcomes& outcomes;
+ const diff::Outcomes& outcomes;
const Options& options;
NameCache& names;
};
-void Report(const Reporting&, const Comparison&, std::ostream&);
+void Report(const Reporting&, const diff::Comparison&, std::ostream&);
bool FidelityDiff(const stg::FidelityDiff&, std::ostream&);
diff --git a/scc.h b/scc.h
index ca196b1..3199a53 100644
--- a/scc.h
+++ b/scc.h
@@ -21,8 +21,8 @@
#define STG_SCC_H_
#include <cstddef>
+#include <exception>
#include <iterator>
-#include <memory>
#include <optional>
#include <unordered_map>
#include <utility>
@@ -84,8 +84,11 @@
template <typename Node, typename Hash = std::hash<Node>>
class SCC {
public:
- bool Empty() const {
- return open_.empty() && is_open_.empty() && root_index_.empty();
+ ~SCC() noexcept(false) {
+ if (std::uncaught_exceptions() == 0) {
+ Check(open_.empty() && is_open_.empty() && root_index_.empty())
+ << "internal error: SCC state broken";
+ }
}
std::optional<size_t> Open(const Node& node) {
diff --git a/scc_test.cc b/scc_test.cc
index a82fd6c..47f5de8 100644
--- a/scc_test.cc
+++ b/scc_test.cc
@@ -68,10 +68,10 @@
for (size_t i = 0; i < n; ++i) {
// since we scan the nodes k in order, it suffices to consider just paths:
// i -> k -> j
- if (g[i].count(k)) {
+ if (g[i].contains(k)) {
// we have i -> k
for (size_t j = 0; j < n; ++j) {
- if (g[k].count(j)) {
+ if (g[k].contains(j)) {
// and k -> j
g[i].insert(j);
}
@@ -83,8 +83,8 @@
for (size_t i = 0; i < n; ++i) {
for (size_t j = i + 1; j < n; ++j) {
// discard i -> j if not j -> i and vice versa
- auto ij = g[i].count(j);
- auto ji = g[j].count(i);
+ auto ij = g[i].contains(j);
+ auto ji = g[j].contains(i);
if (ij < ji) {
g[j].erase(i);
}
@@ -118,7 +118,7 @@
void dfs(std::set<size_t>& visited, SCC<size_t>& scc, const Graph& g,
size_t node, std::vector<std::set<size_t>>& sccs) {
- if (visited.count(node)) {
+ if (visited.contains(node)) {
return;
}
auto handle = scc.Open(node);
@@ -149,7 +149,6 @@
// could reuse a single SCC finder but assert stronger invariants this way
SCC<size_t> scc;
dfs(visited, scc, g, o, sccs);
- CHECK(scc.Empty());
}
// check partition and topological order properties
@@ -165,7 +164,7 @@
for (auto node : nodes) {
for (auto o : g[node]) {
// edges point to nodes in this or earlier SCCs
- CHECK(seen.count(o));
+ CHECK(seen.contains(o));
}
}
}
diff --git a/stg.proto b/stg.proto
index 5ba2d6c..ed6c86a 100644
--- a/stg.proto
+++ b/stg.proto
@@ -223,11 +223,12 @@
enum SymbolType {
SYMBOL_TYPE_UNSPECIFIED = 0;
- OBJECT = 1;
- FUNCTION = 2;
- COMMON = 3;
- TLS = 4;
- GNU_IFUNC = 5;
+ NOTYPE = 1;
+ OBJECT = 2;
+ FUNCTION = 3;
+ COMMON = 4;
+ TLS = 5;
+ GNU_IFUNC = 6;
}
enum Binding {
diff --git a/stgdiff.cc b/stgdiff.cc
index ecc7fdb..d737767 100644
--- a/stgdiff.cc
+++ b/stgdiff.cc
@@ -76,11 +76,8 @@
return diffs_reported ? kFidelityChange : 0;
}
-int RunExact(stg::Runtime& runtime, const Inputs& inputs,
- stg::ReadOptions options) {
- stg::Graph graph;
- const auto roots = Read(runtime, inputs, graph, options);
-
+int RunExact(stg::Runtime& runtime, const stg::Graph& graph,
+ const std::vector<stg::Id>& roots) {
struct PairCache {
std::optional<bool> Query(const stg::Pair& comparison) const {
return equalities.find(comparison) != equalities.end()
@@ -103,21 +100,16 @@
: kAbiChange;
}
-int Run(stg::Runtime& runtime, const Inputs& inputs, const Outputs& outputs,
- stg::Ignore ignore, stg::ReadOptions options,
- std::optional<const char*> fidelity) {
- // Read inputs.
- stg::Graph graph;
- const auto roots = Read(runtime, inputs, graph, options);
-
+int Run(stg::Runtime& runtime, const stg::Graph& graph,
+ const std::vector<stg::Id>& roots, const Outputs& outputs,
+ stg::diff::Ignore ignore, std::optional<const char*> fidelity) {
// Compute differences.
- stg::Compare compare{runtime, graph, ignore};
- std::pair<bool, std::optional<stg::Comparison>> result;
+ stg::diff::Compare compare{runtime, graph, ignore};
+ std::pair<bool, std::optional<stg::diff::Comparison>> result;
{
const stg::Time compute(runtime, "compute diffs");
result = compare(roots[0], roots[1]);
}
- stg::Check(compare.scc.Empty()) << "internal error: SCC state broken";
const auto& [equals, comparison] = result;
int status = equals ? 0 : kAbiChange;
@@ -155,7 +147,7 @@
bool opt_exact = false;
stg::ReadOptions opt_read_options;
std::optional<const char*> opt_fidelity = std::nullopt;
- stg::Ignore opt_ignore;
+ stg::diff::Ignore opt_ignore;
stg::InputFormat opt_input_format = stg::InputFormat::ABI;
stg::reporting::OutputFormat opt_output_format =
stg::reporting::OutputFormat::PLAIN;
@@ -189,7 +181,7 @@
<< "implicit defaults: --abi --format plain\n"
<< "--exact (node equality) cannot be combined with --output\n"
<< stg::reporting::OutputFormatUsage()
- << stg::IgnoreUsage();
+ << stg::diff::IgnoreUsage();
return 1;
};
while (true) {
@@ -225,11 +217,11 @@
inputs.emplace_back(opt_input_format, argument);
break;
case 'i':
- if (const auto ignore = stg::ParseIgnore(argument)) {
+ if (const auto ignore = stg::diff::ParseIgnore(argument)) {
opt_ignore.Set(ignore.value());
} else {
std::cerr << "unknown ignore option: " << argument << '\n'
- << stg::IgnoreUsage();
+ << stg::diff::IgnoreUsage();
return 1;
}
break;
@@ -264,9 +256,11 @@
try {
stg::Runtime runtime(std::cerr, opt_metrics);
- return opt_exact ? RunExact(runtime, inputs, opt_read_options)
- : Run(runtime, inputs, outputs, opt_ignore,
- opt_read_options, opt_fidelity);
+ stg::Graph graph;
+ const auto roots = Read(runtime, inputs, graph, opt_read_options);
+ return opt_exact ? RunExact(runtime, graph, roots)
+ : Run(runtime, graph, roots, outputs, opt_ignore,
+ opt_fidelity);
} catch (const stg::Exception& e) {
std::cerr << e.what();
return 1;
diff --git a/stgdiff_test.cc b/stgdiff_test.cc
index 306ddc3..b0f82cc 100644
--- a/stgdiff_test.cc
+++ b/stgdiff_test.cc
@@ -38,7 +38,7 @@
const std::string file0;
const stg::InputFormat format1;
const std::string file1;
- const stg::Ignore ignore;
+ const stg::diff::Ignore ignore;
const std::string expected_output;
const bool expected_equals;
};
@@ -61,7 +61,7 @@
"symbol_type_presence_0.xml",
stg::InputFormat::ABI,
"symbol_type_presence_1.xml",
- stg::Ignore(),
+ stg::diff::Ignore(),
"symbol_type_presence_small_diff",
false}),
IgnoreTestCase(
@@ -70,7 +70,7 @@
"symbol_type_presence_0.xml",
stg::InputFormat::ABI,
"symbol_type_presence_1.xml",
- stg::Ignore(stg::Ignore::SYMBOL_TYPE_PRESENCE),
+ stg::diff::Ignore(stg::diff::Ignore::SYMBOL_TYPE_PRESENCE),
"empty",
true}),
IgnoreTestCase(
@@ -79,7 +79,7 @@
"type_declaration_status_0.xml",
stg::InputFormat::ABI,
"type_declaration_status_1.xml",
- stg::Ignore(),
+ stg::diff::Ignore(),
"type_declaration_status_small_diff",
false}),
IgnoreTestCase(
@@ -88,7 +88,7 @@
"type_declaration_status_0.xml",
stg::InputFormat::ABI,
"type_declaration_status_1.xml",
- stg::Ignore(stg::Ignore::TYPE_DECLARATION_STATUS),
+ stg::diff::Ignore(stg::diff::Ignore::TYPE_DECLARATION_STATUS),
"empty",
true}),
IgnoreTestCase(
@@ -97,7 +97,7 @@
"primitive_type_encoding_0.stg",
stg::InputFormat::STG,
"primitive_type_encoding_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"primitive_type_encoding_small_diff",
false}),
IgnoreTestCase(
@@ -106,7 +106,7 @@
"primitive_type_encoding_0.stg",
stg::InputFormat::STG,
"primitive_type_encoding_1.stg",
- stg::Ignore(stg::Ignore::PRIMITIVE_TYPE_ENCODING),
+ stg::diff::Ignore(stg::diff::Ignore::PRIMITIVE_TYPE_ENCODING),
"empty",
true}),
IgnoreTestCase(
@@ -115,7 +115,7 @@
"member_size_0.stg",
stg::InputFormat::STG,
"member_size_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"member_size_small_diff",
false}),
IgnoreTestCase(
@@ -124,7 +124,7 @@
"member_size_0.stg",
stg::InputFormat::STG,
"member_size_1.stg",
- stg::Ignore(stg::Ignore::MEMBER_SIZE),
+ stg::diff::Ignore(stg::diff::Ignore::MEMBER_SIZE),
"empty",
true}),
IgnoreTestCase(
@@ -133,7 +133,7 @@
"enum_underlying_type_0.stg",
stg::InputFormat::STG,
"enum_underlying_type_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"enum_underlying_type_small_diff",
false}),
IgnoreTestCase(
@@ -142,7 +142,7 @@
"enum_underlying_type_0.stg",
stg::InputFormat::STG,
"enum_underlying_type_1.stg",
- stg::Ignore(stg::Ignore::ENUM_UNDERLYING_TYPE),
+ stg::diff::Ignore(stg::diff::Ignore::ENUM_UNDERLYING_TYPE),
"empty",
true}),
IgnoreTestCase(
@@ -151,7 +151,7 @@
"qualifier_0.stg",
stg::InputFormat::STG,
"qualifier_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"qualifier_small_diff",
false}),
IgnoreTestCase(
@@ -160,7 +160,7 @@
"qualifier_0.stg",
stg::InputFormat::STG,
"qualifier_1.stg",
- stg::Ignore(stg::Ignore::QUALIFIER),
+ stg::diff::Ignore(stg::diff::Ignore::QUALIFIER),
"empty",
true}),
IgnoreTestCase(
@@ -169,7 +169,7 @@
"crc_change_0.stg",
stg::InputFormat::STG,
"crc_change_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"crc_change_small_diff",
false}),
IgnoreTestCase(
@@ -178,7 +178,7 @@
"crc_change_0.stg",
stg::InputFormat::STG,
"crc_change_1.stg",
- stg::Ignore(stg::Ignore::SYMBOL_CRC),
+ stg::diff::Ignore(stg::diff::Ignore::SYMBOL_CRC),
"empty",
true}),
IgnoreTestCase(
@@ -187,7 +187,7 @@
"interface_addition_0.stg",
stg::InputFormat::STG,
"interface_addition_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"interface_addition_small_diff",
false}),
IgnoreTestCase(
@@ -196,7 +196,7 @@
"interface_addition_0.stg",
stg::InputFormat::STG,
"interface_addition_1.stg",
- stg::Ignore(stg::Ignore::INTERFACE_ADDITION),
+ stg::diff::Ignore(stg::diff::Ignore::INTERFACE_ADDITION),
"empty",
true}),
IgnoreTestCase(
@@ -205,7 +205,7 @@
"type_addition_0.stg",
stg::InputFormat::STG,
"type_addition_1.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"type_addition_small_diff",
false}),
IgnoreTestCase(
@@ -214,7 +214,7 @@
"type_addition_0.stg",
stg::InputFormat::STG,
"type_addition_1.stg",
- stg::Ignore(stg::Ignore::INTERFACE_ADDITION),
+ stg::diff::Ignore(stg::diff::Ignore::INTERFACE_ADDITION),
"empty",
true}),
IgnoreTestCase(
@@ -223,7 +223,7 @@
"type_addition_1.stg",
stg::InputFormat::STG,
"type_addition_2.stg",
- stg::Ignore(),
+ stg::diff::Ignore(),
"type_definition_addition_small_diff",
false}),
IgnoreTestCase(
@@ -232,7 +232,7 @@
"type_addition_1.stg",
stg::InputFormat::STG,
"type_addition_2.stg",
- stg::Ignore(stg::Ignore::TYPE_DEFINITION_ADDITION),
+ stg::diff::Ignore(stg::diff::Ignore::TYPE_DEFINITION_ADDITION),
"empty",
true})
);
@@ -247,7 +247,7 @@
const auto id1 = Read(runtime, graph, test.format1, test.file1);
// Compute differences.
- stg::Compare compare{runtime, graph, test.ignore};
+ stg::diff::Compare compare{runtime, graph, test.ignore};
const auto& [equals, comparison] = compare(id0, id1);
// Write SMALL reports.
@@ -302,7 +302,7 @@
const auto id1 = Read(runtime, graph, stg::InputFormat::ABI, test.xml1);
// Compute differences.
- stg::Compare compare{runtime, graph, {}};
+ stg::diff::Compare compare{runtime, graph, {}};
const auto& [equals, comparison] = compare(id0, id1);
// Write SHORT reports.
diff --git a/test_cases/diff_tests/describe/types.0.c b/test_cases/diff_tests/describe/types.0.c
index 7c4353b..4435d36 100644
--- a/test_cases/diff_tests/describe/types.0.c
+++ b/test_cases/diff_tests/describe/types.0.c
@@ -28,14 +28,12 @@
struct amusement * fun() { return 0; }
-void tweak(int);
+int M() { return 1; }
+int N() { return 2; }
+int O() { return 3; }
+int P() { return 4; }
-int M() { tweak(0); return 0; }
-int N() { tweak(1); return 0; }
-int O() { tweak(2); return 0; }
-int P() { tweak(3); return 0; }
-
-int m() { tweak(4); return 0; }
-int n() { tweak(5); return 0; }
-int o() { tweak(6); return 0; }
-int p() { tweak(7); return 0; }
+int m() { return 5; }
+int n() { return 6; }
+int o() { return 7; }
+int p() { return 8; }
diff --git a/test_cases/diff_tests/describe/types.1.c b/test_cases/diff_tests/describe/types.1.c
index 4411bd8..ff22ac7 100644
--- a/test_cases/diff_tests/describe/types.1.c
+++ b/test_cases/diff_tests/describe/types.1.c
@@ -52,22 +52,20 @@
struct amusement * fun(void) { return 0; }
-void tweak(int);
-
// declare M as function (void) returning int
-int M(void ) { tweak(0); return 0; }
+int M(void ) { return 1; }
// declare N as function (void) returning pointer to array 7 of int
-int (*N(void ))[7] { tweak(1); return 0; }
+int (*N(void ))[7] { static int array[7]; return &array; }
// declare O as function (void) returning pointer to int
-int *O(void ) { tweak(2); return 0; }
+int *O(void ) { static int number; return &number; }
// declare P as function (void) returning pointer to function (void) returning int
-int (*P(void ))(void ) { tweak(3); return 0; }
+int (*P(void ))(void ) { return &M; }
// declare m as function (void) returning int
-int m(void ) { tweak(4); return 0; }
+int m(void ) { return 5; }
// declare n as function (void) returning pointer to array 7 of volatile int
-volatile int (*n(void ))[7] { tweak(5); return 0; }
+volatile int (*n(void ))[7] { static volatile int array[7]; return &array; }
// declare o as function (void) returning pointer to volatile int
-volatile int *o(void ) { tweak(6); return 0; }
+volatile int *o(void ) { static volatile int number; return &number; }
// declare p as function (void) returning pointer to function (void) returning int
-int (*p(void ))(void ) { tweak(7); return 0; }
+int (*p(void ))(void ) { return &m; }
diff --git a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_flat b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_flat
index 63fa50e..a56a281 100644
--- a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_flat
+++ b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_flat
@@ -10,13 +10,13 @@
variable symbol '_ZTV15NormalToVirtual' was added
-function symbol 'void NormalToVirtual::print(struct NormalToVirtual*)' {_ZN15NormalToVirtual5printEv} changed
- type 'void(struct NormalToVirtual*)' changed
+function symbol 'int NormalToVirtual::print(struct NormalToVirtual*)' {_ZN15NormalToVirtual5printEv} changed
+ type 'int(struct NormalToVirtual*)' changed
parameter 1 type 'struct NormalToVirtual*' changed
pointed-to type 'struct NormalToVirtual' changed
-function symbol 'void VirtualToNormal::print(struct VirtualToNormal*)' {_ZN15VirtualToNormal5printEv} changed
- type 'void(struct VirtualToNormal*)' changed
+function symbol 'int VirtualToNormal::print(struct VirtualToNormal*)' {_ZN15VirtualToNormal5printEv} changed
+ type 'int(struct VirtualToNormal*)' changed
parameter 1 type 'struct VirtualToNormal*' changed
pointed-to type 'struct VirtualToNormal' changed
@@ -28,12 +28,12 @@
type 'struct NormalToVirtual' changed
byte size changed from 1 to 8
- method 'void print(struct NormalToVirtual*)' was added
+ method 'int print(struct NormalToVirtual*)' was added
member 'int(** _vptr$NormalToVirtual)()' was added
type 'struct VirtualToNormal' changed
byte size changed from 8 to 1
- method 'void print(struct VirtualToNormal*)' was removed
+ method 'int print(struct VirtualToNormal*)' was removed
member 'int(** _vptr$VirtualToNormal)()' was removed
exit code 4
diff --git a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_plain b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_plain
index 1aabae0..e61d2c7 100644
--- a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_plain
+++ b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_plain
@@ -10,20 +10,20 @@
variable symbol '_ZTV15NormalToVirtual' was added
-function symbol 'void NormalToVirtual::print(struct NormalToVirtual*)' {_ZN15NormalToVirtual5printEv} changed
- type 'void(struct NormalToVirtual*)' changed
+function symbol 'int NormalToVirtual::print(struct NormalToVirtual*)' {_ZN15NormalToVirtual5printEv} changed
+ type 'int(struct NormalToVirtual*)' changed
parameter 1 type 'struct NormalToVirtual*' changed
pointed-to type 'struct NormalToVirtual' changed
byte size changed from 1 to 8
- method 'void print(struct NormalToVirtual*)' was added
+ method 'int print(struct NormalToVirtual*)' was added
member 'int(** _vptr$NormalToVirtual)()' was added
-function symbol 'void VirtualToNormal::print(struct VirtualToNormal*)' {_ZN15VirtualToNormal5printEv} changed
- type 'void(struct VirtualToNormal*)' changed
+function symbol 'int VirtualToNormal::print(struct VirtualToNormal*)' {_ZN15VirtualToNormal5printEv} changed
+ type 'int(struct VirtualToNormal*)' changed
parameter 1 type 'struct VirtualToNormal*' changed
pointed-to type 'struct VirtualToNormal' changed
byte size changed from 8 to 1
- method 'void print(struct VirtualToNormal*)' was removed
+ method 'int print(struct VirtualToNormal*)' was removed
member 'int(** _vptr$VirtualToNormal)()' was removed
variable symbol 'struct NormalToVirtual normal_to_virtual' changed
diff --git a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_small b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_small
index d5757f7..4df3199 100644
--- a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_small
+++ b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_small
@@ -12,12 +12,12 @@
type 'struct NormalToVirtual' changed
byte size changed from 1 to 8
- method 'void print(struct NormalToVirtual*)' was added
+ method 'int print(struct NormalToVirtual*)' was added
member 'int(** _vptr$NormalToVirtual)()' was added
type 'struct VirtualToNormal' changed
byte size changed from 8 to 1
- method 'void print(struct VirtualToNormal*)' was removed
+ method 'int print(struct VirtualToNormal*)' was removed
member 'int(** _vptr$VirtualToNormal)()' was removed
exit code 4
diff --git a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_viz b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_viz
index e315dce..0184d33 100644
--- a/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_viz
+++ b/test_cases/diff_tests/function/expected/virtual_vs_non_virtual_cc.o_o_viz
@@ -12,13 +12,13 @@
"0" -> "5" [label=""]
"6" [color=red, label="added(_ZTV15NormalToVirtual)"]
"0" -> "6" [label=""]
- "7" [label="'void NormalToVirtual::print(struct NormalToVirtual*)' {_ZN15NormalToVirtual5printEv}"]
- "8" [label="'void(struct NormalToVirtual*)'"]
+ "7" [label="'int NormalToVirtual::print(struct NormalToVirtual*)' {_ZN15NormalToVirtual5printEv}"]
+ "8" [label="'int(struct NormalToVirtual*)'"]
"9" [label="'struct NormalToVirtual*'"]
"10" [color=red, shape=rectangle, label="'struct NormalToVirtual'"]
"10" -> "10:0"
"10:0" [color=red, label="byte size changed from 1 to 8"]
- "11" [color=red, label="added(void print(struct NormalToVirtual*))"]
+ "11" [color=red, label="added(int print(struct NormalToVirtual*))"]
"10" -> "11" [label=""]
"12" [color=red, label="added(int(** _vptr$NormalToVirtual)())"]
"10" -> "12" [label=""]
@@ -26,13 +26,13 @@
"8" -> "9" [label="parameter 1"]
"7" -> "8" [label=""]
"0" -> "7" [label=""]
- "13" [label="'void VirtualToNormal::print(struct VirtualToNormal*)' {_ZN15VirtualToNormal5printEv}"]
- "14" [label="'void(struct VirtualToNormal*)'"]
+ "13" [label="'int VirtualToNormal::print(struct VirtualToNormal*)' {_ZN15VirtualToNormal5printEv}"]
+ "14" [label="'int(struct VirtualToNormal*)'"]
"15" [label="'struct VirtualToNormal*'"]
"16" [color=red, shape=rectangle, label="'struct VirtualToNormal'"]
"16" -> "16:0"
"16:0" [color=red, label="byte size changed from 8 to 1"]
- "17" [color=red, label="removed(void print(struct VirtualToNormal*))"]
+ "17" [color=red, label="removed(int print(struct VirtualToNormal*))"]
"16" -> "17" [label=""]
"18" [color=red, label="removed(int(** _vptr$VirtualToNormal)())"]
"16" -> "18" [label=""]
diff --git a/test_cases/diff_tests/function/virtual_vs_non_virtual.0.cc b/test_cases/diff_tests/function/virtual_vs_non_virtual.0.cc
index e244040..565eb66 100644
--- a/test_cases/diff_tests/function/virtual_vs_non_virtual.0.cc
+++ b/test_cases/diff_tests/function/virtual_vs_non_virtual.0.cc
@@ -1,11 +1,11 @@
-void tweak(int);
-
struct VirtualToNormal {
- virtual void print();
+ virtual int print();
} virtual_to_normal;
-void VirtualToNormal::print() { tweak(0); }
+
+int VirtualToNormal::print() { return 0; }
struct NormalToVirtual {
- void print();
+ int print();
} normal_to_virtual;
-void NormalToVirtual::print() { tweak(1); }
+
+int NormalToVirtual::print() { return 1; }
diff --git a/test_cases/diff_tests/function/virtual_vs_non_virtual.1.cc b/test_cases/diff_tests/function/virtual_vs_non_virtual.1.cc
index a89b6fe..f79a583 100644
--- a/test_cases/diff_tests/function/virtual_vs_non_virtual.1.cc
+++ b/test_cases/diff_tests/function/virtual_vs_non_virtual.1.cc
@@ -1,11 +1,11 @@
-void tweak(int);
-
struct VirtualToNormal {
- void print();
+ int print();
} virtual_to_normal;
-void VirtualToNormal::print() { tweak(0); }
+
+int VirtualToNormal::print() { return 0; }
struct NormalToVirtual {
- virtual void print();
+ virtual int print();
} normal_to_virtual;
-void NormalToVirtual::print() { tweak(1); }
+
+int NormalToVirtual::print() { return 1; }
diff --git a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_flat b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_flat
index 59e5a0e..27c752f 100644
--- a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_flat
+++ b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_flat
@@ -4,6 +4,8 @@
function symbol 'void pmz_fun()' {_Z7pmz_funv} was added
+function symbol 'void X::f(struct X*, int)' {_ZN1X1fEi} was added
+
variable symbol 'char struct Y::* pmc' was added
variable symbol 'int union U::* pmcu' was added
diff --git a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_plain b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_plain
index 59e5a0e..27c752f 100644
--- a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_plain
+++ b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_plain
@@ -4,6 +4,8 @@
function symbol 'void pmz_fun()' {_Z7pmz_funv} was added
+function symbol 'void X::f(struct X*, int)' {_ZN1X1fEi} was added
+
variable symbol 'char struct Y::* pmc' was added
variable symbol 'int union U::* pmcu' was added
diff --git a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_small b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_small
index 59e5a0e..27c752f 100644
--- a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_small
+++ b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_small
@@ -4,6 +4,8 @@
function symbol 'void pmz_fun()' {_Z7pmz_funv} was added
+function symbol 'void X::f(struct X*, int)' {_ZN1X1fEi} was added
+
variable symbol 'char struct Y::* pmc' was added
variable symbol 'int union U::* pmcu' was added
diff --git a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_viz b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_viz
index 292ca80..b1cbb30 100644
--- a/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_viz
+++ b/test_cases/diff_tests/member/expected/pointer_to_member_cc.o_o_viz
@@ -6,44 +6,46 @@
"0" -> "2" [label=""]
"3" [color=red, label="added(void pmz_fun() {_Z7pmz_funv})"]
"0" -> "3" [label=""]
- "4" [color=red, label="added(char struct Y::* pmc)"]
+ "4" [color=red, label="added(void X::f(struct X*, int) {_ZN1X1fEi})"]
"0" -> "4" [label=""]
- "5" [color=red, label="added(int union U::* pmcu)"]
+ "5" [color=red, label="added(char struct Y::* pmc)"]
"0" -> "5" [label=""]
- "6" [color=red, label="added(double struct X::* pmd)"]
+ "6" [color=red, label="added(int union U::* pmcu)"]
"0" -> "6" [label=""]
- "7" [color=red, label="added(void(struct X::* pmf)(struct X*, int))"]
+ "7" [color=red, label="added(double struct X::* pmd)"]
"0" -> "7" [label=""]
- "8" [color=red, label="added(int struct X::* pmi)"]
+ "8" [color=red, label="added(void(struct X::* pmf)(struct X*, int))"]
"0" -> "8" [label=""]
- "9" [color=red, label="added(int union U::* pmu)"]
+ "9" [color=red, label="added(int struct X::* pmi)"]
"0" -> "9" [label=""]
- "10" [color=red, label="added(int struct { int t; }::* pmy)"]
+ "10" [color=red, label="added(int union U::* pmu)"]
"0" -> "10" [label=""]
- "11" [color=red, label="added(int struct S::* s0)"]
+ "11" [color=red, label="added(int struct { int t; }::* pmy)"]
"0" -> "11" [label=""]
- "12" [color=red, label="added(int struct S::** s1)"]
+ "12" [color=red, label="added(int struct S::* s0)"]
"0" -> "12" [label=""]
- "13" [color=red, label="added(int struct S::*(* s3)())"]
+ "13" [color=red, label="added(int struct S::** s1)"]
"0" -> "13" [label=""]
- "14" [color=red, label="added(int struct S::* s4[7])"]
+ "14" [color=red, label="added(int struct S::*(* s3)())"]
"0" -> "14" [label=""]
- "15" [color=red, label="added(int* struct S::* s5)"]
+ "15" [color=red, label="added(int struct S::* s4[7])"]
"0" -> "15" [label=""]
- "16" [color=red, label="added(int(* struct S::* s6)())"]
+ "16" [color=red, label="added(int* struct S::* s5)"]
"0" -> "16" [label=""]
- "17" [color=red, label="added(int(struct S::* s7)(struct S*))"]
+ "17" [color=red, label="added(int(* struct S::* s6)())"]
"0" -> "17" [label=""]
- "18" [color=red, label="added(int(struct S::* s8)[7])"]
+ "18" [color=red, label="added(int(struct S::* s7)(struct S*))"]
"0" -> "18" [label=""]
- "19" [color=red, label="added(const int struct S::* volatile s9)"]
+ "19" [color=red, label="added(int(struct S::* s8)[7])"]
"0" -> "19" [label=""]
- "20" [label="'char struct A::* diff' -> 'int struct B::* diff'"]
- "21" [label="'char struct A::*' -> 'int struct B::*'"]
- "22" [color=red, label="'struct A' -> 'struct B'"]
- "21" -> "22" [label="containing"]
- "23" [color=red, label="'char' -> 'int'"]
- "21" -> "23" [label=""]
- "20" -> "21" [label=""]
+ "20" [color=red, label="added(const int struct S::* volatile s9)"]
"0" -> "20" [label=""]
+ "21" [label="'char struct A::* diff' -> 'int struct B::* diff'"]
+ "22" [label="'char struct A::*' -> 'int struct B::*'"]
+ "23" [color=red, label="'struct A' -> 'struct B'"]
+ "22" -> "23" [label="containing"]
+ "24" [color=red, label="'char' -> 'int'"]
+ "22" -> "24" [label=""]
+ "21" -> "22" [label=""]
+ "0" -> "21" [label=""]
}
diff --git a/test_cases/diff_tests/member/pointer_to_member.1.cc b/test_cases/diff_tests/member/pointer_to_member.1.cc
index 9779061..5034120 100644
--- a/test_cases/diff_tests/member/pointer_to_member.1.cc
+++ b/test_cases/diff_tests/member/pointer_to_member.1.cc
@@ -26,7 +26,7 @@
int s10(int S::*) { return 0; }
struct X {
- void f(int);
+ void f(int) {}
int a;
};
struct Y;
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_flat b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_flat
index 57d3100..cec1b14 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_flat
+++ b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_flat
@@ -1,18 +1,18 @@
-function symbol 'void bar_1(const volatile struct foo*)' was removed
+function symbol 'int bar_1(const volatile struct foo*)' was removed
-function symbol 'void bar_2(struct foo*)' was added
+function symbol 'int bar_2(struct foo*)' was added
-function symbol changed from 'void bar(struct foo)' to 'void bar(const volatile struct foo*)'
- type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int bar(struct foo)' to 'int bar(const volatile struct foo*)'
+ type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-function symbol changed from 'void baz(void(*)(struct foo))' to 'void baz(void(* volatile const)(const volatile struct foo*))'
- type changed from 'void(void(*)(struct foo))' to 'void(void(* volatile const)(const volatile struct foo*))'
- parameter 1 type changed from 'void(*)(struct foo)' to 'void(* volatile const)(const volatile struct foo*)'
+function symbol changed from 'int baz(int(*)(struct foo))' to 'int baz(int(* volatile const)(const volatile struct foo*))'
+ type changed from 'int(int(*)(struct foo))' to 'int(int(* volatile const)(const volatile struct foo*))'
+ parameter 1 type changed from 'int(*)(struct foo)' to 'int(* volatile const)(const volatile struct foo*)'
qualifier const added
qualifier volatile added
- underlying type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+ underlying type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
exit code 4
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_plain b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_plain
index 57d3100..cec1b14 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_plain
+++ b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_plain
@@ -1,18 +1,18 @@
-function symbol 'void bar_1(const volatile struct foo*)' was removed
+function symbol 'int bar_1(const volatile struct foo*)' was removed
-function symbol 'void bar_2(struct foo*)' was added
+function symbol 'int bar_2(struct foo*)' was added
-function symbol changed from 'void bar(struct foo)' to 'void bar(const volatile struct foo*)'
- type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int bar(struct foo)' to 'int bar(const volatile struct foo*)'
+ type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-function symbol changed from 'void baz(void(*)(struct foo))' to 'void baz(void(* volatile const)(const volatile struct foo*))'
- type changed from 'void(void(*)(struct foo))' to 'void(void(* volatile const)(const volatile struct foo*))'
- parameter 1 type changed from 'void(*)(struct foo)' to 'void(* volatile const)(const volatile struct foo*)'
+function symbol changed from 'int baz(int(*)(struct foo))' to 'int baz(int(* volatile const)(const volatile struct foo*))'
+ type changed from 'int(int(*)(struct foo))' to 'int(int(* volatile const)(const volatile struct foo*))'
+ parameter 1 type changed from 'int(*)(struct foo)' to 'int(* volatile const)(const volatile struct foo*)'
qualifier const added
qualifier volatile added
- underlying type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+ underlying type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
exit code 4
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_small b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_small
index 57d3100..cec1b14 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_small
+++ b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_small
@@ -1,18 +1,18 @@
-function symbol 'void bar_1(const volatile struct foo*)' was removed
+function symbol 'int bar_1(const volatile struct foo*)' was removed
-function symbol 'void bar_2(struct foo*)' was added
+function symbol 'int bar_2(struct foo*)' was added
-function symbol changed from 'void bar(struct foo)' to 'void bar(const volatile struct foo*)'
- type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int bar(struct foo)' to 'int bar(const volatile struct foo*)'
+ type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-function symbol changed from 'void baz(void(*)(struct foo))' to 'void baz(void(* volatile const)(const volatile struct foo*))'
- type changed from 'void(void(*)(struct foo))' to 'void(void(* volatile const)(const volatile struct foo*))'
- parameter 1 type changed from 'void(*)(struct foo)' to 'void(* volatile const)(const volatile struct foo*)'
+function symbol changed from 'int baz(int(*)(struct foo))' to 'int baz(int(* volatile const)(const volatile struct foo*))'
+ type changed from 'int(int(*)(struct foo))' to 'int(int(* volatile const)(const volatile struct foo*))'
+ parameter 1 type changed from 'int(*)(struct foo)' to 'int(* volatile const)(const volatile struct foo*)'
qualifier const added
qualifier volatile added
- underlying type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+ underlying type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
exit code 4
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_viz b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_viz
index ac7228e..96578bf 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_viz
+++ b/test_cases/diff_tests/qualified/expected/useless_c.btf_btf_viz
@@ -1,24 +1,24 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [color=red, label="removed(void bar_1(const volatile struct foo*))"]
+ "1" [color=red, label="removed(int bar_1(const volatile struct foo*))"]
"0" -> "1" [label=""]
- "2" [color=red, label="added(void bar_2(struct foo*))"]
+ "2" [color=red, label="added(int bar_2(struct foo*))"]
"0" -> "2" [label=""]
- "3" [label="'void bar(struct foo)' -> 'void bar(const volatile struct foo*)'"]
- "4" [label="'void(struct foo)' -> 'void(const volatile struct foo*)'"]
+ "3" [label="'int bar(struct foo)' -> 'int bar(const volatile struct foo*)'"]
+ "4" [label="'int(struct foo)' -> 'int(const volatile struct foo*)'"]
"5" [color=red, label="'struct foo' -> 'const volatile struct foo*'"]
"4" -> "5" [label="parameter 1"]
"3" -> "4" [label=""]
"0" -> "3" [label=""]
- "6" [label="'void baz(void(*)(struct foo))' -> 'void baz(void(* volatile const)(const volatile struct foo*))'"]
- "7" [label="'void(void(*)(struct foo))' -> 'void(void(* volatile const)(const volatile struct foo*))'"]
- "8" [color=red, label="'void(*)(struct foo)' -> 'void(* volatile const)(const volatile struct foo*)'"]
+ "6" [label="'int baz(int(*)(struct foo))' -> 'int baz(int(* volatile const)(const volatile struct foo*))'"]
+ "7" [label="'int(int(*)(struct foo))' -> 'int(int(* volatile const)(const volatile struct foo*))'"]
+ "8" [color=red, label="'int(*)(struct foo)' -> 'int(* volatile const)(const volatile struct foo*)'"]
"8" -> "8:0"
"8:0" [color=red, label="qualifier const added"]
"8" -> "8:1"
"8:1" [color=red, label="qualifier volatile added"]
- "9" [label="'void(*)(struct foo)' -> 'void(*)(const volatile struct foo*)'"]
- "10" [label="'void(struct foo)' -> 'void(const volatile struct foo*)'"]
+ "9" [label="'int(*)(struct foo)' -> 'int(*)(const volatile struct foo*)'"]
+ "10" [label="'int(struct foo)' -> 'int(const volatile struct foo*)'"]
"10" -> "5" [label="parameter 1"]
"9" -> "10" [label="pointed-to"]
"8" -> "9" [label="underlying"]
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.o_o_flat b/test_cases/diff_tests/qualified/expected/useless_c.o_o_flat
index a5c95a6..acfb82a 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.o_o_flat
+++ b/test_cases/diff_tests/qualified/expected/useless_c.o_o_flat
@@ -1,23 +1,23 @@
-function symbol 'void bar_1(const volatile struct foo*)' was removed
+function symbol 'int bar_1(const volatile struct foo*)' was removed
-function symbol 'void bar_2(struct foo*)' was added
+function symbol 'int bar_2(struct foo*)' was added
-function symbol changed from 'void bar(struct foo)' to 'void bar(const volatile struct foo*)'
- type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int bar(struct foo)' to 'int bar(const volatile struct foo*)'
+ type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-function symbol changed from 'void baz(void(*)(struct foo))' to 'void baz(void(*)(const volatile struct foo*))'
- type changed from 'void(void(*)(struct foo))' to 'void(void(*)(const volatile struct foo*))'
- parameter 1 type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int baz(int(*)(struct foo))' to 'int baz(int(*)(const volatile struct foo*))'
+ type changed from 'int(int(*)(struct foo))' to 'int(int(*)(const volatile struct foo*))'
+ parameter 1 type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-variable symbol changed from 'void(* quux)(struct foo)' to 'void(* volatile const quux)(const volatile struct foo*)'
- type changed from 'void(*)(struct foo)' to 'void(* volatile const)(const volatile struct foo*)'
+variable symbol changed from 'int(* quux)(struct foo)' to 'int(* volatile const quux)(const volatile struct foo*)'
+ type changed from 'int(*)(struct foo)' to 'int(* volatile const)(const volatile struct foo*)'
qualifier const added
qualifier volatile added
- underlying type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+ underlying type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
exit code 4
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.o_o_plain b/test_cases/diff_tests/qualified/expected/useless_c.o_o_plain
index a5c95a6..acfb82a 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.o_o_plain
+++ b/test_cases/diff_tests/qualified/expected/useless_c.o_o_plain
@@ -1,23 +1,23 @@
-function symbol 'void bar_1(const volatile struct foo*)' was removed
+function symbol 'int bar_1(const volatile struct foo*)' was removed
-function symbol 'void bar_2(struct foo*)' was added
+function symbol 'int bar_2(struct foo*)' was added
-function symbol changed from 'void bar(struct foo)' to 'void bar(const volatile struct foo*)'
- type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int bar(struct foo)' to 'int bar(const volatile struct foo*)'
+ type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-function symbol changed from 'void baz(void(*)(struct foo))' to 'void baz(void(*)(const volatile struct foo*))'
- type changed from 'void(void(*)(struct foo))' to 'void(void(*)(const volatile struct foo*))'
- parameter 1 type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int baz(int(*)(struct foo))' to 'int baz(int(*)(const volatile struct foo*))'
+ type changed from 'int(int(*)(struct foo))' to 'int(int(*)(const volatile struct foo*))'
+ parameter 1 type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-variable symbol changed from 'void(* quux)(struct foo)' to 'void(* volatile const quux)(const volatile struct foo*)'
- type changed from 'void(*)(struct foo)' to 'void(* volatile const)(const volatile struct foo*)'
+variable symbol changed from 'int(* quux)(struct foo)' to 'int(* volatile const quux)(const volatile struct foo*)'
+ type changed from 'int(*)(struct foo)' to 'int(* volatile const)(const volatile struct foo*)'
qualifier const added
qualifier volatile added
- underlying type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+ underlying type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
exit code 4
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.o_o_small b/test_cases/diff_tests/qualified/expected/useless_c.o_o_small
index a5c95a6..acfb82a 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.o_o_small
+++ b/test_cases/diff_tests/qualified/expected/useless_c.o_o_small
@@ -1,23 +1,23 @@
-function symbol 'void bar_1(const volatile struct foo*)' was removed
+function symbol 'int bar_1(const volatile struct foo*)' was removed
-function symbol 'void bar_2(struct foo*)' was added
+function symbol 'int bar_2(struct foo*)' was added
-function symbol changed from 'void bar(struct foo)' to 'void bar(const volatile struct foo*)'
- type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int bar(struct foo)' to 'int bar(const volatile struct foo*)'
+ type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-function symbol changed from 'void baz(void(*)(struct foo))' to 'void baz(void(*)(const volatile struct foo*))'
- type changed from 'void(void(*)(struct foo))' to 'void(void(*)(const volatile struct foo*))'
- parameter 1 type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+function symbol changed from 'int baz(int(*)(struct foo))' to 'int baz(int(*)(const volatile struct foo*))'
+ type changed from 'int(int(*)(struct foo))' to 'int(int(*)(const volatile struct foo*))'
+ parameter 1 type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
-variable symbol changed from 'void(* quux)(struct foo)' to 'void(* volatile const quux)(const volatile struct foo*)'
- type changed from 'void(*)(struct foo)' to 'void(* volatile const)(const volatile struct foo*)'
+variable symbol changed from 'int(* quux)(struct foo)' to 'int(* volatile const quux)(const volatile struct foo*)'
+ type changed from 'int(*)(struct foo)' to 'int(* volatile const)(const volatile struct foo*)'
qualifier const added
qualifier volatile added
- underlying type changed from 'void(*)(struct foo)' to 'void(*)(const volatile struct foo*)'
- pointed-to type changed from 'void(struct foo)' to 'void(const volatile struct foo*)'
+ underlying type changed from 'int(*)(struct foo)' to 'int(*)(const volatile struct foo*)'
+ pointed-to type changed from 'int(struct foo)' to 'int(const volatile struct foo*)'
parameter 1 type changed from 'struct foo' to 'const volatile struct foo*'
exit code 4
diff --git a/test_cases/diff_tests/qualified/expected/useless_c.o_o_viz b/test_cases/diff_tests/qualified/expected/useless_c.o_o_viz
index e8cf8c8..9b8691d 100644
--- a/test_cases/diff_tests/qualified/expected/useless_c.o_o_viz
+++ b/test_cases/diff_tests/qualified/expected/useless_c.o_o_viz
@@ -1,26 +1,26 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [color=red, label="removed(void bar_1(const volatile struct foo*))"]
+ "1" [color=red, label="removed(int bar_1(const volatile struct foo*))"]
"0" -> "1" [label=""]
- "2" [color=red, label="added(void bar_2(struct foo*))"]
+ "2" [color=red, label="added(int bar_2(struct foo*))"]
"0" -> "2" [label=""]
- "3" [label="'void bar(struct foo)' -> 'void bar(const volatile struct foo*)'"]
- "4" [label="'void(struct foo)' -> 'void(const volatile struct foo*)'"]
+ "3" [label="'int bar(struct foo)' -> 'int bar(const volatile struct foo*)'"]
+ "4" [label="'int(struct foo)' -> 'int(const volatile struct foo*)'"]
"5" [color=red, label="'struct foo' -> 'const volatile struct foo*'"]
"4" -> "5" [label="parameter 1"]
"3" -> "4" [label=""]
"0" -> "3" [label=""]
- "6" [label="'void baz(void(*)(struct foo))' -> 'void baz(void(*)(const volatile struct foo*))'"]
- "7" [label="'void(void(*)(struct foo))' -> 'void(void(*)(const volatile struct foo*))'"]
- "8" [label="'void(*)(struct foo)' -> 'void(*)(const volatile struct foo*)'"]
- "9" [label="'void(struct foo)' -> 'void(const volatile struct foo*)'"]
+ "6" [label="'int baz(int(*)(struct foo))' -> 'int baz(int(*)(const volatile struct foo*))'"]
+ "7" [label="'int(int(*)(struct foo))' -> 'int(int(*)(const volatile struct foo*))'"]
+ "8" [label="'int(*)(struct foo)' -> 'int(*)(const volatile struct foo*)'"]
+ "9" [label="'int(struct foo)' -> 'int(const volatile struct foo*)'"]
"9" -> "5" [label="parameter 1"]
"8" -> "9" [label="pointed-to"]
"7" -> "8" [label="parameter 1"]
"6" -> "7" [label=""]
"0" -> "6" [label=""]
- "10" [label="'void(* quux)(struct foo)' -> 'void(* volatile const quux)(const volatile struct foo*)'"]
- "11" [color=red, label="'void(*)(struct foo)' -> 'void(* volatile const)(const volatile struct foo*)'"]
+ "10" [label="'int(* quux)(struct foo)' -> 'int(* volatile const quux)(const volatile struct foo*)'"]
+ "11" [color=red, label="'int(*)(struct foo)' -> 'int(* volatile const)(const volatile struct foo*)'"]
"11" -> "11:0"
"11:0" [color=red, label="qualifier const added"]
"11" -> "11:1"
diff --git a/test_cases/diff_tests/qualified/useless.0.c b/test_cases/diff_tests/qualified/useless.0.c
index 5207883..6450a7a 100644
--- a/test_cases/diff_tests/qualified/useless.0.c
+++ b/test_cases/diff_tests/qualified/useless.0.c
@@ -1,21 +1,19 @@
-void tweak(int);
-
struct foo {
};
-void bar(struct foo y) {
+int bar(struct foo y) {
(void) y;
- tweak(0);
+ return 0;
}
-void bar_1(const volatile struct foo* y) {
+int bar_1(const volatile struct foo* y) {
(void) y;
- tweak(1);
+ return 1;
}
-void baz(void(*y)(struct foo)) {
+int baz(int (*y)(struct foo)) {
(void) y;
- tweak(2);
+ return 2;
}
-void(*quux)(struct foo) = &bar;
+int (*quux)(struct foo) = &bar;
diff --git a/test_cases/diff_tests/qualified/useless.1.c b/test_cases/diff_tests/qualified/useless.1.c
index a077d5b..53fdc50 100644
--- a/test_cases/diff_tests/qualified/useless.1.c
+++ b/test_cases/diff_tests/qualified/useless.1.c
@@ -1,21 +1,19 @@
-void tweak(int);
-
struct foo {
};
-void bar_2(struct foo* y) {
+int bar_2(struct foo* y) {
(void) y;
- tweak(0);
+ return 0;
}
-void bar(const volatile struct foo* y) {
+int bar(const volatile struct foo* y) {
(void) y;
- tweak(1);
+ return 1;
}
-void baz(void(*const volatile y)(const volatile struct foo*)) {
+int baz(int (*const volatile y)(const volatile struct foo*)) {
(void) y;
- tweak(2);
+ return 2;
}
-void(*const volatile quux)(const volatile struct foo*) = &bar;
+int (*const volatile quux)(const volatile struct foo*) = &bar;
diff --git a/test_cases/diff_tests/struct/expected/nested_c.btf_btf_flat b/test_cases/diff_tests/struct/expected/nested_c.btf_btf_flat
index 7606cd0..1fd0cff 100644
--- a/test_cases/diff_tests/struct/expected/nested_c.btf_btf_flat
+++ b/test_cases/diff_tests/struct/expected/nested_c.btf_btf_flat
@@ -1,18 +1,18 @@
-function symbol 'void register_ops6(struct containing)' changed
- type 'void(struct containing)' changed
+function symbol 'int register_ops6(struct containing)' changed
+ type 'int(struct containing)' changed
parameter 1 type 'struct containing' changed
-function symbol 'void register_ops7(struct containing*)' changed
- type 'void(struct containing*)' changed
+function symbol 'int register_ops7(struct containing*)' changed
+ type 'int(struct containing*)' changed
parameter 1 type 'struct containing*' changed
pointed-to type 'struct containing' changed
-function symbol 'void register_ops8(struct referring)' changed
- type 'void(struct referring)' changed
+function symbol 'int register_ops8(struct referring)' changed
+ type 'int(struct referring)' changed
parameter 1 type 'struct referring' changed
-function symbol 'void register_ops9(struct referring*)' changed
- type 'void(struct referring*)' changed
+function symbol 'int register_ops9(struct referring*)' changed
+ type 'int(struct referring*)' changed
parameter 1 type 'struct referring*' changed
pointed-to type 'struct referring' changed
diff --git a/test_cases/diff_tests/struct/expected/nested_c.btf_btf_plain b/test_cases/diff_tests/struct/expected/nested_c.btf_btf_plain
index a057172..d783357 100644
--- a/test_cases/diff_tests/struct/expected/nested_c.btf_btf_plain
+++ b/test_cases/diff_tests/struct/expected/nested_c.btf_btf_plain
@@ -1,5 +1,5 @@
-function symbol 'void register_ops6(struct containing)' changed
- type 'void(struct containing)' changed
+function symbol 'int register_ops6(struct containing)' changed
+ type 'int(struct containing)' changed
parameter 1 type 'struct containing' changed
byte size changed from 4 to 8
member 'struct nested inner' changed
@@ -8,22 +8,22 @@
member changed from 'int x' to 'long x'
type changed from 'int' to 'long'
-function symbol 'void register_ops7(struct containing*)' changed
- type 'void(struct containing*)' changed
+function symbol 'int register_ops7(struct containing*)' changed
+ type 'int(struct containing*)' changed
parameter 1 type 'struct containing*' changed
pointed-to type 'struct containing' changed
(already reported)
-function symbol 'void register_ops8(struct referring)' changed
- type 'void(struct referring)' changed
+function symbol 'int register_ops8(struct referring)' changed
+ type 'int(struct referring)' changed
parameter 1 type 'struct referring' changed
member 'struct nested* inner' changed
type 'struct nested*' changed
pointed-to type 'struct nested' changed
(already reported)
-function symbol 'void register_ops9(struct referring*)' changed
- type 'void(struct referring*)' changed
+function symbol 'int register_ops9(struct referring*)' changed
+ type 'int(struct referring*)' changed
parameter 1 type 'struct referring*' changed
pointed-to type 'struct referring' changed
(already reported)
diff --git a/test_cases/diff_tests/struct/expected/nested_c.btf_btf_viz b/test_cases/diff_tests/struct/expected/nested_c.btf_btf_viz
index 6e18086..54aded6 100644
--- a/test_cases/diff_tests/struct/expected/nested_c.btf_btf_viz
+++ b/test_cases/diff_tests/struct/expected/nested_c.btf_btf_viz
@@ -1,7 +1,7 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [label="'void register_ops6(struct containing)'"]
- "2" [label="'void(struct containing)'"]
+ "1" [label="'int register_ops6(struct containing)'"]
+ "2" [label="'int(struct containing)'"]
"3" [color=red, shape=rectangle, label="'struct containing'"]
"3" -> "3:0"
"3:0" [color=red, label="byte size changed from 4 to 8"]
@@ -18,15 +18,15 @@
"2" -> "3" [label="parameter 1"]
"1" -> "2" [label=""]
"0" -> "1" [label=""]
- "8" [label="'void register_ops7(struct containing*)'"]
- "9" [label="'void(struct containing*)'"]
+ "8" [label="'int register_ops7(struct containing*)'"]
+ "9" [label="'int(struct containing*)'"]
"10" [label="'struct containing*'"]
"10" -> "3" [label="pointed-to"]
"9" -> "10" [label="parameter 1"]
"8" -> "9" [label=""]
"0" -> "8" [label=""]
- "11" [label="'void register_ops8(struct referring)'"]
- "12" [label="'void(struct referring)'"]
+ "11" [label="'int register_ops8(struct referring)'"]
+ "12" [label="'int(struct referring)'"]
"13" [shape=rectangle, label="'struct referring'"]
"14" [label="'struct nested* inner'"]
"15" [label="'struct nested*'"]
@@ -36,8 +36,8 @@
"12" -> "13" [label="parameter 1"]
"11" -> "12" [label=""]
"0" -> "11" [label=""]
- "16" [label="'void register_ops9(struct referring*)'"]
- "17" [label="'void(struct referring*)'"]
+ "16" [label="'int register_ops9(struct referring*)'"]
+ "17" [label="'int(struct referring*)'"]
"18" [label="'struct referring*'"]
"18" -> "13" [label="pointed-to"]
"17" -> "18" [label="parameter 1"]
diff --git a/test_cases/diff_tests/struct/expected/nested_c.o_o_flat b/test_cases/diff_tests/struct/expected/nested_c.o_o_flat
index 7606cd0..1fd0cff 100644
--- a/test_cases/diff_tests/struct/expected/nested_c.o_o_flat
+++ b/test_cases/diff_tests/struct/expected/nested_c.o_o_flat
@@ -1,18 +1,18 @@
-function symbol 'void register_ops6(struct containing)' changed
- type 'void(struct containing)' changed
+function symbol 'int register_ops6(struct containing)' changed
+ type 'int(struct containing)' changed
parameter 1 type 'struct containing' changed
-function symbol 'void register_ops7(struct containing*)' changed
- type 'void(struct containing*)' changed
+function symbol 'int register_ops7(struct containing*)' changed
+ type 'int(struct containing*)' changed
parameter 1 type 'struct containing*' changed
pointed-to type 'struct containing' changed
-function symbol 'void register_ops8(struct referring)' changed
- type 'void(struct referring)' changed
+function symbol 'int register_ops8(struct referring)' changed
+ type 'int(struct referring)' changed
parameter 1 type 'struct referring' changed
-function symbol 'void register_ops9(struct referring*)' changed
- type 'void(struct referring*)' changed
+function symbol 'int register_ops9(struct referring*)' changed
+ type 'int(struct referring*)' changed
parameter 1 type 'struct referring*' changed
pointed-to type 'struct referring' changed
diff --git a/test_cases/diff_tests/struct/expected/nested_c.o_o_plain b/test_cases/diff_tests/struct/expected/nested_c.o_o_plain
index a057172..d783357 100644
--- a/test_cases/diff_tests/struct/expected/nested_c.o_o_plain
+++ b/test_cases/diff_tests/struct/expected/nested_c.o_o_plain
@@ -1,5 +1,5 @@
-function symbol 'void register_ops6(struct containing)' changed
- type 'void(struct containing)' changed
+function symbol 'int register_ops6(struct containing)' changed
+ type 'int(struct containing)' changed
parameter 1 type 'struct containing' changed
byte size changed from 4 to 8
member 'struct nested inner' changed
@@ -8,22 +8,22 @@
member changed from 'int x' to 'long x'
type changed from 'int' to 'long'
-function symbol 'void register_ops7(struct containing*)' changed
- type 'void(struct containing*)' changed
+function symbol 'int register_ops7(struct containing*)' changed
+ type 'int(struct containing*)' changed
parameter 1 type 'struct containing*' changed
pointed-to type 'struct containing' changed
(already reported)
-function symbol 'void register_ops8(struct referring)' changed
- type 'void(struct referring)' changed
+function symbol 'int register_ops8(struct referring)' changed
+ type 'int(struct referring)' changed
parameter 1 type 'struct referring' changed
member 'struct nested* inner' changed
type 'struct nested*' changed
pointed-to type 'struct nested' changed
(already reported)
-function symbol 'void register_ops9(struct referring*)' changed
- type 'void(struct referring*)' changed
+function symbol 'int register_ops9(struct referring*)' changed
+ type 'int(struct referring*)' changed
parameter 1 type 'struct referring*' changed
pointed-to type 'struct referring' changed
(already reported)
diff --git a/test_cases/diff_tests/struct/expected/nested_c.o_o_viz b/test_cases/diff_tests/struct/expected/nested_c.o_o_viz
index 6e18086..54aded6 100644
--- a/test_cases/diff_tests/struct/expected/nested_c.o_o_viz
+++ b/test_cases/diff_tests/struct/expected/nested_c.o_o_viz
@@ -1,7 +1,7 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [label="'void register_ops6(struct containing)'"]
- "2" [label="'void(struct containing)'"]
+ "1" [label="'int register_ops6(struct containing)'"]
+ "2" [label="'int(struct containing)'"]
"3" [color=red, shape=rectangle, label="'struct containing'"]
"3" -> "3:0"
"3:0" [color=red, label="byte size changed from 4 to 8"]
@@ -18,15 +18,15 @@
"2" -> "3" [label="parameter 1"]
"1" -> "2" [label=""]
"0" -> "1" [label=""]
- "8" [label="'void register_ops7(struct containing*)'"]
- "9" [label="'void(struct containing*)'"]
+ "8" [label="'int register_ops7(struct containing*)'"]
+ "9" [label="'int(struct containing*)'"]
"10" [label="'struct containing*'"]
"10" -> "3" [label="pointed-to"]
"9" -> "10" [label="parameter 1"]
"8" -> "9" [label=""]
"0" -> "8" [label=""]
- "11" [label="'void register_ops8(struct referring)'"]
- "12" [label="'void(struct referring)'"]
+ "11" [label="'int register_ops8(struct referring)'"]
+ "12" [label="'int(struct referring)'"]
"13" [shape=rectangle, label="'struct referring'"]
"14" [label="'struct nested* inner'"]
"15" [label="'struct nested*'"]
@@ -36,8 +36,8 @@
"12" -> "13" [label="parameter 1"]
"11" -> "12" [label=""]
"0" -> "11" [label=""]
- "16" [label="'void register_ops9(struct referring*)'"]
- "17" [label="'void(struct referring*)'"]
+ "16" [label="'int register_ops9(struct referring*)'"]
+ "17" [label="'int(struct referring*)'"]
"18" [label="'struct referring*'"]
"18" -> "13" [label="pointed-to"]
"17" -> "18" [label="parameter 1"]
diff --git a/test_cases/diff_tests/struct/expected/nested_cc.o_o_flat b/test_cases/diff_tests/struct/expected/nested_cc.o_o_flat
index b936e6d..6719855 100644
--- a/test_cases/diff_tests/struct/expected/nested_cc.o_o_flat
+++ b/test_cases/diff_tests/struct/expected/nested_cc.o_o_flat
@@ -1,18 +1,18 @@
-function symbol 'void register_ops6(struct containing)' {_Z13register_ops610containing} changed
- type 'void(struct containing)' changed
+function symbol 'int register_ops6(struct containing)' {_Z13register_ops610containing} changed
+ type 'int(struct containing)' changed
parameter 1 type 'struct containing' changed
-function symbol 'void register_ops7(struct containing*)' {_Z13register_ops7P10containing} changed
- type 'void(struct containing*)' changed
+function symbol 'int register_ops7(struct containing*)' {_Z13register_ops7P10containing} changed
+ type 'int(struct containing*)' changed
parameter 1 type 'struct containing*' changed
pointed-to type 'struct containing' changed
-function symbol 'void register_ops8(struct referring)' {_Z13register_ops89referring} changed
- type 'void(struct referring)' changed
+function symbol 'int register_ops8(struct referring)' {_Z13register_ops89referring} changed
+ type 'int(struct referring)' changed
parameter 1 type 'struct referring' changed
-function symbol 'void register_ops9(struct referring*)' {_Z13register_ops9P9referring} changed
- type 'void(struct referring*)' changed
+function symbol 'int register_ops9(struct referring*)' {_Z13register_ops9P9referring} changed
+ type 'int(struct referring*)' changed
parameter 1 type 'struct referring*' changed
pointed-to type 'struct referring' changed
diff --git a/test_cases/diff_tests/struct/expected/nested_cc.o_o_plain b/test_cases/diff_tests/struct/expected/nested_cc.o_o_plain
index 20bd034..46a7993 100644
--- a/test_cases/diff_tests/struct/expected/nested_cc.o_o_plain
+++ b/test_cases/diff_tests/struct/expected/nested_cc.o_o_plain
@@ -1,5 +1,5 @@
-function symbol 'void register_ops6(struct containing)' {_Z13register_ops610containing} changed
- type 'void(struct containing)' changed
+function symbol 'int register_ops6(struct containing)' {_Z13register_ops610containing} changed
+ type 'int(struct containing)' changed
parameter 1 type 'struct containing' changed
byte size changed from 4 to 8
member 'struct nested inner' changed
@@ -8,22 +8,22 @@
member changed from 'int x' to 'long x'
type changed from 'int' to 'long'
-function symbol 'void register_ops7(struct containing*)' {_Z13register_ops7P10containing} changed
- type 'void(struct containing*)' changed
+function symbol 'int register_ops7(struct containing*)' {_Z13register_ops7P10containing} changed
+ type 'int(struct containing*)' changed
parameter 1 type 'struct containing*' changed
pointed-to type 'struct containing' changed
(already reported)
-function symbol 'void register_ops8(struct referring)' {_Z13register_ops89referring} changed
- type 'void(struct referring)' changed
+function symbol 'int register_ops8(struct referring)' {_Z13register_ops89referring} changed
+ type 'int(struct referring)' changed
parameter 1 type 'struct referring' changed
member 'struct nested* inner' changed
type 'struct nested*' changed
pointed-to type 'struct nested' changed
(already reported)
-function symbol 'void register_ops9(struct referring*)' {_Z13register_ops9P9referring} changed
- type 'void(struct referring*)' changed
+function symbol 'int register_ops9(struct referring*)' {_Z13register_ops9P9referring} changed
+ type 'int(struct referring*)' changed
parameter 1 type 'struct referring*' changed
pointed-to type 'struct referring' changed
(already reported)
diff --git a/test_cases/diff_tests/struct/expected/nested_cc.o_o_viz b/test_cases/diff_tests/struct/expected/nested_cc.o_o_viz
index 1b76e07..9e5aaad 100644
--- a/test_cases/diff_tests/struct/expected/nested_cc.o_o_viz
+++ b/test_cases/diff_tests/struct/expected/nested_cc.o_o_viz
@@ -1,7 +1,7 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [label="'void register_ops6(struct containing)' {_Z13register_ops610containing}"]
- "2" [label="'void(struct containing)'"]
+ "1" [label="'int register_ops6(struct containing)' {_Z13register_ops610containing}"]
+ "2" [label="'int(struct containing)'"]
"3" [color=red, shape=rectangle, label="'struct containing'"]
"3" -> "3:0"
"3:0" [color=red, label="byte size changed from 4 to 8"]
@@ -18,15 +18,15 @@
"2" -> "3" [label="parameter 1"]
"1" -> "2" [label=""]
"0" -> "1" [label=""]
- "8" [label="'void register_ops7(struct containing*)' {_Z13register_ops7P10containing}"]
- "9" [label="'void(struct containing*)'"]
+ "8" [label="'int register_ops7(struct containing*)' {_Z13register_ops7P10containing}"]
+ "9" [label="'int(struct containing*)'"]
"10" [label="'struct containing*'"]
"10" -> "3" [label="pointed-to"]
"9" -> "10" [label="parameter 1"]
"8" -> "9" [label=""]
"0" -> "8" [label=""]
- "11" [label="'void register_ops8(struct referring)' {_Z13register_ops89referring}"]
- "12" [label="'void(struct referring)'"]
+ "11" [label="'int register_ops8(struct referring)' {_Z13register_ops89referring}"]
+ "12" [label="'int(struct referring)'"]
"13" [shape=rectangle, label="'struct referring'"]
"14" [label="'struct nested* inner'"]
"15" [label="'struct nested*'"]
@@ -36,8 +36,8 @@
"12" -> "13" [label="parameter 1"]
"11" -> "12" [label=""]
"0" -> "11" [label=""]
- "16" [label="'void register_ops9(struct referring*)' {_Z13register_ops9P9referring}"]
- "17" [label="'void(struct referring*)'"]
+ "16" [label="'int register_ops9(struct referring*)' {_Z13register_ops9P9referring}"]
+ "17" [label="'int(struct referring*)'"]
"18" [label="'struct referring*'"]
"18" -> "13" [label="pointed-to"]
"17" -> "18" [label="parameter 1"]
diff --git a/test_cases/diff_tests/struct/nested.0.c b/test_cases/diff_tests/struct/nested.0.c
index bb693e9..80fb601 100644
--- a/test_cases/diff_tests/struct/nested.0.c
+++ b/test_cases/diff_tests/struct/nested.0.c
@@ -10,8 +10,7 @@
struct nested * inner;
};
-void tweak(int);
-void register_ops6(struct containing y) { (void) y; tweak(6); }
-void register_ops7(struct containing* y) { (void) y; tweak(7); }
-void register_ops8(struct referring y) { (void) y; tweak(8); }
-void register_ops9(struct referring* y) { (void) y; tweak(9); }
+int register_ops6(struct containing y) { (void) y; return 6; }
+int register_ops7(struct containing* y) { (void) y; return 7; }
+int register_ops8(struct referring y) { (void) y; return 8; }
+int register_ops9(struct referring* y) { (void) y; return 9; }
diff --git a/test_cases/diff_tests/struct/nested.0.cc b/test_cases/diff_tests/struct/nested.0.cc
index 3dfbea8..ce51ef8 100644
--- a/test_cases/diff_tests/struct/nested.0.cc
+++ b/test_cases/diff_tests/struct/nested.0.cc
@@ -10,8 +10,7 @@
struct nested * inner;
};
-void tweak(int);
-void register_ops6(containing) { tweak(6); }
-void register_ops7(containing*) { tweak(7); }
-void register_ops8(referring) { tweak(8); }
-void register_ops9(referring*) { tweak(9); }
+int register_ops6(containing) { return 6; }
+int register_ops7(containing*) { return 7; }
+int register_ops8(referring) { return 8; }
+int register_ops9(referring*) { return 9; }
diff --git a/test_cases/diff_tests/struct/nested.1.c b/test_cases/diff_tests/struct/nested.1.c
index 003207c..bd30e5f 100644
--- a/test_cases/diff_tests/struct/nested.1.c
+++ b/test_cases/diff_tests/struct/nested.1.c
@@ -10,8 +10,7 @@
struct nested * inner;
};
-void tweak(int);
-void register_ops6(struct containing y) { (void) y; tweak(6); }
-void register_ops7(struct containing* y) { (void) y; tweak(7); }
-void register_ops8(struct referring y) { (void) y; tweak(8); }
-void register_ops9(struct referring* y) { (void) y; tweak(9); }
+int register_ops6(struct containing y) { (void) y; return 6; }
+int register_ops7(struct containing* y) { (void) y; return 7; }
+int register_ops8(struct referring y) { (void) y; return 8; }
+int register_ops9(struct referring* y) { (void) y; return 9; }
diff --git a/test_cases/diff_tests/struct/nested.1.cc b/test_cases/diff_tests/struct/nested.1.cc
index 7c986de..8c6ff89 100644
--- a/test_cases/diff_tests/struct/nested.1.cc
+++ b/test_cases/diff_tests/struct/nested.1.cc
@@ -10,8 +10,7 @@
struct nested * inner;
};
-void tweak(int);
-void register_ops6(containing) { tweak(6); }
-void register_ops7(containing*) { tweak(7); }
-void register_ops8(referring) { tweak(8); }
-void register_ops9(referring*) { tweak(9); }
+int register_ops6(containing) { return 6; }
+int register_ops7(containing*) { return 7; }
+int register_ops8(referring) { return 8; }
+int register_ops9(referring*) { return 9; }
diff --git a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_flat b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_flat
index b310d1b..e8339bd 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_flat
+++ b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_flat
@@ -1,8 +1,8 @@
-function symbol 'void c()' was removed
+function symbol 'int c()' was removed
-function symbol 'void d()' was removed
+function symbol 'int d()' was removed
-function symbol 'void b()' changed
+function symbol 'int b()' changed
visibility changed from default to protected
exit code 4
diff --git a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_plain b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_plain
index b310d1b..e8339bd 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_plain
+++ b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_plain
@@ -1,8 +1,8 @@
-function symbol 'void c()' was removed
+function symbol 'int c()' was removed
-function symbol 'void d()' was removed
+function symbol 'int d()' was removed
-function symbol 'void b()' changed
+function symbol 'int b()' changed
visibility changed from default to protected
exit code 4
diff --git a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_small b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_small
index b310d1b..e8339bd 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_small
+++ b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_small
@@ -1,8 +1,8 @@
-function symbol 'void c()' was removed
+function symbol 'int c()' was removed
-function symbol 'void d()' was removed
+function symbol 'int d()' was removed
-function symbol 'void b()' changed
+function symbol 'int b()' changed
visibility changed from default to protected
exit code 4
diff --git a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_viz b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_viz
index cbfa0ad..90bc9ac 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_c.o_o_viz
+++ b/test_cases/diff_tests/symbol/expected/visibility_c.o_o_viz
@@ -1,10 +1,10 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [color=red, label="removed(void c())"]
+ "1" [color=red, label="removed(int c())"]
"0" -> "1" [label=""]
- "2" [color=red, label="removed(void d())"]
+ "2" [color=red, label="removed(int d())"]
"0" -> "2" [label=""]
- "3" [color=red, label="'void b()'"]
+ "3" [color=red, label="'int b()'"]
"3" -> "3:0"
"3:0" [color=red, label="visibility changed from default to protected"]
"0" -> "3" [label=""]
diff --git a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_flat b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_flat
index 329e2bd..7913819 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_flat
+++ b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_flat
@@ -1,8 +1,8 @@
-function symbol 'void c()' {_Z1cv} was removed
+function symbol 'int c()' {_Z1cv} was removed
-function symbol 'void d()' {_Z1dv} was removed
+function symbol 'int d()' {_Z1dv} was removed
-function symbol 'void b()' {_Z1bv} changed
+function symbol 'int b()' {_Z1bv} changed
visibility changed from default to protected
exit code 4
diff --git a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_plain b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_plain
index 329e2bd..7913819 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_plain
+++ b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_plain
@@ -1,8 +1,8 @@
-function symbol 'void c()' {_Z1cv} was removed
+function symbol 'int c()' {_Z1cv} was removed
-function symbol 'void d()' {_Z1dv} was removed
+function symbol 'int d()' {_Z1dv} was removed
-function symbol 'void b()' {_Z1bv} changed
+function symbol 'int b()' {_Z1bv} changed
visibility changed from default to protected
exit code 4
diff --git a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_small b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_small
index 329e2bd..7913819 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_small
+++ b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_small
@@ -1,8 +1,8 @@
-function symbol 'void c()' {_Z1cv} was removed
+function symbol 'int c()' {_Z1cv} was removed
-function symbol 'void d()' {_Z1dv} was removed
+function symbol 'int d()' {_Z1dv} was removed
-function symbol 'void b()' {_Z1bv} changed
+function symbol 'int b()' {_Z1bv} changed
visibility changed from default to protected
exit code 4
diff --git a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_viz b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_viz
index f391ae4..6bc35e3 100644
--- a/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_viz
+++ b/test_cases/diff_tests/symbol/expected/visibility_cc.o_o_viz
@@ -1,10 +1,10 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [color=red, label="removed(void c() {_Z1cv})"]
+ "1" [color=red, label="removed(int c() {_Z1cv})"]
"0" -> "1" [label=""]
- "2" [color=red, label="removed(void d() {_Z1dv})"]
+ "2" [color=red, label="removed(int d() {_Z1dv})"]
"0" -> "2" [label=""]
- "3" [color=red, label="'void b()' {_Z1bv}"]
+ "3" [color=red, label="'int b()' {_Z1bv}"]
"3" -> "3:0"
"3:0" [color=red, label="visibility changed from default to protected"]
"0" -> "3" [label=""]
diff --git a/test_cases/diff_tests/symbol/version_definition.0.c b/test_cases/diff_tests/symbol/version_definition.0.c
index 6c902b8..2a61728 100644
--- a/test_cases/diff_tests/symbol/version_definition.0.c
+++ b/test_cases/diff_tests/symbol/version_definition.0.c
@@ -4,16 +4,14 @@
// produce wrong results.
// TODO: remove statement above after support is implemented
-void tweak(int dummy);
-
__asm__(".symver versioned_foo_v1, versioned_foo@VERS_1");
-void versioned_foo_v1(void) { tweak(1); }
+int versioned_foo_v1(void) { return 1; }
__asm__(".symver versioned_foo_v2, versioned_foo@VERS_2");
-void versioned_foo_v2(void) { tweak(2); }
+int versioned_foo_v2(void) { return 2; }
__asm__(".symver versioned_foo_v3, versioned_foo@@VERS_3");
-void versioned_foo_v3(void) { tweak(3); }
+int versioned_foo_v3(void) { return 3; }
// Using a libc function helps to add the "version needs" section
// in addition to the "version definitions". This helps to catch
diff --git a/test_cases/diff_tests/symbol/version_definition.1.c b/test_cases/diff_tests/symbol/version_definition.1.c
index 0127d57..289ae19 100644
--- a/test_cases/diff_tests/symbol/version_definition.1.c
+++ b/test_cases/diff_tests/symbol/version_definition.1.c
@@ -4,16 +4,14 @@
// produce wrong results.
// TODO: remove statement above after support is implemented
-void tweak(int dummy);
-
__asm__(".symver versioned_foo_v1, versioned_foo@@VERS_1");
-void versioned_foo_v1(void) { tweak(1); }
+int versioned_foo_v1(void) { return 1; }
__asm__(".symver versioned_foo_v2, versioned_foo@VERS_2");
-void versioned_foo_v2(void) { tweak(2); }
+int versioned_foo_v2(void) { return 2; }
__asm__(".symver versioned_foo_v3, versioned_foo@VERS_3");
-void versioned_foo_v3(void) { tweak(3); }
+int versioned_foo_v3(void) { return 3; }
// Using a libc function helps to add the "version needs" section
// in addition to the "version definitions". This helps to catch
diff --git a/test_cases/diff_tests/symbol/visibility.0.c b/test_cases/diff_tests/symbol/visibility.0.c
index 596b55a..76b3ac6 100644
--- a/test_cases/diff_tests/symbol/visibility.0.c
+++ b/test_cases/diff_tests/symbol/visibility.0.c
@@ -1,5 +1,4 @@
-void tweak(int);
-void a() { tweak(0); }
-void b() { tweak(1); }
-void c() { tweak(2); }
-void d() { tweak(3); }
+int a() { return 0; }
+int b() { return 1; }
+int c() { return 2; }
+int d() { return 3; }
diff --git a/test_cases/diff_tests/symbol/visibility.0.cc b/test_cases/diff_tests/symbol/visibility.0.cc
index 596b55a..76b3ac6 100644
--- a/test_cases/diff_tests/symbol/visibility.0.cc
+++ b/test_cases/diff_tests/symbol/visibility.0.cc
@@ -1,5 +1,4 @@
-void tweak(int);
-void a() { tweak(0); }
-void b() { tweak(1); }
-void c() { tweak(2); }
-void d() { tweak(3); }
+int a() { return 0; }
+int b() { return 1; }
+int c() { return 2; }
+int d() { return 3; }
diff --git a/test_cases/diff_tests/symbol/visibility.1.c b/test_cases/diff_tests/symbol/visibility.1.c
index 45fcbb5..13dfa0c 100644
--- a/test_cases/diff_tests/symbol/visibility.1.c
+++ b/test_cases/diff_tests/symbol/visibility.1.c
@@ -1,5 +1,4 @@
-void tweak(int);
-__attribute__ ((visibility ("default"))) void a() { tweak(0); }
-__attribute__ ((visibility ("protected"))) void b() { tweak(1); }
-__attribute__ ((visibility ("hidden"))) void c() { tweak(2); }
-__attribute__ ((visibility ("internal"))) void d() { tweak(3); }
+__attribute__ ((visibility ("default"))) int a() { return 0; }
+__attribute__ ((visibility ("protected"))) int b() { return 1; }
+__attribute__ ((visibility ("hidden"))) int c() { return 2; }
+__attribute__ ((visibility ("internal"))) int d() { return 3; }
diff --git a/test_cases/diff_tests/symbol/visibility.1.cc b/test_cases/diff_tests/symbol/visibility.1.cc
index 45fcbb5..13dfa0c 100644
--- a/test_cases/diff_tests/symbol/visibility.1.cc
+++ b/test_cases/diff_tests/symbol/visibility.1.cc
@@ -1,5 +1,4 @@
-void tweak(int);
-__attribute__ ((visibility ("default"))) void a() { tweak(0); }
-__attribute__ ((visibility ("protected"))) void b() { tweak(1); }
-__attribute__ ((visibility ("hidden"))) void c() { tweak(2); }
-__attribute__ ((visibility ("internal"))) void d() { tweak(3); }
+__attribute__ ((visibility ("default"))) int a() { return 0; }
+__attribute__ ((visibility ("protected"))) int b() { return 1; }
+__attribute__ ((visibility ("hidden"))) int c() { return 2; }
+__attribute__ ((visibility ("internal"))) int d() { return 3; }
diff --git a/test_cases/diff_tests/types/char.0.c b/test_cases/diff_tests/types/char.0.c
index d24d0ab..8efd700 100644
--- a/test_cases/diff_tests/types/char.0.c
+++ b/test_cases/diff_tests/types/char.0.c
@@ -1,8 +1,7 @@
// tweaked due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112372
-void tweak(int);
-void u(char c) { (void)c; tweak(0); }
-void v(unsigned char c) { (void)c; tweak(1); }
-void w(signed char c) { (void)c; tweak(2); }
-void x(char c) { (void)c; tweak(3); }
-void y(unsigned char c) { (void)c; tweak(4); }
-void z(signed char c) { (void)c; tweak(5); }
+int u(char c) { (void)c; return 0; }
+int v(unsigned char c) { (void)c; return 1; }
+int w(signed char c) { (void)c; return 2; }
+int x(char c) { (void)c; return 3; }
+int y(unsigned char c) { (void)c; return 4; }
+int z(signed char c) { (void)c; return 5; }
diff --git a/test_cases/diff_tests/types/char.1.c b/test_cases/diff_tests/types/char.1.c
index 8ab40a0..7f33ffa 100644
--- a/test_cases/diff_tests/types/char.1.c
+++ b/test_cases/diff_tests/types/char.1.c
@@ -1,8 +1,7 @@
// tweaked due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112372
-void tweak(int);
-void u(unsigned char c) { (void)c; tweak(0); }
-void v(signed char c) { (void)c; tweak(1); }
-void w(char c) { (void)c; tweak(2); }
-void x(signed char c) { (void)c; tweak(3); }
-void y(char c) { (void)c; tweak(4); }
-void z(unsigned char c) { (void)c; tweak(5); }
+int u(unsigned char c) { (void)c; return 0; }
+int v(signed char c) { (void)c; return 1; }
+int w(char c) { (void)c; return 2; }
+int x(signed char c) { (void)c; return 3; }
+int y(char c) { (void)c; return 4; }
+int z(unsigned char c) { (void)c; return 5; }
diff --git a/test_cases/diff_tests/types/expected/char_c.btf_btf_flat b/test_cases/diff_tests/types/expected/char_c.btf_btf_flat
index 719cc42..02eef34 100644
--- a/test_cases/diff_tests/types/expected/char_c.btf_btf_flat
+++ b/test_cases/diff_tests/types/expected/char_c.btf_btf_flat
@@ -1,25 +1,25 @@
-function symbol changed from 'void u(char)' to 'void u(unsigned char)'
- type changed from 'void(char)' to 'void(unsigned char)'
+function symbol changed from 'int u(char)' to 'int u(unsigned char)'
+ type changed from 'int(char)' to 'int(unsigned char)'
parameter 1 type changed from 'char' to 'unsigned char'
-function symbol changed from 'void v(unsigned char)' to 'void v(signed char)'
- type changed from 'void(unsigned char)' to 'void(signed char)'
+function symbol changed from 'int v(unsigned char)' to 'int v(signed char)'
+ type changed from 'int(unsigned char)' to 'int(signed char)'
parameter 1 type changed from 'unsigned char' to 'signed char'
-function symbol changed from 'void w(signed char)' to 'void w(char)'
- type changed from 'void(signed char)' to 'void(char)'
+function symbol changed from 'int w(signed char)' to 'int w(char)'
+ type changed from 'int(signed char)' to 'int(char)'
parameter 1 type changed from 'signed char' to 'char'
-function symbol changed from 'void x(char)' to 'void x(signed char)'
- type changed from 'void(char)' to 'void(signed char)'
+function symbol changed from 'int x(char)' to 'int x(signed char)'
+ type changed from 'int(char)' to 'int(signed char)'
parameter 1 type changed from 'char' to 'signed char'
-function symbol changed from 'void y(unsigned char)' to 'void y(char)'
- type changed from 'void(unsigned char)' to 'void(char)'
+function symbol changed from 'int y(unsigned char)' to 'int y(char)'
+ type changed from 'int(unsigned char)' to 'int(char)'
parameter 1 type changed from 'unsigned char' to 'char'
-function symbol changed from 'void z(signed char)' to 'void z(unsigned char)'
- type changed from 'void(signed char)' to 'void(unsigned char)'
+function symbol changed from 'int z(signed char)' to 'int z(unsigned char)'
+ type changed from 'int(signed char)' to 'int(unsigned char)'
parameter 1 type changed from 'signed char' to 'unsigned char'
exit code 4
diff --git a/test_cases/diff_tests/types/expected/char_c.btf_btf_plain b/test_cases/diff_tests/types/expected/char_c.btf_btf_plain
index 719cc42..02eef34 100644
--- a/test_cases/diff_tests/types/expected/char_c.btf_btf_plain
+++ b/test_cases/diff_tests/types/expected/char_c.btf_btf_plain
@@ -1,25 +1,25 @@
-function symbol changed from 'void u(char)' to 'void u(unsigned char)'
- type changed from 'void(char)' to 'void(unsigned char)'
+function symbol changed from 'int u(char)' to 'int u(unsigned char)'
+ type changed from 'int(char)' to 'int(unsigned char)'
parameter 1 type changed from 'char' to 'unsigned char'
-function symbol changed from 'void v(unsigned char)' to 'void v(signed char)'
- type changed from 'void(unsigned char)' to 'void(signed char)'
+function symbol changed from 'int v(unsigned char)' to 'int v(signed char)'
+ type changed from 'int(unsigned char)' to 'int(signed char)'
parameter 1 type changed from 'unsigned char' to 'signed char'
-function symbol changed from 'void w(signed char)' to 'void w(char)'
- type changed from 'void(signed char)' to 'void(char)'
+function symbol changed from 'int w(signed char)' to 'int w(char)'
+ type changed from 'int(signed char)' to 'int(char)'
parameter 1 type changed from 'signed char' to 'char'
-function symbol changed from 'void x(char)' to 'void x(signed char)'
- type changed from 'void(char)' to 'void(signed char)'
+function symbol changed from 'int x(char)' to 'int x(signed char)'
+ type changed from 'int(char)' to 'int(signed char)'
parameter 1 type changed from 'char' to 'signed char'
-function symbol changed from 'void y(unsigned char)' to 'void y(char)'
- type changed from 'void(unsigned char)' to 'void(char)'
+function symbol changed from 'int y(unsigned char)' to 'int y(char)'
+ type changed from 'int(unsigned char)' to 'int(char)'
parameter 1 type changed from 'unsigned char' to 'char'
-function symbol changed from 'void z(signed char)' to 'void z(unsigned char)'
- type changed from 'void(signed char)' to 'void(unsigned char)'
+function symbol changed from 'int z(signed char)' to 'int z(unsigned char)'
+ type changed from 'int(signed char)' to 'int(unsigned char)'
parameter 1 type changed from 'signed char' to 'unsigned char'
exit code 4
diff --git a/test_cases/diff_tests/types/expected/char_c.btf_btf_small b/test_cases/diff_tests/types/expected/char_c.btf_btf_small
index 719cc42..02eef34 100644
--- a/test_cases/diff_tests/types/expected/char_c.btf_btf_small
+++ b/test_cases/diff_tests/types/expected/char_c.btf_btf_small
@@ -1,25 +1,25 @@
-function symbol changed from 'void u(char)' to 'void u(unsigned char)'
- type changed from 'void(char)' to 'void(unsigned char)'
+function symbol changed from 'int u(char)' to 'int u(unsigned char)'
+ type changed from 'int(char)' to 'int(unsigned char)'
parameter 1 type changed from 'char' to 'unsigned char'
-function symbol changed from 'void v(unsigned char)' to 'void v(signed char)'
- type changed from 'void(unsigned char)' to 'void(signed char)'
+function symbol changed from 'int v(unsigned char)' to 'int v(signed char)'
+ type changed from 'int(unsigned char)' to 'int(signed char)'
parameter 1 type changed from 'unsigned char' to 'signed char'
-function symbol changed from 'void w(signed char)' to 'void w(char)'
- type changed from 'void(signed char)' to 'void(char)'
+function symbol changed from 'int w(signed char)' to 'int w(char)'
+ type changed from 'int(signed char)' to 'int(char)'
parameter 1 type changed from 'signed char' to 'char'
-function symbol changed from 'void x(char)' to 'void x(signed char)'
- type changed from 'void(char)' to 'void(signed char)'
+function symbol changed from 'int x(char)' to 'int x(signed char)'
+ type changed from 'int(char)' to 'int(signed char)'
parameter 1 type changed from 'char' to 'signed char'
-function symbol changed from 'void y(unsigned char)' to 'void y(char)'
- type changed from 'void(unsigned char)' to 'void(char)'
+function symbol changed from 'int y(unsigned char)' to 'int y(char)'
+ type changed from 'int(unsigned char)' to 'int(char)'
parameter 1 type changed from 'unsigned char' to 'char'
-function symbol changed from 'void z(signed char)' to 'void z(unsigned char)'
- type changed from 'void(signed char)' to 'void(unsigned char)'
+function symbol changed from 'int z(signed char)' to 'int z(unsigned char)'
+ type changed from 'int(signed char)' to 'int(unsigned char)'
parameter 1 type changed from 'signed char' to 'unsigned char'
exit code 4
diff --git a/test_cases/diff_tests/types/expected/char_c.btf_btf_viz b/test_cases/diff_tests/types/expected/char_c.btf_btf_viz
index c92c7f3..c68b05c 100644
--- a/test_cases/diff_tests/types/expected/char_c.btf_btf_viz
+++ b/test_cases/diff_tests/types/expected/char_c.btf_btf_viz
@@ -1,37 +1,37 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [label="'void u(char)' -> 'void u(unsigned char)'"]
- "2" [label="'void(char)' -> 'void(unsigned char)'"]
+ "1" [label="'int u(char)' -> 'int u(unsigned char)'"]
+ "2" [label="'int(char)' -> 'int(unsigned char)'"]
"3" [color=red, label="'char' -> 'unsigned char'"]
"2" -> "3" [label="parameter 1"]
"1" -> "2" [label=""]
"0" -> "1" [label=""]
- "4" [label="'void v(unsigned char)' -> 'void v(signed char)'"]
- "5" [label="'void(unsigned char)' -> 'void(signed char)'"]
+ "4" [label="'int v(unsigned char)' -> 'int v(signed char)'"]
+ "5" [label="'int(unsigned char)' -> 'int(signed char)'"]
"6" [color=red, label="'unsigned char' -> 'signed char'"]
"5" -> "6" [label="parameter 1"]
"4" -> "5" [label=""]
"0" -> "4" [label=""]
- "7" [label="'void w(signed char)' -> 'void w(char)'"]
- "8" [label="'void(signed char)' -> 'void(char)'"]
+ "7" [label="'int w(signed char)' -> 'int w(char)'"]
+ "8" [label="'int(signed char)' -> 'int(char)'"]
"9" [color=red, label="'signed char' -> 'char'"]
"8" -> "9" [label="parameter 1"]
"7" -> "8" [label=""]
"0" -> "7" [label=""]
- "10" [label="'void x(char)' -> 'void x(signed char)'"]
- "11" [label="'void(char)' -> 'void(signed char)'"]
+ "10" [label="'int x(char)' -> 'int x(signed char)'"]
+ "11" [label="'int(char)' -> 'int(signed char)'"]
"12" [color=red, label="'char' -> 'signed char'"]
"11" -> "12" [label="parameter 1"]
"10" -> "11" [label=""]
"0" -> "10" [label=""]
- "13" [label="'void y(unsigned char)' -> 'void y(char)'"]
- "14" [label="'void(unsigned char)' -> 'void(char)'"]
+ "13" [label="'int y(unsigned char)' -> 'int y(char)'"]
+ "14" [label="'int(unsigned char)' -> 'int(char)'"]
"15" [color=red, label="'unsigned char' -> 'char'"]
"14" -> "15" [label="parameter 1"]
"13" -> "14" [label=""]
"0" -> "13" [label=""]
- "16" [label="'void z(signed char)' -> 'void z(unsigned char)'"]
- "17" [label="'void(signed char)' -> 'void(unsigned char)'"]
+ "16" [label="'int z(signed char)' -> 'int z(unsigned char)'"]
+ "17" [label="'int(signed char)' -> 'int(unsigned char)'"]
"18" [color=red, label="'signed char' -> 'unsigned char'"]
"17" -> "18" [label="parameter 1"]
"16" -> "17" [label=""]
diff --git a/test_cases/diff_tests/types/expected/char_c.o_o_flat b/test_cases/diff_tests/types/expected/char_c.o_o_flat
index 719cc42..02eef34 100644
--- a/test_cases/diff_tests/types/expected/char_c.o_o_flat
+++ b/test_cases/diff_tests/types/expected/char_c.o_o_flat
@@ -1,25 +1,25 @@
-function symbol changed from 'void u(char)' to 'void u(unsigned char)'
- type changed from 'void(char)' to 'void(unsigned char)'
+function symbol changed from 'int u(char)' to 'int u(unsigned char)'
+ type changed from 'int(char)' to 'int(unsigned char)'
parameter 1 type changed from 'char' to 'unsigned char'
-function symbol changed from 'void v(unsigned char)' to 'void v(signed char)'
- type changed from 'void(unsigned char)' to 'void(signed char)'
+function symbol changed from 'int v(unsigned char)' to 'int v(signed char)'
+ type changed from 'int(unsigned char)' to 'int(signed char)'
parameter 1 type changed from 'unsigned char' to 'signed char'
-function symbol changed from 'void w(signed char)' to 'void w(char)'
- type changed from 'void(signed char)' to 'void(char)'
+function symbol changed from 'int w(signed char)' to 'int w(char)'
+ type changed from 'int(signed char)' to 'int(char)'
parameter 1 type changed from 'signed char' to 'char'
-function symbol changed from 'void x(char)' to 'void x(signed char)'
- type changed from 'void(char)' to 'void(signed char)'
+function symbol changed from 'int x(char)' to 'int x(signed char)'
+ type changed from 'int(char)' to 'int(signed char)'
parameter 1 type changed from 'char' to 'signed char'
-function symbol changed from 'void y(unsigned char)' to 'void y(char)'
- type changed from 'void(unsigned char)' to 'void(char)'
+function symbol changed from 'int y(unsigned char)' to 'int y(char)'
+ type changed from 'int(unsigned char)' to 'int(char)'
parameter 1 type changed from 'unsigned char' to 'char'
-function symbol changed from 'void z(signed char)' to 'void z(unsigned char)'
- type changed from 'void(signed char)' to 'void(unsigned char)'
+function symbol changed from 'int z(signed char)' to 'int z(unsigned char)'
+ type changed from 'int(signed char)' to 'int(unsigned char)'
parameter 1 type changed from 'signed char' to 'unsigned char'
exit code 4
diff --git a/test_cases/diff_tests/types/expected/char_c.o_o_plain b/test_cases/diff_tests/types/expected/char_c.o_o_plain
index 719cc42..02eef34 100644
--- a/test_cases/diff_tests/types/expected/char_c.o_o_plain
+++ b/test_cases/diff_tests/types/expected/char_c.o_o_plain
@@ -1,25 +1,25 @@
-function symbol changed from 'void u(char)' to 'void u(unsigned char)'
- type changed from 'void(char)' to 'void(unsigned char)'
+function symbol changed from 'int u(char)' to 'int u(unsigned char)'
+ type changed from 'int(char)' to 'int(unsigned char)'
parameter 1 type changed from 'char' to 'unsigned char'
-function symbol changed from 'void v(unsigned char)' to 'void v(signed char)'
- type changed from 'void(unsigned char)' to 'void(signed char)'
+function symbol changed from 'int v(unsigned char)' to 'int v(signed char)'
+ type changed from 'int(unsigned char)' to 'int(signed char)'
parameter 1 type changed from 'unsigned char' to 'signed char'
-function symbol changed from 'void w(signed char)' to 'void w(char)'
- type changed from 'void(signed char)' to 'void(char)'
+function symbol changed from 'int w(signed char)' to 'int w(char)'
+ type changed from 'int(signed char)' to 'int(char)'
parameter 1 type changed from 'signed char' to 'char'
-function symbol changed from 'void x(char)' to 'void x(signed char)'
- type changed from 'void(char)' to 'void(signed char)'
+function symbol changed from 'int x(char)' to 'int x(signed char)'
+ type changed from 'int(char)' to 'int(signed char)'
parameter 1 type changed from 'char' to 'signed char'
-function symbol changed from 'void y(unsigned char)' to 'void y(char)'
- type changed from 'void(unsigned char)' to 'void(char)'
+function symbol changed from 'int y(unsigned char)' to 'int y(char)'
+ type changed from 'int(unsigned char)' to 'int(char)'
parameter 1 type changed from 'unsigned char' to 'char'
-function symbol changed from 'void z(signed char)' to 'void z(unsigned char)'
- type changed from 'void(signed char)' to 'void(unsigned char)'
+function symbol changed from 'int z(signed char)' to 'int z(unsigned char)'
+ type changed from 'int(signed char)' to 'int(unsigned char)'
parameter 1 type changed from 'signed char' to 'unsigned char'
exit code 4
diff --git a/test_cases/diff_tests/types/expected/char_c.o_o_small b/test_cases/diff_tests/types/expected/char_c.o_o_small
index 719cc42..02eef34 100644
--- a/test_cases/diff_tests/types/expected/char_c.o_o_small
+++ b/test_cases/diff_tests/types/expected/char_c.o_o_small
@@ -1,25 +1,25 @@
-function symbol changed from 'void u(char)' to 'void u(unsigned char)'
- type changed from 'void(char)' to 'void(unsigned char)'
+function symbol changed from 'int u(char)' to 'int u(unsigned char)'
+ type changed from 'int(char)' to 'int(unsigned char)'
parameter 1 type changed from 'char' to 'unsigned char'
-function symbol changed from 'void v(unsigned char)' to 'void v(signed char)'
- type changed from 'void(unsigned char)' to 'void(signed char)'
+function symbol changed from 'int v(unsigned char)' to 'int v(signed char)'
+ type changed from 'int(unsigned char)' to 'int(signed char)'
parameter 1 type changed from 'unsigned char' to 'signed char'
-function symbol changed from 'void w(signed char)' to 'void w(char)'
- type changed from 'void(signed char)' to 'void(char)'
+function symbol changed from 'int w(signed char)' to 'int w(char)'
+ type changed from 'int(signed char)' to 'int(char)'
parameter 1 type changed from 'signed char' to 'char'
-function symbol changed from 'void x(char)' to 'void x(signed char)'
- type changed from 'void(char)' to 'void(signed char)'
+function symbol changed from 'int x(char)' to 'int x(signed char)'
+ type changed from 'int(char)' to 'int(signed char)'
parameter 1 type changed from 'char' to 'signed char'
-function symbol changed from 'void y(unsigned char)' to 'void y(char)'
- type changed from 'void(unsigned char)' to 'void(char)'
+function symbol changed from 'int y(unsigned char)' to 'int y(char)'
+ type changed from 'int(unsigned char)' to 'int(char)'
parameter 1 type changed from 'unsigned char' to 'char'
-function symbol changed from 'void z(signed char)' to 'void z(unsigned char)'
- type changed from 'void(signed char)' to 'void(unsigned char)'
+function symbol changed from 'int z(signed char)' to 'int z(unsigned char)'
+ type changed from 'int(signed char)' to 'int(unsigned char)'
parameter 1 type changed from 'signed char' to 'unsigned char'
exit code 4
diff --git a/test_cases/diff_tests/types/expected/char_c.o_o_viz b/test_cases/diff_tests/types/expected/char_c.o_o_viz
index c92c7f3..c68b05c 100644
--- a/test_cases/diff_tests/types/expected/char_c.o_o_viz
+++ b/test_cases/diff_tests/types/expected/char_c.o_o_viz
@@ -1,37 +1,37 @@
digraph "ABI diff" {
"0" [shape=rectangle, label="'interface'"]
- "1" [label="'void u(char)' -> 'void u(unsigned char)'"]
- "2" [label="'void(char)' -> 'void(unsigned char)'"]
+ "1" [label="'int u(char)' -> 'int u(unsigned char)'"]
+ "2" [label="'int(char)' -> 'int(unsigned char)'"]
"3" [color=red, label="'char' -> 'unsigned char'"]
"2" -> "3" [label="parameter 1"]
"1" -> "2" [label=""]
"0" -> "1" [label=""]
- "4" [label="'void v(unsigned char)' -> 'void v(signed char)'"]
- "5" [label="'void(unsigned char)' -> 'void(signed char)'"]
+ "4" [label="'int v(unsigned char)' -> 'int v(signed char)'"]
+ "5" [label="'int(unsigned char)' -> 'int(signed char)'"]
"6" [color=red, label="'unsigned char' -> 'signed char'"]
"5" -> "6" [label="parameter 1"]
"4" -> "5" [label=""]
"0" -> "4" [label=""]
- "7" [label="'void w(signed char)' -> 'void w(char)'"]
- "8" [label="'void(signed char)' -> 'void(char)'"]
+ "7" [label="'int w(signed char)' -> 'int w(char)'"]
+ "8" [label="'int(signed char)' -> 'int(char)'"]
"9" [color=red, label="'signed char' -> 'char'"]
"8" -> "9" [label="parameter 1"]
"7" -> "8" [label=""]
"0" -> "7" [label=""]
- "10" [label="'void x(char)' -> 'void x(signed char)'"]
- "11" [label="'void(char)' -> 'void(signed char)'"]
+ "10" [label="'int x(char)' -> 'int x(signed char)'"]
+ "11" [label="'int(char)' -> 'int(signed char)'"]
"12" [color=red, label="'char' -> 'signed char'"]
"11" -> "12" [label="parameter 1"]
"10" -> "11" [label=""]
"0" -> "10" [label=""]
- "13" [label="'void y(unsigned char)' -> 'void y(char)'"]
- "14" [label="'void(unsigned char)' -> 'void(char)'"]
+ "13" [label="'int y(unsigned char)' -> 'int y(char)'"]
+ "14" [label="'int(unsigned char)' -> 'int(char)'"]
"15" [color=red, label="'unsigned char' -> 'char'"]
"14" -> "15" [label="parameter 1"]
"13" -> "14" [label=""]
"0" -> "13" [label=""]
- "16" [label="'void z(signed char)' -> 'void z(unsigned char)'"]
- "17" [label="'void(signed char)' -> 'void(unsigned char)'"]
+ "16" [label="'int z(signed char)' -> 'int z(unsigned char)'"]
+ "17" [label="'int(signed char)' -> 'int(unsigned char)'"]
"18" [color=red, label="'signed char' -> 'unsigned char'"]
"17" -> "18" [label="parameter 1"]
"16" -> "17" [label=""]
diff --git a/test_cases/info_tests/array/expected/variable_length_c.btf_stg b/test_cases/info_tests/array/expected/variable_length_c.btf_stg
index a9f6bde..6d73ea7 100644
--- a/test_cases/info_tests/array/expected/variable_length_c.btf_stg
+++ b/test_cases/info_tests/array/expected/variable_length_c.btf_stg
@@ -7,17 +7,18 @@
bytesize: 0x00000004
}
function {
- id: 0x9d80e32f
+ id: 0x8448d7e4
return_type_id: 0x6720d32f # int
+ parameter_id: 0x6720d32f # int
}
elf_symbol {
id: 0xa58ca0b6
name: "bar"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x9d80e32f # int()
+ type_id: 0x8448d7e4 # int(int)
}
interface {
id: 0x84ea5130
- symbol_id: 0xa58ca0b6 # int bar()
+ symbol_id: 0xa58ca0b6 # int bar(int)
}
diff --git a/test_cases/info_tests/array/expected/variable_length_c.elf_stg b/test_cases/info_tests/array/expected/variable_length_c.elf_stg
index 80c4c20..bb33daa 100644
--- a/test_cases/info_tests/array/expected/variable_length_c.elf_stg
+++ b/test_cases/info_tests/array/expected/variable_length_c.elf_stg
@@ -7,18 +7,19 @@
bytesize: 0x00000004
}
function {
- id: 0x9d80e32f
+ id: 0x8448d7e4
return_type_id: 0x6720d32f # int
+ parameter_id: 0x6720d32f # int
}
elf_symbol {
id: 0xa58ca0b6
name: "bar"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x9d80e32f # int()
+ type_id: 0x8448d7e4 # int(int)
full_name: "bar"
}
interface {
id: 0x84ea5130
- symbol_id: 0xa58ca0b6 # int bar()
+ symbol_id: 0xa58ca0b6 # int bar(int)
}
diff --git a/test_cases/info_tests/array/variable_length.c b/test_cases/info_tests/array/variable_length.c
index fa86172..1dc52df 100644
--- a/test_cases/info_tests/array/variable_length.c
+++ b/test_cases/info_tests/array/variable_length.c
@@ -1,7 +1,4 @@
-int foo(void);
-
-int bar(void) {
- int n = foo();
+int bar(int n) {
int a[n];
return a[n - 1];
}
diff --git a/test_cases/info_tests/function/expected/virtual_method_cc.elf_stg b/test_cases/info_tests/function/expected/virtual_method_cc.elf_stg
index cbc7e61..19fe631 100644
--- a/test_cases/info_tests/function/expected/virtual_method_cc.elf_stg
+++ b/test_cases/info_tests/function/expected/virtual_method_cc.elf_stg
@@ -1,9 +1,5 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
pointer_reference {
id: 0x01ec39fc
kind: POINTER
@@ -29,14 +25,14 @@
id: 0x91a60460
mangled_name: "_ZN3Foo3barEv"
name: "bar"
- type_id: 0x1d536fb5 # void(struct Foo*)
+ type_id: 0x904bdd09 # int(struct Foo*)
}
method {
id: 0x3bae9a68
mangled_name: "_ZN3Foo3bazEv"
name: "baz"
vtable_offset: 1
- type_id: 0x1d536fb5 # void(struct Foo*)
+ type_id: 0x904bdd09 # int(struct Foo*)
}
member {
id: 0xc9e943fb
@@ -49,14 +45,14 @@
name: "Foo"
definition {
bytesize: 8
- method_id: 0x91a60460 # void bar(struct Foo*)
- method_id: 0x3bae9a68 # void baz(struct Foo*)
+ method_id: 0x91a60460 # int bar(struct Foo*)
+ method_id: 0x3bae9a68 # int baz(struct Foo*)
member_id: 0xc9e943fb # int(** _vptr$Foo)()
}
}
function {
- id: 0x1d536fb5
- return_type_id: 0x48b5725f # void
+ id: 0x904bdd09
+ return_type_id: 0x6720d32f # int
parameter_id: 0x372cf89a # struct Foo*
}
function {
@@ -68,7 +64,7 @@
name: "_ZN3Foo3barEv"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1d536fb5 # void(struct Foo*)
+ type_id: 0x904bdd09 # int(struct Foo*)
full_name: "Foo::bar"
}
elf_symbol {
@@ -76,7 +72,7 @@
name: "_ZN3Foo3bazEv"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1d536fb5 # void(struct Foo*)
+ type_id: 0x904bdd09 # int(struct Foo*)
full_name: "Foo::baz"
}
elf_symbol {
@@ -107,8 +103,8 @@
}
interface {
id: 0x84ea5130
- symbol_id: 0x043f549e # void Foo::bar(struct Foo*)
- symbol_id: 0x39ee62e8 # void Foo::baz(struct Foo*)
+ symbol_id: 0x043f549e # int Foo::bar(struct Foo*)
+ symbol_id: 0x39ee62e8 # int Foo::baz(struct Foo*)
symbol_id: 0x263987d0 # _ZTI3Foo
symbol_id: 0x264c5a0d # _ZTS3Foo
symbol_id: 0x9e36cb56 # _ZTV3Foo
diff --git a/test_cases/info_tests/function/virtual_method.cc b/test_cases/info_tests/function/virtual_method.cc
index 0bf3e48..577b16d 100644
--- a/test_cases/info_tests/function/virtual_method.cc
+++ b/test_cases/info_tests/function/virtual_method.cc
@@ -1,8 +1,7 @@
struct Foo {
- virtual void bar();
- virtual void baz();
+ virtual int bar();
+ virtual int baz();
} foo;
-void tweak(int);
-void Foo::bar() { tweak(0); }
-void Foo::baz() { tweak(1); }
+int Foo::bar() { return 0; }
+int Foo::baz() { return 1; }
diff --git a/test_cases/info_tests/qualified/expected/useless_c.btf_stg b/test_cases/info_tests/qualified/expected/useless_c.btf_stg
index d42abf1..3eb718b 100644
--- a/test_cases/info_tests/qualified/expected/useless_c.btf_stg
+++ b/test_cases/info_tests/qualified/expected/useless_c.btf_stg
@@ -1,28 +1,24 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
-pointer_reference {
- id: 0x0dd55c4a
- kind: POINTER
- pointee_type_id: 0x1d1597b4 # void(const volatile struct foo*)
-}
pointer_reference {
id: 0x24b3ee1b
kind: POINTER
pointee_type_id: 0xb88f5ef1 # struct foo
}
pointer_reference {
+ id: 0x2e9370e5
+ kind: POINTER
+ pointee_type_id: 0x900d2508 # int(const volatile struct foo*)
+}
+pointer_reference {
id: 0x3637189c
kind: POINTER
pointee_type_id: 0xf29c84ee # const volatile struct foo
}
qualified {
- id: 0x9763259f
+ id: 0x9fb2aeb4
qualifier: VOLATILE
- qualified_type_id: 0x0dd55c4a # void(*)(const volatile struct foo*)
+ qualified_type_id: 0x2e9370e5 # int(*)(const volatile struct foo*)
}
qualified {
id: 0xba35a531
@@ -35,9 +31,15 @@
qualified_type_id: 0xba35a531 # volatile struct foo
}
qualified {
- id: 0xf9c924c5
+ id: 0xfbfd460f
qualifier: CONST
- qualified_type_id: 0x9763259f # void(* volatile)(const volatile struct foo*)
+ qualified_type_id: 0x9fb2aeb4 # int(* volatile)(const volatile struct foo*)
+}
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
}
struct_union {
id: 0xb88f5ef1
@@ -47,44 +49,44 @@
}
}
function {
- id: 0x19b4aa15
- return_type_id: 0x48b5725f # void
- parameter_id: 0x24b3ee1b # struct foo*
-}
-function {
- id: 0x1d1597b4
- return_type_id: 0x48b5725f # void
+ id: 0x900d2508
+ return_type_id: 0x6720d32f # int
parameter_id: 0x3637189c # const volatile struct foo*
}
function {
- id: 0x2eea18a2
- return_type_id: 0x48b5725f # void
- parameter_id: 0xf9c924c5 # void(* volatile const)(const volatile struct foo*)
+ id: 0x94ac18a9
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0x24b3ee1b # struct foo*
+}
+function {
+ id: 0xa37fb2ac
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0xfbfd460f # int(* volatile const)(const volatile struct foo*)
}
elf_symbol {
id: 0xa58ca0b6
name: "bar"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1d1597b4 # void(const volatile struct foo*)
+ type_id: 0x900d2508 # int(const volatile struct foo*)
}
elf_symbol {
id: 0xe89bbaac
name: "bar_2"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x19b4aa15 # void(struct foo*)
+ type_id: 0x94ac18a9 # int(struct foo*)
}
elf_symbol {
id: 0xbf8fc404
name: "baz"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x2eea18a2 # void(void(* volatile const)(const volatile struct foo*))
+ type_id: 0xa37fb2ac # int(int(* volatile const)(const volatile struct foo*))
}
interface {
id: 0x84ea5130
- symbol_id: 0xa58ca0b6 # void bar(const volatile struct foo*)
- symbol_id: 0xe89bbaac # void bar_2(struct foo*)
- symbol_id: 0xbf8fc404 # void baz(void(* volatile const)(const volatile struct foo*))
+ symbol_id: 0xa58ca0b6 # int bar(const volatile struct foo*)
+ symbol_id: 0xe89bbaac # int bar_2(struct foo*)
+ symbol_id: 0xbf8fc404 # int baz(int(* volatile const)(const volatile struct foo*))
}
diff --git a/test_cases/info_tests/qualified/expected/useless_c.elf_stg b/test_cases/info_tests/qualified/expected/useless_c.elf_stg
index 2449a6c..360ac52 100644
--- a/test_cases/info_tests/qualified/expected/useless_c.elf_stg
+++ b/test_cases/info_tests/qualified/expected/useless_c.elf_stg
@@ -1,28 +1,24 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
-pointer_reference {
- id: 0x0dd55c4a
- kind: POINTER
- pointee_type_id: 0x1d1597b4 # void(const volatile struct foo*)
-}
pointer_reference {
id: 0x24b3ee1b
kind: POINTER
pointee_type_id: 0xb88f5ef1 # struct foo
}
pointer_reference {
+ id: 0x2e9370e5
+ kind: POINTER
+ pointee_type_id: 0x900d2508 # int(const volatile struct foo*)
+}
+pointer_reference {
id: 0x3637189c
kind: POINTER
pointee_type_id: 0xf29c84ee # const volatile struct foo
}
qualified {
- id: 0x9763259f
+ id: 0x9fb2aeb4
qualifier: VOLATILE
- qualified_type_id: 0x0dd55c4a # void(*)(const volatile struct foo*)
+ qualified_type_id: 0x2e9370e5 # int(*)(const volatile struct foo*)
}
qualified {
id: 0xba35a531
@@ -35,9 +31,15 @@
qualified_type_id: 0xba35a531 # volatile struct foo
}
qualified {
- id: 0xf9c924c5
+ id: 0xfbfd460f
qualifier: CONST
- qualified_type_id: 0x9763259f # void(* volatile)(const volatile struct foo*)
+ qualified_type_id: 0x9fb2aeb4 # int(* volatile)(const volatile struct foo*)
+}
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
}
struct_union {
id: 0xb88f5ef1
@@ -47,26 +49,26 @@
}
}
function {
- id: 0x13ed0681
- return_type_id: 0x48b5725f # void
- parameter_id: 0x0dd55c4a # void(*)(const volatile struct foo*)
+ id: 0x900d2508
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0x3637189c # const volatile struct foo*
}
function {
- id: 0x19b4aa15
- return_type_id: 0x48b5725f # void
+ id: 0x94ac18a9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x24b3ee1b # struct foo*
}
function {
- id: 0x1d1597b4
- return_type_id: 0x48b5725f # void
- parameter_id: 0x3637189c # const volatile struct foo*
+ id: 0x96243f16
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0x2e9370e5 # int(*)(const volatile struct foo*)
}
elf_symbol {
id: 0xa58ca0b6
name: "bar"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1d1597b4 # void(const volatile struct foo*)
+ type_id: 0x900d2508 # int(const volatile struct foo*)
full_name: "bar"
}
elf_symbol {
@@ -74,7 +76,7 @@
name: "bar_2"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x19b4aa15 # void(struct foo*)
+ type_id: 0x94ac18a9 # int(struct foo*)
full_name: "bar_2"
}
elf_symbol {
@@ -82,7 +84,7 @@
name: "baz"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x13ed0681 # void(void(*)(const volatile struct foo*))
+ type_id: 0x96243f16 # int(int(*)(const volatile struct foo*))
full_name: "baz"
}
elf_symbol {
@@ -90,13 +92,13 @@
name: "quux"
is_defined: true
symbol_type: OBJECT
- type_id: 0xf9c924c5 # void(* volatile const)(const volatile struct foo*)
+ type_id: 0xfbfd460f # int(* volatile const)(const volatile struct foo*)
full_name: "quux"
}
interface {
id: 0x84ea5130
- symbol_id: 0xa58ca0b6 # void bar(const volatile struct foo*)
- symbol_id: 0xe89bbaac # void bar_2(struct foo*)
- symbol_id: 0xbf8fc404 # void baz(void(*)(const volatile struct foo*))
- symbol_id: 0x4602d7e1 # void(* volatile const quux)(const volatile struct foo*)
+ symbol_id: 0xa58ca0b6 # int bar(const volatile struct foo*)
+ symbol_id: 0xe89bbaac # int bar_2(struct foo*)
+ symbol_id: 0xbf8fc404 # int baz(int(*)(const volatile struct foo*))
+ symbol_id: 0x4602d7e1 # int(* volatile const quux)(const volatile struct foo*)
}
diff --git a/test_cases/info_tests/qualified/useless.c b/test_cases/info_tests/qualified/useless.c
index a077d5b..f044239 100644
--- a/test_cases/info_tests/qualified/useless.c
+++ b/test_cases/info_tests/qualified/useless.c
@@ -1,21 +1,19 @@
-void tweak(int);
-
struct foo {
};
-void bar_2(struct foo* y) {
+int bar_2(struct foo* y) {
(void) y;
- tweak(0);
+ return 0;
}
-void bar(const volatile struct foo* y) {
+int bar(const volatile struct foo* y) {
(void) y;
- tweak(1);
+ return 1;
}
-void baz(void(*const volatile y)(const volatile struct foo*)) {
+int baz(int(*const volatile y)(const volatile struct foo*)) {
(void) y;
- tweak(2);
+ return 2;
}
-void(*const volatile quux)(const volatile struct foo*) = &bar;
+int(*const volatile quux)(const volatile struct foo*) = &bar;
diff --git a/test_cases/info_tests/struct/expected/nested_c.btf_stg b/test_cases/info_tests/struct/expected/nested_c.btf_stg
index 5c41c48..fc7fd63 100644
--- a/test_cases/info_tests/struct/expected/nested_c.btf_stg
+++ b/test_cases/info_tests/struct/expected/nested_c.btf_stg
@@ -1,9 +1,5 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
pointer_reference {
id: 0x12c83f93
kind: POINTER
@@ -20,6 +16,12 @@
pointee_type_id: 0xe16078fd # struct referring
}
primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
+}
+primitive {
id: 0xfc0e1dbd
name: "long"
encoding: SIGNED_INTEGER
@@ -68,23 +70,23 @@
}
}
function {
- id: 0x01533705
- return_type_id: 0x48b5725f # void
+ id: 0x8c4b85b9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x472d9a5b # struct containing
}
function {
- id: 0x164e865f
- return_type_id: 0x48b5725f # void
- parameter_id: 0x1b5b5f31 # struct containing*
-}
-function {
- id: 0x1c2a5875
- return_type_id: 0x48b5725f # void
+ id: 0x9132eac9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x32c82798 # struct referring*
}
function {
- id: 0x28c04fac
- return_type_id: 0x48b5725f # void
+ id: 0x9b5634e3
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0x1b5b5f31 # struct containing*
+}
+function {
+ id: 0xa5d8fd10
+ return_type_id: 0x6720d32f # int
parameter_id: 0xe16078fd # struct referring
}
elf_symbol {
@@ -92,33 +94,33 @@
name: "register_ops6"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x01533705 # void(struct containing)
+ type_id: 0x8c4b85b9 # int(struct containing)
}
elf_symbol {
id: 0x68a86d39
name: "register_ops7"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x164e865f # void(struct containing*)
+ type_id: 0x9b5634e3 # int(struct containing*)
}
elf_symbol {
id: 0x1f6abcc7
name: "register_ops8"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x28c04fac # void(struct referring)
+ type_id: 0xa5d8fd10 # int(struct referring)
}
elf_symbol {
id: 0xdc2ac9cf
name: "register_ops9"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1c2a5875 # void(struct referring*)
+ type_id: 0x9132eac9 # int(struct referring*)
}
interface {
id: 0x84ea5130
- symbol_id: 0x97e8ca66 # void register_ops6(struct containing)
- symbol_id: 0x68a86d39 # void register_ops7(struct containing*)
- symbol_id: 0x1f6abcc7 # void register_ops8(struct referring)
- symbol_id: 0xdc2ac9cf # void register_ops9(struct referring*)
+ symbol_id: 0x97e8ca66 # int register_ops6(struct containing)
+ symbol_id: 0x68a86d39 # int register_ops7(struct containing*)
+ symbol_id: 0x1f6abcc7 # int register_ops8(struct referring)
+ symbol_id: 0xdc2ac9cf # int register_ops9(struct referring*)
}
diff --git a/test_cases/info_tests/struct/expected/nested_c.elf_stg b/test_cases/info_tests/struct/expected/nested_c.elf_stg
index 28fd1ee..f2c2d35 100644
--- a/test_cases/info_tests/struct/expected/nested_c.elf_stg
+++ b/test_cases/info_tests/struct/expected/nested_c.elf_stg
@@ -1,9 +1,5 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
pointer_reference {
id: 0x12c83f93
kind: POINTER
@@ -20,6 +16,12 @@
pointee_type_id: 0xe16078fd # struct referring
}
primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
+}
+primitive {
id: 0xfc0e1dbd
name: "long"
encoding: SIGNED_INTEGER
@@ -68,23 +70,23 @@
}
}
function {
- id: 0x01533705
- return_type_id: 0x48b5725f # void
+ id: 0x8c4b85b9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x472d9a5b # struct containing
}
function {
- id: 0x164e865f
- return_type_id: 0x48b5725f # void
- parameter_id: 0x1b5b5f31 # struct containing*
-}
-function {
- id: 0x1c2a5875
- return_type_id: 0x48b5725f # void
+ id: 0x9132eac9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x32c82798 # struct referring*
}
function {
- id: 0x28c04fac
- return_type_id: 0x48b5725f # void
+ id: 0x9b5634e3
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0x1b5b5f31 # struct containing*
+}
+function {
+ id: 0xa5d8fd10
+ return_type_id: 0x6720d32f # int
parameter_id: 0xe16078fd # struct referring
}
elf_symbol {
@@ -92,7 +94,7 @@
name: "register_ops6"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x01533705 # void(struct containing)
+ type_id: 0x8c4b85b9 # int(struct containing)
full_name: "register_ops6"
}
elf_symbol {
@@ -100,7 +102,7 @@
name: "register_ops7"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x164e865f # void(struct containing*)
+ type_id: 0x9b5634e3 # int(struct containing*)
full_name: "register_ops7"
}
elf_symbol {
@@ -108,7 +110,7 @@
name: "register_ops8"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x28c04fac # void(struct referring)
+ type_id: 0xa5d8fd10 # int(struct referring)
full_name: "register_ops8"
}
elf_symbol {
@@ -116,13 +118,13 @@
name: "register_ops9"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1c2a5875 # void(struct referring*)
+ type_id: 0x9132eac9 # int(struct referring*)
full_name: "register_ops9"
}
interface {
id: 0x84ea5130
- symbol_id: 0x97e8ca66 # void register_ops6(struct containing)
- symbol_id: 0x68a86d39 # void register_ops7(struct containing*)
- symbol_id: 0x1f6abcc7 # void register_ops8(struct referring)
- symbol_id: 0xdc2ac9cf # void register_ops9(struct referring*)
+ symbol_id: 0x97e8ca66 # int register_ops6(struct containing)
+ symbol_id: 0x68a86d39 # int register_ops7(struct containing*)
+ symbol_id: 0x1f6abcc7 # int register_ops8(struct referring)
+ symbol_id: 0xdc2ac9cf # int register_ops9(struct referring*)
}
diff --git a/test_cases/info_tests/struct/expected/nested_cc.elf_stg b/test_cases/info_tests/struct/expected/nested_cc.elf_stg
index 6e0fa99..06fd04c 100644
--- a/test_cases/info_tests/struct/expected/nested_cc.elf_stg
+++ b/test_cases/info_tests/struct/expected/nested_cc.elf_stg
@@ -1,9 +1,5 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
pointer_reference {
id: 0x12c83f93
kind: POINTER
@@ -20,6 +16,12 @@
pointee_type_id: 0xe16078fd # struct referring
}
primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
+}
+primitive {
id: 0xfc0e1dbd
name: "long"
encoding: SIGNED_INTEGER
@@ -68,23 +70,23 @@
}
}
function {
- id: 0x01533705
- return_type_id: 0x48b5725f # void
+ id: 0x8c4b85b9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x472d9a5b # struct containing
}
function {
- id: 0x164e865f
- return_type_id: 0x48b5725f # void
- parameter_id: 0x1b5b5f31 # struct containing*
-}
-function {
- id: 0x1c2a5875
- return_type_id: 0x48b5725f # void
+ id: 0x9132eac9
+ return_type_id: 0x6720d32f # int
parameter_id: 0x32c82798 # struct referring*
}
function {
- id: 0x28c04fac
- return_type_id: 0x48b5725f # void
+ id: 0x9b5634e3
+ return_type_id: 0x6720d32f # int
+ parameter_id: 0x1b5b5f31 # struct containing*
+}
+function {
+ id: 0xa5d8fd10
+ return_type_id: 0x6720d32f # int
parameter_id: 0xe16078fd # struct referring
}
elf_symbol {
@@ -92,7 +94,7 @@
name: "_Z13register_ops610containing"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x01533705 # void(struct containing)
+ type_id: 0x8c4b85b9 # int(struct containing)
full_name: "register_ops6"
}
elf_symbol {
@@ -100,7 +102,7 @@
name: "_Z13register_ops7P10containing"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x164e865f # void(struct containing*)
+ type_id: 0x9b5634e3 # int(struct containing*)
full_name: "register_ops7"
}
elf_symbol {
@@ -108,7 +110,7 @@
name: "_Z13register_ops89referring"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x28c04fac # void(struct referring)
+ type_id: 0xa5d8fd10 # int(struct referring)
full_name: "register_ops8"
}
elf_symbol {
@@ -116,13 +118,13 @@
name: "_Z13register_ops9P9referring"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x1c2a5875 # void(struct referring*)
+ type_id: 0x9132eac9 # int(struct referring*)
full_name: "register_ops9"
}
interface {
id: 0x84ea5130
- symbol_id: 0x347b0ec1 # void register_ops6(struct containing)
- symbol_id: 0xcc14c364 # void register_ops7(struct containing*)
- symbol_id: 0xe408ab24 # void register_ops8(struct referring)
- symbol_id: 0x9d450b2c # void register_ops9(struct referring*)
+ symbol_id: 0x347b0ec1 # int register_ops6(struct containing)
+ symbol_id: 0xcc14c364 # int register_ops7(struct containing*)
+ symbol_id: 0xe408ab24 # int register_ops8(struct referring)
+ symbol_id: 0x9d450b2c # int register_ops9(struct referring*)
}
diff --git a/test_cases/info_tests/struct/nested.c b/test_cases/info_tests/struct/nested.c
index 003207c..bd30e5f 100644
--- a/test_cases/info_tests/struct/nested.c
+++ b/test_cases/info_tests/struct/nested.c
@@ -10,8 +10,7 @@
struct nested * inner;
};
-void tweak(int);
-void register_ops6(struct containing y) { (void) y; tweak(6); }
-void register_ops7(struct containing* y) { (void) y; tweak(7); }
-void register_ops8(struct referring y) { (void) y; tweak(8); }
-void register_ops9(struct referring* y) { (void) y; tweak(9); }
+int register_ops6(struct containing y) { (void) y; return 6; }
+int register_ops7(struct containing* y) { (void) y; return 7; }
+int register_ops8(struct referring y) { (void) y; return 8; }
+int register_ops9(struct referring* y) { (void) y; return 9; }
diff --git a/test_cases/info_tests/struct/nested.cc b/test_cases/info_tests/struct/nested.cc
index 7c986de..8c6ff89 100644
--- a/test_cases/info_tests/struct/nested.cc
+++ b/test_cases/info_tests/struct/nested.cc
@@ -10,8 +10,7 @@
struct nested * inner;
};
-void tweak(int);
-void register_ops6(containing) { tweak(6); }
-void register_ops7(containing*) { tweak(7); }
-void register_ops8(referring) { tweak(8); }
-void register_ops9(referring*) { tweak(9); }
+int register_ops6(containing) { return 6; }
+int register_ops7(containing*) { return 7; }
+int register_ops8(referring) { return 8; }
+int register_ops9(referring*) { return 9; }
diff --git a/test_cases/info_tests/symbol/expected/version_definition_c.elf_stg b/test_cases/info_tests/symbol/expected/version_definition_c.elf_stg
index 5a80408..2215c46 100644
--- a/test_cases/info_tests/symbol/expected/version_definition_c.elf_stg
+++ b/test_cases/info_tests/symbol/expected/version_definition_c.elf_stg
@@ -1,9 +1,5 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
-}
primitive {
id: 0x6720d32f
name: "int"
@@ -11,10 +7,6 @@
bytesize: 0x00000004
}
function {
- id: 0x10985193
- return_type_id: 0x48b5725f # void
-}
-function {
id: 0x9d80e32f
return_type_id: 0x6720d32f # int
}
@@ -31,7 +23,7 @@
name: "versioned_foo"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "versioned_foo"
}
elf_symbol {
@@ -39,7 +31,7 @@
name: "versioned_foo_v1"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "versioned_foo_v1"
}
elf_symbol {
@@ -47,7 +39,7 @@
name: "versioned_foo_v2"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "versioned_foo_v2"
}
elf_symbol {
@@ -55,14 +47,14 @@
name: "versioned_foo_v3"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "versioned_foo_v3"
}
interface {
id: 0x84ea5130
symbol_id: 0x886f3c7a # int test()
- symbol_id: 0x48a2620a # void versioned_foo()
- symbol_id: 0xc828cd97 # void versioned_foo_v1()
- symbol_id: 0x77e76a1f # void versioned_foo_v2()
- symbol_id: 0x36a79a97 # void versioned_foo_v3()
+ symbol_id: 0x48a2620a # int versioned_foo()
+ symbol_id: 0xc828cd97 # int versioned_foo_v1()
+ symbol_id: 0x77e76a1f # int versioned_foo_v2()
+ symbol_id: 0x36a79a97 # int versioned_foo_v3()
}
diff --git a/test_cases/info_tests/symbol/expected/visibility_c.btf_stg b/test_cases/info_tests/symbol/expected/visibility_c.btf_stg
index 0bdc7f0..c1c0aef 100644
--- a/test_cases/info_tests/symbol/expected/visibility_c.btf_stg
+++ b/test_cases/info_tests/symbol/expected/visibility_c.btf_stg
@@ -1,45 +1,47 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
}
function {
- id: 0x10985193
- return_type_id: 0x48b5725f # void
+ id: 0x9d80e32f
+ return_type_id: 0x6720d32f # int
}
elf_symbol {
id: 0xa7b0241d
name: "a"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
}
elf_symbol {
id: 0xe371117a
name: "b"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
}
elf_symbol {
id: 0x2230fb28
name: "c"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
}
elf_symbol {
id: 0x63f6f9b1
name: "d"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
}
interface {
id: 0x84ea5130
- symbol_id: 0xa7b0241d # void a()
- symbol_id: 0xe371117a # void b()
- symbol_id: 0x2230fb28 # void c()
- symbol_id: 0x63f6f9b1 # void d()
+ symbol_id: 0xa7b0241d # int a()
+ symbol_id: 0xe371117a # int b()
+ symbol_id: 0x2230fb28 # int c()
+ symbol_id: 0x63f6f9b1 # int d()
}
diff --git a/test_cases/info_tests/symbol/expected/visibility_c.elf_stg b/test_cases/info_tests/symbol/expected/visibility_c.elf_stg
index eec44c6..a0a86e7 100644
--- a/test_cases/info_tests/symbol/expected/visibility_c.elf_stg
+++ b/test_cases/info_tests/symbol/expected/visibility_c.elf_stg
@@ -1,19 +1,21 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
}
function {
- id: 0x10985193
- return_type_id: 0x48b5725f # void
+ id: 0x9d80e32f
+ return_type_id: 0x6720d32f # int
}
elf_symbol {
id: 0xa7b0241d
name: "a"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "a"
}
elf_symbol {
@@ -22,11 +24,11 @@
is_defined: true
symbol_type: FUNCTION
visibility: PROTECTED
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "b"
}
interface {
id: 0x84ea5130
- symbol_id: 0xa7b0241d # void a()
- symbol_id: 0xe371117a # void b()
+ symbol_id: 0xa7b0241d # int a()
+ symbol_id: 0xe371117a # int b()
}
diff --git a/test_cases/info_tests/symbol/expected/visibility_cc.elf_stg b/test_cases/info_tests/symbol/expected/visibility_cc.elf_stg
index 5b6960d..6b445f5 100644
--- a/test_cases/info_tests/symbol/expected/visibility_cc.elf_stg
+++ b/test_cases/info_tests/symbol/expected/visibility_cc.elf_stg
@@ -1,19 +1,21 @@
version: 0x00000002
root_id: 0x84ea5130 # interface
-special {
- id: 0x48b5725f
- kind: VOID
+primitive {
+ id: 0x6720d32f
+ name: "int"
+ encoding: SIGNED_INTEGER
+ bytesize: 0x00000004
}
function {
- id: 0x10985193
- return_type_id: 0x48b5725f # void
+ id: 0x9d80e32f
+ return_type_id: 0x6720d32f # int
}
elf_symbol {
id: 0x60468be1
name: "_Z1av"
is_defined: true
symbol_type: FUNCTION
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "a"
}
elf_symbol {
@@ -22,11 +24,11 @@
is_defined: true
symbol_type: FUNCTION
visibility: PROTECTED
- type_id: 0x10985193 # void()
+ type_id: 0x9d80e32f # int()
full_name: "b"
}
interface {
id: 0x84ea5130
- symbol_id: 0x60468be1 # void a()
- symbol_id: 0xfe73b6f7 # void b()
+ symbol_id: 0x60468be1 # int a()
+ symbol_id: 0xfe73b6f7 # int b()
}
diff --git a/test_cases/info_tests/symbol/version_definition.c b/test_cases/info_tests/symbol/version_definition.c
index af87429..57dc203 100644
--- a/test_cases/info_tests/symbol/version_definition.c
+++ b/test_cases/info_tests/symbol/version_definition.c
@@ -4,18 +4,16 @@
// produce wrong results.
// TODO: remove statement above after support is implemented
-void tweak(int dummy);
-
-void versioned_foo(void) { tweak(1); }
+int versioned_foo(void) { return 1; }
__asm__(".symver versioned_foo_v1, versioned_foo@@VERS_1");
-void versioned_foo_v1(void) { tweak(2); }
+int versioned_foo_v1(void) { return 2; }
__asm__(".symver versioned_foo_v2, versioned_foo@VERS_2");
-void versioned_foo_v2(void) { tweak(3); }
+int versioned_foo_v2(void) { return 3; }
__asm__(".symver versioned_foo_v3, versioned_foo@VERS_3");
-void versioned_foo_v3(void) { tweak(4); }
+int versioned_foo_v3(void) { return 4; }
// Using a libc function helps to add the "version needs" section
// in addition to the "version definitions". This helps to catch
diff --git a/test_cases/info_tests/symbol/visibility.c b/test_cases/info_tests/symbol/visibility.c
index 45fcbb5..13dfa0c 100644
--- a/test_cases/info_tests/symbol/visibility.c
+++ b/test_cases/info_tests/symbol/visibility.c
@@ -1,5 +1,4 @@
-void tweak(int);
-__attribute__ ((visibility ("default"))) void a() { tweak(0); }
-__attribute__ ((visibility ("protected"))) void b() { tweak(1); }
-__attribute__ ((visibility ("hidden"))) void c() { tweak(2); }
-__attribute__ ((visibility ("internal"))) void d() { tweak(3); }
+__attribute__ ((visibility ("default"))) int a() { return 0; }
+__attribute__ ((visibility ("protected"))) int b() { return 1; }
+__attribute__ ((visibility ("hidden"))) int c() { return 2; }
+__attribute__ ((visibility ("internal"))) int d() { return 3; }
diff --git a/test_cases/info_tests/symbol/visibility.cc b/test_cases/info_tests/symbol/visibility.cc
index 45fcbb5..13dfa0c 100644
--- a/test_cases/info_tests/symbol/visibility.cc
+++ b/test_cases/info_tests/symbol/visibility.cc
@@ -1,5 +1,4 @@
-void tweak(int);
-__attribute__ ((visibility ("default"))) void a() { tweak(0); }
-__attribute__ ((visibility ("protected"))) void b() { tweak(1); }
-__attribute__ ((visibility ("hidden"))) void c() { tweak(2); }
-__attribute__ ((visibility ("internal"))) void d() { tweak(3); }
+__attribute__ ((visibility ("default"))) int a() { return 0; }
+__attribute__ ((visibility ("protected"))) int b() { return 1; }
+__attribute__ ((visibility ("hidden"))) int c() { return 2; }
+__attribute__ ((visibility ("internal"))) int d() { return 3; }
diff --git a/type_normalisation.cc b/type_normalisation.cc
index 292957b..e5d4a25 100644
--- a/type_normalisation.cc
+++ b/type_normalisation.cc
@@ -206,7 +206,7 @@
const auto it = resolved.find(id);
if (it != resolved.end()) {
id = it->second;
- Check(!resolved.count(id)) << "qualifier was resolved to qualifier";
+ Check(!resolved.contains(id)) << "qualifier was resolved to qualifier";
}
}
@@ -216,7 +216,7 @@
} // namespace
-void RemoveUselessQualifiers(Graph& graph, Id root) {
+Id RemoveUselessQualifiers(Graph& graph, Id root) {
std::unordered_map<Id, Id> resolved;
std::unordered_set<Id> functions;
FindQualifiedTypesAndFunctions(graph, resolved, functions)(root);
@@ -225,6 +225,7 @@
for (const auto& id : functions) {
remove_qualifiers(id);
}
+ return root;
}
} // namespace stg
diff --git a/type_normalisation.h b/type_normalisation.h
index 6bd4362..953b800 100644
--- a/type_normalisation.h
+++ b/type_normalisation.h
@@ -24,7 +24,7 @@
namespace stg {
-void RemoveUselessQualifiers(Graph& graph, Id root);
+Id RemoveUselessQualifiers(Graph& graph, Id root);
} // namespace stg