diff options
Diffstat (limited to 'src/common/module.h')
-rw-r--r-- | src/common/module.h | 231 |
1 files changed, 189 insertions, 42 deletions
diff --git a/src/common/module.h b/src/common/module.h index 7309cedd..c1fd9f59 100644 --- a/src/common/module.h +++ b/src/common/module.h @@ -1,7 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010 Google Inc. -// All rights reserved. +// Copyright 2010 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -13,7 +12,7 @@ // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. -// * Neither the name of Google Inc. nor the names of its +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -38,13 +37,18 @@ #ifndef COMMON_LINUX_MODULE_H__ #define COMMON_LINUX_MODULE_H__ +#include <functional> #include <iostream> +#include <limits> #include <map> +#include <memory> #include <set> #include <string> #include <vector> +#include "common/string_view.h" #include "common/symbol_data.h" +#include "common/unordered.h" #include "common/using_std_string.h" #include "google_breakpad/common/breakpad_types.h" @@ -62,8 +66,11 @@ class Module { public: // The type of addresses and sizes in a symbol table. typedef uint64_t Address; + static constexpr uint64_t kMaxAddress = std::numeric_limits<Address>::max(); struct File; struct Function; + struct InlineOrigin; + struct Inline; struct Line; struct Extern; @@ -74,7 +81,7 @@ class Module { // A source file. struct File { - explicit File(const string &name_input) : name(name_input), source_id(0) {} + explicit File(const string& name_input) : name(name_input), source_id(0) {} // The name of the source file. const string name; @@ -96,17 +103,17 @@ class Module { // A function. struct Function { - Function(const string &name_input, const Address &address_input) : + Function(StringView name_input, const Address& address_input) : name(name_input), address(address_input), parameter_size(0) {} // For sorting by address. (Not style-guide compliant, but it's // stupid not to put this in the struct.) - static bool CompareByAddress(const Function *x, const Function *y) { + static bool CompareByAddress(const Function* x, const Function* y) { return x->address < y->address; } // The function's name. - string name; + StringView name; // The start address and the address ranges covered by the function. const Address address; @@ -118,26 +125,127 @@ class Module { // Source lines belonging to this function, sorted by increasing // address. vector<Line> lines; + + // Inlined call sites belonging to this functions. + vector<std::unique_ptr<Inline>> inlines; + + // If this symbol has been folded with other symbols in the linked binary. + bool is_multiple = false; + }; + + struct InlineOrigin { + explicit InlineOrigin(StringView name) : id(-1), name(name) {} + + // A unique id for each InlineOrigin object. INLINE records use the id to + // refer to its INLINE_ORIGIN record. + int id; + + // The inlined function's name. + StringView name; + + File* file; + + int getFileID() const { return file ? file->source_id : -1; } + }; + + // A inlined call site. + struct Inline { + Inline(InlineOrigin* origin, + const vector<Range>& ranges, + int call_site_line, + int call_site_file_id, + int inline_nest_level, + vector<std::unique_ptr<Inline>> child_inlines) + : origin(origin), + ranges(ranges), + call_site_line(call_site_line), + call_site_file_id(call_site_file_id), + call_site_file(nullptr), + inline_nest_level(inline_nest_level), + child_inlines(std::move(child_inlines)) {} + + InlineOrigin* origin; + + // The list of addresses and sizes. + vector<Range> ranges; + + int call_site_line; + + // The id is only meanful inside a CU. It's only used for looking up real + // File* after scanning a CU. + int call_site_file_id; + + File* call_site_file; + + int inline_nest_level; + + // A list of inlines which are children of this inline. + vector<std::unique_ptr<Inline>> child_inlines; + + int getCallSiteFileID() const { + return call_site_file ? call_site_file->source_id : -1; + } + + static void InlineDFS( + vector<std::unique_ptr<Module::Inline>>& inlines, + std::function<void(std::unique_ptr<Module::Inline>&)> const& forEach) { + for (std::unique_ptr<Module::Inline>& in : inlines) { + forEach(in); + InlineDFS(in->child_inlines, forEach); + } + } + }; + + typedef map<uint64_t, InlineOrigin*> InlineOriginByOffset; + + class InlineOriginMap { + public: + // Add INLINE ORIGIN to the module. Return a pointer to origin . + InlineOrigin* GetOrCreateInlineOrigin(uint64_t offset, StringView name); + + // offset is the offset of a DW_TAG_subprogram. specification_offset is the + // value of its DW_AT_specification or equals to offset if + // DW_AT_specification doesn't exist in that DIE. + void SetReference(uint64_t offset, uint64_t specification_offset); + + ~InlineOriginMap() { + for (const auto& iter : inline_origins_) { + delete iter.second; + } + } + + private: + // A map from a DW_TAG_subprogram's offset to the DW_TAG_subprogram. + InlineOriginByOffset inline_origins_; + + // A map from a DW_TAG_subprogram's offset to the offset of its + // specification or abstract origin subprogram. The set of values in this + // map should always be the same set of keys in inline_origins_. + map<uint64_t, uint64_t> references_; }; + InlineOriginMap inline_origin_map; + // A source line. struct Line { // For sorting by address. (Not style-guide compliant, but it's // stupid not to put this in the struct.) - static bool CompareByAddress(const Module::Line &x, const Module::Line &y) { + static bool CompareByAddress(const Module::Line& x, const Module::Line& y) { return x.address < y.address; } Address address, size; // The address and size of the line's code. - File *file; // The source file. + File* file; // The source file. int number; // The source line number. }; // An exported symbol. struct Extern { - explicit Extern(const Address &address_input) : address(address_input) {} + explicit Extern(const Address& address_input) : address(address_input) {} const Address address; string name; + // If this symbol has been folded with other symbols in the linked binary. + bool is_multiple = false; }; // A map from register names to postfix expressions that recover @@ -170,25 +278,46 @@ class Module { }; struct FunctionCompare { - bool operator() (const Function *lhs, - const Function *rhs) const { + bool operator() (const Function* lhs, const Function* rhs) const { if (lhs->address == rhs->address) return lhs->name < rhs->name; return lhs->address < rhs->address; } }; + struct InlineOriginCompare { + bool operator()(const InlineOrigin* lhs, const InlineOrigin* rhs) const { + return lhs->name < rhs->name; + } + }; + struct ExternCompare { - bool operator() (const Extern *lhs, - const Extern *rhs) const { + // Defining is_transparent allows + // std::set<std::unique_ptr<Extern>, ExternCompare>::find() to be called + // with an Extern* and have set use the overloads below. + using is_transparent = void; + bool operator() (const std::unique_ptr<Extern>& lhs, + const std::unique_ptr<Extern>& rhs) const { + return lhs->address < rhs->address; + } + bool operator() (const Extern* lhs, const std::unique_ptr<Extern>& rhs) const { + return lhs->address < rhs->address; + } + bool operator() (const std::unique_ptr<Extern>& lhs, const Extern* rhs) const { return lhs->address < rhs->address; } }; // Create a new module with the given name, operating system, // architecture, and ID string. - Module(const string &name, const string &os, const string &architecture, - const string &id, const string &code_id = ""); + // NB: `enable_multiple_field` is temporary while transitioning to enabling + // writing the multiple field permanently. + Module(const string& name, + const string& os, + const string& architecture, + const string& id, + const string& code_id = "", + bool enable_multiple_field = false); ~Module(); // Set the module's load address to LOAD_ADDRESS; addresses given @@ -216,83 +345,90 @@ class Module { // Add FUNCTION to the module. FUNCTION's name must not be empty. // This module owns all Function objects added with this function: // destroying the module destroys them as well. - void AddFunction(Function *function); - - // Add all the functions in [BEGIN,END) to the module. - // This module owns all Function objects added with this function: - // destroying the module destroys them as well. - void AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end); + // Return false if the function is duplicate and needs to be freed. + bool AddFunction(Function* function); // Add STACK_FRAME_ENTRY to the module. // This module owns all StackFrameEntry objects added with this // function: destroying the module destroys them as well. - void AddStackFrameEntry(StackFrameEntry *stack_frame_entry); + void AddStackFrameEntry(std::unique_ptr<StackFrameEntry> stack_frame_entry); // Add PUBLIC to the module. // This module owns all Extern objects added with this function: // destroying the module destroys them as well. - void AddExtern(Extern *ext); + void AddExtern(std::unique_ptr<Extern> ext); // If this module has a file named NAME, return a pointer to it. If // it has none, then create one and return a pointer to the new // file. This module owns all File objects created using these // functions; destroying the module destroys them as well. - File *FindFile(const string &name); - File *FindFile(const char *name); + File* FindFile(const string& name); + File* FindFile(const char* name); // If this module has a file named NAME, return a pointer to it. // Otherwise, return NULL. - File *FindExistingFile(const string &name); + File* FindExistingFile(const string& name); // Insert pointers to the functions added to this module at I in // VEC. The pointed-to Functions are still owned by this module. // (Since this is effectively a copy of the function list, this is // mostly useful for testing; other uses should probably get a more // appropriate interface.) - void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i); + void GetFunctions(vector<Function*>* vec, vector<Function*>::iterator i); // Insert pointers to the externs added to this module at I in // VEC. The pointed-to Externs are still owned by this module. // (Since this is effectively a copy of the extern list, this is // mostly useful for testing; other uses should probably get a more // appropriate interface.) - void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i); + void GetExterns(vector<Extern*>* vec, vector<Extern*>::iterator i); // Clear VEC and fill it with pointers to the Files added to this // module, sorted by name. The pointed-to Files are still owned by // this module. (Since this is effectively a copy of the file list, // this is mostly useful for testing; other uses should probably get // a more appropriate interface.) - void GetFiles(vector<File *> *vec); + void GetFiles(vector<File*>* vec); // Clear VEC and fill it with pointers to the StackFrameEntry // objects that have been added to this module. (Since this is // effectively a copy of the stack frame entry list, this is mostly // useful for testing; other uses should probably get // a more appropriate interface.) - void GetStackFrameEntries(vector<StackFrameEntry *> *vec) const; + void GetStackFrameEntries(vector<StackFrameEntry*>* vec) const; // Find those files in this module that are actually referred to by // functions' line number data, and assign them source id numbers. // Set the source id numbers for all other files --- unused by the // source line data --- to -1. We do this before writing out the // symbol file, at which point we omit any unused files. - void AssignSourceIds(); + void AssignSourceIds(set<InlineOrigin*, InlineOriginCompare>& inline_origins); + + // This function should be called before AssignSourceIds() to get the set of + // valid InlineOrigins*. + void CreateInlineOrigins( + set<InlineOrigin*, InlineOriginCompare>& inline_origins); // Call AssignSourceIds, and write this module to STREAM in the // breakpad symbol format. Return true if all goes well, or false if // an error occurs. This method writes out: // - a header based on the values given to the constructor, - // If symbol_data is not ONLY_CFI then: + // If symbol_data is not CFI then: // - the source files added via FindFile, // - the functions added via AddFunctions, each with its lines, // - all public records, - // If symbol_data is not NO_CFI then: + // If symbol_data is CFI then: // - all CFI records. // Addresses in the output are all relative to the load address // established by SetLoadAddress. - bool Write(std::ostream &stream, SymbolData symbol_data); + bool Write(std::ostream& stream, SymbolData symbol_data); + + // Place the name in the global set of strings. Return a StringView points to + // a string inside the pool. + StringView AddStringToPool(const string& str) { + auto result = common_strings_.insert(str); + return *(result.first); + } string name() const { return name_; } string os() const { return os_; } @@ -308,7 +444,7 @@ class Module { // Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI' // records, without a final newline. Return true if all goes well; // if an error occurs, return false, and leave errno set. - static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream); + static bool WriteRuleMap(const RuleMap& rule_map, std::ostream& stream); // Returns true of the specified address resides with an specified address // range, or if no ranges have been specified. @@ -329,32 +465,43 @@ class Module { // Relation for maps whose keys are strings shared with some other // structure. struct CompareStringPtrs { - bool operator()(const string *x, const string *y) const { return *x < *y; } + bool operator()(const string* x, const string* y) const { return *x < *y; } }; // A map from filenames to File structures. The map's keys are // pointers to the Files' names. - typedef map<const string *, File *, CompareStringPtrs> FileByNameMap; + typedef map<const string*, File*, CompareStringPtrs> FileByNameMap; // A set containing Function structures, sorted by address. - typedef set<Function *, FunctionCompare> FunctionSet; + typedef set<Function*, FunctionCompare> FunctionSet; // A set containing Extern structures, sorted by address. - typedef set<Extern *, ExternCompare> ExternSet; + typedef set<std::unique_ptr<Extern>, ExternCompare> ExternSet; // The module owns all the files and functions that have been added // to it; destroying the module frees the Files and Functions these // point to. FileByNameMap files_; // This module's source files. FunctionSet functions_; // This module's functions. + // Used to quickly look up whether a function exists at a particular address. + unordered_set<Address> function_addresses_; // The module owns all the call frame info entries that have been // added to it. - vector<StackFrameEntry *> stack_frame_entries_; + vector<std::unique_ptr<StackFrameEntry>> stack_frame_entries_; // The module owns all the externs that have been added to it; // destroying the module frees the Externs these point to. ExternSet externs_; + + unordered_set<string> common_strings_; + + // Whether symbols sharing an address should be collapsed into a single entry + // and marked with an `m` in the output. See + // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=751 and docs + // at + // https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md#records-3 + bool enable_multiple_field_; }; } // namespace google_breakpad |