diff options
Diffstat (limited to 'src/common')
114 files changed, 1634 insertions, 589 deletions
diff --git a/src/common/basictypes.h b/src/common/basictypes.h index 6458a893..79c9b775 100644 --- a/src/common/basictypes.h +++ b/src/common/basictypes.h @@ -29,14 +29,6 @@ #ifndef COMMON_BASICTYPES_H_ #define COMMON_BASICTYPES_H_ -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif // DISALLOW_COPY_AND_ASSIGN - namespace google_breakpad { // Used to explicitly mark the return value of a function as unused. If you are diff --git a/src/common/byte_cursor_unittest.cc b/src/common/byte_cursor_unittest.cc index 00648f76..41180ca2 100644 --- a/src/common/byte_cursor_unittest.cc +++ b/src/common/byte_cursor_unittest.cc @@ -31,6 +31,10 @@ // byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer // and google_breakpad::ByteCursor. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string> #include <string.h> diff --git a/src/common/convert_UTF.cc b/src/common/convert_UTF.cc index 4a5df1eb..6e95b2f9 100644 --- a/src/common/convert_UTF.cc +++ b/src/common/convert_UTF.cc @@ -55,6 +55,10 @@ See the header file "ConvertUTF.h" for complete documentation. ------------------------------------------------------------------------ */ +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "convert_UTF.h" #ifdef CVTUTF_DEBUG #include <stdio.h> diff --git a/src/common/dwarf/bytereader.cc b/src/common/dwarf/bytereader.cc index 46bed6d0..faa7d680 100644 --- a/src/common/dwarf/bytereader.cc +++ b/src/common/dwarf/bytereader.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> #include <stdint.h> #include <stdlib.h> diff --git a/src/common/dwarf/bytereader_unittest.cc b/src/common/dwarf/bytereader_unittest.cc index c23c737b..a5eb0da5 100644 --- a/src/common/dwarf/bytereader_unittest.cc +++ b/src/common/dwarf/bytereader_unittest.cc @@ -30,6 +30,10 @@ // bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <string> diff --git a/src/common/dwarf/cfi_assembler.cc b/src/common/dwarf/cfi_assembler.cc index 9ed979b4..b3e064f0 100644 --- a/src/common/dwarf/cfi_assembler.cc +++ b/src/common/dwarf/cfi_assembler.cc @@ -31,6 +31,10 @@ // cfi_assembler.cc: Implementation of google_breakpad::CFISection class. // See cfi_assembler.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/dwarf/cfi_assembler.h" #include <assert.h> diff --git a/src/common/dwarf/dwarf2diehandler.cc b/src/common/dwarf/dwarf2diehandler.cc index ea3ac71c..8aea0f2f 100644 --- a/src/common/dwarf/dwarf2diehandler.cc +++ b/src/common/dwarf/dwarf2diehandler.cc @@ -31,6 +31,10 @@ // dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. // See dwarf2diehandler.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> #include <stdint.h> diff --git a/src/common/dwarf/dwarf2diehandler_unittest.cc b/src/common/dwarf/dwarf2diehandler_unittest.cc index 67c9489d..afcbf625 100644 --- a/src/common/dwarf/dwarf2diehandler_unittest.cc +++ b/src/common/dwarf/dwarf2diehandler_unittest.cc @@ -32,6 +32,10 @@ // dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <string> diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index 777d9bfc..f1c995f9 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -580,10 +580,10 @@ enum DwarfSectionId { DW_SECT_TYPES = 2, DW_SECT_ABBREV = 3, DW_SECT_LINE = 4, - DW_SECT_LOC = 5, + DW_SECT_LOCLISTS = 5, DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 8 + DW_SECT_MACRO = 7, + DW_SECT_RNGLISTS = 8 }; // Source languages. These are values for DW_AT_language. diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index b191d78c..8a8bf6f8 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -31,6 +31,10 @@ // Implementation of LineInfo, CompilationUnit, // and CallFrameInfo. See dwarf2reader.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/dwarf/dwarf2reader.h" #include <stdint.h> @@ -76,9 +80,10 @@ CompilationUnit::CompilationUnit(const string& path, str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), addr_buffer_(NULL), addr_buffer_length_(0), is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), - skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), - dwp_byte_reader_(), dwp_reader_() {} + skeleton_dwo_id_(0), addr_base_(0), + str_offsets_base_(0), have_checked_for_dwp_(false), + should_process_split_dwarf_(false), low_pc_(0), + has_source_line_info_(false), source_line_offset_(0) {} // Initialize a compilation unit from a .dwo or .dwp file. // In this case, we need the .debug_addr section from the @@ -87,16 +92,10 @@ CompilationUnit::CompilationUnit(const string& path, // the executable file, and call it as if we were still // processing the original compilation unit. -void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, - uint64_t addr_buffer_length, - uint64_t addr_base, - uint64_t ranges_base, +void CompilationUnit::SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id) { is_split_dwarf_ = true; - addr_buffer_ = addr_buffer; - addr_buffer_length_ = addr_buffer_length; addr_base_ = addr_base; - ranges_base_ = ranges_base; skeleton_dwo_id_ = dwo_id; } @@ -396,7 +395,13 @@ uint64_t CompilationUnit::Start() { // Set up our buffer buffer_ = iter->second.first + offset_from_section_start_; - buffer_length_ = iter->second.second - offset_from_section_start_; + if (is_split_dwarf_) { + iter = GetSectionByName(sections_, ".debug_info_offset"); + assert(iter != sections_.end()); + buffer_length_ = iter->second.second; + } else { + buffer_length_ = iter->second.second - offset_from_section_start_; + } // Read the header ReadHeader(); @@ -430,6 +435,12 @@ uint64_t CompilationUnit::Start() { string_buffer_length_ = iter->second.second; } + iter = GetSectionByName(sections_, ".debug_line"); + if (iter != sections_.end()) { + line_buffer_ = iter->second.first; + line_buffer_length_ = iter->second.second; + } + // Set the line string section if we have one. iter = GetSectionByName(sections_, ".debug_line_str"); if (iter != sections_.end()) { @@ -457,10 +468,8 @@ uint64_t CompilationUnit::Start() { // If this is a skeleton compilation unit generated with split DWARF, // and the client needs the full debug info, we need to find the full // compilation unit in a .dwo or .dwp file. - if (!is_split_dwarf_ - && dwo_name_ != NULL - && handler_->NeedSplitDebugInfo()) - ProcessSplitDwarf(); + should_process_split_dwarf_ = + !is_split_dwarf_ && dwo_name_ != NULL && handler_->NeedSplitDebugInfo(); return ourlength; } @@ -881,7 +890,9 @@ const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset, // DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must // be found and processed before trying to process the other attributes; // otherwise the string or address values will all come out incorrect. - if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) { + if ((abbrev.tag == DW_TAG_compile_unit || + abbrev.tag == DW_TAG_skeleton_unit) && + header_.version == 5) { uint64_t dieoffset_copy = dieoffset; const uint8_t* start_copy = start; for (AttributeList::const_iterator i = abbrev.attributes.begin(); @@ -990,66 +1001,69 @@ inline int GetElfWidth(const ElfReader& elf) { return 0; } -void CompilationUnit::ProcessSplitDwarf() { +bool CompilationUnit::ProcessSplitDwarf(std::string& split_file, + SectionMap& sections, + ByteReader& split_byte_reader, + uint64_t& cu_offset) { + if (!should_process_split_dwarf_) + return false; struct stat statbuf; + bool found_in_dwp = false; if (!have_checked_for_dwp_) { // Look for a .dwp file in the same directory as the executable. have_checked_for_dwp_ = true; string dwp_suffix(".dwp"); - dwp_path_ = path_ + dwp_suffix; - if (stat(dwp_path_.c_str(), &statbuf) != 0) { + std::string dwp_path = path_ + dwp_suffix; + if (stat(dwp_path.c_str(), &statbuf) != 0) { // Fall back to a split .debug file in the same directory. string debug_suffix(".debug"); - dwp_path_ = path_; + dwp_path = path_; size_t found = path_.rfind(debug_suffix); - if (found + debug_suffix.length() == path_.length()) - dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); + if (found != string::npos && + found + debug_suffix.length() == path_.length()) + dwp_path = dwp_path.replace(found, debug_suffix.length(), dwp_suffix); } - if (stat(dwp_path_.c_str(), &statbuf) == 0) { - ElfReader* elf = new ElfReader(dwp_path_); - int width = GetElfWidth(*elf); + if (stat(dwp_path.c_str(), &statbuf) == 0) { + split_elf_reader_ = std::make_unique<ElfReader>(dwp_path); + int width = GetElfWidth(*split_elf_reader_.get()); if (width != 0) { - dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); - dwp_byte_reader_->SetAddressSize(width); - dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); + split_byte_reader = ByteReader(reader_->GetEndianness()); + split_byte_reader.SetAddressSize(width); + dwp_reader_ = std::make_unique<DwpReader>(split_byte_reader, + split_elf_reader_.get()); dwp_reader_->Initialize(); - } else { - delete elf; + // If we have a .dwp file, read the debug sections for the requested CU. + dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); + if (!sections.empty()) { + SectionMap::const_iterator cu_iter = + GetSectionByName(sections, ".debug_info_offset"); + SectionMap::const_iterator debug_info_iter = + GetSectionByName(sections, ".debug_info"); + assert(cu_iter != sections.end()); + assert(debug_info_iter != sections.end()); + cu_offset = cu_iter->second.first - debug_info_iter->second.first; + found_in_dwp = true; + split_file = dwp_path; + } } } } - bool found_in_dwp = false; - if (dwp_reader_) { - // If we have a .dwp file, read the debug sections for the requested CU. - SectionMap sections; - dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); - if (!sections.empty()) { - found_in_dwp = true; - CompilationUnit dwp_comp_unit(dwp_path_, sections, 0, - dwp_byte_reader_.get(), handler_); - dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_, - ranges_base_, dwo_id_); - dwp_comp_unit.Start(); - } - } if (!found_in_dwp) { // If no .dwp file, try to open the .dwo file. if (stat(dwo_name_, &statbuf) == 0) { - ElfReader elf(dwo_name_); - int width = GetElfWidth(elf); + split_elf_reader_ = std::make_unique<ElfReader>(dwo_name_); + int width = GetElfWidth(*split_elf_reader_.get()); if (width != 0) { - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(width); - SectionMap sections; - ReadDebugSectionsFromDwo(&elf, §ions); - CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, - handler_); - dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, - addr_base_, ranges_base_, dwo_id_); - dwo_comp_unit.Start(); + split_byte_reader = ByteReader(ENDIANNESS_LITTLE); + split_byte_reader.SetAddressSize(width); + ReadDebugSectionsFromDwo(split_elf_reader_.get(), §ions); + if (!sections.empty()) { + split_file = dwo_name_; + } } } } + return !split_file.empty(); } void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, @@ -1084,10 +1098,6 @@ DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader) abbrev_size_(0), info_data_(NULL), info_size_(0), str_offsets_data_(NULL), str_offsets_size_(0) {} -DwpReader::~DwpReader() { - if (elf_reader_) delete elf_reader_; -} - void DwpReader::Initialize() { cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", &cu_index_size_); @@ -1127,6 +1137,8 @@ void DwpReader::Initialize() { info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", &str_offsets_size_); + rnglist_data_ = + elf_reader_->GetSectionByName(".debug_rnglists.dwo", &rnglist_size_); if (size_table_ >= cu_index_ + cu_index_size_) { version_ = 0; } @@ -1227,13 +1239,24 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id, } else if (section_id == DW_SECT_INFO) { sections->insert(std::make_pair( ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t*> (info_data_) - + offset, size))); + std::make_pair(reinterpret_cast<const uint8_t*>(info_data_), 0))); + // .debug_info_offset will points the buffer for the CU with given + // dwo_id. + sections->insert(std::make_pair( + ".debug_info_offset", + std::make_pair( + reinterpret_cast<const uint8_t*>(info_data_) + offset, size))); } else if (section_id == DW_SECT_STR_OFFSETS) { sections->insert(std::make_pair( ".debug_str_offsets", std::make_pair(reinterpret_cast<const uint8_t*> (str_offsets_data_) + offset, size))); + } else if (section_id == DW_SECT_RNGLISTS) { + sections->insert(std::make_pair( + ".debug_rnglists", + std::make_pair( + reinterpret_cast<const uint8_t*>(rnglist_data_) + offset, + size))); } } sections->insert(std::make_pair( @@ -1819,6 +1842,11 @@ bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { return ReadDebugRngList(data); } } else if (form == DW_FORM_rnglistx) { + if (cu_info_->ranges_base_ == 0) { + // In split dwarf, there's no DW_AT_rnglists_base attribute, range_base + // will just be the first byte after the header. + cu_info_->ranges_base_ = reader_->OffsetSize() == 4? 12: 20; + } offset_array_ = cu_info_->ranges_base_; uint64_t index_offset = reader_->OffsetSize() * data; uint64_t range_list_offset = diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index ddcdd801..b6bd2f31 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -469,8 +469,7 @@ class CompilationUnit { // compilation unit. We also inherit the Dwarf2Handler from // the executable file, and call it as if we were still // processing the original compilation unit. - void SetSplitDwarf(const uint8_t* addr_buffer, uint64_t addr_buffer_length, - uint64_t addr_base, uint64_t ranges_base, uint64_t dwo_id); + void SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id); // Begin reading a Dwarf2 compilation unit, and calling the // callbacks in the Dwarf2Handler @@ -481,6 +480,36 @@ class CompilationUnit { // start of the next compilation unit, if there is one. uint64_t Start(); + // Process the actual debug information in a split DWARF file. + bool ProcessSplitDwarf(std::string& split_file, + SectionMap& sections, + ByteReader& split_byte_reader, + uint64_t& cu_offset); + + const uint8_t* GetAddrBuffer() { return addr_buffer_; } + + uint64_t GetAddrBufferLen() { return addr_buffer_length_; } + + uint64_t GetAddrBase() { return addr_base_; } + + uint64_t GetLowPC() { return low_pc_; } + + uint64_t GetDWOID() { return dwo_id_; } + + const uint8_t* GetLineBuffer() { return line_buffer_; } + + uint64_t GetLineBufferLen() { return line_buffer_length_; } + + const uint8_t* GetLineStrBuffer() { return line_string_buffer_; } + + uint64_t GetLineStrBufferLen() { return line_string_buffer_length_; } + + bool HasSourceLineInfo() { return has_source_line_info_; } + + uint64_t GetSourceLineOffset() { return source_line_offset_; } + + bool ShouldProcessSplitDwarf() { return should_process_split_dwarf_; } + private: // This struct represents a single DWARF2/3 abbreviation @@ -565,14 +594,12 @@ class CompilationUnit { else if (attr == DW_AT_str_offsets_base) { str_offsets_base_ = data; } - else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) { - ranges_base_ = data; + else if (attr == DW_AT_low_pc) { + low_pc_ = data; } - // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, - // that base will apply to DW_AT_ranges attributes in the - // skeleton CU as well as in the .dwo/.dwp files. - else if (attr == DW_AT_ranges && is_split_dwarf_) { - data += ranges_base_; + else if (attr == DW_AT_stmt_list) { + has_source_line_info_ = true; + source_line_offset_ = data; } handler_->ProcessAttributeUnsigned(offset, attr, form, data); } @@ -647,9 +674,6 @@ class CompilationUnit { // new place to position the stream to. const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form); - // Process the actual debug information in a split DWARF file. - void ProcessSplitDwarf(); - // Read the debug sections from a .dwo file. void ReadDebugSectionsFromDwo(ElfReader* elf_reader, SectionMap* sections); @@ -658,7 +682,7 @@ class CompilationUnit { const string path_; // Offset from section start is the offset of this compilation unit - // from the beginning of the .debug_info section. + // from the beginning of the .debug_info/.debug_info.dwo section. uint64_t offset_from_section_start_; // buffer is the buffer for our CU, starting at .debug_info + offset @@ -688,7 +712,7 @@ class CompilationUnit { const uint8_t* string_buffer_; uint64_t string_buffer_length_; - // Similarly for .debug_line_string. + // Similarly for .debug_line_str. const uint8_t* line_string_buffer_; uint64_t line_string_buffer_length_; @@ -702,6 +726,10 @@ class CompilationUnit { const uint8_t* addr_buffer_; uint64_t addr_buffer_length_; + // .debug_line section buffer and length. + const uint8_t* line_buffer_; + uint64_t line_buffer_length_; + // Flag indicating whether this compilation unit is part of a .dwo // or .dwp file. If true, we are reading this unit because a // skeleton compilation unit in an executable file had a @@ -730,10 +758,6 @@ class CompilationUnit { // from the skeleton CU. uint64_t skeleton_dwo_id_; - // The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute, - // if any. - uint64_t ranges_base_; - // The value of the DW_AT_GNU_addr_base attribute, if any. uint64_t addr_base_; @@ -743,14 +767,20 @@ class CompilationUnit { // True if we have already looked for a .dwp file. bool have_checked_for_dwp_; - // Path to the .dwp file. - string dwp_path_; - - // ByteReader for the DWP file. - std::unique_ptr<ByteReader> dwp_byte_reader_; + // ElfReader for the dwo/dwo file. + std::unique_ptr<ElfReader> split_elf_reader_; // DWP reader. - std::unique_ptr<DwpReader> dwp_reader_; + std::unique_ptr<DwpReader> dwp_reader_; + + bool should_process_split_dwarf_; + + // The value of the DW_AT_low_pc attribute, if any. + uint64_t low_pc_; + + // The value of DW_AT_stmt_list attribute if any. + bool has_source_line_info_; + uint64_t source_line_offset_; }; // A Reader for a .dwp file. Supports the fetching of DWARF debug @@ -770,8 +800,6 @@ class DwpReader { public: DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); - ~DwpReader(); - // Read the CU index and initialize data members. void Initialize(); @@ -839,6 +867,8 @@ class DwpReader { size_t info_size_; const char* str_offsets_data_; size_t str_offsets_size_; + const char* rnglist_data_; + size_t rnglist_size_; }; // This class is a reader for DWARF's Call Frame Information. CFI diff --git a/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/src/common/dwarf/dwarf2reader_cfi_unittest.cc index dc4418c7..67b662a3 100644 --- a/src/common/dwarf/dwarf2reader_cfi_unittest.cc +++ b/src/common/dwarf/dwarf2reader_cfi_unittest.cc @@ -30,6 +30,10 @@ // dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <stdlib.h> diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index fc639a64..2b365396 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -30,6 +30,10 @@ // dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <stdlib.h> @@ -329,7 +333,8 @@ struct DwarfFormsFixture: public DIEFixture { uint64_t offset=0) { ByteReader byte_reader(params.endianness == kLittleEndian ? ENDIANNESS_LITTLE : ENDIANNESS_BIG); - CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler); + CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, + &handler); EXPECT_EQ(offset + parser.Start(), info_contents.size()); } diff --git a/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc index 033c6333..7de627d3 100644 --- a/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc +++ b/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc @@ -30,6 +30,10 @@ // dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <stdlib.h> diff --git a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc index 9ceea109..12b27e68 100644 --- a/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc +++ b/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc @@ -32,6 +32,10 @@ // information generated when with splitting optimizations such as // -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc). +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <stdlib.h> diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc index 7664377c..31deb9db 100644 --- a/src/common/dwarf/elf_reader.cc +++ b/src/common/dwarf/elf_reader.cc @@ -30,6 +30,10 @@ #define _GNU_SOURCE // needed for pread() #endif +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <fcntl.h> #include <limits.h> #include <string.h> diff --git a/src/common/dwarf/functioninfo.cc b/src/common/dwarf/functioninfo.cc index d8fdb842..5b0ce81a 100644 --- a/src/common/dwarf/functioninfo.cc +++ b/src/common/dwarf/functioninfo.cc @@ -29,6 +29,10 @@ // This is a client for the dwarf2reader to extract function and line // information from the debug info. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> #include <limits.h> #include <stdio.h> diff --git a/src/common/dwarf_cfi_to_module.cc b/src/common/dwarf_cfi_to_module.cc index 7da8507d..4c594175 100644 --- a/src/common/dwarf_cfi_to_module.cc +++ b/src/common/dwarf_cfi_to_module.cc @@ -33,6 +33,10 @@ // Implementation of google_breakpad::DwarfCFIToModule. // See dwarf_cfi_to_module.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <memory> #include <sstream> #include <utility> @@ -143,6 +147,29 @@ vector<string> DwarfCFIToModule::RegisterNames::MIPS() { sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); } +vector<string> DwarfCFIToModule::RegisterNames::RISCV() { + static const char *const names[] = { + "pc", "ra", "sp", "gp", "tp", "t0", "t1", "t2", + "s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "", "", "", "", "", "", "", "", + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" + }; + + return MakeVector(names, sizeof(names) / sizeof(names[0])); +} + bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length, uint8_t version, const string& augmentation, unsigned return_address) { diff --git a/src/common/dwarf_cfi_to_module.h b/src/common/dwarf_cfi_to_module.h index 42b618d5..19297db9 100644 --- a/src/common/dwarf_cfi_to_module.h +++ b/src/common/dwarf_cfi_to_module.h @@ -114,6 +114,9 @@ class DwarfCFIToModule: public CallFrameInfo::Handler { // MIPS. static vector<string> MIPS(); + // RISC-V. + static vector<string> RISCV(); + private: // Given STRINGS, an array of C strings with SIZE elements, return an // equivalent vector<string>. diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_to_module_unittest.cc index 0b677b21..52653ec6 100644 --- a/src/common/dwarf_cfi_to_module_unittest.cc +++ b/src/common/dwarf_cfi_to_module_unittest.cc @@ -30,6 +30,10 @@ // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string> #include <vector> @@ -303,3 +307,15 @@ TEST(RegisterNames, X86_64) { EXPECT_EQ("$rsp", names[7]); EXPECT_EQ("$rip", names[16]); } + +TEST(RegisterNames, RISCV) { + vector<string> names = DwarfCFIToModule::RegisterNames::RISCV(); + + EXPECT_EQ("pc", names[0]); + EXPECT_EQ("t6", names[31]); + EXPECT_EQ("f0", names[32]); + EXPECT_EQ("f31", names[63]); + EXPECT_EQ("v0", names[96]); + EXPECT_EQ("v31", names[127]); +} + diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index a5a1fd06..94a0d428 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -35,6 +35,10 @@ #define __STDC_FORMAT_MACROS #endif /* __STDC_FORMAT_MACROS */ +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/dwarf_cu_to_module.h" #include <assert.h> @@ -165,19 +169,23 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( // parsing. This is for data shared across the CU's entire DIE tree, // and parameters from the code invoking the CU parser. struct DwarfCUToModule::CUContext { - CUContext(FileContext* file_context_arg, WarningReporter* reporter_arg, - RangesHandler* ranges_handler_arg) + CUContext(FileContext* file_context_arg, + WarningReporter* reporter_arg, + RangesHandler* ranges_handler_arg, + uint64_t low_pc, + uint64_t addr_base) : version(0), file_context(file_context_arg), reporter(reporter_arg), ranges_handler(ranges_handler_arg), language(Language::CPlusPlus), - low_pc(0), + low_pc(low_pc), high_pc(0), ranges_form(DW_FORM_sec_offset), ranges_data(0), ranges_base(0), - str_offsets_base(0) { } + addr_base(addr_base), + str_offsets_base(0) {} ~CUContext() { for (vector<Module::Function*>::iterator it = functions.begin(); @@ -326,7 +334,10 @@ class DwarfCUToModule::GenericDIEHandler: public DIEHandler { // Use this from EndAttributes member functions, not ProcessAttribute* // functions; only the former can be sure that all the DIE's attributes // have been seen. - StringView ComputeQualifiedName(); + // + // On return, if has_qualified_name is non-NULL, *has_qualified_name is set to + // true if the DIE includes a fully-qualified name, false otherwise. + StringView ComputeQualifiedName(bool* has_qualified_name); CUContext* cu_context_; DIEContext* parent_context_; @@ -462,7 +473,8 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( } } -StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { +StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName( + bool* has_qualified_name) { // Use the demangled name, if one is available. Demangled names are // preferable to those inferred from the DWARF structure because they // include argument types. @@ -478,6 +490,15 @@ StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { StringView* unqualified_name = nullptr; StringView* enclosing_name = nullptr; if (!qualified_name) { + if (has_qualified_name) { + // dSYMs built with -gmlt do not include the DW_AT_linkage_name + // with the unmangled symbol, but rather include it in the + // LC_SYMTAB STABS, which end up in the externs of the module. + // + // Remember this so the Module can copy over the extern name later. + *has_qualified_name = false; + } + // Find the unqualified name. If the DIE has its own DW_AT_name // attribute, then use that; otherwise, check the specification. if (!name_attribute_.empty()) { @@ -496,6 +517,10 @@ StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { } else if (parent_context_) { enclosing_name = &parent_context_->name; } + } else { + if (has_qualified_name) { + *has_qualified_name = true; + } } // Prepare the return value before upcoming mutations possibly invalidate the @@ -554,6 +579,7 @@ class DwarfCUToModule::InlineHandler : public GenericDIEHandler { ranges_data_(0), call_site_line_(0), inline_nest_level_(inline_nest_level), + has_range_data_(false), inlines_(inlines) {} void ProcessAttributeUnsigned(enum DwarfAttribute attr, @@ -575,6 +601,7 @@ class DwarfCUToModule::InlineHandler : public GenericDIEHandler { int call_site_line_; // DW_AT_call_line int call_site_file_id_; // DW_AT_call_file int inline_nest_level_; + bool has_range_data_; // A vector of inlines in the same nest level. It's owned by its parent // function/inline. At Finish(), add this inline into the vector. vector<unique_ptr<Module::Inline>>& inlines_; @@ -595,6 +622,7 @@ void DwarfCUToModule::InlineHandler::ProcessAttributeUnsigned( high_pc_ = data; break; case DW_AT_ranges: + has_range_data_ = true; ranges_data_ = data; ranges_form_ = form; break; @@ -638,7 +666,7 @@ bool DwarfCUToModule::InlineHandler::EndAttributes() { void DwarfCUToModule::InlineHandler::Finish() { vector<Module::Range> ranges; - if (low_pc_ && high_pc_) { + if (!has_range_data_) { if (high_pc_form_ != DW_FORM_addr && high_pc_form_ != DW_FORM_GNU_addr_index && high_pc_form_ != DW_FORM_addrx && @@ -675,11 +703,12 @@ void DwarfCUToModule::InlineHandler::Finish() { // Every DW_TAG_inlined_subroutine should have a DW_AT_abstract_origin. assert(specification_offset_ != 0); - cu_context_->file_context->module_->inline_origin_map.SetReference( - specification_offset_, specification_offset_); + Module::InlineOriginMap& inline_origin_map = + cu_context_->file_context->module_ + ->inline_origin_maps[cu_context_->file_context->filename_]; + inline_origin_map.SetReference(specification_offset_, specification_offset_); Module::InlineOrigin* origin = - cu_context_->file_context->module_->inline_origin_map - .GetOrCreateInlineOrigin(specification_offset_, name_); + inline_origin_map.GetOrCreateInlineOrigin(specification_offset_, name_); unique_ptr<Module::Inline> in( new Module::Inline(origin, ranges, call_site_line_, call_site_file_id_, inline_nest_level_, std::move(child_inlines_))); @@ -718,7 +747,9 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { ranges_form_(DW_FORM_sec_offset), ranges_data_(0), inline_(false), - handle_inline_(handle_inline) {} + handle_inline_(handle_inline), + has_qualified_name_(false), + has_range_data_(false) {} void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, @@ -741,6 +772,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { bool inline_; vector<unique_ptr<Module::Inline>> child_inlines_; bool handle_inline_; + bool has_qualified_name_; + bool has_range_data_; DIEContext child_context_; // A context for our children. }; @@ -760,6 +793,7 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( high_pc_ = data; break; case DW_AT_ranges: + has_range_data_ = true; ranges_data_ = data; ranges_form_ = form; break; @@ -804,7 +838,7 @@ DIEHandler* DwarfCUToModule::FuncHandler::FindChildHandler( bool DwarfCUToModule::FuncHandler::EndAttributes() { // Compute our name, and record a specification, if appropriate. - name_ = ComputeQualifiedName(); + name_ = ComputeQualifiedName(&has_qualified_name_); if (name_.empty() && abstract_origin_) { name_ = abstract_origin_->name; } @@ -830,7 +864,7 @@ void DwarfCUToModule::FuncHandler::Finish() { iter->second->name = name_; } - if (!ranges_data_) { + if (!has_range_data_) { // Make high_pc_ an address, if it isn't already. if (high_pc_form_ != DW_FORM_addr && high_pc_form_ != DW_FORM_GNU_addr_index && @@ -877,6 +911,9 @@ void DwarfCUToModule::FuncHandler::Finish() { scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_)); func->ranges = ranges; func->parameter_size = 0; + // If the name was unqualified, prefer the Extern name if there's a mismatch + // (the Extern name will be fully-qualified in that case). + func->prefer_extern_name = !has_qualified_name_; if (func->address) { // If the function address is zero this is a sign that this function // description is just empty debug data and should just be discarded. @@ -903,15 +940,16 @@ void DwarfCUToModule::FuncHandler::Finish() { StringView name = name_.empty() ? name_omitted : name_; uint64_t offset = specification_offset_ != 0 ? specification_offset_ : offset_; - cu_context_->file_context->module_->inline_origin_map.SetReference(offset_, - offset); - cu_context_->file_context->module_->inline_origin_map - .GetOrCreateInlineOrigin(offset_, name); + Module::InlineOriginMap& inline_origin_map = + cu_context_->file_context->module_ + ->inline_origin_maps[cu_context_->file_context->filename_]; + inline_origin_map.SetReference(offset_, offset); + inline_origin_map.GetOrCreateInlineOrigin(offset_, name); } } bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { - child_context_.name = ComputeQualifiedName(); + child_context_.name = ComputeQualifiedName(NULL); if (child_context_.name.empty() && no_specification) { cu_context_->reporter->UnknownSpecification(offset_, specification_offset_); } @@ -1041,12 +1079,21 @@ DwarfCUToModule::DwarfCUToModule(FileContext* file_context, LineToModuleHandler* line_reader, RangesHandler* ranges_handler, WarningReporter* reporter, - bool handle_inline) + bool handle_inline, + uint64_t low_pc, + uint64_t addr_base, + bool has_source_line_info, + uint64_t source_line_offset) : RootDIEHandler(handle_inline), line_reader_(line_reader), - cu_context_(new CUContext(file_context, reporter, ranges_handler)), + cu_context_(new CUContext(file_context, + reporter, + ranges_handler, + low_pc, + addr_base)), child_context_(new DIEContext()), - has_source_line_info_(false) {} + has_source_line_info_(has_source_line_info), + source_line_offset_(source_line_offset) {} DwarfCUToModule::~DwarfCUToModule() { } diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h index 5a800104..1ff0ebc7 100644 --- a/src/common/dwarf_cu_to_module.h +++ b/src/common/dwarf_cu_to_module.h @@ -264,7 +264,11 @@ class DwarfCUToModule: public RootDIEHandler { LineToModuleHandler* line_reader, RangesHandler* ranges_handler, WarningReporter* reporter, - bool handle_inline = false); + bool handle_inline = false, + uint64_t low_pc = 0, + uint64_t addr_base = 0, + bool has_source_line_info = false, + uint64_t source_line_offset = 0); ~DwarfCUToModule(); void ProcessAttributeSigned(enum DwarfAttribute attr, diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc index f3fa4903..134b2c24 100644 --- a/src/common/dwarf_cu_to_module_unittest.cc +++ b/src/common/dwarf_cu_to_module_unittest.cc @@ -30,6 +30,10 @@ // dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdint.h> #include <string> @@ -263,6 +267,10 @@ class CUFixtureBase { void TestFunction(int i, const string& name, Module::Address address, Module::Address size); + // Test that the I'th function (ordered by address) in the module + // this.module_ has the given prefer_extern_name. + void TestFunctionPreferExternName(int i, bool prefer_extern_name); + // Test that the number of source lines owned by the I'th function // in the module this.module_ is equal to EXPECTED. void TestLineCount(int i, size_t expected); @@ -611,6 +619,15 @@ void CUFixtureBase::TestFunction(int i, const string& name, EXPECT_EQ(0U, function->parameter_size); } +void CUFixtureBase::TestFunctionPreferExternName(int i, + bool prefer_extern_name) { + FillFunctions(); + ASSERT_LT((size_t)i, functions_.size()); + + Module::Function* function = functions_[i]; + EXPECT_EQ(prefer_extern_name, function->prefer_extern_name); +} + void CUFixtureBase::TestLineCount(int i, size_t expected) { FillFunctions(); ASSERT_LT((size_t) i, functions_.size()); diff --git a/src/common/dwarf_line_to_module.cc b/src/common/dwarf_line_to_module.cc index e716d483..940ab2d6 100644 --- a/src/common/dwarf_line_to_module.cc +++ b/src/common/dwarf_line_to_module.cc @@ -31,6 +31,10 @@ // dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. // See dwarf_line_to_module.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdio.h> #include <string> diff --git a/src/common/dwarf_line_to_module_unittest.cc b/src/common/dwarf_line_to_module_unittest.cc index c4a02dfa..9eb1469f 100644 --- a/src/common/dwarf_line_to_module_unittest.cc +++ b/src/common/dwarf_line_to_module_unittest.cc @@ -30,6 +30,10 @@ // dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <vector> #include "breakpad_googletest_includes.h" diff --git a/src/common/dwarf_range_list_handler.cc b/src/common/dwarf_range_list_handler.cc index 4d3dbd2e..c40a5c3b 100644 --- a/src/common/dwarf_range_list_handler.cc +++ b/src/common/dwarf_range_list_handler.cc @@ -32,6 +32,10 @@ // dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class. // See dwarf_range_list_handler.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <algorithm> #include "common/dwarf_range_list_handler.h" diff --git a/src/common/language.cc b/src/common/language.cc index 0096a8d1..61693a8c 100644 --- a/src/common/language.cc +++ b/src/common/language.cc @@ -31,6 +31,10 @@ // language.cc: Subclasses and singletons for google_breakpad::Language. // See language.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/language.h" #include <stdlib.h> diff --git a/src/common/linux/breakpad_getcontext.h b/src/common/linux/breakpad_getcontext.h index c553219f..d64784d4 100644 --- a/src/common/linux/breakpad_getcontext.h +++ b/src/common/linux/breakpad_getcontext.h @@ -29,10 +29,6 @@ #ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H #define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifndef HAVE_GETCONTEXT #include <signal.h> diff --git a/src/common/linux/breakpad_getcontext_unittest.cc b/src/common/linux/breakpad_getcontext_unittest.cc index 573ddd88..5b340eb7 100644 --- a/src/common/linux/breakpad_getcontext_unittest.cc +++ b/src/common/linux/breakpad_getcontext_unittest.cc @@ -29,6 +29,10 @@ // asm/sigcontext.h can't be included with signal.h on glibc or // musl, so only compare _libc_fpstate and _fpstate on Android. #if defined(__ANDROID__) && defined(__x86_64__) +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <asm/sigcontext.h> #endif diff --git a/src/common/linux/crc32.cc b/src/common/linux/crc32.cc index c02f06c4..cf386a24 100644 --- a/src/common/linux/crc32.cc +++ b/src/common/linux/crc32.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/crc32.h" namespace google_breakpad { diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index b436f765..b693fc9e 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -31,6 +31,10 @@ // dump_symbols.cc: implement google_breakpad::WriteSymbolFile: // Find all the debugging info in a file and dump it as a Breakpad symbol file. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/dump_symbols.h" #include <assert.h> @@ -47,6 +51,9 @@ #include <sys/stat.h> #include <unistd.h> #include <zlib.h> +#ifdef HAVE_LIBZSTD +#include <zstd.h> +#endif #include <set> #include <string> @@ -104,6 +111,11 @@ using google_breakpad::wasteful_vector; #define EM_AARCH64 183 #endif +// Define ZStd compression if host machine does not include this define. +#ifndef ELFCOMPRESS_ZSTD +#define ELFCOMPRESS_ZSTD 2 +#endif + // // FDWrapper // @@ -301,7 +313,7 @@ uint32_t GetCompressionHeader( return sizeof (*header); } -std::pair<uint8_t *, uint64_t> UncompressSectionContents( +std::pair<uint8_t *, uint64_t> UncompressZlibSectionContents( const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { z_stream stream; memset(&stream, 0, sizeof stream); @@ -330,6 +342,90 @@ std::pair<uint8_t *, uint64_t> UncompressSectionContents( : std::make_pair(uncompressed_buffer.release(), uncompressed_size); } +#ifdef HAVE_LIBZSTD +std::pair<uint8_t *, uint64_t> UncompressZstdSectionContents( + const uint8_t* compressed_buffer, uint64_t compressed_size,uint64_t uncompressed_size) { + + google_breakpad::scoped_array<uint8_t> uncompressed_buffer(new uint8_t[uncompressed_size]); + size_t out_size = ZSTD_decompress(uncompressed_buffer.get(), uncompressed_size, + compressed_buffer, compressed_size); + if (ZSTD_isError(out_size)) { + return std::make_pair(nullptr, 0); + } + assert(out_size == uncompressed_size); + return std::make_pair(uncompressed_buffer.release(), uncompressed_size); +} +#endif + +std::pair<uint8_t *, uint64_t> UncompressSectionContents( + uint64_t compression_type, const uint8_t* compressed_buffer, + uint64_t compressed_size, uint64_t uncompressed_size) { + if (compression_type == ELFCOMPRESS_ZLIB) { + return UncompressZlibSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } + +#ifdef HAVE_LIBZSTD + if (compression_type == ELFCOMPRESS_ZSTD) { + return UncompressZstdSectionContents(compressed_buffer, compressed_size, uncompressed_size); + } +#endif + + return std::make_pair(nullptr, 0); +} + +void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (!reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + template<typename ElfClass> bool LoadDwarf(const string& dwarf_filename, const typename ElfClass::Ehdr* elf_header, @@ -380,7 +476,7 @@ bool LoadDwarf(const string& dwarf_filename, size -= compression_header_size; std::pair<uint8_t *, uint64_t> uncompressed = - UncompressSectionContents(contents, size, chdr.ch_size); + UncompressSectionContents(chdr.ch_type, contents, size, chdr.ch_size); if (uncompressed.first != nullptr && uncompressed.second != 0) { file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second); @@ -417,6 +513,11 @@ bool LoadDwarf(const string& dwarf_filename, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += reader.Start(); + // Start to process split dwarf file. + if (reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&reader, module, endianness, handle_inter_cu_refs, + handle_inline); + } } return true; } @@ -445,6 +546,9 @@ bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, case EM_X86_64: *register_names = DwarfCFIToModule::RegisterNames::X86_64(); return true; + case EM_RISCV: + *register_names = DwarfCFIToModule::RegisterNames::RISCV(); + return true; default: return false; } @@ -522,7 +626,7 @@ bool LoadDwarfCFI(const string& dwarf_filename, cfi_size -= compression_header_size; std::pair<uint8_t *, uint64_t> uncompressed = - UncompressSectionContents(cfi, cfi_size, chdr.ch_size); + UncompressSectionContents(chdr.ch_type, cfi, cfi_size, chdr.ch_size); if (uncompressed.first == nullptr || uncompressed.second == 0) { fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str()); @@ -1018,6 +1122,7 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { case EM_SPARC: return "sparc"; case EM_SPARCV9: return "sparcv9"; case EM_X86_64: return "x86_64"; + case EM_RISCV: return "riscv"; default: return NULL; } } diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 97d5827e..55dcdeed 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -31,6 +31,10 @@ // dump_symbols_unittest.cc: // Unittests for google_breakpad::DumpSymbols +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <link.h> #include <stdio.h> diff --git a/src/common/linux/elf_core_dump.cc b/src/common/linux/elf_core_dump.cc index f5ee3033..67257fd2 100644 --- a/src/common/linux/elf_core_dump.cc +++ b/src/common/linux/elf_core_dump.cc @@ -29,6 +29,10 @@ // elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. // See elf_core_dump.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/elf_core_dump.h" #include <stddef.h> diff --git a/src/common/linux/elf_core_dump_unittest.cc b/src/common/linux/elf_core_dump_unittest.cc index 6789dd84..25cab99f 100644 --- a/src/common/linux/elf_core_dump_unittest.cc +++ b/src/common/linux/elf_core_dump_unittest.cc @@ -28,6 +28,10 @@ // elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <sys/procfs.h> #include <set> diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc index 3c33be99..70d50f89 100644 --- a/src/common/linux/elf_symbols_to_module.cc +++ b/src/common/linux/elf_symbols_to_module.cc @@ -30,6 +30,10 @@ // Original author: Ted Mielczarek <ted.mielczarek@gmail.com> +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/elf_symbols_to_module.h" #include <cxxabi.h> diff --git a/src/common/linux/elf_symbols_to_module_unittest.cc b/src/common/linux/elf_symbols_to_module_unittest.cc index 17eb670f..a74b29f0 100644 --- a/src/common/linux/elf_symbols_to_module_unittest.cc +++ b/src/common/linux/elf_symbols_to_module_unittest.cc @@ -31,6 +31,10 @@ // elf_symbols_to_module_unittest.cc: // Unittests for google_breakpad::ELFSymbolsToModule +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <string> diff --git a/src/common/linux/elfutils.cc b/src/common/linux/elfutils.cc index a68cc0af..95b5db82 100644 --- a/src/common/linux/elfutils.cc +++ b/src/common/linux/elfutils.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/elfutils.h" #include <assert.h> diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc index 0bd2a759..d8fcbd8d 100644 --- a/src/common/linux/file_id.cc +++ b/src/common/linux/file_id.cc @@ -31,6 +31,10 @@ // See file_id.h for documentation // +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/file_id.h" #include <arpa/inet.h> diff --git a/src/common/linux/file_id_unittest.cc b/src/common/linux/file_id_unittest.cc index 74bf9e1b..0ef45353 100644 --- a/src/common/linux/file_id_unittest.cc +++ b/src/common/linux/file_id_unittest.cc @@ -28,6 +28,10 @@ // Unit tests for FileID +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <spawn.h> #include <stdlib.h> diff --git a/src/common/linux/google_crashdump_uploader.cc b/src/common/linux/google_crashdump_uploader.cc index 6242e6d2..8c5e0492 100644 --- a/src/common/linux/google_crashdump_uploader.cc +++ b/src/common/linux/google_crashdump_uploader.cc @@ -27,6 +27,10 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/google_crashdump_uploader.h" #include <sys/types.h> diff --git a/src/common/linux/google_crashdump_uploader_test.cc b/src/common/linux/google_crashdump_uploader_test.cc index 39aab65d..e81f21d6 100644 --- a/src/common/linux/google_crashdump_uploader_test.cc +++ b/src/common/linux/google_crashdump_uploader_test.cc @@ -28,6 +28,10 @@ // Unit test for crash dump uploader. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string> #include "common/linux/google_crashdump_uploader.h" diff --git a/src/common/linux/guid_creator.cc b/src/common/linux/guid_creator.cc index 31a326c7..8635f9dc 100644 --- a/src/common/linux/guid_creator.cc +++ b/src/common/linux/guid_creator.cc @@ -27,7 +27,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef HAVE_CONFIG_H -#include <config.h> +#include <config.h> // Must come first #endif #include "common/linux/eintr_wrapper.h" diff --git a/src/common/linux/http_upload.cc b/src/common/linux/http_upload.cc index 1b576ea6..0a5bdb50 100644 --- a/src/common/linux/http_upload.cc +++ b/src/common/linux/http_upload.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/http_upload.h" #include <assert.h> diff --git a/src/common/linux/libcurl_wrapper.cc b/src/common/linux/libcurl_wrapper.cc index a53087d9..2b639098 100644 --- a/src/common/linux/libcurl_wrapper.cc +++ b/src/common/linux/libcurl_wrapper.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <dlfcn.h> #include <iostream> @@ -303,12 +307,10 @@ bool LibcurlWrapper::SendRequestInner(const string& url, (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); } -#ifndef NDEBUG if (err_code != CURLE_OK) fprintf(stderr, "Failed to send http request to %s, error: %s\n", url.c_str(), (*easy_strerror_)(err_code)); -#endif Reset(); diff --git a/src/common/linux/linux_libc_support.cc b/src/common/linux/linux_libc_support.cc index 10cbeaef..abcbfde8 100644 --- a/src/common/linux/linux_libc_support.cc +++ b/src/common/linux/linux_libc_support.cc @@ -30,6 +30,10 @@ // we call the libc functions directly we risk crashing in the dynamic linker // as it tries to resolve uncached PLT entries. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/linux_libc_support.h" #include <stddef.h> diff --git a/src/common/linux/linux_libc_support_unittest.cc b/src/common/linux/linux_libc_support_unittest.cc index 449f995f..30dd1430 100644 --- a/src/common/linux/linux_libc_support_unittest.cc +++ b/src/common/linux/linux_libc_support_unittest.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/linux/linux_libc_support.h" diff --git a/src/common/linux/memory_mapped_file.cc b/src/common/linux/memory_mapped_file.cc index 7e444607..a7b96eb5 100644 --- a/src/common/linux/memory_mapped_file.cc +++ b/src/common/linux/memory_mapped_file.cc @@ -29,6 +29,10 @@ // memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile. // See memory_mapped_file.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/memory_mapped_file.h" #include <fcntl.h> @@ -57,8 +61,11 @@ MemoryMappedFile::~MemoryMappedFile() { bool MemoryMappedFile::Map(const char* path, size_t offset) { Unmap(); - - int fd = sys_open(path, O_RDONLY, 0); + // Based on https://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html + // If O_NONBLOCK is set: The open() function will return without blocking + // for the device to be ready or available. Setting this value will provent + // hanging if file is not avilable. + int fd = sys_open(path, O_RDONLY | O_NONBLOCK, 0); if (fd == -1) { return false; } diff --git a/src/common/linux/memory_mapped_file.h b/src/common/linux/memory_mapped_file.h index d4a85051..462e116e 100644 --- a/src/common/linux/memory_mapped_file.h +++ b/src/common/linux/memory_mapped_file.h @@ -33,7 +33,7 @@ #define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ #include <stddef.h> -#include "common/basictypes.h" + #include "common/memory_range.h" namespace google_breakpad { @@ -49,6 +49,9 @@ class MemoryMappedFile { // If Map() fails, the object behaves as if it is default constructed. MemoryMappedFile(const char* path, size_t offset); + MemoryMappedFile(const MemoryMappedFile&) = delete; + void operator=(const MemoryMappedFile&) = delete; + ~MemoryMappedFile(); // Maps a file at |path| into memory, which can then be accessed via @@ -77,8 +80,6 @@ class MemoryMappedFile { private: // Mapped file content as a MemoryRange object. MemoryRange content_; - - DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); }; } // namespace google_breakpad diff --git a/src/common/linux/memory_mapped_file_unittest.cc b/src/common/linux/memory_mapped_file_unittest.cc index 5ed677df..b7a61a70 100644 --- a/src/common/linux/memory_mapped_file_unittest.cc +++ b/src/common/linux/memory_mapped_file_unittest.cc @@ -29,6 +29,10 @@ // memory_mapped_file_unittest.cc: // Unit tests for google_breakpad::MemoryMappedFile. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <fcntl.h> #include <string.h> #include <unistd.h> diff --git a/src/common/linux/safe_readlink.cc b/src/common/linux/safe_readlink.cc index 97ea62c0..a42b01a5 100644 --- a/src/common/linux/safe_readlink.cc +++ b/src/common/linux/safe_readlink.cc @@ -29,6 +29,10 @@ // safe_readlink.cc: Implement google_breakpad::SafeReadLink. // See safe_readlink.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stddef.h> #include "third_party/lss/linux_syscall_support.h" diff --git a/src/common/linux/safe_readlink_unittest.cc b/src/common/linux/safe_readlink_unittest.cc index 6f5f9d75..8fa6d065 100644 --- a/src/common/linux/safe_readlink_unittest.cc +++ b/src/common/linux/safe_readlink_unittest.cc @@ -28,6 +28,10 @@ // safe_readlink_unittest.cc: Unit tests for google_breakpad::SafeReadLink. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/linux/safe_readlink.h" diff --git a/src/common/linux/scoped_pipe.cc b/src/common/linux/scoped_pipe.cc new file mode 100644 index 00000000..8de04ce9 --- /dev/null +++ b/src/common/linux/scoped_pipe.cc @@ -0,0 +1,132 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// 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 LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_pipe.h" + +#include <unistd.h> + +#include "common/linux/eintr_wrapper.h" + +namespace google_breakpad { + +ScopedPipe::ScopedPipe() { + fds_[0] = -1; + fds_[1] = -1; +} + +ScopedPipe::~ScopedPipe() { + CloseReadFd(); + CloseWriteFd(); +} + +bool ScopedPipe::Init() { + return pipe(fds_) == 0; +} + +void ScopedPipe::CloseReadFd() { + if (fds_[0] != -1) { + close(fds_[0]); + fds_[0] = -1; + } +} + +void ScopedPipe::CloseWriteFd() { + if (fds_[1] != -1) { + close(fds_[1]); + fds_[1] = -1; + } +} + +bool ScopedPipe::ReadLine(std::string& line) { + // Simple buffered file read. `read_buffer_` stores previously read bytes, and + // we either return a line from this buffer, or we append blocks of read bytes + // to the buffer until we have a complete line. + size_t eol_index = read_buffer_.find('\n'); + + // While we don't have a full line, and read pipe is valid. + while (eol_index == std::string::npos && GetReadFd() != -1) { + // Read a block of 128 bytes from the read pipe. + char read_buf[128]; + ssize_t read_len = HANDLE_EINTR( + read(GetReadFd(), read_buf, sizeof(read_buf))); + if (read_len <= 0) { + // Pipe error, or pipe has been closed. + CloseReadFd(); + break; + } + + // Append the block, and check if we have a full line now. + read_buffer_.append(read_buf, read_len); + eol_index = read_buffer_.find('\n'); + } + + if (eol_index != std::string::npos) { + // We have a full line to output. + line = read_buffer_.substr(0, eol_index); + if (eol_index < read_buffer_.size()) { + read_buffer_ = read_buffer_.substr(eol_index + 1); + } else { + read_buffer_ = ""; + } + + return true; + } + + if (read_buffer_.size()) { + // We don't have a full line to output, but we can only reach here if the + // pipe has closed and there are some bytes left at the end, so we should + // return those bytes. + line = std::move(read_buffer_); + read_buffer_ = ""; + + return true; + } + + // We don't have any buffered data left, and the pipe has closed. + return false; +} + +int ScopedPipe::Dup2WriteFd(int new_fd) const { + return dup2(fds_[1], new_fd); +} + +bool ScopedPipe::WriteForTesting(const void* bytes, size_t bytes_len) { + ssize_t r = HANDLE_EINTR(write(GetWriteFd(), bytes, bytes_len)); + if (r != static_cast<ssize_t>(bytes_len)) { + CloseWriteFd(); + return false; + } + + return true; +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_pipe.h b/src/common/linux/scoped_pipe.h new file mode 100644 index 00000000..25394c2a --- /dev/null +++ b/src/common/linux/scoped_pipe.h @@ -0,0 +1,115 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// 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 LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_LINUX_SCOPED_PIPE_H_ +#define COMMON_LINUX_SCOPED_PIPE_H_ + +#include <stdint.h> +#include <string> + +namespace google_breakpad { + +// Small RAII wrapper for a pipe pair. +// +// Example (both ends of pipe in same process): +// ScopedPipe tmp; +// std::string line; +// if (tmp.Init() && tmp.Write(bytes, bytes_len)) { +// tmp.CloseWriteFd(); +// while (tmp.ReadLine(&line)) { +// std::cerr << line << std::endl; +// } +// } +// +// Example (reading output from a child process): +// ScopedPipe tmp; +// if (fork()) { +// // Parent process, read from the read end of the pipe. +// std::string line; +// while (tmp.ReadLine(line)) { +// // Process output... +// } +// // Close read pipe once done processing the output that we wanted, this +// // should ensure that the child process exits even if we didn't read all +// // of the output. +// tmp.CloseReadFd(); +// // Parent process should handle waiting for child to exit here... +// } else { +// // Child process, close the read fd and dup the write fd before exec'ing. +// tmp.CloseReadFd(); +// tmp.Dup2WriteFd(STDOUT_FILENO); +// tmp.Dup2WriteFd(STDERR_FILENO); +// execl("some-command", "some-arguments"); +// } +class ScopedPipe { + public: + ScopedPipe(); + ~ScopedPipe(); + + // Creates the pipe pair - returns false on error. + bool Init(); + + // Close the read pipe. This only needs to be used when the read pipe needs to + // be closed earlier. + void CloseReadFd(); + + // Close the write pipe. This only needs to be used when the write pipe needs + // to be closed earlier. + void CloseWriteFd(); + + // Reads characters until newline or end of pipe. On read failure this will + // close the read pipe, but continue to return true and read buffered lines + // until the internal buffering is exhausted. This will block if there is no + // data available on the read pipe. + bool ReadLine(std::string& line); + + // Writes bytes to the write end of the pipe, returns false and closes write + // pipe on failure. + bool WriteForTesting(const void* bytes, size_t bytes_len); + + // Calls the dup2 system call to replace any existing open file descriptor + // with number new_fd with a copy of the current write end file descriptor + // for the pipe. + int Dup2WriteFd(int new_fd) const; + + private: + int GetReadFd() const { + return fds_[0]; + } + + int GetWriteFd() const { + return fds_[1]; + } + + int fds_[2]; + std::string read_buffer_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SCOPED_PIPE_H_ diff --git a/src/common/linux/scoped_pipe_unittest.cc b/src/common/linux/scoped_pipe_unittest.cc new file mode 100644 index 00000000..4daa5c25 --- /dev/null +++ b/src/common/linux/scoped_pipe_unittest.cc @@ -0,0 +1,75 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// 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 LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// scoped_pipe_unittest.cc: Unit tests for google_breakpad::ScopedPipe. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_pipe.h" + +#include "breakpad_googletest_includes.h" + +namespace google_breakpad { + +TEST(ScopedPipeTest, WriteAndClose) { + const char kTestData[] = "One\nTwo\nThree"; + ScopedPipe pipe; + std::string line; + + ASSERT_TRUE(pipe.Init()); + ASSERT_TRUE(pipe.WriteForTesting(kTestData, strlen(kTestData))); + pipe.CloseWriteFd(); + + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "One"); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Two"); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Three"); + ASSERT_FALSE(pipe.ReadLine(line)); +} + +TEST(ScopedPipeTest, MultipleWrites) { + const char kTestDataOne[] = "One\n"; + const char kTestDataTwo[] = "Two\n"; + ScopedPipe pipe; + std::string line; + + ASSERT_TRUE(pipe.Init()); + ASSERT_TRUE(pipe.WriteForTesting(kTestDataOne, strlen(kTestDataOne))); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "One"); + + ASSERT_TRUE(pipe.WriteForTesting(kTestDataTwo, strlen(kTestDataTwo))); + ASSERT_TRUE(pipe.ReadLine(line)); + ASSERT_EQ(line, "Two"); +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_tmpfile.cc b/src/common/linux/scoped_tmpfile.cc new file mode 100644 index 00000000..2395a64e --- /dev/null +++ b/src/common/linux/scoped_tmpfile.cc @@ -0,0 +1,103 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// 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 LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility class for creating a temporary file that is deleted in the +// destructor. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_tmpfile.h" + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "common/linux/eintr_wrapper.h" + +#if !defined(__ANDROID__) +#define TEMPDIR "/tmp" +#else +#define TEMPDIR "/data/local/tmp" +#endif + +namespace google_breakpad { + +ScopedTmpFile::ScopedTmpFile() = default; + +ScopedTmpFile::~ScopedTmpFile() { + if (fd_ >= 0) { + close(fd_); + fd_ = -1; + } +} + +bool ScopedTmpFile::InitEmpty() { + // Prevent calling Init when fd_ is already valid, leaking the file. + if (fd_ != -1) { + return false; + } + + // Respect the TMPDIR environment variable. + const char* tempdir = getenv("TMPDIR"); + if (!tempdir) { + tempdir = TEMPDIR; + } + + // Create a temporary file that is not linked in to the filesystem, and that + // is only accessible by the current user. + fd_ = open(tempdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); + + return fd_ >= 0; +} + +bool ScopedTmpFile::InitString(const char* text) { + return InitData(text, strlen(text)); +} + +bool ScopedTmpFile::InitData(const void* data, size_t data_len) { + if (!InitEmpty()) { + return false; + } + + return SetContents(data, data_len); +} + +bool ScopedTmpFile::SetContents(const void* data, size_t data_len) { + ssize_t r = HANDLE_EINTR(write(fd_, data, data_len)); + if (r != static_cast<ssize_t>(data_len)) { + return false; + } + + return 0 == lseek(fd_, 0, SEEK_SET); +} + +} // namespace google_breakpad diff --git a/src/common/linux/scoped_tmpfile.h b/src/common/linux/scoped_tmpfile.h new file mode 100644 index 00000000..dffec182 --- /dev/null +++ b/src/common/linux/scoped_tmpfile.h @@ -0,0 +1,85 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// 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 LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility class for creating a temporary file for that is deleted in the +// destructor. + +#ifndef COMMON_LINUX_SCOPED_TMPFILE_H_ +#define COMMON_LINUX_SCOPED_TMPFILE_H_ + +#include <string> + +namespace google_breakpad { + +// Small RAII wrapper for temporary files. +// +// Example: +// ScopedTmpFile tmp; +// if (tmp.Init("Some file contents")) { +// ... +// } +class ScopedTmpFile { + public: + // Initialize the ScopedTmpFile object - this does not create the temporary + // file until Init is called. + ScopedTmpFile(); + + // Destroy temporary file on scope exit. + ~ScopedTmpFile(); + + // Creates the empty temporary file - returns true iff the temporary file was + // created successfully. Should always be checked before using the file. + bool InitEmpty(); + + // Creates the temporary file with the provided C string. The terminating null + // is not written. Returns true iff the temporary file was created + // successfully and the contents were written successfully. + bool InitString(const char* text); + + // Creates the temporary file with the provided data. Returns true iff the + // temporary file was created successfully and the contents were written + // successfully. + bool InitData(const void* data, size_t data_len); + + // Returns the Posix file descriptor for the test file, or -1 if Init() + // returned false. Note: on Windows, this always returns -1. + int GetFd() const { + return fd_; + } + + private: + // Set the contents of the temporary file, and seek back to the start of the + // file. On failure, returns false. + bool SetContents(const void* data, size_t data_len); + + int fd_ = -1; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SCOPED_TMPFILE_H_ diff --git a/src/common/linux/scoped_tmpfile_unittest.cc b/src/common/linux/scoped_tmpfile_unittest.cc new file mode 100644 index 00000000..f0bb2bbb --- /dev/null +++ b/src/common/linux/scoped_tmpfile_unittest.cc @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// 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 LLC nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// scoped_tmpfile_unittest.cc: Unit tests for google_breakpad::ScopedTmpfile. + +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + +#include "common/linux/scoped_tmpfile.h" + +#include <unistd.h> + +#include "breakpad_googletest_includes.h" + +using google_breakpad::ScopedTmpFile; + +TEST(ScopedTmpFileTest, CheckContentsMatch) { + ScopedTmpFile file; + ASSERT_TRUE(file.InitString("Test")); + + char file_contents[5] = {0}; + ASSERT_EQ(4, read(file.GetFd(), file_contents, sizeof(file_contents))); + EXPECT_STREQ(file_contents, "Test"); +} diff --git a/src/common/linux/symbol_collector_client.cc b/src/common/linux/symbol_collector_client.cc index 1c1dc97a..e9a1893c 100644 --- a/src/common/linux/symbol_collector_client.cc +++ b/src/common/linux/symbol_collector_client.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/symbol_collector_client.h" #include <stdio.h> diff --git a/src/common/linux/symbol_upload.cc b/src/common/linux/symbol_upload.cc index c080533a..8ab143c6 100644 --- a/src/common/linux/symbol_upload.cc +++ b/src/common/linux/symbol_upload.cc @@ -29,6 +29,10 @@ // symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper // function for linux symbol upload tool. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/symbol_upload.h" #include <assert.h> diff --git a/src/common/linux/synth_elf.cc b/src/common/linux/synth_elf.cc index 2ba25e61..8e9170e7 100644 --- a/src/common/linux/synth_elf.cc +++ b/src/common/linux/synth_elf.cc @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/synth_elf.h" #include <assert.h> diff --git a/src/common/linux/synth_elf_unittest.cc b/src/common/linux/synth_elf_unittest.cc index 44ef6ef3..578f6a26 100644 --- a/src/common/linux/synth_elf_unittest.cc +++ b/src/common/linux/synth_elf_unittest.cc @@ -31,6 +31,10 @@ // synth_elf_unittest.cc: // Unittests for google_breakpad::synth_elf::ELF +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include "breakpad_googletest_includes.h" diff --git a/src/common/linux/tests/auto_testfile.h b/src/common/linux/tests/auto_testfile.h deleted file mode 100644 index e2d2ff23..00000000 --- a/src/common/linux/tests/auto_testfile.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2013 Google LLC -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// 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 LLC nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Utility class for creating a temporary file for unit tests -// that is deleted in the destructor. - -#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE -#define GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE - -#include <unistd.h> -#include <sys/types.h> - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/linux/eintr_wrapper.h" -#include "common/tests/auto_tempdir.h" - -namespace google_breakpad { - -class AutoTestFile { - public: - // Create a new empty test file. - // test_prefix: (input) test-specific prefix, can't be NULL. - explicit AutoTestFile(const char* test_prefix) { - Init(test_prefix); - } - - // Create a new test file, and fill it with initial data from a C string. - // The terminating zero is not written. - // test_prefix: (input) test-specific prefix, can't be NULL. - // text: (input) initial content. - AutoTestFile(const char* test_prefix, const char* text) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, static_cast<size_t>(strlen(text))); - } - - AutoTestFile(const char* test_prefix, const char* text, size_t text_len) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, text_len); - } - - // Destroy test file on scope exit. - ~AutoTestFile() { - if (fd_ >= 0) { - close(fd_); - fd_ = -1; - } - } - - // Returns true iff the test file could be created properly. - // Useful in tests inside EXPECT_TRUE(file.IsOk()); - bool IsOk() { - return fd_ >= 0; - } - - // Returns the Posix file descriptor for the test file, or -1 - // If IsOk() returns false. Note: on Windows, this always returns -1. - int GetFd() { - return fd_; - } - - private: - void Init(const char* test_prefix) { - fd_ = -1; - char path_templ[PATH_MAX]; - int ret = snprintf(path_templ, sizeof(path_templ), - TEMPDIR "/%s-unittest.XXXXXX", - test_prefix); - if (ret >= static_cast<int>(sizeof(path_templ))) - return; - - fd_ = mkstemp(path_templ); - if (fd_ < 0) - return; - - unlink(path_templ); - } - - void WriteText(const char* text, size_t text_len) { - ssize_t r = HANDLE_EINTR(write(fd_, text, text_len)); - if (r != static_cast<ssize_t>(text_len)) { - close(fd_); - fd_ = -1; - return; - } - - lseek(fd_, 0, SEEK_SET); - } - - int fd_; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE diff --git a/src/common/linux/tests/crash_generator.cc b/src/common/linux/tests/crash_generator.cc index 0db0c4a2..1cad9ae2 100644 --- a/src/common/linux/tests/crash_generator.cc +++ b/src/common/linux/tests/crash_generator.cc @@ -29,6 +29,10 @@ // crash_generator.cc: Implement google_breakpad::CrashGenerator. // See crash_generator.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/linux/tests/crash_generator.h" #include <pthread.h> diff --git a/src/common/long_string_dictionary.cc b/src/common/long_string_dictionary.cc index f504aa42..19a649e7 100644 --- a/src/common/long_string_dictionary.cc +++ b/src/common/long_string_dictionary.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/long_string_dictionary.h" #include <assert.h> diff --git a/src/common/long_string_dictionary_unittest.cc b/src/common/long_string_dictionary_unittest.cc index be34efdf..f10dc0d9 100644 --- a/src/common/long_string_dictionary_unittest.cc +++ b/src/common/long_string_dictionary_unittest.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <algorithm> #include <string> diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc index 392efe78..96340d54 100644 --- a/src/common/mac/arch_utilities.cc +++ b/src/common/mac/arch_utilities.cc @@ -26,113 +26,22 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/arch_utilities.h" +#include <mach/machine.h> #include <mach-o/arch.h> #include <mach-o/fat.h> #include <stdio.h> #include <string.h> -#ifndef CPU_SUBTYPE_ARM_V7S -#define CPU_SUBTYPE_ARM_V7S (static_cast<cpu_subtype_t>(11)) -#endif // CPU_SUBTYPE_ARM_V7S - -#ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) -#endif // CPU_TYPE_ARM64 - -#ifndef CPU_SUBTYPE_ARM64_ALL -#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_subtype_t>(0)) -#endif // CPU_SUBTYPE_ARM64_ALL - -#ifndef CPU_SUBTYPE_ARM64_E -#define CPU_SUBTYPE_ARM64_E (static_cast<cpu_subtype_t>(2)) -#endif // CPU_SUBTYPE_ARM64_E - -namespace { - -const NXArchInfo* ArchInfo_arm64(cpu_subtype_t cpu_subtype) { - const char* name = NULL; - switch (cpu_subtype) { - case CPU_SUBTYPE_ARM64_ALL: - name = "arm64"; - break; - case CPU_SUBTYPE_ARM64_E: - name = "arm64e"; - break; - default: - return NULL; - } - - NXArchInfo* arm64 = new NXArchInfo; - *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_V7); - arm64->name = name; - arm64->cputype = CPU_TYPE_ARM64; - arm64->cpusubtype = cpu_subtype; - arm64->description = "arm 64"; - return arm64; -} - -const NXArchInfo* ArchInfo_armv7s() { - NXArchInfo* armv7s = new NXArchInfo; - *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_V7); - armv7s->name = "armv7s"; - armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S; - armv7s->description = "arm v7s"; - return armv7s; -} - -} // namespace - -namespace google_breakpad { - -const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) { - // TODO: Remove this when the OS knows about arm64. - if (!strcmp("arm64", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_ALL); - - if (!strcmp("arm64e", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_E); - - // TODO: Remove this when the OS knows about armv7s. - if (!strcmp("armv7s", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S); - - return NXGetArchInfoFromName(arch_name); -} - -const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { - // TODO: Remove this when the OS knows about arm64. - if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) { - static const NXArchInfo* arm64 = ArchInfo_arm64(cpu_subtype); - return arm64; - } - - if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_E) { - static const NXArchInfo* arm64e = ArchInfo_arm64(cpu_subtype); - return arm64e; - } - - // TODO: Remove this when the OS knows about armv7s. - if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) { - static const NXArchInfo* armv7s = ArchInfo_armv7s(); - return armv7s; - } - - return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); -} - -} // namespace google_breakpad +#ifdef __APPLE__ +#include <mach-o/utils.h> +#endif -// TODO(crbug.com/1242776): The "#ifndef __APPLE__" should be here, but the -// system version of NXGetLocalArchInfo returns incorrect information on -// x86_64 machines (treating them as just x86), so use the Breakpad version -// all the time for now. namespace { enum Architecture { @@ -147,69 +56,31 @@ enum Architecture { kNumArchitectures }; +struct NamedArchInfo { + const char* name; + ArchInfo info; +}; + // enum Architecture above and kKnownArchitectures below // must be kept in sync. -const NXArchInfo kKnownArchitectures[] = { - { - "i386", - CPU_TYPE_I386, - CPU_SUBTYPE_I386_ALL, - NX_LittleEndian, - "Intel 80x86" - }, - { - "x86_64", - CPU_TYPE_X86_64, - CPU_SUBTYPE_X86_64_ALL, - NX_LittleEndian, - "Intel x86-64" - }, - { - "x86_64h", - CPU_TYPE_X86_64, - CPU_SUBTYPE_X86_64_H, - NX_LittleEndian, - "Intel x86-64h Haswell" - }, - { - "arm", - CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_ALL, - NX_LittleEndian, - "ARM" - }, - { - "arm64", - CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_ALL, - NX_LittleEndian, - "ARM64" - }, - { - "arm64e", - CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_E, - NX_LittleEndian, - "ARM64e" - }, - { - "ppc", - CPU_TYPE_POWERPC, - CPU_SUBTYPE_POWERPC_ALL, - NX_BigEndian, - "PowerPC" - } -}; +constexpr NamedArchInfo kKnownArchitectures[] = { + {"i386", {CPU_TYPE_I386, CPU_SUBTYPE_I386_ALL}}, + {"x86_64", {CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL}}, + {"x86_64h", {CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H}}, + {"arm", {CPU_TYPE_ARM, CPU_SUBTYPE_ARM_ALL}}, + {"arm64", {CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL}}, + {"arm64e", {CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E}}, + {"ppc", {CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL}}}; } // namespace -const NXArchInfo *NXGetLocalArchInfo(void) { +ArchInfo GetLocalArchInfo(void) { Architecture arch; #if defined(__i386__) arch = kArch_i386; #elif defined(__x86_64__) arch = kArch_x86_64; -#elif defined(__arm64) +#elif defined(__arm64__) || defined(__aarch64__) arch = kArch_arm64; #elif defined(__arm__) arch = kArch_arm; @@ -218,51 +89,72 @@ const NXArchInfo *NXGetLocalArchInfo(void) { #else #error "Unsupported CPU architecture" #endif - return &kKnownArchitectures[arch]; + return kKnownArchitectures[arch].info; } -#ifndef __APPLE__ +#ifdef __APPLE__ -const NXArchInfo *NXGetArchInfoFromName(const char *name) { - for (int arch = 0; arch < kNumArchitectures; ++arch) { - if (!strcmp(name, kKnownArchitectures[arch].name)) { - return &kKnownArchitectures[arch]; +std::optional<ArchInfo> GetArchInfoFromName(const char* arch_name) { + if (__builtin_available(macOS 13.0, iOS 16.0, *)) { + cpu_type_t type; + cpu_subtype_t subtype; + if (macho_cpu_type_for_arch_name(arch_name, &type, &subtype)) { + return ArchInfo{type, subtype}; + } + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + const NXArchInfo* info = NXGetArchInfoFromName(arch_name); +#pragma clang diagnostic pop + if (info) { + return ArchInfo{info->cputype, info->cpusubtype}; } } - return NULL; + return std::nullopt; } -const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, - cpu_subtype_t cpusubtype) { - const NXArchInfo *candidate = NULL; +const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + if (__builtin_available(macOS 13.0, iOS 16.0, *)) { + const char* name = macho_arch_name_for_cpu_type(cpu_type, cpu_subtype); + if (name) { + return name; + } + } else { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + const NXArchInfo* info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); +#pragma clang diagnostic pop + if (info) { + return info->name; + } + } + + return kUnknownArchName; +} + +#else + +std::optional<ArchInfo> GetArchInfoFromName(const char* arch_name) { for (int arch = 0; arch < kNumArchitectures; ++arch) { - if (kKnownArchitectures[arch].cputype == cputype) { - if (kKnownArchitectures[arch].cpusubtype == cpusubtype) { - return &kKnownArchitectures[arch]; - } - if (!candidate) { - candidate = &kKnownArchitectures[arch]; - } + if (!strcmp(arch_name, kKnownArchitectures[arch].name)) { + return kKnownArchitectures[arch].info; } } - return candidate; + return std::nullopt; } -struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, - cpu_subtype_t cpusubtype, - struct fat_arch *fat_archs, - uint32_t nfat_archs) { - struct fat_arch *candidate = NULL; - for (uint32_t f = 0; f < nfat_archs; ++f) { - if (fat_archs[f].cputype == cputype) { - if (fat_archs[f].cpusubtype == cpusubtype) { - return &fat_archs[f]; +const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { + const char* candidate = kUnknownArchName; + for (int arch = 0; arch < kNumArchitectures; ++arch) { + if (kKnownArchitectures[arch].info.cputype == cpu_type) { + if (kKnownArchitectures[arch].info.cpusubtype == cpu_subtype) { + return kKnownArchitectures[arch].name; } - if (!candidate) { - candidate = &fat_archs[f]; + if (!strcmp(candidate, kUnknownArchName)) { + candidate = kKnownArchitectures[arch].name; } } } return candidate; } -#endif // !__APPLE__ +#endif // __APPLE__ diff --git a/src/common/mac/arch_utilities.h b/src/common/mac/arch_utilities.h index d267c43b..3b036738 100644 --- a/src/common/mac/arch_utilities.h +++ b/src/common/mac/arch_utilities.h @@ -31,16 +31,26 @@ #ifndef COMMON_MAC_ARCH_UTILITIES_H__ #define COMMON_MAC_ARCH_UTILITIES_H__ -#include <mach-o/arch.h> +#include <mach/machine.h> -namespace google_breakpad { +#include <optional> -// Custom implementation of |NXGetArchInfoFromName| and -// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes. -const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name); -const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype); +static constexpr const char* kUnknownArchName = "<Unknown architecture>"; -} // namespace google_breakpad +struct ArchInfo { + cpu_type_t cputype; + cpu_subtype_t cpusubtype; +}; + +// Returns architecture info if `arch_name` corresponds to a valid, known +// architecture, and std::nullopt otherwise. +std::optional<ArchInfo> GetArchInfoFromName(const char* arch_name); + +// Returns the name of the architecture specified by `cpu_type` and +// `cpu_subtype`, or `kUnknownArchName` if it's unknown or invalid. +const char* GetNameFromCPUType(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); + +// Returns the architecture of the machine this code is running on. +ArchInfo GetLocalArchInfo(); #endif // COMMON_MAC_ARCH_UTILITIES_H__ diff --git a/src/common/mac/bootstrap_compat.cc b/src/common/mac/bootstrap_compat.cc index 6647bae3..408589ba 100644 --- a/src/common/mac/bootstrap_compat.cc +++ b/src/common/mac/bootstrap_compat.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/bootstrap_compat.h" namespace breakpad { diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc index 9658b2c6..c06945e4 100644 --- a/src/common/mac/dump_syms.cc +++ b/src/common/mac/dump_syms.cc @@ -32,6 +32,10 @@ // dump_syms.cc: Create a symbol file for use with minidumps +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/dump_syms.h" #include <assert.h> @@ -217,11 +221,10 @@ bool DumpSymbols::ReadData(uint8_t* contents, size_t size, return true; } -bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { +bool DumpSymbols::SetArchitecture(const ArchInfo& info) { // Find the best match for the architecture the user requested. - const SuperFatArch* best_match = FindBestMatchForArchitecture( - cpu_type, cpu_subtype); + const SuperFatArch* best_match = + FindBestMatchForArchitecture(info.cputype, info.cpusubtype); if (!best_match) return false; // Record the selected object file. @@ -229,70 +232,37 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, return true; } -bool DumpSymbols::SetArchitecture(const std::string& arch_name) { - bool arch_set = false; - const NXArchInfo* arch_info = - google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str()); - if (arch_info) { - arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype); - } - return arch_set; -} SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( - cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - // Check if all the object files can be converted to struct fat_arch. - bool can_convert_to_fat_arch = true; - vector<struct fat_arch> fat_arch_vector; - for (vector<SuperFatArch>::const_iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - struct fat_arch arch; - bool success = it->ConvertToFatArch(&arch); - if (!success) { - can_convert_to_fat_arch = false; - break; - } - fat_arch_vector.push_back(arch); - } - - // If all the object files can be converted to struct fat_arch, use - // NXFindBestFatArch. - if (can_convert_to_fat_arch) { - const struct fat_arch* best_match - = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0], - static_cast<uint32_t>(fat_arch_vector.size())); - - for (size_t i = 0; i < fat_arch_vector.size(); ++i) { - if (best_match == &fat_arch_vector[i]) - return &object_files_[i]; + cpu_type_t cpu_type, + cpu_subtype_t cpu_subtype) { + SuperFatArch* closest_match = nullptr; + for (auto& object_file : object_files_) { + if (static_cast<cpu_type_t>(object_file.cputype) == cpu_type) { + // If there's an exact match, return it directly. + if ((static_cast<cpu_subtype_t>(object_file.cpusubtype) & + ~CPU_SUBTYPE_MASK) == (cpu_subtype & ~CPU_SUBTYPE_MASK)) { + return &object_file; + } + // Otherwise, hold on to this as the closest match since at least the CPU + // type matches. + if (!closest_match) { + closest_match = &object_file; + } } - assert(best_match == NULL); - // Fall through since NXFindBestFatArch can't find arm slices on x86_64 - // macOS 13. See FB11955188. } - - // Check for an exact match with cpu_type and cpu_subtype. - for (vector<SuperFatArch>::iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - if (static_cast<cpu_type_t>(it->cputype) == cpu_type && - (static_cast<cpu_subtype_t>(it->cpusubtype) & ~CPU_SUBTYPE_MASK) == - (cpu_subtype & ~CPU_SUBTYPE_MASK)) - return &*it; - } - // No exact match found. - // TODO(erikchen): If it becomes necessary, we can copy the implementation of - // NXFindBestFatArch, located at - // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. - fprintf(stderr, "Failed to find an exact match for an object file with cpu " - "type: %d and cpu subtype: %d.\n", cpu_type, cpu_subtype); - if (!can_convert_to_fat_arch) { - fprintf(stderr, "Furthermore, at least one object file is larger " - "than 2**32.\n"); + fprintf(stderr, + "Failed to find an exact match for an object file with cpu " + "type: %d and cpu subtype: %d.\n", + cpu_type, cpu_subtype); + if (closest_match) { + fprintf(stderr, "Using %s as the closest match.\n", + GetNameFromCPUType(closest_match->cputype, + closest_match->cpusubtype)); + return closest_match; } - return NULL; + return nullptr; } string DumpSymbols::Identifier() { @@ -398,8 +368,8 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { selected_object_file_ = &object_files_[0]; else { // Look for an object file whose architecture matches our own. - const NXArchInfo* local_arch = NXGetLocalArchInfo(); - if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { + ArchInfo local_arch = GetLocalArchInfo(); + if (!SetArchitecture(local_arch)) { fprintf(stderr, "%s: object file contains more than one" " architecture, none of which match the current" " architecture; specify an architecture explicitly" @@ -414,18 +384,16 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { // Find the name of the selected file's architecture, to appear in // the MODULE record and in error messages. - const NXArchInfo* selected_arch_info = - google_breakpad::BreakpadGetArchInfoFromCpuType( - selected_object_file_->cputype, selected_object_file_->cpusubtype); + const char* selected_arch_name = GetNameFromCPUType( + selected_object_file_->cputype, selected_object_file_->cpusubtype); // In certain cases, it is possible that architecture info can't be reliably // determined, e.g. new architectures that breakpad is unware of. In that // case, avoid crashing and return false instead. - if (selected_arch_info == NULL) { + if (selected_arch_name == kUnknownArchName) { return false; } - const char* selected_arch_name = selected_arch_info->name; if (strcmp(selected_arch_name, "i386") == 0) selected_arch_name = "x86"; @@ -438,7 +406,12 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { } // Compute a module name, to appear in the MODULE record. - string module_name = google_breakpad::BaseName(object_filename_); + string module_name; + if (!module_name_.empty()) { + module_name = module_name_; + } else { + module_name = google_breakpad::BaseName(object_filename_); + } // Choose an identifier string, to appear in the MODULE record. string identifier = Identifier(); @@ -447,18 +420,71 @@ bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { // Create a module to hold the debugging information. module.reset(new Module(module_name, "mac", selected_arch_name, identifier, - "", enable_multiple_)); + "", enable_multiple_, prefer_extern_name_)); return true; } +void DumpSymbols::StartProcessSplitDwarf( + google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const { + std::string split_file; + google_breakpad::SectionMap split_sections; + google_breakpad::ByteReader split_byte_reader(endianness); + uint64_t cu_offset = 0; + if (reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader, + cu_offset)) + return; + DwarfCUToModule::FileContext file_context(split_file, module, + handle_inter_cu_refs); + for (auto section : split_sections) + file_context.AddSectionToSectionMap(section.first, section.second.first, + section.second.second); + // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str, + // its debug info will refer to .debug_addr/.debug_line in the main binary. + if (file_context.section_map().find(".debug_addr") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(), + reader->GetAddrBufferLen()); + if (file_context.section_map().find(".debug_line") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(), + reader->GetLineBufferLen()); + if (file_context.section_map().find(".debug_line_str") == + file_context.section_map().end()) + file_context.AddSectionToSectionMap(".debug_line_str", + reader->GetLineStrBuffer(), + reader->GetLineStrBufferLen()); + DumperRangesHandler ranges_handler(&split_byte_reader); + DumperLineToModule line_to_module(&split_byte_reader); + DwarfCUToModule::WarningReporter reporter(split_file, cu_offset); + DwarfCUToModule root_handler( + &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline, + reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(), + reader->GetSourceLineOffset()); + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + google_breakpad::CompilationUnit split_reader( + split_file, file_context.section_map(), cu_offset, &split_byte_reader, + &die_dispatcher); + split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID()); + split_reader.Start(); + // Normally, it won't happen unless we have transitive reference. + if (split_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&split_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } +} + void DumpSymbols::ReadDwarf(google_breakpad::Module* module, const mach_o::Reader& macho_reader, const mach_o::SectionMap& dwarf_sections, bool handle_inter_cu_refs) const { // Build a byte reader of the appropriate endianness. - ByteReader byte_reader(macho_reader.big_endian() - ? ENDIANNESS_BIG - : ENDIANNESS_LITTLE); + google_breakpad::Endianness endianness = + macho_reader.big_endian() ? ENDIANNESS_BIG : ENDIANNESS_LITTLE; + ByteReader byte_reader(endianness); // Construct a context for this file. DwarfCUToModule::FileContext file_context(selected_object_name_, @@ -494,14 +520,14 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, // Walk the __debug_info section, one compilation unit at a time. uint64_t debug_info_length = debug_info_section.second; + bool handle_inline = symbol_data_ & INLINES; for (uint64_t offset = 0; offset < debug_info_length;) { // Make a handler for the root DIE that populates MODULE with the // debug info. DwarfCUToModule::WarningReporter reporter(selected_object_name_, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - &ranges_handler, &reporter, - symbol_data_ & INLINES); + &ranges_handler, &reporter, handle_inline); // Make a Dwarf2Handler that drives our DIEHandler. DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. @@ -512,6 +538,11 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, &die_dispatcher); // Process the entire compilation unit; get the offset of the next. offset += dwarf_reader.Start(); + // Start to process split dwarf file. + if (dwarf_reader.ShouldProcessSplitDwarf()) { + StartProcessSplitDwarf(&dwarf_reader, module, endianness, + handle_inter_cu_refs, handle_inline); + } } } @@ -536,16 +567,14 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module* module, register_names = DwarfCFIToModule::RegisterNames::ARM64(); break; default: { - const NXArchInfo* arch = google_breakpad::BreakpadGetArchInfoFromCpuType( - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, "%s: cannot convert DWARF call frame information for ", - selected_object_name_.c_str()); - if (arch) - fprintf(stderr, "architecture '%s'", arch->name); - else - fprintf(stderr, "architecture %d,%d", - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, " to Breakpad symbol file: no register name table\n"); + const char* arch_name = GetNameFromCPUType(macho_reader.cpu_type(), + macho_reader.cpu_subtype()); + fprintf( + stderr, + "%s: cannot convert DWARF call frame information for architecture " + "'%s' (%d, %d) to Breakpad symbol file: no register name table\n", + selected_object_name_.c_str(), arch_name, macho_reader.cpu_type(), + macho_reader.cpu_subtype()); return false; } } diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index c2e1b40b..5ccf49e3 100644 --- a/src/common/mac/dump_syms.h +++ b/src/common/mac/dump_syms.h @@ -43,6 +43,8 @@ #include <vector> #include "common/byte_cursor.h" +#include "common/dwarf/dwarf2reader.h" +#include "common/mac/arch_utilities.h" #include "common/mac/macho_reader.h" #include "common/mac/super_fat_arch.h" #include "common/module.h" @@ -55,7 +57,9 @@ class DumpSymbols { public: DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs, - bool enable_multiple = false) + bool enable_multiple = false, + const std::string& module_name = "", + bool prefer_extern_name = false) : symbol_data_(symbol_data), handle_inter_cu_refs_(handle_inter_cu_refs), object_filename_(), @@ -65,12 +69,19 @@ class DumpSymbols { object_files_(), selected_object_file_(), selected_object_name_(), - enable_multiple_(enable_multiple) {} + enable_multiple_(enable_multiple), + module_name_(module_name), + prefer_extern_name_(prefer_extern_name) {} ~DumpSymbols() = default; // Prepare to read debugging information from |filename|. |filename| may be // the name of a fat file, a Mach-O file, or a dSYM bundle containing either - // of the above. On success, return true; if there is a problem reading + // of the above. + // + // If |module_name_| is empty, uses the basename of |filename| as the module + // name. Otherwise, uses |module_name_| as the module name. + // + // On success, return true; if there is a problem reading // |filename|, report it and return false. bool Read(const std::string& filename); @@ -82,26 +93,15 @@ class DumpSymbols { // problem reading |contents|, report it and return false. bool ReadData(uint8_t* contents, size_t size, const std::string& filename); - // If this dumper's file includes an object file for |cpu_type| and - // |cpu_subtype|, then select that object file for dumping, and return - // true. Otherwise, return false, and leave this dumper's selected - // architecture unchanged. - // - // By default, if this dumper's file contains only one object file, then - // the dumper will dump those symbols; and if it contains more than one - // object file, then the dumper will dump the object file whose - // architecture matches that of this dumper program. - bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); - - // If this dumper's file includes an object file for |arch_name|, then select - // that object file for dumping, and return true. Otherwise, return false, - // and leave this dumper's selected architecture unchanged. + // If this dumper's file includes an object file for `info`, then select that + // object file for dumping, and return true. Otherwise, return false, and + // leave this dumper's selected architecture unchanged. // // By default, if this dumper's file contains only one object file, then // the dumper will dump those symbols; and if it contains more than one // object file, then the dumper will dump the object file whose // architecture matches that of this dumper program. - bool SetArchitecture(const std::string& arch_name); + bool SetArchitecture(const ArchInfo& info); // Return a pointer to an array of SuperFatArch structures describing the // object files contained in this dumper's file. Set *|count| to the number @@ -144,6 +144,13 @@ class DumpSymbols { // Creates an empty module object. bool CreateEmptyModule(scoped_ptr<Module>& module); + // Process the split dwarf file referenced by reader. + void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader, + Module* module, + google_breakpad::Endianness endianness, + bool handle_inter_cu_refs, + bool handle_inline) const; + // Read debugging information from |dwarf_sections|, which was taken from // |macho_reader|, and add it to |module|. void ReadDwarf(google_breakpad::Module* module, @@ -204,6 +211,19 @@ class DumpSymbols { // See: https://crbug.com/google-breakpad/751 and docs at // docs/symbol_files.md#records-3 bool enable_multiple_; + + // If non-empty, used as the module name. Otherwise, the basename of + // |object_filename_| is used as the module name. + const std::string module_name_; + + // If a Function and an Extern share the same address but have a different + // name, prefer the name of the Extern. + // + // Use this when dumping Mach-O .dSYMs built with -gmlt (Minimum Line Tables), + // as the Function's fully-qualified name will only be present in the STABS + // (which are placed in the Extern), not in the DWARF symbols (which are + // placed in the Function). + bool prefer_extern_name_; }; } // namespace google_breakpad diff --git a/src/common/mac/file_id.cc b/src/common/mac/file_id.cc index a6c1d26f..ee4a66bb 100644 --- a/src/common/mac/file_id.cc +++ b/src/common/mac/file_id.cc @@ -32,6 +32,10 @@ // // Author: Dan Waylonis +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/file_id.h" #include <fcntl.h> diff --git a/src/common/mac/launch_reporter.cc b/src/common/mac/launch_reporter.cc index de554ee3..f6b8aed1 100644 --- a/src/common/mac/launch_reporter.cc +++ b/src/common/mac/launch_reporter.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <stdio.h> #include <sys/wait.h> #include <unistd.h> diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc index e67ccddb..bb0058ce 100644 --- a/src/common/mac/macho_id.cc +++ b/src/common/mac/macho_id.cc @@ -33,6 +33,10 @@ // Author: Dan Waylonis +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <fcntl.h> #include <mach-o/loader.h> #include <stdio.h> diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc index 23c809c4..0324be14 100644 --- a/src/common/mac/macho_reader.cc +++ b/src/common/mac/macho_reader.cc @@ -31,6 +31,10 @@ // macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and // google_breakpad::Mach_O::Reader. See macho_reader.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/macho_reader.h" #include <assert.h> diff --git a/src/common/mac/macho_reader_unittest.cc b/src/common/mac/macho_reader_unittest.cc index 3beec341..4b5ac6ca 100644 --- a/src/common/mac/macho_reader_unittest.cc +++ b/src/common/mac/macho_reader_unittest.cc @@ -31,6 +31,10 @@ // macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader // and google_breakpad::Mach_O::Reader. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <map> #include <string> #include <vector> diff --git a/src/common/mac/macho_utilities.cc b/src/common/mac/macho_utilities.cc index 16e430df..113e8d3f 100644 --- a/src/common/mac/macho_utilities.cc +++ b/src/common/mac/macho_utilities.cc @@ -30,6 +30,10 @@ // // Author: Dave Camp +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/mac/byteswap.h" #include "common/mac/macho_utilities.h" diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc index 505a4df1..4b9f56c2 100644 --- a/src/common/mac/macho_walker.cc +++ b/src/common/mac/macho_walker.cc @@ -32,17 +32,21 @@ // // Author: Dan Waylonis +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> #include <fcntl.h> -#include <mach-o/arch.h> #include <mach-o/fat.h> #include <mach-o/loader.h> #include <string.h> #include <unistd.h> +#include "common/mac/arch_utilities.h" #include "common/mac/byteswap.h" -#include "common/mac/macho_walker.h" #include "common/mac/macho_utilities.h" +#include "common/mac/macho_walker.h" namespace MacFileUtilities { @@ -81,9 +85,8 @@ bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { cpu_subtype_t valid_cpu_subtype = cpu_subtype; // if |cpu_type| is 0, use the native cpu type. if (cpu_type == 0) { - const NXArchInfo* arch = NXGetLocalArchInfo(); - assert(arch); - valid_cpu_type = arch->cputype; + ArchInfo arch = GetLocalArchInfo(); + valid_cpu_type = arch.cputype; valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; } off_t offset; diff --git a/src/common/mac/string_utilities.cc b/src/common/mac/string_utilities.cc index 861029d4..3b83351f 100644 --- a/src/common/mac/string_utilities.cc +++ b/src/common/mac/string_utilities.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/scoped_ptr.h" #include "common/mac/string_utilities.h" diff --git a/src/common/md5.cc b/src/common/md5.cc index b6e710da..86298f4d 100644 --- a/src/common/md5.cc +++ b/src/common/md5.cc @@ -13,6 +13,10 @@ * will fill a supplied 16-byte array with the digest. */ +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string.h> #include "common/md5.h" diff --git a/src/common/memory_allocator_unittest.cc b/src/common/memory_allocator_unittest.cc index 6ca625bb..8ef68913 100644 --- a/src/common/memory_allocator_unittest.cc +++ b/src/common/memory_allocator_unittest.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/memory_allocator.h" diff --git a/src/common/memory_range_unittest.cc b/src/common/memory_range_unittest.cc index f112e761..f081d679 100644 --- a/src/common/memory_range_unittest.cc +++ b/src/common/memory_range_unittest.cc @@ -28,6 +28,10 @@ // memory_range_unittest.cc: Unit tests for google_breakpad::MemoryRange. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/memory_range.h" diff --git a/src/common/module.cc b/src/common/module.cc index 75782ab1..0eb5aad8 100644 --- a/src/common/module.cc +++ b/src/common/module.cc @@ -30,6 +30,10 @@ // module.cc: Implement google_breakpad::Module. See module.h. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/module.h" #include "common/string_view.h" @@ -101,14 +105,16 @@ Module::Module(const string& name, const string& architecture, const string& id, const string& code_id /* = "" */, - bool enable_multiple_field /* = false*/) + bool enable_multiple_field /* = false*/, + bool prefer_extern_name /* = false*/) : name_(name), os_(os), architecture_(architecture), id_(id), code_id_(code_id), load_address_(0), - enable_multiple_field_(enable_multiple_field) {} + enable_multiple_field_(enable_multiple_field), + prefer_extern_name_(prefer_extern_name) {} Module::~Module() { for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) @@ -148,11 +154,28 @@ bool Module::AddFunction(Function* function) { it_ext = externs_.find(&arm_thumb_ext); } if (it_ext != externs_.end()) { + Extern* found_ext = it_ext->get(); + bool name_mismatch = found_ext->name != function->name; if (enable_multiple_field_) { - Extern* found_ext = it_ext->get(); + bool is_multiple_based_on_name; + // In the case of a .dSYM built with -gmlt, the external name will be the + // fully-qualified symbol name, but the function name will be the partial + // name (or omitted). + // + // Don't mark multiple in this case. + if (name_mismatch && + (function->name == "<name omitted>" || + found_ext->name.find(function->name.str()) != string::npos)) { + is_multiple_based_on_name = false; + } else { + is_multiple_based_on_name = name_mismatch; + } // If the PUBLIC is for the same symbol as the FUNC, don't mark multiple. function->is_multiple |= - found_ext->name != function->name || found_ext->is_multiple; + is_multiple_based_on_name || found_ext->is_multiple; + } + if (name_mismatch && prefer_extern_name_) { + function->name = AddStringToPool(it_ext->get()->name); } externs_.erase(it_ext); } @@ -266,8 +289,7 @@ void Module::GetStackFrameEntries(vector<StackFrameEntry*>* vec) const { } } -void Module::AssignSourceIds( - set<InlineOrigin*, InlineOriginCompare>& inline_origins) { +void Module::AssignSourceIds() { // First, give every source file an id of -1. for (FileByNameMap::iterator file_it = files_.begin(); file_it != files_.end(); ++file_it) { @@ -371,7 +393,7 @@ bool Module::Write(std::ostream& stream, SymbolData symbol_data) { // Get all referenced inline origins. set<InlineOrigin*, InlineOriginCompare> inline_origins; CreateInlineOrigins(inline_origins); - AssignSourceIds(inline_origins); + AssignSourceIds(); // Write out files. for (FileByNameMap::iterator file_it = files_.begin(); diff --git a/src/common/module.h b/src/common/module.h index c1fd9f59..28e8e9c5 100644 --- a/src/common/module.h +++ b/src/common/module.h @@ -131,6 +131,10 @@ class Module { // If this symbol has been folded with other symbols in the linked binary. bool is_multiple = false; + + // If the function's name should be filled out from a matching Extern, + // should they not match. + bool prefer_extern_name = false; }; struct InlineOrigin { @@ -142,10 +146,6 @@ class Module { // The inlined function's name. StringView name; - - File* file; - - int getFileID() const { return file ? file->source_id : -1; } }; // A inlined call site. @@ -224,7 +224,7 @@ class Module { map<uint64_t, uint64_t> references_; }; - InlineOriginMap inline_origin_map; + map<std::string, InlineOriginMap> inline_origin_maps; // A source line. struct Line { @@ -317,7 +317,8 @@ class Module { const string& architecture, const string& id, const string& code_id = "", - bool enable_multiple_field = false); + bool enable_multiple_field = false, + bool prefer_extern_name = false); ~Module(); // Set the module's load address to LOAD_ADDRESS; addresses given @@ -402,7 +403,7 @@ class Module { // 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(set<InlineOrigin*, InlineOriginCompare>& inline_origins); + void AssignSourceIds(); // This function should be called before AssignSourceIds() to get the set of // valid InlineOrigins*. @@ -502,6 +503,15 @@ class Module { // at // https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md#records-3 bool enable_multiple_field_; + + // If a Function and an Extern share the same address but have a different + // name, prefer the name of the Extern. + // + // Use this when dumping Mach-O .dSYMs built with -gmlt (Minimum Line Tables), + // as the Function's fully-qualified name will only be present in the STABS + // (which are placed in the Extern), not in the DWARF symbols (which are + // placed in the Function). + bool prefer_extern_name_; }; } // namespace google_breakpad diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc index 39727554..c51162e5 100644 --- a/src/common/module_unittest.cc +++ b/src/common/module_unittest.cc @@ -30,6 +30,10 @@ // module_unittest.cc: Unit tests for google_breakpad::Module. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <errno.h> #include <stdio.h> #include <stdlib.h> @@ -194,9 +198,7 @@ TEST(Module, WriteOmitUnusedFiles) { function->lines.push_back(line1); function->lines.push_back(line2); m.AddFunction(function); - - std::set<Module::InlineOrigin*, Module::InlineOriginCompare> inline_origins; - m.AssignSourceIds(inline_origins); + m.AssignSourceIds(); vector<Module::File*> vec; m.GetFiles(&vec); @@ -637,6 +639,37 @@ TEST(Module, ConstructFunctionsAndExternsWithSameAddress) { } // If there exists an extern and a function at the same address, only write +// out the FUNC entry. +TEST(Module, ConstructFunctionsAndExternsWithSameAddressPreferExternName) { + stringstream s; + Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, "", false, true); + + // Two externs. + auto extern1 = std::make_unique<Module::Extern>(0xabc0); + extern1->name = "extern1"; + auto extern2 = std::make_unique<Module::Extern>(0xfff0); + extern2->name = "extern2"; + + m.AddExtern(std::move(extern1)); + m.AddExtern(std::move(extern2)); + + Module::Function* function = new Module::Function("function2", 0xfff0); + Module::Range range(0xfff0, 0x10); + function->ranges.push_back(range); + function->parameter_size = 0; + m.AddFunction(function); + + m.Write(s, ALL_SYMBOL_DATA); + string contents = s.str(); + + EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " MODULE_ID " " MODULE_NAME + "\n" + "FUNC fff0 10 0 extern2\n" + "PUBLIC abc0 0 extern1\n", + contents.c_str()); +} + +// If there exists an extern and a function at the same address, only write // out the FUNC entry, and mark it with `m` if the multiple field is enabled. TEST(Module, ConstructFunctionsAndExternsWithSameAddressMultiple) { stringstream s; diff --git a/src/common/path_helper.cc b/src/common/path_helper.cc index e51a1b68..fbbcfca3 100644 --- a/src/common/path_helper.cc +++ b/src/common/path_helper.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/path_helper.h" #include <assert.h> diff --git a/src/common/safe_math_unittest.cc b/src/common/safe_math_unittest.cc index 1908155d..453afbe0 100644 --- a/src/common/safe_math_unittest.cc +++ b/src/common/safe_math_unittest.cc @@ -28,6 +28,10 @@ // safe_math_unittest.cc: Unit tests for SafeMath +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "safe_math.h" #include "breakpad_googletest_includes.h" diff --git a/src/common/simple_string_dictionary.cc b/src/common/simple_string_dictionary.cc index 68288897..d3e09b8f 100644 --- a/src/common/simple_string_dictionary.cc +++ b/src/common/simple_string_dictionary.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/simple_string_dictionary.h" namespace google_breakpad { diff --git a/src/common/simple_string_dictionary.h b/src/common/simple_string_dictionary.h index f7253a34..166d56c8 100644 --- a/src/common/simple_string_dictionary.h +++ b/src/common/simple_string_dictionary.h @@ -32,8 +32,6 @@ #include <assert.h> #include <string.h> -#include "common/basictypes.h" - namespace google_breakpad { // Opaque type for the serialized representation of a NonAllocatingMap. One is @@ -80,6 +78,8 @@ class NonAllocatingMap { : map_(map), current_(0) { } + Iterator(const Iterator&) = delete; + void operator=(const Iterator&) = delete; // Returns the next entry in the map, or NULL if at the end of the // collection. @@ -90,14 +90,12 @@ class NonAllocatingMap { return entry; } } - return NULL; + return nullptr; } private: const NonAllocatingMap& map_; size_t current_; - - DISALLOW_COPY_AND_ASSIGN(Iterator); }; NonAllocatingMap() : entries_() { diff --git a/src/common/simple_string_dictionary_unittest.cc b/src/common/simple_string_dictionary_unittest.cc index 4f3f1f5c..b4dd7fe9 100644 --- a/src/common/simple_string_dictionary_unittest.cc +++ b/src/common/simple_string_dictionary_unittest.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "breakpad_googletest_includes.h" #include "common/simple_string_dictionary.h" diff --git a/src/common/solaris/dump_symbols.cc b/src/common/solaris/dump_symbols.cc index 8277fd66..09e5b376 100644 --- a/src/common/solaris/dump_symbols.cc +++ b/src/common/solaris/dump_symbols.cc @@ -28,6 +28,10 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <demangle.h> #include <fcntl.h> #include <gelf.h> diff --git a/src/common/solaris/file_id.cc b/src/common/solaris/file_id.cc index 53d205b6..5a9982bb 100644 --- a/src/common/solaris/file_id.cc +++ b/src/common/solaris/file_id.cc @@ -32,6 +32,10 @@ // // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <elf.h> #include <fcntl.h> #include <gelf.h> diff --git a/src/common/solaris/guid_creator.cc b/src/common/solaris/guid_creator.cc index 4802f5a7..998d2499 100644 --- a/src/common/solaris/guid_creator.cc +++ b/src/common/solaris/guid_creator.cc @@ -28,6 +28,10 @@ // Author: Alfred Peng +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <cassert> #include <ctime> diff --git a/src/common/stabs_reader.cc b/src/common/stabs_reader.cc index 30118830..e18780c9 100644 --- a/src/common/stabs_reader.cc +++ b/src/common/stabs_reader.cc @@ -31,6 +31,10 @@ // This file implements the google_breakpad::StabsReader class. // See stabs_reader.h. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/stabs_reader.h" #include <assert.h> diff --git a/src/common/stabs_reader.h b/src/common/stabs_reader.h index 3f5f0a8f..655683f1 100644 --- a/src/common/stabs_reader.h +++ b/src/common/stabs_reader.h @@ -49,10 +49,6 @@ #include <stddef.h> #include <stdint.h> -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - #ifdef HAVE_MACH_O_NLIST_H #include <mach-o/nlist.h> #elif defined(HAVE_A_OUT_H) diff --git a/src/common/stabs_reader_unittest.cc b/src/common/stabs_reader_unittest.cc index 79888815..294e8836 100644 --- a/src/common/stabs_reader_unittest.cc +++ b/src/common/stabs_reader_unittest.cc @@ -30,6 +30,10 @@ // stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> #include <errno.h> #include <stab.h> diff --git a/src/common/stabs_to_module.cc b/src/common/stabs_to_module.cc index 3d026c22..f04c987a 100644 --- a/src/common/stabs_to_module.cc +++ b/src/common/stabs_to_module.cc @@ -30,6 +30,10 @@ // dump_stabs.cc --- implement the StabsToModule class. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> #include <cxxabi.h> #include <stdarg.h> diff --git a/src/common/stabs_to_module_unittest.cc b/src/common/stabs_to_module_unittest.cc index 95bdb261..c6d40281 100644 --- a/src/common/stabs_to_module_unittest.cc +++ b/src/common/stabs_to_module_unittest.cc @@ -30,6 +30,10 @@ // dump_stabs_unittest.cc: Unit tests for StabsToModule. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <vector> #include "breakpad_googletest_includes.h" diff --git a/src/common/string_conversion.cc b/src/common/string_conversion.cc index 213d6ed7..a4e64ff0 100644 --- a/src/common/string_conversion.cc +++ b/src/common/string_conversion.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string.h> #include "common/convert_UTF.h" diff --git a/src/common/string_conversion_unittest.cc b/src/common/string_conversion_unittest.cc index 2e64a957..0f372c80 100644 --- a/src/common/string_conversion_unittest.cc +++ b/src/common/string_conversion_unittest.cc @@ -28,6 +28,10 @@ // string_conversion_unittest.cc: Unit tests for google_breakpad::UTF* helpers. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string> #include <vector> diff --git a/src/common/test_assembler.cc b/src/common/test_assembler.cc index 91899663..6b1c1fd3 100644 --- a/src/common/test_assembler.cc +++ b/src/common/test_assembler.cc @@ -31,6 +31,10 @@ // test_assembler.cc: Implementation of google_breakpad::TestAssembler. // See test_assembler.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/test_assembler.h" #include <assert.h> diff --git a/src/common/test_assembler_unittest.cc b/src/common/test_assembler_unittest.cc index f16594f1..0307fdbf 100644 --- a/src/common/test_assembler_unittest.cc +++ b/src/common/test_assembler_unittest.cc @@ -30,6 +30,10 @@ // test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <string> #include <string.h> diff --git a/src/common/tests/file_utils.cc b/src/common/tests/file_utils.cc index 814b2094..84a22809 100644 --- a/src/common/tests/file_utils.cc +++ b/src/common/tests/file_utils.cc @@ -29,6 +29,10 @@ // file_utils.cc: Implement utility functions for file manipulation. // See file_utils.h for details. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <fcntl.h> #include <stdio.h> #include <string.h> diff --git a/src/common/windows/dia_util.cc b/src/common/windows/dia_util.cc index dcfe0ef9..a5d984d1 100644 --- a/src/common/windows/dia_util.cc +++ b/src/common/windows/dia_util.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/dia_util.h" #include <atlbase.h> diff --git a/src/common/windows/guid_string.cc b/src/common/windows/guid_string.cc index be9eb8a3..2c298c33 100644 --- a/src/common/windows/guid_string.cc +++ b/src/common/windows/guid_string.cc @@ -30,6 +30,10 @@ // // See guid_string.h for documentation. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <wchar.h> #include "common/windows/string_utils-inl.h" diff --git a/src/common/windows/http_upload.cc b/src/common/windows/http_upload.cc index 088a5e54..bd48a233 100644 --- a/src/common/windows/http_upload.cc +++ b/src/common/windows/http_upload.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <assert.h> // Disable exception handler warnings. diff --git a/src/common/windows/omap.cc b/src/common/windows/omap.cc index ad916997..1ffcec76 100644 --- a/src/common/windows/omap.cc +++ b/src/common/windows/omap.cc @@ -100,6 +100,10 @@ // position) so that resolution will work as expected for translated addresses. // This is transparent to the rest of the toolchain. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/omap.h" #include <atlbase.h> diff --git a/src/common/windows/omap_unittest.cc b/src/common/windows/omap_unittest.cc index 841e5391..ebe0d47e 100644 --- a/src/common/windows/omap_unittest.cc +++ b/src/common/windows/omap_unittest.cc @@ -28,6 +28,10 @@ // Unittests for OMAP related functions. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/omap.h" #include "breakpad_googletest_includes.h" diff --git a/src/common/windows/pdb_source_line_writer.cc b/src/common/windows/pdb_source_line_writer.cc index 800c316f..dd80a6d2 100644 --- a/src/common/windows/pdb_source_line_writer.cc +++ b/src/common/windows/pdb_source_line_writer.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/pdb_source_line_writer.h" #include <windows.h> diff --git a/src/common/windows/pe_source_line_writer.cc b/src/common/windows/pe_source_line_writer.cc index a568e0c7..d1d25cf4 100644 --- a/src/common/windows/pe_source_line_writer.cc +++ b/src/common/windows/pe_source_line_writer.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/pe_source_line_writer.h" #include "common/windows/pe_util.h" diff --git a/src/common/windows/pe_source_line_writer.h b/src/common/windows/pe_source_line_writer.h index a3748145..324663ba 100644 --- a/src/common/windows/pe_source_line_writer.h +++ b/src/common/windows/pe_source_line_writer.h @@ -31,7 +31,6 @@ #include <string> -#include "common/basictypes.h" #include "common/windows/module_info.h" namespace google_breakpad { @@ -44,6 +43,8 @@ using std::wstring; class PESourceLineWriter { public: explicit PESourceLineWriter(const wstring& pe_file); + PESourceLineWriter(const PESourceLineWriter&) = delete; + void operator=(const PESourceLineWriter&) = delete; ~PESourceLineWriter(); // Writes Breakpad symbols from the pe file to |symbol_file|. @@ -58,9 +59,7 @@ public: bool GetPEInfo(PEModuleInfo* info); private: - const wstring pe_file_; - - DISALLOW_COPY_AND_ASSIGN(PESourceLineWriter); + const wstring pe_file_; }; } // namespace google_breakpad diff --git a/src/common/windows/pe_util.cc b/src/common/windows/pe_util.cc index 1df93105..2d4aebe7 100644 --- a/src/common/windows/pe_util.cc +++ b/src/common/windows/pe_util.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "pe_util.h" #include <windows.h> diff --git a/src/common/windows/string_utils.cc b/src/common/windows/string_utils.cc index 01dca193..1e570b52 100644 --- a/src/common/windows/string_utils.cc +++ b/src/common/windows/string_utils.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include <cassert> #include <vector> diff --git a/src/common/windows/sym_upload_v2_protocol.cc b/src/common/windows/sym_upload_v2_protocol.cc index f2dc660c..450f3626 100644 --- a/src/common/windows/sym_upload_v2_protocol.cc +++ b/src/common/windows/sym_upload_v2_protocol.cc @@ -26,6 +26,10 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/sym_upload_v2_protocol.h" #include <cstdio> diff --git a/src/common/windows/symbol_collector_client.cc b/src/common/windows/symbol_collector_client.cc index 187b100e..d91b702b 100644 --- a/src/common/windows/symbol_collector_client.cc +++ b/src/common/windows/symbol_collector_client.cc @@ -1,3 +1,7 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> // Must come first +#endif + #include "common/windows/symbol_collector_client.h" #include <stdio.h> |