aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/basictypes.h8
-rw-r--r--src/common/byte_cursor_unittest.cc4
-rw-r--r--src/common/convert_UTF.cc4
-rw-r--r--src/common/dwarf/bytereader.cc4
-rw-r--r--src/common/dwarf/bytereader_unittest.cc4
-rw-r--r--src/common/dwarf/cfi_assembler.cc4
-rw-r--r--src/common/dwarf/dwarf2diehandler.cc4
-rw-r--r--src/common/dwarf/dwarf2diehandler_unittest.cc4
-rw-r--r--src/common/dwarf/dwarf2enums.h6
-rw-r--r--src/common/dwarf/dwarf2reader.cc150
-rw-r--r--src/common/dwarf/dwarf2reader.h82
-rw-r--r--src/common/dwarf/dwarf2reader_cfi_unittest.cc4
-rw-r--r--src/common/dwarf/dwarf2reader_die_unittest.cc7
-rw-r--r--src/common/dwarf/dwarf2reader_lineinfo_unittest.cc4
-rw-r--r--src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc4
-rw-r--r--src/common/dwarf/elf_reader.cc4
-rw-r--r--src/common/dwarf/functioninfo.cc4
-rw-r--r--src/common/dwarf_cfi_to_module.cc27
-rw-r--r--src/common/dwarf_cfi_to_module.h3
-rw-r--r--src/common/dwarf_cfi_to_module_unittest.cc16
-rw-r--r--src/common/dwarf_cu_to_module.cc91
-rw-r--r--src/common/dwarf_cu_to_module.h6
-rw-r--r--src/common/dwarf_cu_to_module_unittest.cc17
-rw-r--r--src/common/dwarf_line_to_module.cc4
-rw-r--r--src/common/dwarf_line_to_module_unittest.cc4
-rw-r--r--src/common/dwarf_range_list_handler.cc4
-rw-r--r--src/common/language.cc4
-rw-r--r--src/common/linux/breakpad_getcontext.h4
-rw-r--r--src/common/linux/breakpad_getcontext_unittest.cc4
-rw-r--r--src/common/linux/crc32.cc4
-rw-r--r--src/common/linux/dump_symbols.cc111
-rw-r--r--src/common/linux/dump_symbols_unittest.cc4
-rw-r--r--src/common/linux/elf_core_dump.cc4
-rw-r--r--src/common/linux/elf_core_dump_unittest.cc4
-rw-r--r--src/common/linux/elf_symbols_to_module.cc4
-rw-r--r--src/common/linux/elf_symbols_to_module_unittest.cc4
-rw-r--r--src/common/linux/elfutils.cc4
-rw-r--r--src/common/linux/file_id.cc4
-rw-r--r--src/common/linux/file_id_unittest.cc4
-rw-r--r--src/common/linux/google_crashdump_uploader.cc4
-rw-r--r--src/common/linux/google_crashdump_uploader_test.cc4
-rw-r--r--src/common/linux/guid_creator.cc2
-rw-r--r--src/common/linux/http_upload.cc4
-rw-r--r--src/common/linux/libcurl_wrapper.cc6
-rw-r--r--src/common/linux/linux_libc_support.cc4
-rw-r--r--src/common/linux/linux_libc_support_unittest.cc4
-rw-r--r--src/common/linux/memory_mapped_file.cc11
-rw-r--r--src/common/linux/memory_mapped_file.h7
-rw-r--r--src/common/linux/memory_mapped_file_unittest.cc4
-rw-r--r--src/common/linux/safe_readlink.cc4
-rw-r--r--src/common/linux/safe_readlink_unittest.cc4
-rw-r--r--src/common/linux/scoped_pipe.cc132
-rw-r--r--src/common/linux/scoped_pipe.h115
-rw-r--r--src/common/linux/scoped_pipe_unittest.cc75
-rw-r--r--src/common/linux/scoped_tmpfile.cc103
-rw-r--r--src/common/linux/scoped_tmpfile.h85
-rw-r--r--src/common/linux/scoped_tmpfile_unittest.cc50
-rw-r--r--src/common/linux/symbol_collector_client.cc4
-rw-r--r--src/common/linux/symbol_upload.cc4
-rw-r--r--src/common/linux/synth_elf.cc4
-rw-r--r--src/common/linux/synth_elf_unittest.cc4
-rw-r--r--src/common/linux/tests/auto_testfile.h123
-rw-r--r--src/common/linux/tests/crash_generator.cc4
-rw-r--r--src/common/long_string_dictionary.cc4
-rw-r--r--src/common/long_string_dictionary_unittest.cc4
-rw-r--r--src/common/mac/arch_utilities.cc256
-rw-r--r--src/common/mac/arch_utilities.h26
-rw-r--r--src/common/mac/bootstrap_compat.cc4
-rw-r--r--src/common/mac/dump_syms.cc201
-rw-r--r--src/common/mac/dump_syms.h56
-rw-r--r--src/common/mac/file_id.cc4
-rw-r--r--src/common/mac/launch_reporter.cc4
-rw-r--r--src/common/mac/macho_id.cc4
-rw-r--r--src/common/mac/macho_reader.cc4
-rw-r--r--src/common/mac/macho_reader_unittest.cc4
-rw-r--r--src/common/mac/macho_utilities.cc4
-rw-r--r--src/common/mac/macho_walker.cc13
-rw-r--r--src/common/mac/string_utilities.cc4
-rw-r--r--src/common/md5.cc4
-rw-r--r--src/common/memory_allocator_unittest.cc4
-rw-r--r--src/common/memory_range_unittest.cc4
-rw-r--r--src/common/module.cc36
-rw-r--r--src/common/module.h24
-rw-r--r--src/common/module_unittest.cc39
-rw-r--r--src/common/path_helper.cc4
-rw-r--r--src/common/safe_math_unittest.cc4
-rw-r--r--src/common/simple_string_dictionary.cc4
-rw-r--r--src/common/simple_string_dictionary.h8
-rw-r--r--src/common/simple_string_dictionary_unittest.cc4
-rw-r--r--src/common/solaris/dump_symbols.cc4
-rw-r--r--src/common/solaris/file_id.cc4
-rw-r--r--src/common/solaris/guid_creator.cc4
-rw-r--r--src/common/stabs_reader.cc4
-rw-r--r--src/common/stabs_reader.h4
-rw-r--r--src/common/stabs_reader_unittest.cc4
-rw-r--r--src/common/stabs_to_module.cc4
-rw-r--r--src/common/stabs_to_module_unittest.cc4
-rw-r--r--src/common/string_conversion.cc4
-rw-r--r--src/common/string_conversion_unittest.cc4
-rw-r--r--src/common/test_assembler.cc4
-rw-r--r--src/common/test_assembler_unittest.cc4
-rw-r--r--src/common/tests/file_utils.cc4
-rw-r--r--src/common/windows/dia_util.cc4
-rw-r--r--src/common/windows/guid_string.cc4
-rw-r--r--src/common/windows/http_upload.cc4
-rw-r--r--src/common/windows/omap.cc4
-rw-r--r--src/common/windows/omap_unittest.cc4
-rw-r--r--src/common/windows/pdb_source_line_writer.cc4
-rw-r--r--src/common/windows/pe_source_line_writer.cc4
-rw-r--r--src/common/windows/pe_source_line_writer.h7
-rw-r--r--src/common/windows/pe_util.cc4
-rw-r--r--src/common/windows/string_utils.cc4
-rw-r--r--src/common/windows/sym_upload_v2_protocol.cc4
-rw-r--r--src/common/windows/symbol_collector_client.cc4
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_, &sections);
+ 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_, &sections);
- 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, &sections);
- 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(), &sections);
+ 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>