mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-31 01:30:02 +02:00
* Updated breakpad to latest version.
This commit is contained in:
39
thirdparty/breakpad/common/basictypes.h
vendored
Normal file
39
thirdparty/breakpad/common/basictypes.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2011 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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_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
|
||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
#endif // COMMON_BASICTYPES_H_
|
@@ -176,11 +176,21 @@ void DIEDispatcher::ProcessAttributeBuffer(uint64 offset,
|
||||
void DIEDispatcher::ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data) {
|
||||
const std::string& data) {
|
||||
HandlerStack ¤t = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeString(attr, form, data);
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeSignature(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 signature) {
|
||||
HandlerStack ¤t = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeSignature(attr, form, signature);
|
||||
}
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
@@ -208,7 +208,10 @@ class DIEHandler {
|
||||
uint64 len) { }
|
||||
virtual void ProcessAttributeString(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data) { }
|
||||
const std::string& data) { }
|
||||
virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 signture) { }
|
||||
|
||||
// Once we have reported all the DIE's attributes' values, we call
|
||||
// this member function. If it returns false, we skip all the DIE's
|
||||
@@ -313,7 +316,11 @@ class DIEDispatcher: public Dwarf2Handler {
|
||||
void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string &data);
|
||||
const std::string &data);
|
||||
void ProcessAttributeSignature(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 signature);
|
||||
void EndDIE(uint64 offset);
|
||||
|
||||
private:
|
||||
@@ -347,7 +354,7 @@ class DIEDispatcher: public Dwarf2Handler {
|
||||
// - When we decide to ignore a subtree, we only push an entry on
|
||||
// the stack for the root of the tree being ignored, rather than
|
||||
// pushing lots of stack entries with handler_ set to NULL.
|
||||
stack<HandlerStack> die_handlers_;
|
||||
std::stack<HandlerStack> die_handlers_;
|
||||
|
||||
// The root handler. We don't push it on die_handlers_ until we
|
||||
// actually get the StartDIE call for the root.
|
||||
|
@@ -32,10 +32,16 @@
|
||||
|
||||
// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
|
||||
using std::make_pair;
|
||||
using std::string;
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::ContainerEq;
|
||||
using ::testing::ElementsAreArray;
|
||||
@@ -65,6 +71,8 @@ class MockDIEHandler: public DIEHandler {
|
||||
void(DwarfAttribute, DwarfForm, const char *, uint64));
|
||||
MOCK_METHOD3(ProcessAttributeString,
|
||||
void(DwarfAttribute, DwarfForm, const string &));
|
||||
MOCK_METHOD3(ProcessAttributeSignature,
|
||||
void(DwarfAttribute, DwarfForm, uint64));
|
||||
MOCK_METHOD0(EndAttributes, bool());
|
||||
MOCK_METHOD3(FindChildHandler, DIEHandler *(uint64, DwarfTag,
|
||||
const AttributeList &));
|
||||
@@ -83,6 +91,8 @@ class MockRootDIEHandler: public RootDIEHandler {
|
||||
void(DwarfAttribute, DwarfForm, const char *, uint64));
|
||||
MOCK_METHOD3(ProcessAttributeString,
|
||||
void(DwarfAttribute, DwarfForm, const string &));
|
||||
MOCK_METHOD3(ProcessAttributeSignature,
|
||||
void(DwarfAttribute, DwarfForm, uint64));
|
||||
MOCK_METHOD0(EndAttributes, bool());
|
||||
MOCK_METHOD3(FindChildHandler, DIEHandler *(uint64, DwarfTag,
|
||||
const AttributeList &));
|
||||
@@ -238,6 +248,11 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
(DwarfForm) 0x15762fec,
|
||||
StrEq(str)))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeSignature((DwarfAttribute) 0x58790d72,
|
||||
(DwarfForm) 0x4159f138,
|
||||
0x94682463613e6a5fULL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler, FindChildHandler(_, _, _))
|
||||
@@ -279,6 +294,10 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
(DwarfAttribute) 0x310ed065,
|
||||
(DwarfForm) 0x15762fec,
|
||||
str);
|
||||
die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x58790d72,
|
||||
(DwarfForm) 0x4159f138,
|
||||
0x94682463613e6a5fULL);
|
||||
|
||||
// Finish the root DIE (and thus the CU).
|
||||
die_dispatcher.EndDIE(0xe2222da01e29f2a9LL);
|
||||
|
@@ -143,7 +143,13 @@ enum DwarfForm {
|
||||
DW_FORM_ref4 = 0x13,
|
||||
DW_FORM_ref8 = 0x14,
|
||||
DW_FORM_ref_udata = 0x15,
|
||||
DW_FORM_indirect = 0x16
|
||||
DW_FORM_indirect = 0x16,
|
||||
|
||||
// Added in DWARF 4:
|
||||
DW_FORM_sec_offset = 0x17,
|
||||
DW_FORM_exprloc = 0x18,
|
||||
DW_FORM_flag_present = 0x19,
|
||||
DW_FORM_ref_sig8 = 0x20
|
||||
};
|
||||
|
||||
// Attribute names and codes
|
||||
|
123
thirdparty/breakpad/common/dwarf/dwarf2reader.cc
vendored
123
thirdparty/breakpad/common/dwarf/dwarf2reader.cc
vendored
@@ -39,6 +39,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
|
||||
@@ -74,7 +75,7 @@ void CompilationUnit::ReadAbbrevs() {
|
||||
iter = sections_.find("__debug_abbrev");
|
||||
assert(iter != sections_.end());
|
||||
|
||||
abbrevs_ = new vector<Abbrev>;
|
||||
abbrevs_ = new std::vector<Abbrev>;
|
||||
abbrevs_->resize(1);
|
||||
|
||||
// The only way to check whether we are reading over the end of the
|
||||
@@ -121,7 +122,7 @@ void CompilationUnit::ReadAbbrevs() {
|
||||
const enum DwarfAttribute name =
|
||||
static_cast<enum DwarfAttribute>(nametemp);
|
||||
const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp);
|
||||
abbrev.attributes.push_back(make_pair(name, form));
|
||||
abbrev.attributes.push_back(std::make_pair(name, form));
|
||||
}
|
||||
assert(abbrev.number == abbrevs_->size());
|
||||
abbrevs_->push_back(abbrev);
|
||||
@@ -150,41 +151,35 @@ const char* CompilationUnit::SkipAttribute(const char* start,
|
||||
&len));
|
||||
start += len;
|
||||
return SkipAttribute(start, form);
|
||||
break;
|
||||
|
||||
case DW_FORM_flag_present:
|
||||
return start;
|
||||
case DW_FORM_data1:
|
||||
case DW_FORM_flag:
|
||||
case DW_FORM_ref1:
|
||||
return start + 1;
|
||||
break;
|
||||
case DW_FORM_ref2:
|
||||
case DW_FORM_data2:
|
||||
return start + 2;
|
||||
break;
|
||||
case DW_FORM_ref4:
|
||||
case DW_FORM_data4:
|
||||
return start + 4;
|
||||
break;
|
||||
case DW_FORM_ref8:
|
||||
case DW_FORM_data8:
|
||||
case DW_FORM_ref_sig8:
|
||||
return start + 8;
|
||||
break;
|
||||
case DW_FORM_string:
|
||||
return start + strlen(start) + 1;
|
||||
break;
|
||||
case DW_FORM_udata:
|
||||
case DW_FORM_ref_udata:
|
||||
reader_->ReadUnsignedLEB128(start, &len);
|
||||
return start + len;
|
||||
break;
|
||||
|
||||
case DW_FORM_sdata:
|
||||
reader_->ReadSignedLEB128(start, &len);
|
||||
return start + len;
|
||||
break;
|
||||
case DW_FORM_addr:
|
||||
return start + reader_->AddressSize();
|
||||
break;
|
||||
case DW_FORM_ref_addr:
|
||||
// DWARF2 and 3 differ on whether ref_addr is address size or
|
||||
// offset size.
|
||||
@@ -194,27 +189,21 @@ const char* CompilationUnit::SkipAttribute(const char* start,
|
||||
} else if (header_.version == 3) {
|
||||
return start + reader_->OffsetSize();
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_FORM_block1:
|
||||
return start + 1 + reader_->ReadOneByte(start);
|
||||
break;
|
||||
case DW_FORM_block2:
|
||||
return start + 2 + reader_->ReadTwoBytes(start);
|
||||
break;
|
||||
case DW_FORM_block4:
|
||||
return start + 4 + reader_->ReadFourBytes(start);
|
||||
break;
|
||||
case DW_FORM_block: {
|
||||
case DW_FORM_block:
|
||||
case DW_FORM_exprloc: {
|
||||
uint64 size = reader_->ReadUnsignedLEB128(start, &len);
|
||||
return start + size + len;
|
||||
}
|
||||
break;
|
||||
case DW_FORM_strp:
|
||||
return start + reader_->OffsetSize();
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unhandled form type");
|
||||
case DW_FORM_sec_offset:
|
||||
return start + reader_->OffsetSize();
|
||||
}
|
||||
fprintf(stderr,"Unhandled form type");
|
||||
return NULL;
|
||||
@@ -326,85 +315,78 @@ const char* CompilationUnit::ProcessAttribute(
|
||||
&len));
|
||||
start += len;
|
||||
return ProcessAttribute(dieoffset, start, attr, form);
|
||||
break;
|
||||
|
||||
case DW_FORM_flag_present:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form, 1);
|
||||
return start;
|
||||
case DW_FORM_data1:
|
||||
case DW_FORM_flag:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadOneByte(start));
|
||||
return start + 1;
|
||||
break;
|
||||
case DW_FORM_data2:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadTwoBytes(start));
|
||||
return start + 2;
|
||||
break;
|
||||
case DW_FORM_data4:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadFourBytes(start));
|
||||
return start + 4;
|
||||
break;
|
||||
case DW_FORM_data8:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadEightBytes(start));
|
||||
return start + 8;
|
||||
break;
|
||||
case DW_FORM_string: {
|
||||
const char* str = start;
|
||||
handler_->ProcessAttributeString(dieoffset, attr, form,
|
||||
str);
|
||||
return start + strlen(str) + 1;
|
||||
}
|
||||
break;
|
||||
case DW_FORM_udata:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadUnsignedLEB128(start,
|
||||
&len));
|
||||
return start + len;
|
||||
break;
|
||||
|
||||
case DW_FORM_sdata:
|
||||
handler_->ProcessAttributeSigned(dieoffset, attr, form,
|
||||
reader_->ReadSignedLEB128(start, &len));
|
||||
return start + len;
|
||||
break;
|
||||
case DW_FORM_addr:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadAddress(start));
|
||||
return start + reader_->AddressSize();
|
||||
break;
|
||||
case DW_FORM_sec_offset:
|
||||
handler_->ProcessAttributeUnsigned(dieoffset, attr, form,
|
||||
reader_->ReadOffset(start));
|
||||
return start + reader_->OffsetSize();
|
||||
|
||||
case DW_FORM_ref1:
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadOneByte(start)
|
||||
+ offset_from_section_start_);
|
||||
return start + 1;
|
||||
break;
|
||||
case DW_FORM_ref2:
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadTwoBytes(start)
|
||||
+ offset_from_section_start_);
|
||||
return start + 2;
|
||||
break;
|
||||
case DW_FORM_ref4:
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadFourBytes(start)
|
||||
+ offset_from_section_start_);
|
||||
return start + 4;
|
||||
break;
|
||||
case DW_FORM_ref8:
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadEightBytes(start)
|
||||
+ offset_from_section_start_);
|
||||
return start + 8;
|
||||
break;
|
||||
case DW_FORM_ref_udata:
|
||||
handler_->ProcessAttributeReference(dieoffset, attr, form,
|
||||
reader_->ReadUnsignedLEB128(start,
|
||||
&len)
|
||||
+ offset_from_section_start_);
|
||||
return start + len;
|
||||
break;
|
||||
case DW_FORM_ref_addr:
|
||||
// DWARF2 and 3 differ on whether ref_addr is address size or
|
||||
// offset size.
|
||||
@@ -419,35 +401,36 @@ const char* CompilationUnit::ProcessAttribute(
|
||||
return start + reader_->OffsetSize();
|
||||
}
|
||||
break;
|
||||
case DW_FORM_ref_sig8:
|
||||
handler_->ProcessAttributeSignature(dieoffset, attr, form,
|
||||
reader_->ReadEightBytes(start));
|
||||
return start + 8;
|
||||
|
||||
case DW_FORM_block1: {
|
||||
uint64 datalen = reader_->ReadOneByte(start);
|
||||
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1,
|
||||
datalen);
|
||||
datalen);
|
||||
return start + 1 + datalen;
|
||||
}
|
||||
break;
|
||||
case DW_FORM_block2: {
|
||||
uint64 datalen = reader_->ReadTwoBytes(start);
|
||||
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 2,
|
||||
datalen);
|
||||
datalen);
|
||||
return start + 2 + datalen;
|
||||
}
|
||||
break;
|
||||
case DW_FORM_block4: {
|
||||
uint64 datalen = reader_->ReadFourBytes(start);
|
||||
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 4,
|
||||
datalen);
|
||||
datalen);
|
||||
return start + 4 + datalen;
|
||||
}
|
||||
break;
|
||||
case DW_FORM_block: {
|
||||
case DW_FORM_block:
|
||||
case DW_FORM_exprloc: {
|
||||
uint64 datalen = reader_->ReadUnsignedLEB128(start, &len);
|
||||
handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + len,
|
||||
datalen);
|
||||
datalen);
|
||||
return start + datalen + len;
|
||||
}
|
||||
break;
|
||||
case DW_FORM_strp: {
|
||||
assert(string_buffer_ != NULL);
|
||||
|
||||
@@ -459,11 +442,8 @@ const char* CompilationUnit::ProcessAttribute(
|
||||
str);
|
||||
return start + reader_->OffsetSize();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unhandled form type");
|
||||
}
|
||||
fprintf(stderr, "Unhandled form type");
|
||||
fprintf(stderr, "Unhandled form type\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -493,7 +473,7 @@ void CompilationUnit::ProcessDIEs() {
|
||||
else
|
||||
lengthstart += 4;
|
||||
|
||||
stack<uint64> die_stack;
|
||||
std::stack<uint64> die_stack;
|
||||
|
||||
while (dieptr < (lengthstart + header_.length)) {
|
||||
// We give the user the absolute offset from the beginning of
|
||||
@@ -583,7 +563,7 @@ void LineInfo::ReadHeader() {
|
||||
header_.opcode_base = reader_->ReadOneByte(lineptr);
|
||||
lineptr += 1;
|
||||
|
||||
header_.std_opcode_lengths = new vector<unsigned char>;
|
||||
header_.std_opcode_lengths = new std::vector<unsigned char>;
|
||||
header_.std_opcode_lengths->resize(header_.opcode_base + 1);
|
||||
(*header_.std_opcode_lengths)[0] = 0;
|
||||
for (int i = 1; i < header_.opcode_base; i++) {
|
||||
@@ -1024,7 +1004,7 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule {
|
||||
// Rule: EXPRESSION evaluates to the address at which the register is saved.
|
||||
class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
|
||||
public:
|
||||
explicit ExpressionRule(const string &expression)
|
||||
explicit ExpressionRule(const std::string &expression)
|
||||
: expression_(expression) { }
|
||||
~ExpressionRule() { }
|
||||
bool Handle(Handler *handler, uint64 address, int reg) const {
|
||||
@@ -1038,13 +1018,13 @@ class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
|
||||
}
|
||||
Rule *Copy() const { return new ExpressionRule(*this); }
|
||||
private:
|
||||
string expression_;
|
||||
std::string expression_;
|
||||
};
|
||||
|
||||
// Rule: EXPRESSION evaluates to the address at which the register is saved.
|
||||
class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
|
||||
public:
|
||||
explicit ValExpressionRule(const string &expression)
|
||||
explicit ValExpressionRule(const std::string &expression)
|
||||
: expression_(expression) { }
|
||||
~ValExpressionRule() { }
|
||||
bool Handle(Handler *handler, uint64 address, int reg) const {
|
||||
@@ -1059,7 +1039,7 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
|
||||
}
|
||||
Rule *Copy() const { return new ValExpressionRule(*this); }
|
||||
private:
|
||||
string expression_;
|
||||
std::string expression_;
|
||||
};
|
||||
|
||||
// A map from register numbers to rules.
|
||||
@@ -1096,7 +1076,7 @@ class CallFrameInfo::RuleMap {
|
||||
|
||||
private:
|
||||
// A map from register numbers to Rules.
|
||||
typedef map<int, Rule *> RuleByNumber;
|
||||
typedef std::map<int, Rule *> RuleByNumber;
|
||||
|
||||
// Remove all register rules and clear cfa_rule_.
|
||||
void Clear();
|
||||
@@ -1240,7 +1220,7 @@ class CallFrameInfo::State {
|
||||
unsigned register_number; // A register number.
|
||||
uint64 offset; // An offset or address.
|
||||
long signed_offset; // A signed offset.
|
||||
string expression; // A DWARF expression.
|
||||
std::string expression; // A DWARF expression.
|
||||
};
|
||||
|
||||
// Parse CFI instruction operands from STATE's instruction stream as
|
||||
@@ -1341,7 +1321,7 @@ class CallFrameInfo::State {
|
||||
|
||||
// A stack of saved states, for DW_CFA_remember_state and
|
||||
// DW_CFA_restore_state.
|
||||
stack<RuleMap> saved_rules_;
|
||||
std::stack<RuleMap> saved_rules_;
|
||||
};
|
||||
|
||||
bool CallFrameInfo::State::InterpretCIE(const CIE &cie) {
|
||||
@@ -1427,7 +1407,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
|
||||
if (len > bytes_left || expression_length > bytes_left - len)
|
||||
return ReportIncomplete();
|
||||
cursor_ += len;
|
||||
operands->expression = string(cursor_, expression_length);
|
||||
operands->expression = std::string(cursor_, expression_length);
|
||||
cursor_ += expression_length;
|
||||
break;
|
||||
}
|
||||
@@ -1877,20 +1857,14 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
||||
cie->version = reader_->ReadOneByte(cursor);
|
||||
cursor++;
|
||||
|
||||
// If we don't recognize the version, we can't parse any more fields
|
||||
// of the CIE. For DWARF CFI, we handle versions 1 through 3 (there
|
||||
// was never a version 2 of CFI data). For .eh_frame, we handle only
|
||||
// version 1.
|
||||
if (eh_frame_) {
|
||||
if (cie->version != 1) {
|
||||
reporter_->UnrecognizedVersion(cie->offset, cie->version);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (cie->version < 1 || cie->version > 3) {
|
||||
reporter_->UnrecognizedVersion(cie->offset, cie->version);
|
||||
return false;
|
||||
}
|
||||
// If we don't recognize the version, we can't parse any more fields of the
|
||||
// CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a
|
||||
// version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well;
|
||||
// the difference between those versions seems to be the same as for
|
||||
// .debug_frame.
|
||||
if (cie->version < 1 || cie->version > 3) {
|
||||
reporter_->UnrecognizedVersion(cie->offset, cie->version);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *augmentation_start = cursor;
|
||||
@@ -1898,7 +1872,8 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
||||
memchr(augmentation_start, '\0', cie->end - augmentation_start);
|
||||
if (! augmentation_end) return ReportIncomplete(cie);
|
||||
cursor = static_cast<const char *>(augmentation_end);
|
||||
cie->augmentation = string(augmentation_start, cursor - augmentation_start);
|
||||
cie->augmentation = std::string(augmentation_start,
|
||||
cursor - augmentation_start);
|
||||
// Skip the terminating '\0'.
|
||||
cursor++;
|
||||
|
||||
@@ -2285,7 +2260,7 @@ void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) {
|
||||
}
|
||||
|
||||
void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64 offset,
|
||||
const string &aug) {
|
||||
const std::string &aug) {
|
||||
fprintf(stderr,
|
||||
"%s: CFI frame description entry at offset 0x%llx in '%s':"
|
||||
" CIE specifies unrecognized augmentation: '%s'\n",
|
||||
|
44
thirdparty/breakpad/common/dwarf/dwarf2reader.h
vendored
44
thirdparty/breakpad/common/dwarf/dwarf2reader.h
vendored
@@ -50,8 +50,6 @@
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
#include "common/dwarf/types.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace dwarf2reader {
|
||||
struct LineStateMachine;
|
||||
class Dwarf2Handler;
|
||||
@@ -59,8 +57,9 @@ class LineInfoHandler;
|
||||
|
||||
// This maps from a string naming a section to a pair containing a
|
||||
// the data for the section, and the size of the section.
|
||||
typedef map<string, pair<const char*, uint64> > SectionMap;
|
||||
typedef list<pair<enum DwarfAttribute, enum DwarfForm> > AttributeList;
|
||||
typedef std::map<std::string, std::pair<const char*, uint64> > SectionMap;
|
||||
typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
|
||||
AttributeList;
|
||||
typedef AttributeList::iterator AttributeIterator;
|
||||
typedef AttributeList::const_iterator ConstAttributeIterator;
|
||||
|
||||
@@ -75,7 +74,7 @@ struct LineInfoHeader {
|
||||
uint8 opcode_base;
|
||||
// Use a pointer so that signalsafe_addr2line is able to use this structure
|
||||
// without heap allocation problem.
|
||||
vector<unsigned char> *std_opcode_lengths;
|
||||
std::vector<unsigned char> *std_opcode_lengths;
|
||||
};
|
||||
|
||||
class LineInfo {
|
||||
@@ -157,7 +156,7 @@ class LineInfoHandler {
|
||||
|
||||
// Called when we define a directory. NAME is the directory name,
|
||||
// DIR_NUM is the directory number
|
||||
virtual void DefineDir(const string& name, uint32 dir_num) { }
|
||||
virtual void DefineDir(const std::string& name, uint32 dir_num) { }
|
||||
|
||||
// Called when we define a filename. NAME is the filename, FILE_NUM
|
||||
// is the file number which is -1 if the file index is the next
|
||||
@@ -166,7 +165,7 @@ class LineInfoHandler {
|
||||
// directory index for the directory name of this file, MOD_TIME is
|
||||
// the modification time of the file, and LENGTH is the length of
|
||||
// the file
|
||||
virtual void DefineFile(const string& name, int32 file_num,
|
||||
virtual void DefineFile(const std::string& name, int32 file_num,
|
||||
uint32 dir_num, uint64 mod_time,
|
||||
uint64 length) { }
|
||||
|
||||
@@ -313,7 +312,7 @@ class CompilationUnit {
|
||||
// Set of DWARF2/3 abbreviations for this compilation unit. Indexed
|
||||
// by abbreviation number, which means that abbrevs_[0] is not
|
||||
// valid.
|
||||
vector<Abbrev>* abbrevs_;
|
||||
std::vector<Abbrev>* abbrevs_;
|
||||
|
||||
// String section buffer and length, if we have a string section.
|
||||
// This is here to avoid doing a section lookup for strings in
|
||||
@@ -392,7 +391,16 @@ class Dwarf2Handler {
|
||||
virtual void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data) { }
|
||||
const std::string& data) { }
|
||||
|
||||
// Called when we have an attribute whose value is the 64-bit signature
|
||||
// of a type unit in the .debug_types section. OFFSET is the offset of
|
||||
// the DIE whose attribute we're reporting. ATTR and FORM are the
|
||||
// attribute's name and form. SIGNATURE is the type unit's signature.
|
||||
virtual void ProcessAttributeSignature(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 signature) { }
|
||||
|
||||
// Called when finished processing the DIE at OFFSET.
|
||||
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
|
||||
@@ -691,7 +699,7 @@ class CallFrameInfo {
|
||||
// A common information entry (CIE).
|
||||
struct CIE: public Entry {
|
||||
uint8 version; // CFI data version number
|
||||
string augmentation; // vendor format extension markers
|
||||
std::string augmentation; // vendor format extension markers
|
||||
uint64 code_alignment_factor; // scale for code address adjustments
|
||||
int data_alignment_factor; // scale for stack pointer adjustments
|
||||
unsigned return_address_register; // which register holds the return addr
|
||||
@@ -825,7 +833,7 @@ class CallFrameInfo::Handler {
|
||||
// process a given FDE, the parser reiterates the appropriate CIE's
|
||||
// contents at the beginning of the FDE's rules.
|
||||
virtual bool Entry(size_t offset, uint64 address, uint64 length,
|
||||
uint8 version, const string &augmentation,
|
||||
uint8 version, const std::string &augmentation,
|
||||
unsigned return_address) = 0;
|
||||
|
||||
// When the Entry function returns true, the parser calls these
|
||||
@@ -874,13 +882,13 @@ class CallFrameInfo::Handler {
|
||||
// At ADDRESS, the DWARF expression EXPRESSION yields the address at
|
||||
// which REG was saved.
|
||||
virtual bool ExpressionRule(uint64 address, int reg,
|
||||
const string &expression) = 0;
|
||||
const std::string &expression) = 0;
|
||||
|
||||
// At ADDRESS, the DWARF expression EXPRESSION yields the caller's
|
||||
// value for REG. (This rule doesn't provide an address at which the
|
||||
// register's value is saved.)
|
||||
virtual bool ValExpressionRule(uint64 address, int reg,
|
||||
const string &expression) = 0;
|
||||
const std::string &expression) = 0;
|
||||
|
||||
// Indicate that the rules for the address range reported by the
|
||||
// last call to Entry are complete. End should return true if
|
||||
@@ -957,8 +965,8 @@ class CallFrameInfo::Reporter {
|
||||
// in a Mach-O section named __debug_frame. If we support
|
||||
// Linux-style exception handling data, we could be reading an
|
||||
// .eh_frame section.
|
||||
Reporter(const string &filename,
|
||||
const string §ion = ".debug_frame")
|
||||
Reporter(const std::string &filename,
|
||||
const std::string §ion = ".debug_frame")
|
||||
: filename_(filename), section_(section) { }
|
||||
virtual ~Reporter() { }
|
||||
|
||||
@@ -990,7 +998,7 @@ class CallFrameInfo::Reporter {
|
||||
// which we don't recognize. We cannot parse DWARF CFI if it uses
|
||||
// augmentations we don't recognize.
|
||||
virtual void UnrecognizedAugmentation(uint64 offset,
|
||||
const string &augmentation);
|
||||
const std::string &augmentation);
|
||||
|
||||
// The pointer encoding ENCODING, specified by the CIE at OFFSET, is not
|
||||
// a valid encoding.
|
||||
@@ -1031,10 +1039,10 @@ class CallFrameInfo::Reporter {
|
||||
|
||||
protected:
|
||||
// The name of the file whose CFI we're reading.
|
||||
string filename_;
|
||||
std::string filename_;
|
||||
|
||||
// The name of the CFI section in that file.
|
||||
string section_;
|
||||
std::string section_;
|
||||
};
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// The '.eh_frame' format, used by the Linux C++ ABI for exception
|
||||
@@ -75,6 +76,7 @@ using dwarf2reader::ENDIANNESS_LITTLE;
|
||||
using dwarf2reader::ByteReader;
|
||||
using dwarf2reader::CallFrameInfo;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using testing::InSequence;
|
||||
using testing::Return;
|
||||
|
486
thirdparty/breakpad/common/dwarf/dwarf2reader_die_unittest.cc
vendored
Normal file
486
thirdparty/breakpad/common/dwarf/dwarf2reader_die_unittest.cc
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/dwarf2reader_test_common.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
using google_breakpad::test_assembler::Endianness;
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using google_breakpad::test_assembler::kBigEndian;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
|
||||
using dwarf2reader::AttributeList;
|
||||
using dwarf2reader::ByteReader;
|
||||
using dwarf2reader::CompilationUnit;
|
||||
using dwarf2reader::Dwarf2Handler;
|
||||
using dwarf2reader::DwarfAttribute;
|
||||
using dwarf2reader::DwarfForm;
|
||||
using dwarf2reader::DwarfHasChild;
|
||||
using dwarf2reader::DwarfTag;
|
||||
using dwarf2reader::ENDIANNESS_BIG;
|
||||
using dwarf2reader::ENDIANNESS_LITTLE;
|
||||
using dwarf2reader::SectionMap;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using testing::InSequence;
|
||||
using testing::Pointee;
|
||||
using testing::Return;
|
||||
using testing::Sequence;
|
||||
using testing::Test;
|
||||
using testing::TestWithParam;
|
||||
using testing::_;
|
||||
|
||||
class MockDwarf2Handler: public Dwarf2Handler {
|
||||
public:
|
||||
MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size,
|
||||
uint8 offset_size, uint64 cu_length,
|
||||
uint8 dwarf_version));
|
||||
MOCK_METHOD3(StartDIE, bool(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs));
|
||||
MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset,
|
||||
DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 data));
|
||||
MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64 data));
|
||||
MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 data));
|
||||
MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const char* data,
|
||||
uint64 len));
|
||||
MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string& data));
|
||||
MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset,
|
||||
DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 signature));
|
||||
MOCK_METHOD1(EndDIE, void(uint64 offset));
|
||||
};
|
||||
|
||||
struct DIEFixture {
|
||||
|
||||
DIEFixture() {
|
||||
// Fix the initial offset of the .debug_info and .debug_abbrev sections.
|
||||
info.start() = 0;
|
||||
abbrevs.start() = 0;
|
||||
|
||||
// Default expectations for the data handler.
|
||||
EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, StartDIE(_, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, EndDIE(_)).Times(0);
|
||||
}
|
||||
|
||||
// Return a reference to a section map whose .debug_info section refers
|
||||
// to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
|
||||
// function returns a reference to the same SectionMap each time; new
|
||||
// calls wipe out maps established by earlier calls.
|
||||
const SectionMap &MakeSectionMap() {
|
||||
// Copy the sections' contents into strings that will live as long as
|
||||
// the map itself.
|
||||
assert(info.GetContents(&info_contents));
|
||||
assert(abbrevs.GetContents(&abbrevs_contents));
|
||||
section_map.clear();
|
||||
section_map[".debug_info"].first = info_contents.data();
|
||||
section_map[".debug_info"].second = info_contents.size();
|
||||
section_map[".debug_abbrev"].first = abbrevs_contents.data();
|
||||
section_map[".debug_abbrev"].second = abbrevs_contents.size();
|
||||
return section_map;
|
||||
}
|
||||
|
||||
TestCompilationUnit info;
|
||||
TestAbbrevTable abbrevs;
|
||||
MockDwarf2Handler handler;
|
||||
string abbrevs_contents, info_contents;
|
||||
SectionMap section_map;
|
||||
};
|
||||
|
||||
struct DwarfHeaderParams {
|
||||
DwarfHeaderParams(Endianness endianness, size_t format_size,
|
||||
int version, size_t address_size)
|
||||
: endianness(endianness), format_size(format_size),
|
||||
version(version), address_size(address_size) { }
|
||||
Endianness endianness;
|
||||
size_t format_size; // 4-byte or 8-byte DWARF offsets
|
||||
int version;
|
||||
size_t address_size;
|
||||
};
|
||||
|
||||
class DwarfHeader: public DIEFixture,
|
||||
public TestWithParam<DwarfHeaderParams> { };
|
||||
|
||||
TEST_P(DwarfHeader, Header) {
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit,
|
||||
dwarf2reader::DW_children_yes)
|
||||
.Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string)
|
||||
.EndAbbrev()
|
||||
.EndTable();
|
||||
|
||||
info.set_format_size(GetParam().format_size);
|
||||
info.set_endianness(GetParam().endianness);
|
||||
|
||||
info.Header(GetParam().version, abbrev_table, GetParam().address_size)
|
||||
.ULEB128(1) // DW_TAG_compile_unit, with children
|
||||
.AppendCString("sam") // DW_AT_name, DW_FORM_string
|
||||
.D8(0); // end of children
|
||||
info.Finish();
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(handler,
|
||||
StartCompilationUnit(0, GetParam().address_size,
|
||||
GetParam().format_size, _,
|
||||
GetParam().version))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit, _))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
|
||||
dwarf2reader::DW_FORM_string,
|
||||
"sam"))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(handler, EndDIE(_))
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
|
||||
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
|
||||
CompilationUnit parser(MakeSectionMap(), 0, &byte_reader, &handler);
|
||||
EXPECT_EQ(parser.Start(), info_contents.size());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
HeaderVariants, DwarfHeader,
|
||||
::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 2, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 8),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 4),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 8),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 4),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 8),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 4),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 8),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 4),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 8),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 4),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 8),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 4),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 8)));
|
||||
|
||||
struct DwarfFormsFixture: public DIEFixture {
|
||||
// Start a compilation unit, as directed by |params|, containing one
|
||||
// childless DIE of the given tag, with one attribute of the given name
|
||||
// and form. The 'info' fixture member is left just after the abbrev
|
||||
// code, waiting for the attribute value to be appended.
|
||||
void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms,
|
||||
DwarfTag tag, DwarfAttribute name,
|
||||
DwarfForm form) {
|
||||
// Create the abbreviation table.
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no)
|
||||
.Attribute(name, form)
|
||||
.EndAbbrev()
|
||||
.EndTable();
|
||||
|
||||
// Create the compilation unit, up to the attribute value.
|
||||
info.set_format_size(params.format_size);
|
||||
info.set_endianness(params.endianness);
|
||||
info.Header(params.version, abbrev_table, params.address_size)
|
||||
.ULEB128(1); // abbrev code
|
||||
}
|
||||
|
||||
// Set up handler to expect a compilation unit matching |params|,
|
||||
// containing one childless DIE of the given tag, in the sequence s. Stop
|
||||
// just before the expectations.
|
||||
void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms,
|
||||
DwarfTag tag, uint64 offset=0) {
|
||||
EXPECT_CALL(handler,
|
||||
StartCompilationUnit(offset, params.address_size,
|
||||
params.format_size, _,
|
||||
params.version))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, StartDIE(_, tag, _))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
void ExpectEndCompilationUnit() {
|
||||
EXPECT_CALL(handler, EndDIE(_))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
void ParseCompilationUnit(const DwarfHeaderParams ¶ms, uint64 offset=0) {
|
||||
ByteReader byte_reader(params.endianness == kLittleEndian ?
|
||||
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
|
||||
CompilationUnit parser(MakeSectionMap(), offset, &byte_reader, &handler);
|
||||
EXPECT_EQ(offset + parser.Start(), info_contents.size());
|
||||
}
|
||||
|
||||
// The sequence to which the fixture's methods append expectations.
|
||||
Sequence s;
|
||||
};
|
||||
|
||||
struct DwarfForms: public DwarfFormsFixture,
|
||||
public TestWithParam<DwarfHeaderParams> { };
|
||||
|
||||
TEST_P(DwarfForms, addr) {
|
||||
StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
|
||||
dwarf2reader::DW_AT_low_pc,
|
||||
dwarf2reader::DW_FORM_addr);
|
||||
u_int64_t value;
|
||||
if (GetParam().address_size == 4) {
|
||||
value = 0xc8e9ffcc;
|
||||
info.D32(value);
|
||||
} else {
|
||||
value = 0xe942517fc2768564ULL;
|
||||
info.D64(value);
|
||||
}
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit);
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc,
|
||||
dwarf2reader::DW_FORM_addr,
|
||||
value))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, block2_empty) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
|
||||
(DwarfAttribute) 0xe52c4463,
|
||||
dwarf2reader::DW_FORM_block2);
|
||||
info.D16(0);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
|
||||
dwarf2reader::DW_FORM_block2,
|
||||
_, 0))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, block2) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
|
||||
(DwarfAttribute) 0xe52c4463,
|
||||
dwarf2reader::DW_FORM_block2);
|
||||
unsigned char data[258];
|
||||
memset(data, '*', sizeof(data));
|
||||
info.D16(sizeof(data))
|
||||
.Append(data, sizeof(data));
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
|
||||
dwarf2reader::DW_FORM_block2,
|
||||
Pointee('*'), 258))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, flag_present) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
|
||||
(DwarfAttribute) 0x359d1972,
|
||||
dwarf2reader::DW_FORM_flag_present);
|
||||
// DW_FORM_flag_present occupies no space in the DIE.
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
|
||||
EXPECT_CALL(handler,
|
||||
ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
|
||||
dwarf2reader::DW_FORM_flag_present,
|
||||
1))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, sec_offset) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
|
||||
(DwarfAttribute) 0xa060bfd1,
|
||||
dwarf2reader::DW_FORM_sec_offset);
|
||||
u_int64_t value;
|
||||
if (GetParam().format_size == 4) {
|
||||
value = 0xacc9c388;
|
||||
info.D32(value);
|
||||
} else {
|
||||
value = 0xcffe5696ffe3ed0aULL;
|
||||
info.D64(value);
|
||||
}
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
|
||||
dwarf2reader::DW_FORM_sec_offset,
|
||||
value))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, exprloc) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
|
||||
(DwarfAttribute) 0xba3ae5cb,
|
||||
dwarf2reader::DW_FORM_exprloc);
|
||||
info.ULEB128(29)
|
||||
.Append(29, 173);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
|
||||
dwarf2reader::DW_FORM_exprloc,
|
||||
Pointee(173), 29))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, ref_sig8) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
|
||||
(DwarfAttribute) 0xd708d908,
|
||||
dwarf2reader::DW_FORM_ref_sig8);
|
||||
info.D64(0xf72fa0cb6ddcf9d6ULL);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
|
||||
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
|
||||
dwarf2reader::DW_FORM_ref_sig8,
|
||||
0xf72fa0cb6ddcf9d6ULL))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
// A value passed to ProcessAttributeSignature is just an absolute number,
|
||||
// not an offset within the compilation unit as most of the other
|
||||
// DW_FORM_ref forms are. Check that the reader doesn't try to apply any
|
||||
// offset to the signature, by reading it from a compilation unit that does
|
||||
// not start at the beginning of the section.
|
||||
TEST_P(DwarfForms, ref_sig8_not_first) {
|
||||
info.Append(98, '*');
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
|
||||
(DwarfAttribute) 0xd708d908,
|
||||
dwarf2reader::DW_FORM_ref_sig8);
|
||||
info.D64(0xf72fa0cb6ddcf9d6ULL);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
|
||||
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
|
||||
dwarf2reader::DW_FORM_ref_sig8,
|
||||
0xf72fa0cb6ddcf9d6ULL))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam(), 98);
|
||||
}
|
||||
|
||||
// Tests for the other attribute forms could go here.
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
HeaderVariants, DwarfForms,
|
||||
::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 2, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 8),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 4),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 8),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 4),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 8),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 4),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 8),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 4),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 8),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 4),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 8),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 4),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 8),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 4),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 8)));
|
149
thirdparty/breakpad/common/dwarf/dwarf2reader_test_common.h
vendored
Normal file
149
thirdparty/breakpad/common/dwarf/dwarf2reader_test_common.h
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2reader_test_common.h: Define TestCompilationUnit and
|
||||
// TestAbbrevTable, classes for creating properly (and improperly)
|
||||
// formatted DWARF compilation unit data for unit tests.
|
||||
|
||||
#ifndef COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
|
||||
#define COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
|
||||
|
||||
#include "common/test_assembler.h"
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
|
||||
// A subclass of test_assembler::Section, specialized for constructing
|
||||
// DWARF compilation units.
|
||||
class TestCompilationUnit: public google_breakpad::test_assembler::Section {
|
||||
public:
|
||||
typedef dwarf2reader::DwarfTag DwarfTag;
|
||||
typedef dwarf2reader::DwarfAttribute DwarfAttribute;
|
||||
typedef dwarf2reader::DwarfForm DwarfForm;
|
||||
typedef google_breakpad::test_assembler::Label Label;
|
||||
|
||||
// Set the section's DWARF format size (the 32-bit DWARF format or the
|
||||
// 64-bit DWARF format, for lengths and section offsets --- not the
|
||||
// address size) to format_size.
|
||||
void set_format_size(size_t format_size) {
|
||||
assert(format_size == 4 || format_size == 8);
|
||||
format_size_ = format_size;
|
||||
}
|
||||
|
||||
// Append a DWARF section offset value, of the appropriate size for this
|
||||
// compilation unit.
|
||||
template<typename T>
|
||||
void SectionOffset(T offset) {
|
||||
if (format_size_ == 4)
|
||||
D32(offset);
|
||||
else
|
||||
D64(offset);
|
||||
}
|
||||
|
||||
// Append a DWARF compilation unit header to the section, with the given
|
||||
// DWARF version, abbrev table offset, and address size.
|
||||
TestCompilationUnit &Header(int version, const Label &abbrev_offset,
|
||||
size_t address_size) {
|
||||
if (format_size_ == 4) {
|
||||
D32(length_);
|
||||
} else {
|
||||
D32(0xffffffff);
|
||||
D64(length_);
|
||||
}
|
||||
post_length_offset_ = Size();
|
||||
D16(version);
|
||||
SectionOffset(abbrev_offset);
|
||||
D8(address_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Mark the end of this header's DIEs.
|
||||
TestCompilationUnit &Finish() {
|
||||
length_ = Size() - post_length_offset_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// The DWARF format size for this compilation unit.
|
||||
size_t format_size_;
|
||||
|
||||
// The offset of the point in the compilation unit header immediately
|
||||
// after the initial length field.
|
||||
u_int64_t post_length_offset_;
|
||||
|
||||
// The length of the compilation unit, not including the initial length field.
|
||||
Label length_;
|
||||
};
|
||||
|
||||
// A subclass of test_assembler::Section specialized for constructing DWARF
|
||||
// abbreviation tables.
|
||||
class TestAbbrevTable: public google_breakpad::test_assembler::Section {
|
||||
public:
|
||||
typedef dwarf2reader::DwarfTag DwarfTag;
|
||||
typedef dwarf2reader::DwarfAttribute DwarfAttribute;
|
||||
typedef dwarf2reader::DwarfForm DwarfForm;
|
||||
typedef dwarf2reader::DwarfHasChild DwarfHasChild;
|
||||
typedef google_breakpad::test_assembler::Label Label;
|
||||
|
||||
// Start a new abbreviation table entry for abbreviation code |code|,
|
||||
// encoding a DIE whose tag is |tag|, and which has children if and only
|
||||
// if |has_children| is true.
|
||||
TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) {
|
||||
assert(code != 0);
|
||||
ULEB128(code);
|
||||
ULEB128(static_cast<unsigned>(tag));
|
||||
D8(static_cast<unsigned>(has_children));
|
||||
return *this;
|
||||
};
|
||||
|
||||
// Add an attribute to the current abbreviation code whose name is |name|
|
||||
// and whose form is |form|.
|
||||
TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm form) {
|
||||
ULEB128(static_cast<unsigned>(name));
|
||||
ULEB128(static_cast<unsigned>(form));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Finish the current abbreviation code.
|
||||
TestAbbrevTable &EndAbbrev() {
|
||||
ULEB128(0);
|
||||
ULEB128(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Finish the current abbreviation table.
|
||||
TestAbbrevTable &EndTable() {
|
||||
ULEB128(0);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
|
31
thirdparty/breakpad/common/dwarf/functioninfo.cc
vendored
31
thirdparty/breakpad/common/dwarf/functioninfo.cc
vendored
@@ -45,8 +45,8 @@
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
CULineInfoHandler::CULineInfoHandler(vector<SourceFileInfo>* files,
|
||||
vector<string>* dirs,
|
||||
CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<std::string>* dirs,
|
||||
LineMap* linemap):linemap_(linemap),
|
||||
files_(files),
|
||||
dirs_(dirs) {
|
||||
@@ -61,13 +61,13 @@ CULineInfoHandler::CULineInfoHandler(vector<SourceFileInfo>* files,
|
||||
files->push_back(s);
|
||||
}
|
||||
|
||||
void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) {
|
||||
void CULineInfoHandler::DefineDir(const std::string& name, uint32 dir_num) {
|
||||
// These should never come out of order, actually
|
||||
assert(dir_num == dirs_->size());
|
||||
dirs_->push_back(name);
|
||||
}
|
||||
|
||||
void CULineInfoHandler::DefineFile(const string& name,
|
||||
void CULineInfoHandler::DefineFile(const std::string& name,
|
||||
int32 file_num, uint32 dir_num,
|
||||
uint64 mod_time, uint64 length) {
|
||||
assert(dir_num >= 0);
|
||||
@@ -75,7 +75,7 @@ void CULineInfoHandler::DefineFile(const string& name,
|
||||
|
||||
// These should never come out of order, actually.
|
||||
if (file_num == (int32)files_->size() || file_num == -1) {
|
||||
string dir = dirs_->at(dir_num);
|
||||
std::string dir = dirs_->at(dir_num);
|
||||
|
||||
SourceFileInfo s;
|
||||
s.lowpc = ULLONG_MAX;
|
||||
@@ -95,8 +95,10 @@ void CULineInfoHandler::DefineFile(const string& name,
|
||||
void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num,
|
||||
uint32 line_num, uint32 column_num) {
|
||||
if (file_num < files_->size()) {
|
||||
linemap_->insert(make_pair(address, make_pair(files_->at(file_num).name.c_str(),
|
||||
line_num)));
|
||||
linemap_->insert(
|
||||
std::make_pair(address,
|
||||
std::make_pair(files_->at(file_num).name.c_str(),
|
||||
line_num)));
|
||||
|
||||
if(address < files_->at(file_num).lowpc) {
|
||||
files_->at(file_num).lowpc = address;
|
||||
@@ -130,7 +132,8 @@ bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
current_function_info_->name = "";
|
||||
current_function_info_->line = 0;
|
||||
current_function_info_->file = "";
|
||||
offset_to_funcinfo_->insert(make_pair(offset, current_function_info_));
|
||||
offset_to_funcinfo_->insert(std::make_pair(offset,
|
||||
current_function_info_));
|
||||
};
|
||||
// FALLTHROUGH
|
||||
case DW_TAG_compile_unit:
|
||||
@@ -146,7 +149,7 @@ bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string &data) {
|
||||
const std::string &data) {
|
||||
if (current_function_info_) {
|
||||
if (attr == DW_AT_name)
|
||||
current_function_info_->name = data;
|
||||
@@ -164,9 +167,9 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
|
||||
assert(iter != sections_.end());
|
||||
|
||||
// this should be a scoped_ptr but we dont' use boost :-(
|
||||
auto_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
|
||||
iter->second.second - data,
|
||||
reader_, linehandler_));
|
||||
std::auto_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
|
||||
iter->second.second - data,
|
||||
reader_, linehandler_));
|
||||
lireader->Start();
|
||||
} else if (current_function_info_) {
|
||||
switch (attr) {
|
||||
@@ -219,8 +222,8 @@ void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset,
|
||||
|
||||
void CUFunctionInfoHandler::EndDIE(uint64 offset) {
|
||||
if (current_function_info_ && current_function_info_->lowpc)
|
||||
address_to_funcinfo_->insert(make_pair(current_function_info_->lowpc,
|
||||
current_function_info_));
|
||||
address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
|
||||
current_function_info_));
|
||||
}
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
34
thirdparty/breakpad/common/dwarf/functioninfo.h
vendored
34
thirdparty/breakpad/common/dwarf/functioninfo.h
vendored
@@ -46,11 +46,11 @@ namespace dwarf2reader {
|
||||
|
||||
struct FunctionInfo {
|
||||
// Name of the function
|
||||
string name;
|
||||
std::string name;
|
||||
// Mangled name of the function
|
||||
string mangled_name;
|
||||
std::string mangled_name;
|
||||
// File containing this function
|
||||
string file;
|
||||
std::string file;
|
||||
// Line number for start of function.
|
||||
uint32 line;
|
||||
// Beginning address for this function
|
||||
@@ -61,13 +61,13 @@ struct FunctionInfo {
|
||||
|
||||
struct SourceFileInfo {
|
||||
// Name of the source file name
|
||||
string name;
|
||||
std::string name;
|
||||
// Low address of source file name
|
||||
uint64 lowpc;
|
||||
};
|
||||
|
||||
typedef map<uint64, FunctionInfo*> FunctionMap;
|
||||
typedef map<uint64, pair<string, uint32> > LineMap;
|
||||
typedef std::map<uint64, FunctionInfo*> FunctionMap;
|
||||
typedef std::map<uint64, std::pair<std::string, uint32> > LineMap;
|
||||
|
||||
// This class is a basic line info handler that fills in the dirs,
|
||||
// file, and linemap passed into it with the data produced from the
|
||||
@@ -76,18 +76,18 @@ class CULineInfoHandler: public LineInfoHandler {
|
||||
public:
|
||||
|
||||
//
|
||||
CULineInfoHandler(vector<SourceFileInfo>* files,
|
||||
vector<string>* dirs,
|
||||
CULineInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<std::string>* dirs,
|
||||
LineMap* linemap);
|
||||
virtual ~CULineInfoHandler() { }
|
||||
|
||||
// Called when we define a directory. We just place NAME into dirs_
|
||||
// at position DIR_NUM.
|
||||
virtual void DefineDir(const string& name, uint32 dir_num);
|
||||
virtual void DefineDir(const std::string& name, uint32 dir_num);
|
||||
|
||||
// Called when we define a filename. We just place
|
||||
// concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM.
|
||||
virtual void DefineFile(const string& name, int32 file_num,
|
||||
virtual void DefineFile(const std::string& name, int32 file_num,
|
||||
uint32 dir_num, uint64 mod_time, uint64 length);
|
||||
|
||||
|
||||
@@ -102,14 +102,14 @@ class CULineInfoHandler: public LineInfoHandler {
|
||||
|
||||
private:
|
||||
LineMap* linemap_;
|
||||
vector<SourceFileInfo>* files_;
|
||||
vector<string>* dirs_;
|
||||
std::vector<SourceFileInfo>* files_;
|
||||
std::vector<std::string>* dirs_;
|
||||
};
|
||||
|
||||
class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
public:
|
||||
CUFunctionInfoHandler(vector<SourceFileInfo>* files,
|
||||
vector<string>* dirs,
|
||||
CUFunctionInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<std::string>* dirs,
|
||||
LineMap* linemap,
|
||||
FunctionMap* offset_to_funcinfo,
|
||||
FunctionMap* address_to_funcinfo,
|
||||
@@ -163,7 +163,7 @@ class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
virtual void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data);
|
||||
const std::string& data);
|
||||
|
||||
// Called when finished processing the DIE at OFFSET.
|
||||
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
|
||||
@@ -172,8 +172,8 @@ class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
virtual void EndDIE(uint64 offset);
|
||||
|
||||
private:
|
||||
vector<SourceFileInfo>* files_;
|
||||
vector<string>* dirs_;
|
||||
std::vector<SourceFileInfo>* files_;
|
||||
std::vector<std::string>* dirs_;
|
||||
LineMap* linemap_;
|
||||
FunctionMap* offset_to_funcinfo_;
|
||||
FunctionMap* address_to_funcinfo_;
|
||||
|
2
thirdparty/breakpad/common/dwarf/types.h
vendored
2
thirdparty/breakpad/common/dwarf/types.h
vendored
@@ -33,6 +33,8 @@
|
||||
#ifndef _COMMON_DWARF_TYPES_H__
|
||||
#define _COMMON_DWARF_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef signed char int8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
|
@@ -132,7 +132,7 @@ string DwarfCFIToModule::RegisterName(int i) {
|
||||
if (reg == return_address_)
|
||||
return ra_name_;
|
||||
|
||||
if (0 <= reg && reg < register_names_.size())
|
||||
if (reg < register_names_.size())
|
||||
return register_names_[reg];
|
||||
|
||||
reporter_->UnnamedRegister(entry_offset_, reg);
|
||||
|
@@ -31,9 +31,15 @@
|
||||
|
||||
// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::DwarfCFIToModule;
|
||||
using testing::ContainerEq;
|
||||
|
@@ -440,7 +440,11 @@ void DwarfCUToModule::FuncHandler::Finish() {
|
||||
func->address = low_pc_;
|
||||
func->size = high_pc_ - low_pc_;
|
||||
func->parameter_size = 0;
|
||||
cu_context_->functions.push_back(func);
|
||||
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.
|
||||
cu_context_->functions.push_back(func);
|
||||
}
|
||||
} else if (inline_) {
|
||||
AbstractOrigin origin(name_);
|
||||
cu_context_->file_context->file_private->origins[offset_] = origin;
|
||||
@@ -553,7 +557,7 @@ void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) {
|
||||
|
||||
void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
|
||||
CUHeading();
|
||||
fprintf(stderr, "%s: warning: function at offset 0x%" PRIx64 " has no name\n",
|
||||
fprintf(stderr, "%s: warning: function at offset 0x%llx has no name\n",
|
||||
filename_.c_str(), offset);
|
||||
}
|
||||
|
||||
|
@@ -58,9 +58,10 @@ using dwarf2reader::DwarfTag;
|
||||
// Populate a google_breakpad::Module with DWARF debugging information.
|
||||
//
|
||||
// An instance of this class can be provided as a handler to a
|
||||
// dwarf2reader::CompilationUnit DWARF parser. The handler uses the
|
||||
// results of parsing to populate a google_breakpad::Module with
|
||||
// source file, function, and source line information.
|
||||
// dwarf2reader::DIEDispatcher, which can in turn be a handler for a
|
||||
// dwarf2reader::CompilationUnit DWARF parser. The handler uses the results
|
||||
// of parsing to populate a google_breakpad::Module with source file,
|
||||
// function, and source line information.
|
||||
class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
struct FilePrivate;
|
||||
public:
|
||||
|
@@ -31,11 +31,15 @@
|
||||
|
||||
// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
|
||||
using std::make_pair;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
using dwarf2reader::AttributeList;
|
||||
@@ -144,8 +148,8 @@ class CUFixtureBase {
|
||||
|
||||
// The handler will consult this section map to decide what to
|
||||
// pass to our line reader.
|
||||
file_context_.section_map[".debug_line"] = std::make_pair(dummy_line_program_,
|
||||
dummy_line_size_);
|
||||
file_context_.section_map[".debug_line"] = make_pair(dummy_line_program_,
|
||||
dummy_line_size_);
|
||||
}
|
||||
|
||||
// Add a line with the given address, size, filename, and line
|
||||
@@ -158,7 +162,7 @@ class CUFixtureBase {
|
||||
// Use LANGUAGE for the compilation unit. More precisely, arrange
|
||||
// for StartCU to pass the compilation unit's root DIE a
|
||||
// DW_AT_language attribute whose value is LANGUAGE.
|
||||
void SetLanguage(dwarf2reader::DwarfLanguage language) {
|
||||
void SetLanguage(dwarf2reader::DwarfLanguage language) {
|
||||
language_ = language;
|
||||
}
|
||||
|
||||
@@ -192,7 +196,7 @@ class CUFixtureBase {
|
||||
// not Finish. If NAME is non-zero, use it as the DW_AT_name
|
||||
// attribute.
|
||||
DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag,
|
||||
uint64 offset, const char *name = NULL);
|
||||
uint64 specification, const char *name = NULL);
|
||||
|
||||
// Define a function as a child of PARENT with the given name,
|
||||
// address, and size. Call EndAttributes and Finish; one cannot
|
||||
|
@@ -41,13 +41,14 @@
|
||||
// it until we actually have to deal with DWARF on Windows.
|
||||
|
||||
// Return true if PATH is an absolute path, false if it is relative.
|
||||
static bool PathIsAbsolute(const string &path) {
|
||||
static bool PathIsAbsolute(const std::string &path) {
|
||||
return (path.size() >= 1 && path[0] == '/');
|
||||
}
|
||||
|
||||
// If PATH is an absolute path, return PATH. If PATH is a relative path,
|
||||
// treat it as relative to BASE and return the combined path.
|
||||
static string ExpandPath(const string &path, const string &base) {
|
||||
static std::string ExpandPath(const std::string &path,
|
||||
const std::string &base) {
|
||||
if (PathIsAbsolute(path))
|
||||
return path;
|
||||
return base + "/" + path;
|
||||
@@ -55,14 +56,14 @@ static string ExpandPath(const string &path, const string &base) {
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void DwarfLineToModule::DefineDir(const string &name, uint32 dir_num) {
|
||||
void DwarfLineToModule::DefineDir(const std::string &name, uint32 dir_num) {
|
||||
// Directory number zero is reserved to mean the compilation
|
||||
// directory. Silently ignore attempts to redefine it.
|
||||
if (dir_num != 0)
|
||||
directories_[dir_num] = name;
|
||||
}
|
||||
|
||||
void DwarfLineToModule::DefineFile(const string &name, int32 file_num,
|
||||
void DwarfLineToModule::DefineFile(const std::string &name, int32 file_num,
|
||||
uint32 dir_num, uint64 mod_time,
|
||||
uint64 length) {
|
||||
if (file_num == -1)
|
||||
|
@@ -31,9 +31,13 @@
|
||||
|
||||
// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::Module;
|
||||
@@ -44,7 +48,7 @@ TEST(SimpleModule, One) {
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
|
||||
h.DefineFile("file1", 0x30bf0f27, 0, 0, 0);
|
||||
h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27,
|
||||
h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27,
|
||||
0x4c090cbf, 0x1cf9fe0d);
|
||||
|
||||
vector<Module::File *> files;
|
||||
|
2
thirdparty/breakpad/common/language.cc
vendored
2
thirdparty/breakpad/common/language.cc
vendored
@@ -49,7 +49,7 @@ class CPPLanguage: public Language {
|
||||
}
|
||||
};
|
||||
|
||||
const CPPLanguage CPPLanguageSingleton;
|
||||
CPPLanguage CPPLanguageSingleton;
|
||||
|
||||
// Java language-specific operations.
|
||||
class JavaLanguage: public Language {
|
||||
|
22
thirdparty/breakpad/common/linux/dump_symbols.cc
vendored
22
thirdparty/breakpad/common/linux/dump_symbols.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// Copyright (c) 2011 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@@ -226,7 +226,7 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleFunctor {
|
||||
explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
|
||||
: byte_reader_(byte_reader) { }
|
||||
void operator()(const char *program, uint64 length,
|
||||
Module *module, vector<Module::Line> *lines) {
|
||||
Module *module, std::vector<Module::Line> *lines) {
|
||||
DwarfLineToModule handler(module, lines);
|
||||
dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler);
|
||||
parser.Start();
|
||||
@@ -235,7 +235,7 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleFunctor {
|
||||
dwarf2reader::ByteReader *byte_reader_;
|
||||
};
|
||||
|
||||
static bool LoadDwarf(const string &dwarf_filename,
|
||||
static bool LoadDwarf(const std::string &dwarf_filename,
|
||||
const ElfW(Ehdr) *elf_header,
|
||||
const bool big_endian,
|
||||
Module *module) {
|
||||
@@ -253,8 +253,8 @@ static bool LoadDwarf(const string &dwarf_filename,
|
||||
const ElfW(Shdr) *section_names = sections + elf_header->e_shstrndx;
|
||||
for (int i = 0; i < num_sections; i++) {
|
||||
const ElfW(Shdr) *section = §ions[i];
|
||||
string name = reinterpret_cast<const char *>(section_names->sh_offset
|
||||
+ section->sh_name);
|
||||
std::string name = reinterpret_cast<const char *>(section_names->sh_offset +
|
||||
section->sh_name);
|
||||
const char *contents = reinterpret_cast<const char *>(section->sh_offset);
|
||||
uint64 length = section->sh_size;
|
||||
file_context.section_map[name] = std::make_pair(contents, length);
|
||||
@@ -292,7 +292,7 @@ static bool LoadDwarf(const string &dwarf_filename,
|
||||
// success, or false if we don't recognize HEADER's machine
|
||||
// architecture.
|
||||
static bool DwarfCFIRegisterNames(const ElfW(Ehdr) *elf_header,
|
||||
vector<string> *register_names) {
|
||||
std::vector<std::string> *register_names) {
|
||||
switch (elf_header->e_machine) {
|
||||
case EM_386:
|
||||
*register_names = DwarfCFIToModule::RegisterNames::I386();
|
||||
@@ -308,7 +308,7 @@ static bool DwarfCFIRegisterNames(const ElfW(Ehdr) *elf_header,
|
||||
}
|
||||
}
|
||||
|
||||
static bool LoadDwarfCFI(const string &dwarf_filename,
|
||||
static bool LoadDwarfCFI(const std::string &dwarf_filename,
|
||||
const ElfW(Ehdr) *elf_header,
|
||||
const char *section_name,
|
||||
const ElfW(Shdr) *section,
|
||||
@@ -319,7 +319,7 @@ static bool LoadDwarfCFI(const string &dwarf_filename,
|
||||
Module *module) {
|
||||
// Find the appropriate set of register names for this file's
|
||||
// architecture.
|
||||
vector<string> register_names;
|
||||
std::vector<std::string> register_names;
|
||||
if (!DwarfCFIRegisterNames(elf_header, ®ister_names)) {
|
||||
fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
|
||||
" cannot convert DWARF call frame information\n",
|
||||
@@ -728,6 +728,7 @@ namespace google_breakpad {
|
||||
bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||
const std::string &obj_filename,
|
||||
const std::string &debug_dir,
|
||||
bool cfi,
|
||||
std::ostream &sym_stream) {
|
||||
ElfW(Ehdr) *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_file);
|
||||
|
||||
@@ -803,7 +804,7 @@ bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!module.Write(sym_stream))
|
||||
if (!module.Write(sym_stream, cfi))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -811,6 +812,7 @@ bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||
|
||||
bool WriteSymbolFile(const std::string &obj_file,
|
||||
const std::string &debug_dir,
|
||||
bool cfi,
|
||||
std::ostream &sym_stream) {
|
||||
MmapWrapper map_wrapper;
|
||||
ElfW(Ehdr) *elf_header = NULL;
|
||||
@@ -818,7 +820,7 @@ bool WriteSymbolFile(const std::string &obj_file,
|
||||
return false;
|
||||
|
||||
return WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(elf_header),
|
||||
obj_file, debug_dir, sym_stream);
|
||||
obj_file, debug_dir, cfi, sym_stream);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@@ -45,8 +45,10 @@ namespace google_breakpad {
|
||||
// file format.
|
||||
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
||||
// then look for the debug file in DEBUG_DIR.
|
||||
// If CFI is set to false, then omit the CFI section.
|
||||
bool WriteSymbolFile(const std::string &obj_file,
|
||||
const std::string &debug_dir,
|
||||
bool cfi,
|
||||
std::ostream &sym_stream);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@@ -47,6 +47,7 @@ namespace google_breakpad {
|
||||
bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||
const std::string &obj_filename,
|
||||
const std::string &debug_dir,
|
||||
bool cfi,
|
||||
std::ostream &sym_stream);
|
||||
}
|
||||
|
||||
@@ -62,7 +63,7 @@ using std::vector;
|
||||
using ::testing::Test;
|
||||
|
||||
class DumpSymbols : public Test {
|
||||
public:
|
||||
public:
|
||||
void GetElfContents(ELF& elf) {
|
||||
string contents;
|
||||
ASSERT_TRUE(elf.GetContents(&contents));
|
||||
@@ -84,6 +85,7 @@ TEST_F(DumpSymbols, Invalid) {
|
||||
EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(&header),
|
||||
"foo",
|
||||
"",
|
||||
true,
|
||||
s));
|
||||
}
|
||||
|
||||
@@ -105,11 +107,11 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||
SHN_UNDEF + 1);
|
||||
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
||||
elf.AddSection(".dynsym", syms,
|
||||
SHT_DYNSYM, // type
|
||||
SHF_ALLOC, // flags
|
||||
0, // addr
|
||||
index, // link
|
||||
sizeof(Elf32_Sym)); // entsize
|
||||
SHT_DYNSYM, // type
|
||||
SHF_ALLOC, // flags
|
||||
0, // addr
|
||||
index, // link
|
||||
sizeof(Elf32_Sym)); // entsize
|
||||
|
||||
elf.Finish();
|
||||
GetElfContents(elf);
|
||||
@@ -118,6 +120,7 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
||||
"foo",
|
||||
"",
|
||||
true,
|
||||
s));
|
||||
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
||||
"PUBLIC 1000 0 superfunc\n",
|
||||
@@ -141,11 +144,11 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||
SHN_UNDEF + 1);
|
||||
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
||||
elf.AddSection(".dynsym", syms,
|
||||
SHT_DYNSYM, // type
|
||||
SHF_ALLOC, // flags
|
||||
0, // addr
|
||||
index, // link
|
||||
sizeof(Elf64_Sym)); // entsize
|
||||
SHT_DYNSYM, // type
|
||||
SHF_ALLOC, // flags
|
||||
0, // addr
|
||||
index, // link
|
||||
sizeof(Elf64_Sym)); // entsize
|
||||
|
||||
elf.Finish();
|
||||
GetElfContents(elf);
|
||||
@@ -154,6 +157,7 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
||||
"foo",
|
||||
"",
|
||||
true,
|
||||
s));
|
||||
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
||||
"PUBLIC 1000 0 superfunc\n",
|
||||
|
179
thirdparty/breakpad/common/linux/elf_core_dump.cc
vendored
Normal file
179
thirdparty/breakpad/common/linux/elf_core_dump.cc
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// elf_core_dump.cc: Implement google_breakpad::ElfCoreDump.
|
||||
// See elf_core_dump.h for details.
|
||||
|
||||
#include "common/linux/elf_core_dump.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Implementation of ElfCoreDump::Note.
|
||||
|
||||
ElfCoreDump::Note::Note() {}
|
||||
|
||||
ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {}
|
||||
|
||||
bool ElfCoreDump::Note::IsValid() const {
|
||||
return GetHeader() != NULL;
|
||||
}
|
||||
|
||||
const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const {
|
||||
return content_.GetData<Nhdr>(0);
|
||||
}
|
||||
|
||||
ElfCoreDump::Word ElfCoreDump::Note::GetType() const {
|
||||
const Nhdr* header = GetHeader();
|
||||
// 0 is not being used as a NOTE type.
|
||||
return header ? header->n_type : 0;
|
||||
}
|
||||
|
||||
MemoryRange ElfCoreDump::Note::GetName() const {
|
||||
const Nhdr* header = GetHeader();
|
||||
if (header) {
|
||||
return content_.Subrange(sizeof(Nhdr), header->n_namesz);
|
||||
}
|
||||
return MemoryRange();
|
||||
}
|
||||
|
||||
MemoryRange ElfCoreDump::Note::GetDescription() const {
|
||||
const Nhdr* header = GetHeader();
|
||||
if (header) {
|
||||
return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz),
|
||||
header->n_descsz);
|
||||
}
|
||||
return MemoryRange();
|
||||
}
|
||||
|
||||
ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const {
|
||||
MemoryRange next_content;
|
||||
const Nhdr* header = GetHeader();
|
||||
if (header) {
|
||||
size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz);
|
||||
next_offset = AlignedSize(next_offset + header->n_descsz);
|
||||
next_content =
|
||||
content_.Subrange(next_offset, content_.length() - next_offset);
|
||||
}
|
||||
return Note(next_content);
|
||||
}
|
||||
|
||||
// static
|
||||
size_t ElfCoreDump::Note::AlignedSize(size_t size) {
|
||||
size_t mask = sizeof(Word) - 1;
|
||||
return (size + mask) & ~mask;
|
||||
}
|
||||
|
||||
|
||||
// Implementation of ElfCoreDump.
|
||||
|
||||
ElfCoreDump::ElfCoreDump() {}
|
||||
|
||||
ElfCoreDump::ElfCoreDump(const MemoryRange& content)
|
||||
: content_(content) {
|
||||
}
|
||||
|
||||
void ElfCoreDump::SetContent(const MemoryRange& content) {
|
||||
content_ = content;
|
||||
}
|
||||
|
||||
bool ElfCoreDump::IsValid() const {
|
||||
const Ehdr* header = GetHeader();
|
||||
return (header &&
|
||||
header->e_ident[0] == ELFMAG0 &&
|
||||
header->e_ident[1] == ELFMAG1 &&
|
||||
header->e_ident[2] == ELFMAG2 &&
|
||||
header->e_ident[3] == ELFMAG3 &&
|
||||
header->e_ident[4] == kClass &&
|
||||
header->e_version == EV_CURRENT &&
|
||||
header->e_type == ET_CORE);
|
||||
}
|
||||
|
||||
const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const {
|
||||
return content_.GetData<Ehdr>(0);
|
||||
}
|
||||
|
||||
const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const {
|
||||
const Ehdr* header = GetHeader();
|
||||
if (header) {
|
||||
return reinterpret_cast<const Phdr*>(content_.GetArrayElement(
|
||||
header->e_phoff, header->e_phentsize, index));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType(
|
||||
Word type) const {
|
||||
for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
|
||||
const Phdr* program = GetProgramHeader(i);
|
||||
if (program->p_type == type) {
|
||||
return program;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned ElfCoreDump::GetProgramHeaderCount() const {
|
||||
const Ehdr* header = GetHeader();
|
||||
return header ? header->e_phnum : 0;
|
||||
}
|
||||
|
||||
bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) {
|
||||
for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
|
||||
const Phdr* program = GetProgramHeader(i);
|
||||
if (program->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
size_t offset_in_segment = virtual_address - program->p_vaddr;
|
||||
if (virtual_address >= program->p_vaddr &&
|
||||
offset_in_segment < program->p_filesz) {
|
||||
const void* data =
|
||||
content_.GetData(program->p_offset + offset_in_segment, length);
|
||||
if (data) {
|
||||
memcpy(buffer, data, length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ElfCoreDump::Note ElfCoreDump::GetFirstNote() const {
|
||||
MemoryRange note_content;
|
||||
const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE);
|
||||
if (program_header) {
|
||||
note_content = content_.Subrange(program_header->p_offset,
|
||||
program_header->p_filesz);
|
||||
}
|
||||
return Note(note_content);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
153
thirdparty/breakpad/common/linux/elf_core_dump.h
vendored
Normal file
153
thirdparty/breakpad/common/linux/elf_core_dump.h
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// elf_core_dump.h: Define the google_breakpad::ElfCoreDump class, which
|
||||
// encapsulates an ELF core dump file mapped into memory.
|
||||
|
||||
#ifndef COMMON_LINUX_ELF_CORE_DUMP_H_
|
||||
#define COMMON_LINUX_ELF_CORE_DUMP_H_
|
||||
|
||||
#include <elf.h>
|
||||
#if !defined(__ANDROID__)
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
#if defined(__ANDROID__)
|
||||
#include "common/linux/android_link.h"
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class encapsulating an ELF core dump file mapped into memory, which
|
||||
// provides methods for accessing program headers and the note section.
|
||||
class ElfCoreDump {
|
||||
public:
|
||||
// ELF types based on the value of __WORDSIZE.
|
||||
typedef ElfW(Ehdr) Ehdr;
|
||||
typedef ElfW(Nhdr) Nhdr;
|
||||
typedef ElfW(Phdr) Phdr;
|
||||
typedef ElfW(Word) Word;
|
||||
typedef ElfW(Addr) Addr;
|
||||
#if __WORDSIZE == 32
|
||||
static const int kClass = ELFCLASS32;
|
||||
#elif __WORDSIZE == 64
|
||||
static const int kClass = ELFCLASS64;
|
||||
#else
|
||||
#error "Unsupported __WORDSIZE for ElfCoreDump."
|
||||
#endif
|
||||
|
||||
// A class encapsulating the note content in a core dump, which provides
|
||||
// methods for accessing the name and description of a note.
|
||||
class Note {
|
||||
public:
|
||||
Note();
|
||||
|
||||
// Constructor that takes the note content from |content|.
|
||||
explicit Note(const MemoryRange& content);
|
||||
|
||||
// Returns true if this note is valid, i,e. a note header is found in
|
||||
// |content_|, or false otherwise.
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns the note header, or NULL if no note header is found in
|
||||
// |content_|.
|
||||
const Nhdr* GetHeader() const;
|
||||
|
||||
// Returns the note type, or 0 if no note header is found in |content_|.
|
||||
Word GetType() const;
|
||||
|
||||
// Returns a memory range covering the note name, or an empty range
|
||||
// if no valid note name is found in |content_|.
|
||||
MemoryRange GetName() const;
|
||||
|
||||
// Returns a memory range covering the note description, or an empty
|
||||
// range if no valid note description is found in |content_|.
|
||||
MemoryRange GetDescription() const;
|
||||
|
||||
// Returns the note following this note, or an empty note if no valid
|
||||
// note is found after this note.
|
||||
Note GetNextNote() const;
|
||||
|
||||
private:
|
||||
// Returns the size in bytes round up to the word alignment, specified
|
||||
// for the note section, of a given size in bytes.
|
||||
static size_t AlignedSize(size_t size);
|
||||
|
||||
// Note content.
|
||||
MemoryRange content_;
|
||||
};
|
||||
|
||||
ElfCoreDump();
|
||||
|
||||
// Constructor that takes the core dump content from |content|.
|
||||
explicit ElfCoreDump(const MemoryRange& content);
|
||||
|
||||
// Sets the core dump content to |content|.
|
||||
void SetContent(const MemoryRange& content);
|
||||
|
||||
// Returns true if a valid ELF header in the core dump, or false otherwise.
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns the ELF header in the core dump, or NULL if no ELF header
|
||||
// is found in |content_|.
|
||||
const Ehdr* GetHeader() const;
|
||||
|
||||
// Returns the |index|-th program header in the core dump, or NULL if no
|
||||
// ELF header is found in |content_| or |index| is out of bounds.
|
||||
const Phdr* GetProgramHeader(unsigned index) const;
|
||||
|
||||
// Returns the first program header of |type| in the core dump, or NULL if
|
||||
// no ELF header is found in |content_| or no program header of |type| is
|
||||
// found.
|
||||
const Phdr* GetFirstProgramHeaderOfType(Word type) const;
|
||||
|
||||
// Returns the number of program headers in the core dump, or 0 if no
|
||||
// ELF header is found in |content_|.
|
||||
unsigned GetProgramHeaderCount() const;
|
||||
|
||||
// Copies |length| bytes of data starting at |virtual_address| in the core
|
||||
// dump to |buffer|. |buffer| should be a valid pointer to a buffer of at
|
||||
// least |length| bytes. Returns true if the data to be copied is found in
|
||||
// the core dump, or false otherwise.
|
||||
bool CopyData(void* buffer, Addr virtual_address, size_t length);
|
||||
|
||||
// Returns the first note found in the note section of the core dump, or
|
||||
// an empty note if no note is found.
|
||||
Note GetFirstNote() const;
|
||||
|
||||
private:
|
||||
// Core dump content.
|
||||
MemoryRange content_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_ELF_CORE_DUMP_H_
|
245
thirdparty/breakpad/common/linux/elf_core_dump_unittest.cc
vendored
Normal file
245
thirdparty/breakpad/common/linux/elf_core_dump_unittest.cc
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump.
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/elf_core_dump.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/tests/file_utils.h"
|
||||
#include "common/linux/tests/crash_generator.h"
|
||||
|
||||
using google_breakpad::AutoTempDir;
|
||||
using google_breakpad::CrashGenerator;
|
||||
using google_breakpad::ElfCoreDump;
|
||||
using google_breakpad::MemoryMappedFile;
|
||||
using google_breakpad::MemoryRange;
|
||||
using google_breakpad::WriteFile;
|
||||
using std::set;
|
||||
using std::string;
|
||||
|
||||
TEST(ElfCoreDumpTest, DefaultConstructor) {
|
||||
ElfCoreDump core;
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
EXPECT_EQ(NULL, core.GetHeader());
|
||||
EXPECT_EQ(0, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(NULL, core.GetProgramHeader(0));
|
||||
EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD));
|
||||
EXPECT_FALSE(core.GetFirstNote().IsValid());
|
||||
}
|
||||
|
||||
TEST(ElfCoreDumpTest, TestElfHeader) {
|
||||
ElfCoreDump::Ehdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string core_path = temp_dir.path() + "/core";
|
||||
const char* core_file = core_path.c_str();
|
||||
MemoryMappedFile mapped_core_file;
|
||||
ElfCoreDump core;
|
||||
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
EXPECT_EQ(NULL, core.GetHeader());
|
||||
EXPECT_EQ(0, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(NULL, core.GetProgramHeader(0));
|
||||
EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD));
|
||||
EXPECT_FALSE(core.GetFirstNote().IsValid());
|
||||
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[0] = ELFMAG0;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[1] = ELFMAG1;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[2] = ELFMAG2;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[3] = ELFMAG3;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[4] = ElfCoreDump::kClass;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_version = EV_CURRENT;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_type = ET_CORE;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_TRUE(core.IsValid());
|
||||
}
|
||||
|
||||
TEST(ElfCoreDumpTest, ValidCoreFile) {
|
||||
CrashGenerator crash_generator;
|
||||
if (!crash_generator.HasDefaultCorePattern()) {
|
||||
fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped "
|
||||
"due to non-default core pattern");
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned kNumOfThreads = 3;
|
||||
const unsigned kCrashThread = 1;
|
||||
const int kCrashSignal = SIGABRT;
|
||||
// TODO(benchan): Revert to use ASSERT_TRUE once the flakiness in
|
||||
// CrashGenerator is identified and fixed.
|
||||
if (!crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
|
||||
kCrashSignal, NULL)) {
|
||||
fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped "
|
||||
"due to no core dump generated");
|
||||
return;
|
||||
}
|
||||
pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread);
|
||||
set<pid_t> expected_thread_ids;
|
||||
for (unsigned i = 0; i < kNumOfThreads; ++i) {
|
||||
expected_thread_ids.insert(crash_generator.GetThreadId(i));
|
||||
}
|
||||
|
||||
MemoryMappedFile mapped_core_file;
|
||||
ASSERT_TRUE(mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str()));
|
||||
|
||||
ElfCoreDump core;
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_TRUE(core.IsValid());
|
||||
|
||||
// Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are
|
||||
// ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific):
|
||||
// Thread Name Type
|
||||
// -------------------------------------------------------------------
|
||||
// 1st thread CORE NT_PRSTATUS
|
||||
// process-wide CORE NT_PRPSINFO
|
||||
// process-wide CORE NT_AUXV
|
||||
// 1st thread CORE NT_FPREGSET
|
||||
// 1st thread LINUX NT_PRXFPREG
|
||||
// 1st thread LINUX NT_386_TLS
|
||||
//
|
||||
// 2nd thread CORE NT_PRSTATUS
|
||||
// 2nd thread CORE NT_FPREGSET
|
||||
// 2nd thread LINUX NT_PRXFPREG
|
||||
// 2nd thread LINUX NT_386_TLS
|
||||
//
|
||||
// 3rd thread CORE NT_PRSTATUS
|
||||
// 3rd thread CORE NT_FPREGSET
|
||||
// 3rd thread LINUX NT_PRXFPREG
|
||||
// 3rd thread LINUX NT_386_TLS
|
||||
|
||||
size_t num_nt_prpsinfo = 0;
|
||||
size_t num_nt_prstatus = 0;
|
||||
size_t num_nt_fpregset = 0;
|
||||
size_t num_nt_prxfpreg = 0;
|
||||
set<pid_t> actual_thread_ids;
|
||||
ElfCoreDump::Note note = core.GetFirstNote();
|
||||
while (note.IsValid()) {
|
||||
MemoryRange name = note.GetName();
|
||||
MemoryRange description = note.GetDescription();
|
||||
EXPECT_FALSE(name.IsEmpty());
|
||||
EXPECT_FALSE(description.IsEmpty());
|
||||
|
||||
switch (note.GetType()) {
|
||||
case NT_PRPSINFO: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(elf_prpsinfo), description.length());
|
||||
++num_nt_prpsinfo;
|
||||
break;
|
||||
}
|
||||
case NT_PRSTATUS: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(elf_prstatus), description.length());
|
||||
const elf_prstatus* status = description.GetData<elf_prstatus>(0);
|
||||
actual_thread_ids.insert(status->pr_pid);
|
||||
if (num_nt_prstatus == 0) {
|
||||
EXPECT_EQ(expected_crash_thread_id, status->pr_pid);
|
||||
EXPECT_EQ(kCrashSignal, status->pr_info.si_signo);
|
||||
}
|
||||
++num_nt_prstatus;
|
||||
break;
|
||||
}
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
case NT_FPREGSET: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(user_fpregs_struct), description.length());
|
||||
++num_nt_fpregset;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(__i386)
|
||||
case NT_PRXFPREG: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(user_fpxregs_struct), description.length());
|
||||
++num_nt_prxfpreg;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
note = note.GetNextNote();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(expected_thread_ids == actual_thread_ids);
|
||||
EXPECT_EQ(1, num_nt_prpsinfo);
|
||||
EXPECT_EQ(kNumOfThreads, num_nt_prstatus);
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
EXPECT_EQ(kNumOfThreads, num_nt_fpregset);
|
||||
#endif
|
||||
#if defined(__i386)
|
||||
EXPECT_EQ(kNumOfThreads, num_nt_prxfpreg);
|
||||
#endif
|
||||
}
|
47
thirdparty/breakpad/common/linux/file_id.cc
vendored
47
thirdparty/breakpad/common/linux/file_id.cc
vendored
@@ -36,22 +36,19 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <elf.h>
|
||||
#include <fcntl.h>
|
||||
#if defined(__ANDROID__)
|
||||
#include <linux/elf.h>
|
||||
#include "client/linux/android_link.h"
|
||||
#else
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
@@ -107,10 +104,10 @@ static void FindElfClassSection(const char *elf_base,
|
||||
const Shdr* section = NULL;
|
||||
for (int i = 0; i < elf_header->e_shnum; ++i) {
|
||||
if (sections[i].sh_type == section_type) {
|
||||
const char* section_name = (char*)(elf_base +
|
||||
string_section->sh_offset +
|
||||
sections[i].sh_name);
|
||||
if (!my_strncmp(section_name, section_name, name_len)) {
|
||||
const char* current_section_name = (char*)(elf_base +
|
||||
string_section->sh_offset +
|
||||
sections[i].sh_name);
|
||||
if (!my_strncmp(current_section_name, section_name, name_len)) {
|
||||
section = §ions[i];
|
||||
break;
|
||||
}
|
||||
@@ -166,8 +163,7 @@ static bool FindElfSection(const void *elf_mapped_base,
|
||||
|
||||
template<typename ElfClass>
|
||||
static bool ElfClassBuildIDNoteIdentifier(const void *section,
|
||||
uint8_t identifier[kMDGUIDSize])
|
||||
{
|
||||
uint8_t identifier[kMDGUIDSize]) {
|
||||
typedef typename ElfClass::Nhdr Nhdr;
|
||||
|
||||
const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
|
||||
@@ -190,8 +186,7 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section,
|
||||
// Attempt to locate a .note.gnu.build-id section in an ELF binary
|
||||
// and copy as many bytes of it as will fit into |identifier|.
|
||||
static bool FindElfBuildIDNote(const void *elf_mapped_base,
|
||||
uint8_t identifier[kMDGUIDSize])
|
||||
{
|
||||
uint8_t identifier[kMDGUIDSize]) {
|
||||
void* note_section;
|
||||
int note_size, elfclass;
|
||||
if (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
|
||||
@@ -213,7 +208,6 @@ static bool FindElfBuildIDNote(const void *elf_mapped_base,
|
||||
// a simple hash by XORing the first page worth of bytes into |identifier|.
|
||||
static bool HashElfTextSection(const void *elf_mapped_base,
|
||||
uint8_t identifier[kMDGUIDSize]) {
|
||||
|
||||
void* text_section;
|
||||
int text_size;
|
||||
if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
|
||||
@@ -234,9 +228,8 @@ static bool HashElfTextSection(const void *elf_mapped_base,
|
||||
}
|
||||
|
||||
// static
|
||||
bool FileID::ElfFileIdentifierFromMappedFile(void* base,
|
||||
uint8_t identifier[kMDGUIDSize])
|
||||
{
|
||||
bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
|
||||
uint8_t identifier[kMDGUIDSize]) {
|
||||
// Look for a build id note first.
|
||||
if (FindElfBuildIDNote(base, identifier))
|
||||
return true;
|
||||
@@ -246,23 +239,11 @@ bool FileID::ElfFileIdentifierFromMappedFile(void* base,
|
||||
}
|
||||
|
||||
bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
|
||||
int fd = open(path_, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) != 0) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
void* base = mmap(NULL, st.st_size,
|
||||
PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
|
||||
close(fd);
|
||||
if (base == MAP_FAILED)
|
||||
MemoryMappedFile mapped_file(path_);
|
||||
if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)?
|
||||
return false;
|
||||
|
||||
bool success = ElfFileIdentifierFromMappedFile(base, identifier);
|
||||
munmap(base, st.st_size);
|
||||
return success;
|
||||
return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
|
||||
}
|
||||
|
||||
// static
|
||||
|
2
thirdparty/breakpad/common/linux/file_id.h
vendored
2
thirdparty/breakpad/common/linux/file_id.h
vendored
@@ -57,7 +57,7 @@ class FileID {
|
||||
// Load the identifier for the elf file mapped into memory at |base| into
|
||||
// |identifier|. Return false if the identifier could not be created for the
|
||||
// file.
|
||||
static bool ElfFileIdentifierFromMappedFile(void* base,
|
||||
static bool ElfFileIdentifierFromMappedFile(const void* base,
|
||||
uint8_t identifier[kMDGUIDSize]);
|
||||
|
||||
// Convert the |identifier| data to a NULL terminated string. The string will
|
||||
|
119
thirdparty/breakpad/common/linux/file_id_unittest.cc
vendored
119
thirdparty/breakpad/common/linux/file_id_unittest.cc
vendored
@@ -33,39 +33,52 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/linux/file_id.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
#include "common/linux/synth_elf.h"
|
||||
#include "common/test_assembler.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
using google_breakpad::SafeReadLink;
|
||||
using google_breakpad::synth_elf::BuildIDNote;
|
||||
using google_breakpad::synth_elf::ELF;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
|
||||
namespace {
|
||||
|
||||
// Simply calling Section::Append(size, byte) produces a uninteresting pattern
|
||||
// that tends to get hashed to 0000...0000. This populates the section with
|
||||
// data to produce better hashes.
|
||||
void PopulateSection(Section* section, int size, int prime_number) {
|
||||
for (int i = 0; i < size; i++)
|
||||
section->Append(1, (i % prime_number) % 256);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FileIDStripTest, StripSelf) {
|
||||
// Calculate the File ID of this binary using
|
||||
// FileID::ElfFileIdentifier, then make a copy of this binary,
|
||||
// strip it, and ensure that the result is the same.
|
||||
char exe_name[PATH_MAX];
|
||||
ssize_t len = readlink("/proc/self/exe", exe_name, PATH_MAX - 1);
|
||||
ASSERT_NE(len, -1);
|
||||
exe_name[len] = '\0';
|
||||
ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name));
|
||||
|
||||
// copy our binary to a temp file, and strip it
|
||||
char templ[] = "/tmp/file-id-unittest-XXXXXX";
|
||||
mktemp(templ);
|
||||
AutoTempDir temp_dir;
|
||||
std::string templ = temp_dir.path() + "/file-id-unittest";
|
||||
char cmdline[4096];
|
||||
sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ);
|
||||
sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str());
|
||||
ASSERT_EQ(system(cmdline), 0);
|
||||
sprintf(cmdline, "strip \"%s\"", templ);
|
||||
sprintf(cmdline, "strip \"%s\"", templ.c_str());
|
||||
ASSERT_EQ(system(cmdline), 0);
|
||||
|
||||
uint8_t identifier1[sizeof(MDGUID)];
|
||||
uint8_t identifier2[sizeof(MDGUID)];
|
||||
FileID fileid1(exe_name);
|
||||
EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1));
|
||||
FileID fileid2(templ);
|
||||
FileID fileid2(templ.c_str());
|
||||
EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2));
|
||||
char identifier_string1[37];
|
||||
char identifier_string2[37];
|
||||
@@ -74,7 +87,6 @@ TEST(FileIDStripTest, StripSelf) {
|
||||
FileID::ConvertIdentifierToString(identifier2, identifier_string2,
|
||||
37);
|
||||
EXPECT_STREQ(identifier_string1, identifier_string2);
|
||||
unlink(templ);
|
||||
}
|
||||
|
||||
class FileIDTest : public testing::Test {
|
||||
@@ -181,3 +193,92 @@ TEST_F(FileIDTest, BuildID) {
|
||||
sizeof(identifier_string));
|
||||
EXPECT_STREQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
// Test to make sure two files with different text sections produce
|
||||
// different hashes when not using a build id.
|
||||
TEST_F(FileIDTest, UniqueHashes32) {
|
||||
char identifier_string_1[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
char identifier_string_2[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
uint8_t identifier_1[sizeof(MDGUID)];
|
||||
uint8_t identifier_2[sizeof(MDGUID)];
|
||||
|
||||
{
|
||||
ELF elf1(EM_386, ELFCLASS32, kLittleEndian);
|
||||
Section foo_1(kLittleEndian);
|
||||
PopulateSection(&foo_1, 32, 5);
|
||||
elf1.AddSection(".foo", foo_1, SHT_PROGBITS);
|
||||
Section text_1(kLittleEndian);
|
||||
PopulateSection(&text_1, 4096, 17);
|
||||
elf1.AddSection(".text", text_1, SHT_PROGBITS);
|
||||
elf1.Finish();
|
||||
GetElfContents(elf1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_1));
|
||||
FileID::ConvertIdentifierToString(identifier_1, identifier_string_1,
|
||||
sizeof(identifier_string_1));
|
||||
|
||||
{
|
||||
ELF elf2(EM_386, ELFCLASS32, kLittleEndian);
|
||||
Section text_2(kLittleEndian);
|
||||
Section foo_2(kLittleEndian);
|
||||
PopulateSection(&foo_2, 32, 5);
|
||||
elf2.AddSection(".foo", foo_2, SHT_PROGBITS);
|
||||
PopulateSection(&text_2, 4096, 31);
|
||||
elf2.AddSection(".text", text_2, SHT_PROGBITS);
|
||||
elf2.Finish();
|
||||
GetElfContents(elf2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_2));
|
||||
FileID::ConvertIdentifierToString(identifier_2, identifier_string_2,
|
||||
sizeof(identifier_string_2));
|
||||
|
||||
EXPECT_STRNE(identifier_string_1, identifier_string_2);
|
||||
}
|
||||
|
||||
// Same as UniqueHashes32, for x86-64.
|
||||
TEST_F(FileIDTest, UniqueHashes64) {
|
||||
char identifier_string_1[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
char identifier_string_2[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
uint8_t identifier_1[sizeof(MDGUID)];
|
||||
uint8_t identifier_2[sizeof(MDGUID)];
|
||||
|
||||
{
|
||||
ELF elf1(EM_X86_64, ELFCLASS64, kLittleEndian);
|
||||
Section foo_1(kLittleEndian);
|
||||
PopulateSection(&foo_1, 32, 5);
|
||||
elf1.AddSection(".foo", foo_1, SHT_PROGBITS);
|
||||
Section text_1(kLittleEndian);
|
||||
PopulateSection(&text_1, 4096, 17);
|
||||
elf1.AddSection(".text", text_1, SHT_PROGBITS);
|
||||
elf1.Finish();
|
||||
GetElfContents(elf1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_1));
|
||||
FileID::ConvertIdentifierToString(identifier_1, identifier_string_1,
|
||||
sizeof(identifier_string_1));
|
||||
|
||||
{
|
||||
ELF elf2(EM_X86_64, ELFCLASS64, kLittleEndian);
|
||||
Section text_2(kLittleEndian);
|
||||
Section foo_2(kLittleEndian);
|
||||
PopulateSection(&foo_2, 32, 5);
|
||||
elf2.AddSection(".foo", foo_2, SHT_PROGBITS);
|
||||
PopulateSection(&text_2, 4096, 31);
|
||||
elf2.AddSection(".text", text_2, SHT_PROGBITS);
|
||||
elf2.Finish();
|
||||
GetElfContents(elf2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_2));
|
||||
FileID::ConvertIdentifierToString(identifier_2, identifier_string_2,
|
||||
sizeof(identifier_string_2));
|
||||
|
||||
EXPECT_STRNE(identifier_string_1, identifier_string_2);
|
||||
}
|
||||
|
24
thirdparty/breakpad/common/linux/guid_creator.cc
vendored
24
thirdparty/breakpad/common/linux/guid_creator.cc
vendored
@@ -30,6 +30,7 @@
|
||||
#include "common/linux/guid_creator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@@ -45,10 +46,6 @@
|
||||
//
|
||||
class GUIDGenerator {
|
||||
public:
|
||||
GUIDGenerator() {
|
||||
srandom(time(NULL));
|
||||
}
|
||||
|
||||
static u_int32_t BytesToUInt32(const u_int8_t bytes[]) {
|
||||
return ((u_int32_t) bytes[0]
|
||||
| ((u_int32_t) bytes[1] << 8)
|
||||
@@ -63,7 +60,8 @@ class GUIDGenerator {
|
||||
bytes[3] = (n >> 24) & 0xff;
|
||||
}
|
||||
|
||||
bool CreateGUID(GUID *guid) const {
|
||||
static bool CreateGUID(GUID *guid) {
|
||||
InitOnce();
|
||||
guid->data1 = random();
|
||||
guid->data2 = (u_int16_t)(random());
|
||||
guid->data3 = (u_int16_t)(random());
|
||||
@@ -71,13 +69,23 @@ class GUIDGenerator {
|
||||
UInt32ToBytes(&guid->data4[4], random());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
static void InitOnce() {
|
||||
pthread_once(&once_control, &InitOnceImpl);
|
||||
}
|
||||
|
||||
static void InitOnceImpl() {
|
||||
srandom(time(NULL));
|
||||
}
|
||||
|
||||
static pthread_once_t once_control;
|
||||
};
|
||||
|
||||
// Guid generator.
|
||||
const GUIDGenerator kGuidGenerator;
|
||||
pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT;
|
||||
|
||||
bool CreateGUID(GUID *guid) {
|
||||
return kGuidGenerator.CreateGUID(guid);
|
||||
return GUIDGenerator::CreateGUID(guid);
|
||||
}
|
||||
|
||||
// Parse guid to string.
|
||||
|
@@ -62,7 +62,11 @@ bool HTTPUpload::SendRequest(const string &url,
|
||||
const string &proxy_user_pwd,
|
||||
const string &ca_certificate_file,
|
||||
string *response_body,
|
||||
long *response_code,
|
||||
string *error_description) {
|
||||
if (response_code != NULL)
|
||||
*response_code = 0;
|
||||
|
||||
if (!CheckParameters(parameters))
|
||||
return false;
|
||||
|
||||
@@ -149,6 +153,11 @@ bool HTTPUpload::SendRequest(const string &url,
|
||||
CURLcode (*curl_easy_perform)(CURL *);
|
||||
*(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform");
|
||||
err_code = (*curl_easy_perform)(curl);
|
||||
if (response_code != NULL) {
|
||||
CURLcode (*curl_easy_getinfo)(CURL *, CURLINFO, ...);
|
||||
*(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo");
|
||||
(*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code);
|
||||
}
|
||||
const char* (*curl_easy_strerror)(CURLcode);
|
||||
*(void**) (&curl_easy_strerror) = dlsym(curl_lib, "curl_easy_strerror");
|
||||
#ifndef NDEBUG
|
||||
|
@@ -53,6 +53,8 @@ class HTTPUpload {
|
||||
// Only HTTP(S) URLs are currently supported. Returns true on success.
|
||||
// If the request is successful and response_body is non-NULL,
|
||||
// the response body will be returned in response_body.
|
||||
// If response_code is non-NULL, it will be set to the HTTP response code
|
||||
// received (or 0 if the request failed before getting an HTTP response).
|
||||
// If the send fails, a description of the error will be
|
||||
// returned in error_description.
|
||||
static bool SendRequest(const string &url,
|
||||
@@ -63,6 +65,7 @@ class HTTPUpload {
|
||||
const string &proxy_user_pwd,
|
||||
const string &ca_certificate_file,
|
||||
string *response_body,
|
||||
long *response_code,
|
||||
string *error_description);
|
||||
|
||||
private:
|
||||
|
@@ -105,7 +105,7 @@ my_strtoui(int* result, const char* s) {
|
||||
// Return the length of the given, non-negative integer when expressed in base
|
||||
// 10.
|
||||
static inline unsigned
|
||||
my_int_len(int i) {
|
||||
my_int_len(intmax_t i) {
|
||||
if (!i)
|
||||
return 1;
|
||||
|
||||
@@ -125,7 +125,7 @@ my_int_len(int i) {
|
||||
// i: the non-negative integer to serialise.
|
||||
// i_len: the length of the integer in base 10 (see |my_int_len|).
|
||||
static inline void
|
||||
my_itos(char* output, int i, unsigned i_len) {
|
||||
my_itos(char* output, intmax_t i, unsigned i_len) {
|
||||
for (unsigned index = i_len; index; --index, i /= 10)
|
||||
output[index - 1] = '0' + (i % 10);
|
||||
}
|
||||
|
@@ -59,8 +59,12 @@ TEST(LinuxLibcSupportTest, strcmp) {
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
if (!test_data[i*2])
|
||||
break;
|
||||
ASSERT_EQ(my_strcmp(test_data[i*2], test_data[i*2 + 1]),
|
||||
strcmp(test_data[i*2], test_data[i*2 + 1]));
|
||||
int libc_result = strcmp(test_data[i*2], test_data[i*2 + 1]);
|
||||
if (libc_result > 1)
|
||||
libc_result = 1;
|
||||
else if (libc_result < -1)
|
||||
libc_result = -1;
|
||||
ASSERT_EQ(my_strcmp(test_data[i*2], test_data[i*2 + 1]), libc_result);
|
||||
}
|
||||
}
|
||||
|
||||
|
108
thirdparty/breakpad/common/linux/memory_mapped_file.cc
vendored
Normal file
108
thirdparty/breakpad/common/linux/memory_mapped_file.cc
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile.
|
||||
// See memory_mapped_file.h for details.
|
||||
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#if defined(__ANDROID__)
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile() {}
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile(const char* path) {
|
||||
Map(path);
|
||||
}
|
||||
|
||||
MemoryMappedFile::~MemoryMappedFile() {
|
||||
Unmap();
|
||||
}
|
||||
|
||||
bool MemoryMappedFile::Map(const char* path) {
|
||||
Unmap();
|
||||
|
||||
int fd = sys_open(path, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) != 0) {
|
||||
#elif defined(__x86_64__)
|
||||
struct kernel_stat st;
|
||||
if (sys_fstat(fd, &st) == -1 || st.st_size < 0) {
|
||||
#else
|
||||
struct kernel_stat64 st;
|
||||
if (sys_fstat64(fd, &st) == -1 || st.st_size < 0) {
|
||||
#endif
|
||||
sys_close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the file size is zero, simply use an empty MemoryRange and return
|
||||
// true. Don't bother to call mmap() even though mmap() can handle an
|
||||
// empty file on some platforms.
|
||||
if (st.st_size == 0) {
|
||||
sys_close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__)
|
||||
void* data = sys_mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
#else
|
||||
void* data = sys_mmap2(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
#endif
|
||||
sys_close(fd);
|
||||
if (data == MAP_FAILED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
content_.Set(data, st.st_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryMappedFile::Unmap() {
|
||||
if (content_.data()) {
|
||||
sys_munmap(const_cast<u_int8_t*>(content_.data()), content_.length());
|
||||
content_.Set(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
86
thirdparty/breakpad/common/linux/memory_mapped_file.h
vendored
Normal file
86
thirdparty/breakpad/common/linux/memory_mapped_file.h
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// memory_mapped_file.h: Define the google_breakpad::MemoryMappedFile
|
||||
// class, which maps a file into memory for read-only access.
|
||||
|
||||
#ifndef COMMON_LINUX_MEMORY_MAPPED_FILE_H_
|
||||
#define COMMON_LINUX_MEMORY_MAPPED_FILE_H_
|
||||
|
||||
#include "common/basictypes.h"
|
||||
#include "common/memory_range.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A utility class for mapping a file into memory for read-only access of
|
||||
// the file content. Its implementation avoids calling into libc functions
|
||||
// by directly making system calls for open, close, mmap, and munmap.
|
||||
class MemoryMappedFile {
|
||||
public:
|
||||
MemoryMappedFile();
|
||||
|
||||
// Constructor that calls Map() to map a file at |path| into memory.
|
||||
// If Map() fails, the object behaves as if it is default constructed.
|
||||
explicit MemoryMappedFile(const char* path);
|
||||
|
||||
~MemoryMappedFile();
|
||||
|
||||
// Maps a file at |path| into memory, which can then be accessed via
|
||||
// content() as a MemoryRange object or via data(), and returns true on
|
||||
// success. Mapping an empty file will succeed but with data() and size()
|
||||
// returning NULL and 0, respectively. An existing mapping is unmapped
|
||||
// before a new mapping is created.
|
||||
bool Map(const char* path);
|
||||
|
||||
// Unmaps the memory for the mapped file. It's a no-op if no file is
|
||||
// mapped.
|
||||
void Unmap();
|
||||
|
||||
// Returns a MemoryRange object that covers the memory for the mapped
|
||||
// file. The MemoryRange object is empty if no file is mapped.
|
||||
const MemoryRange& content() const { return content_; }
|
||||
|
||||
// Returns a pointer to the beginning of the memory for the mapped file.
|
||||
// or NULL if no file is mapped or the mapped file is empty.
|
||||
const void* data() const { return content_.data(); }
|
||||
|
||||
// Returns the size in bytes of the mapped file, or zero if no file
|
||||
// is mapped.
|
||||
size_t size() const { return content_.length(); }
|
||||
|
||||
private:
|
||||
// Mapped file content as a MemoryRange object.
|
||||
MemoryRange content_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile);
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_MEMORY_MAPPED_FILE_H_
|
175
thirdparty/breakpad/common/linux/memory_mapped_file_unittest.cc
vendored
Normal file
175
thirdparty/breakpad/common/linux/memory_mapped_file_unittest.cc
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// memory_mapped_file_unittest.cc:
|
||||
// Unit tests for google_breakpad::MemoryMappedFile.
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/tests/file_utils.h"
|
||||
|
||||
using google_breakpad::AutoTempDir;
|
||||
using google_breakpad::MemoryMappedFile;
|
||||
using google_breakpad::WriteFile;
|
||||
using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
class MemoryMappedFileTest : public testing::Test {
|
||||
protected:
|
||||
void ExpectNoMappedData(const MemoryMappedFile& mapped_file) {
|
||||
EXPECT_TRUE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() == NULL);
|
||||
EXPECT_EQ(0, mapped_file.size());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(MemoryMappedFileTest, DefaultConstructor) {
|
||||
MemoryMappedFile mapped_file;
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, UnmapWithoutMap) {
|
||||
MemoryMappedFile mapped_file;
|
||||
mapped_file.Unmap();
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapNonexistentFile) {
|
||||
{
|
||||
MemoryMappedFile mapped_file("nonexistent-file");
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_FALSE(mapped_file.Map("nonexistent-file"));
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapEmptyFile) {
|
||||
AutoTempDir temp_dir;
|
||||
string test_file = temp_dir.path() + "/empty_file";
|
||||
ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0));
|
||||
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file.c_str());
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_TRUE(mapped_file.Map(test_file.c_str()));
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapNonEmptyFile) {
|
||||
char data[256];
|
||||
size_t data_size = sizeof(data);
|
||||
for (size_t i = 0; i < data_size; ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string test_file = temp_dir.path() + "/test_file";
|
||||
ASSERT_TRUE(WriteFile(test_file.c_str(), data, data_size));
|
||||
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file.c_str());
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size));
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_TRUE(mapped_file.Map(test_file.c_str()));
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, RemapAfterMap) {
|
||||
char data1[256];
|
||||
size_t data1_size = sizeof(data1);
|
||||
for (size_t i = 0; i < data1_size; ++i) {
|
||||
data1[i] = i;
|
||||
}
|
||||
|
||||
char data2[50];
|
||||
size_t data2_size = sizeof(data2);
|
||||
for (size_t i = 0; i < data2_size; ++i) {
|
||||
data2[i] = 255 - i;
|
||||
}
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string test_file1 = temp_dir.path() + "/test_file1";
|
||||
string test_file2 = temp_dir.path() + "/test_file2";
|
||||
ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size));
|
||||
ASSERT_TRUE(WriteFile(test_file2.c_str(), data2, data2_size));
|
||||
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file1.c_str());
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data1_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
|
||||
|
||||
mapped_file.Map(test_file2.c_str());
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data2_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_TRUE(mapped_file.Map(test_file1.c_str()));
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data1_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
|
||||
|
||||
mapped_file.Map(test_file2.c_str());
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data2_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
|
||||
}
|
||||
}
|
53
thirdparty/breakpad/common/linux/safe_readlink.cc
vendored
Normal file
53
thirdparty/breakpad/common/linux/safe_readlink.cc
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// safe_readlink.cc: Implement google_breakpad::SafeReadLink.
|
||||
// See safe_readlink.h for details.
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
bool SafeReadLink(const char* path, char* buffer, size_t buffer_size) {
|
||||
// sys_readlink() does not add a NULL byte to |buffer|. In order to return
|
||||
// a NULL-terminated string in |buffer|, |buffer_size| should be at least
|
||||
// one byte longer than the expected path length. Also, sys_readlink()
|
||||
// returns the actual path length on success, which does not count the
|
||||
// NULL byte, so |result_size| should be less than |buffer_size|.
|
||||
ssize_t result_size = sys_readlink(path, buffer, buffer_size);
|
||||
if (result_size >= 0 && static_cast<size_t>(result_size) < buffer_size) {
|
||||
buffer[result_size] = '\0';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
65
thirdparty/breakpad/common/linux/safe_readlink.h
vendored
Normal file
65
thirdparty/breakpad/common/linux/safe_readlink.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// safe_readlink.h: Define the google_breakpad::SafeReadLink function,
|
||||
// which wraps sys_readlink and gurantees the result is NULL-terminated.
|
||||
|
||||
#ifndef COMMON_LINUX_SAFE_READLINK_H_
|
||||
#define COMMON_LINUX_SAFE_READLINK_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// This function wraps sys_readlink() and performs the same functionalty,
|
||||
// but guarantees |buffer| is NULL-terminated if sys_readlink() returns
|
||||
// no error. It takes the same arguments as sys_readlink(), but unlike
|
||||
// sys_readlink(), it returns true on success.
|
||||
//
|
||||
// |buffer_size| specifies the size of |buffer| in bytes. As this function
|
||||
// always NULL-terminates |buffer| on success, |buffer_size| should be
|
||||
// at least one byte longer than the expected path length (e.g. PATH_MAX,
|
||||
// which is typically defined as the maximum length of a path name
|
||||
// including the NULL byte).
|
||||
//
|
||||
// The implementation of this function calls sys_readlink() instead of
|
||||
// readlink(), it can thus be used in the context where calling to libc
|
||||
// functions is discouraged.
|
||||
bool SafeReadLink(const char* path, char* buffer, size_t buffer_size);
|
||||
|
||||
// Same as the three-argument version of SafeReadLink() but deduces the
|
||||
// size of |buffer| if it is a char array of known size.
|
||||
template <size_t N>
|
||||
bool SafeReadLink(const char* path, char (&buffer)[N]) {
|
||||
return SafeReadLink(path, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_SAFE_READLINK_H_
|
89
thirdparty/breakpad/common/linux/safe_readlink_unittest.cc
vendored
Normal file
89
thirdparty/breakpad/common/linux/safe_readlink_unittest.cc
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// safe_readlink_unittest.cc: Unit tests for google_breakpad::SafeReadLink.
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
|
||||
using google_breakpad::SafeReadLink;
|
||||
|
||||
TEST(SafeReadLinkTest, ZeroBufferSize) {
|
||||
char buffer[1];
|
||||
EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 0));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, BufferSizeTooSmall) {
|
||||
char buffer[1];
|
||||
EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 1));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, BoundaryBufferSize) {
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer, sizeof(buffer)));
|
||||
size_t path_length = strlen(buffer);
|
||||
EXPECT_LT(0, path_length);
|
||||
EXPECT_GT(sizeof(buffer), path_length);
|
||||
|
||||
// Buffer size equals to the expected path length plus 1 for the NULL byte.
|
||||
char buffer2[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2, path_length + 1));
|
||||
EXPECT_EQ(path_length, strlen(buffer2));
|
||||
EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX));
|
||||
|
||||
// Buffer size equals to the expected path length.
|
||||
EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, path_length));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, NonexistentPath) {
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_FALSE(SafeReadLink("nonexistent_path", buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, NonSymbolicLinkPath) {
|
||||
char actual_path[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", actual_path, sizeof(actual_path)));
|
||||
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_FALSE(SafeReadLink(actual_path, buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, DeduceBufferSizeFromCharArray) {
|
||||
char buffer[PATH_MAX];
|
||||
char* buffer_pointer = buffer;
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer_pointer, sizeof(buffer)));
|
||||
size_t path_length = strlen(buffer);
|
||||
|
||||
// Use the template version of SafeReadLink to deduce the buffer size
|
||||
// from the char array.
|
||||
char buffer2[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2));
|
||||
EXPECT_EQ(path_length, strlen(buffer2));
|
||||
EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX));
|
||||
}
|
276
thirdparty/breakpad/common/linux/tests/crash_generator.cc
vendored
Normal file
276
thirdparty/breakpad/common/linux/tests/crash_generator.cc
vendored
Normal file
@@ -0,0 +1,276 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// crash_generator.cc: Implement google_breakpad::CrashGenerator.
|
||||
// See crash_generator.h for details.
|
||||
|
||||
#include "common/linux/tests/crash_generator.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/tests/file_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct ThreadData {
|
||||
pthread_t thread;
|
||||
pthread_barrier_t* barrier;
|
||||
pid_t* thread_id_ptr;
|
||||
};
|
||||
|
||||
const char* const kProcFilesToCopy[] = {
|
||||
"auxv", "cmdline", "environ", "maps", "status"
|
||||
};
|
||||
const size_t kNumProcFilesToCopy =
|
||||
sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]);
|
||||
|
||||
// Core file size limit set to 1 MB, which is big enough for test purposes.
|
||||
const rlim_t kCoreSizeLimit = 1024 * 1024;
|
||||
|
||||
void *thread_function(void *data) {
|
||||
ThreadData* thread_data = reinterpret_cast<ThreadData*>(data);
|
||||
volatile pid_t thread_id = syscall(__NR_gettid);
|
||||
*(thread_data->thread_id_ptr) = thread_id;
|
||||
int result = pthread_barrier_wait(thread_data->barrier);
|
||||
if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) {
|
||||
exit(1);
|
||||
}
|
||||
while (true) {
|
||||
pthread_yield();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
CrashGenerator::CrashGenerator()
|
||||
: shared_memory_(NULL),
|
||||
shared_memory_size_(0) {
|
||||
}
|
||||
|
||||
CrashGenerator::~CrashGenerator() {
|
||||
UnmapSharedMemory();
|
||||
}
|
||||
|
||||
bool CrashGenerator::HasDefaultCorePattern() const {
|
||||
char buffer[8];
|
||||
ssize_t buffer_size = sizeof(buffer);
|
||||
return ReadFile("/proc/sys/kernel/core_pattern", buffer, &buffer_size) &&
|
||||
buffer_size == 5 && memcmp(buffer, "core", 4) == 0;
|
||||
}
|
||||
|
||||
std::string CrashGenerator::GetCoreFilePath() const {
|
||||
return temp_dir_.path() + "/core";
|
||||
}
|
||||
|
||||
std::string CrashGenerator::GetDirectoryOfProcFilesCopy() const {
|
||||
return temp_dir_.path() + "/proc";
|
||||
}
|
||||
|
||||
pid_t CrashGenerator::GetThreadId(unsigned index) const {
|
||||
return reinterpret_cast<pid_t*>(shared_memory_)[index];
|
||||
}
|
||||
|
||||
pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) {
|
||||
return reinterpret_cast<pid_t*>(shared_memory_) + index;
|
||||
}
|
||||
|
||||
bool CrashGenerator::MapSharedMemory(size_t memory_size) {
|
||||
if (!UnmapSharedMemory())
|
||||
return false;
|
||||
|
||||
void* mapped_memory = mmap(0, memory_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||
if (mapped_memory == MAP_FAILED) {
|
||||
perror("CrashGenerator: Failed to map shared memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(mapped_memory, 0, memory_size);
|
||||
shared_memory_ = mapped_memory;
|
||||
shared_memory_size_ = memory_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CrashGenerator::UnmapSharedMemory() {
|
||||
if (!shared_memory_)
|
||||
return true;
|
||||
|
||||
if (munmap(shared_memory_, shared_memory_size_) == 0) {
|
||||
shared_memory_ = NULL;
|
||||
shared_memory_size_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
perror("CrashGenerator: Failed to unmap shared memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const {
|
||||
struct rlimit limits = { limit, limit };
|
||||
if (setrlimit(RLIMIT_CORE, &limits) == -1) {
|
||||
perror("CrashGenerator: Failed to set core file size limit");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CrashGenerator::CreateChildCrash(
|
||||
unsigned num_threads, unsigned crash_thread, int crash_signal,
|
||||
pid_t* child_pid) {
|
||||
if (num_threads == 0 || crash_thread >= num_threads)
|
||||
return false;
|
||||
|
||||
if (!MapSharedMemory(num_threads * sizeof(pid_t)))
|
||||
return false;
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
if (chdir(temp_dir_.path().c_str()) == -1) {
|
||||
perror("CrashGenerator: Failed to change directory");
|
||||
exit(1);
|
||||
}
|
||||
if (SetCoreFileSizeLimit(kCoreSizeLimit)) {
|
||||
CreateThreadsInChildProcess(num_threads);
|
||||
std::string proc_dir = GetDirectoryOfProcFilesCopy();
|
||||
if (mkdir(proc_dir.c_str(), 0755) == -1) {
|
||||
perror("CrashGenerator: Failed to create proc directory");
|
||||
exit(1);
|
||||
}
|
||||
if (!CopyProcFiles(getpid(), proc_dir.c_str())) {
|
||||
fprintf(stderr, "CrashGenerator: Failed to copy proc files\n");
|
||||
exit(1);
|
||||
}
|
||||
if (kill(*GetThreadIdPointer(crash_thread), crash_signal) == -1) {
|
||||
perror("CrashGenerator: Failed to kill thread by signal");
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
} else if (pid == -1) {
|
||||
perror("CrashGenerator: Failed to create child process");
|
||||
return false;
|
||||
}
|
||||
|
||||
int status;
|
||||
if (HANDLE_EINTR(waitpid(pid, &status, 0)) == -1) {
|
||||
perror("CrashGenerator: Failed to wait for child process");
|
||||
return false;
|
||||
}
|
||||
if (!WIFSIGNALED(status) || WTERMSIG(status) != crash_signal) {
|
||||
fprintf(stderr, "CrashGenerator: Child process not killed by the expected signal\n"
|
||||
" exit status=0x%x signaled=%s sig=%d expected=%d\n",
|
||||
status, WIFSIGNALED(status) ? "true" : "false",
|
||||
WTERMSIG(status), crash_signal);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (child_pid)
|
||||
*child_pid = pid;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CrashGenerator::CopyProcFiles(pid_t pid, const char* path) const {
|
||||
char from_path[PATH_MAX], to_path[PATH_MAX];
|
||||
for (size_t i = 0; i < kNumProcFilesToCopy; ++i) {
|
||||
int num_chars = snprintf(from_path, PATH_MAX, "/proc/%d/%s",
|
||||
pid, kProcFilesToCopy[i]);
|
||||
if (num_chars < 0 || num_chars >= PATH_MAX)
|
||||
return false;
|
||||
|
||||
num_chars = snprintf(to_path, PATH_MAX, "%s/%s",
|
||||
path, kProcFilesToCopy[i]);
|
||||
if (num_chars < 0 || num_chars >= PATH_MAX)
|
||||
return false;
|
||||
|
||||
if (!CopyFile(from_path, to_path))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) {
|
||||
*GetThreadIdPointer(0) = getpid();
|
||||
|
||||
if (num_threads <= 1)
|
||||
return;
|
||||
|
||||
// This method does not clean up any pthread resource, as the process
|
||||
// is expected to be killed anyway.
|
||||
ThreadData* thread_data = new ThreadData[num_threads];
|
||||
|
||||
// Create detached threads so that we do not worry about pthread_join()
|
||||
// later being called or not.
|
||||
pthread_attr_t thread_attributes;
|
||||
if (pthread_attr_init(&thread_attributes) != 0 ||
|
||||
pthread_attr_setdetachstate(&thread_attributes,
|
||||
PTHREAD_CREATE_DETACHED) != 0) {
|
||||
fprintf(stderr, "CrashGenerator: Failed to initialize thread attribute\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_barrier_t thread_barrier;
|
||||
if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) {
|
||||
fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i < num_threads; ++i) {
|
||||
thread_data[i].barrier = &thread_barrier;
|
||||
thread_data[i].thread_id_ptr = GetThreadIdPointer(i);
|
||||
if (pthread_create(&thread_data[i].thread, &thread_attributes,
|
||||
thread_function, &thread_data[i]) != 0) {
|
||||
fprintf(stderr, "CrashGenerator: Failed to create thread %d\n", i);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int result = pthread_barrier_wait(&thread_barrier);
|
||||
if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) {
|
||||
fprintf(stderr, "CrashGenerator: Failed to wait for thread barrier\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pthread_barrier_destroy(&thread_barrier);
|
||||
pthread_attr_destroy(&thread_attributes);
|
||||
delete[] thread_data;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
116
thirdparty/breakpad/common/linux/tests/crash_generator.h
vendored
Normal file
116
thirdparty/breakpad/common/linux/tests/crash_generator.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// crash_generator.h: Define the google_breakpad::CrashGenerator class,
|
||||
// which is used to generate a crash (and a core dump file) for testing.
|
||||
|
||||
#ifndef COMMON_LINUX_TESTS_CRASH_GENERATOR_H_
|
||||
#define COMMON_LINUX_TESTS_CRASH_GENERATOR_H_
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A utility class for generating a crash (and a core dump file) for
|
||||
// testing. It creates a child process with the specified number of
|
||||
// threads, which is then termainated by the specified signal. A core
|
||||
// dump file is expected to be created upon the termination of the child
|
||||
// process, which can then be used for testing code that processes core
|
||||
// dump files.
|
||||
class CrashGenerator {
|
||||
public:
|
||||
CrashGenerator();
|
||||
|
||||
~CrashGenerator();
|
||||
|
||||
// Returns true if a core dump file named 'core' will be generated in
|
||||
// the current directory for a test that produces a crash by checking
|
||||
// if /proc/sys/kernel/core_pattern has the default value 'core'.
|
||||
bool HasDefaultCorePattern() const;
|
||||
|
||||
// Returns the expected path of the core dump file.
|
||||
std::string GetCoreFilePath() const;
|
||||
|
||||
// Returns the directory of a copy of proc files of the child process.
|
||||
std::string GetDirectoryOfProcFilesCopy() const;
|
||||
|
||||
// Creates a crash (and a core dump file) by creating a child process with
|
||||
// |num_threads| threads, and the terminating the child process by sending
|
||||
// a signal with number |crash_signal| to the |crash_thread|-th thread.
|
||||
// Returns true on success.
|
||||
bool CreateChildCrash(unsigned num_threads, unsigned crash_thread,
|
||||
int crash_signal, pid_t* child_pid);
|
||||
|
||||
// Returns the thread ID of the |index|-th thread in the child process.
|
||||
// This method does not validate |index|.
|
||||
pid_t GetThreadId(unsigned index) const;
|
||||
|
||||
private:
|
||||
// Copies the following proc files of the process with |pid| to the directory
|
||||
// at |path|: auxv, cmdline, environ, maps, status
|
||||
// The directory must have been created. Returns true on success.
|
||||
bool CopyProcFiles(pid_t pid, const char* path) const;
|
||||
|
||||
// Creates |num_threads| threads in the child process.
|
||||
void CreateThreadsInChildProcess(unsigned num_threads);
|
||||
|
||||
// Sets the maximum size of core dump file (both the soft and hard limit)
|
||||
// to |limit| bytes. Returns true on success.
|
||||
bool SetCoreFileSizeLimit(rlim_t limit) const;
|
||||
|
||||
// Creates a shared memory of |memory_size| bytes for communicating thread
|
||||
// IDs between the parent and child process. Returns true on success.
|
||||
bool MapSharedMemory(size_t memory_size);
|
||||
|
||||
// Releases any shared memory created by MapSharedMemory(). Returns true on
|
||||
// success.
|
||||
bool UnmapSharedMemory();
|
||||
|
||||
// Returns the pointer to the thread ID of the |index|-th thread in the child
|
||||
// process. This method does not validate |index|.
|
||||
pid_t* GetThreadIdPointer(unsigned index);
|
||||
|
||||
// Temporary directory in which a core file is generated.
|
||||
AutoTempDir temp_dir_;
|
||||
|
||||
// Shared memory for communicating thread IDs between the parent and
|
||||
// child process.
|
||||
void* shared_memory_;
|
||||
|
||||
// Number of bytes mapped for |shared_memory_|.
|
||||
size_t shared_memory_size_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_TESTS_CRASH_GENERATOR_H_
|
@@ -29,8 +29,6 @@
|
||||
|
||||
ARCHS = $(ARCHS_STANDARD_32_64_BIT)
|
||||
SDKROOT = macosx10.5
|
||||
SDKROOT[arch=i386] = macosx10.4
|
||||
SDKROOT[arch=ppc] = macosx10.4
|
||||
|
||||
GCC_VERSION = 4.2
|
||||
GCC_VERSION[sdk=macosx10.4][arch=*] = 4.0
|
||||
|
@@ -32,7 +32,7 @@
|
||||
// Each file is sent with a name field in addition to the filename and data
|
||||
// The data will be sent synchronously.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface HTTPMultipartUpload : NSObject {
|
||||
@protected
|
||||
|
@@ -32,6 +32,8 @@
|
||||
|
||||
@interface HTTPMultipartUpload(PrivateMethods)
|
||||
- (NSString *)multipartBoundary;
|
||||
// Each of the following methods will append the starting multipart boundary,
|
||||
// but not the ending one.
|
||||
- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value;
|
||||
- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name;
|
||||
- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name;
|
||||
@@ -67,11 +69,9 @@
|
||||
NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
|
||||
"filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
|
||||
NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped];
|
||||
NSString *post = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
|
||||
|
||||
[data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
[data appendData:contents];
|
||||
[data appendData:[post dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
return data;
|
||||
}
|
||||
@@ -182,6 +182,9 @@
|
||||
[postBody appendData:fileData];
|
||||
}
|
||||
|
||||
NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_];
|
||||
[postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
[req setHTTPBody:postBody];
|
||||
[req setHTTPMethod:@"POST"];
|
||||
|
||||
@@ -193,7 +196,8 @@
|
||||
error:error];
|
||||
|
||||
[response_ retain];
|
||||
|
||||
[req release];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
8
thirdparty/breakpad/common/mac/MachIPC.mm
vendored
8
thirdparty/breakpad/common/mac/MachIPC.mm
vendored
@@ -32,6 +32,7 @@
|
||||
|
||||
#import <stdio.h>
|
||||
#import "MachIPC.h"
|
||||
#include "common/mac/bootstrap_compat.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
//==============================================================================
|
||||
@@ -187,9 +188,10 @@ ReceivePort::ReceivePort(const char *receive_port_name) {
|
||||
if (init_result_ != KERN_SUCCESS)
|
||||
return;
|
||||
|
||||
init_result_ = bootstrap_register(bootstrap_port,
|
||||
const_cast<char*>(receive_port_name),
|
||||
port_);
|
||||
init_result_ = breakpad::BootstrapRegister(
|
||||
bootstrap_port,
|
||||
const_cast<char*>(receive_port_name),
|
||||
port_);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
@@ -134,7 +134,7 @@ class SimpleStringDictionary {
|
||||
// Given |key|, returns its corresponding |value|.
|
||||
// If |key| is NULL, an assert will fire or NULL will be returned. If |key|
|
||||
// is not found or is an empty string, NULL is returned.
|
||||
const char *GetValueForKey(const char *key);
|
||||
const char *GetValueForKey(const char *key) const;
|
||||
|
||||
// Stores a string |value| represented by |key|. If |key| is NULL or an empty
|
||||
// string, this will assert (or do nothing). If |value| is NULL then
|
||||
|
@@ -55,13 +55,13 @@ int SimpleStringDictionary::GetCount() const {
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char *SimpleStringDictionary::GetValueForKey(const char *key) {
|
||||
const char *SimpleStringDictionary::GetValueForKey(const char *key) const {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
KeyValueEntry &entry = entries_[i];
|
||||
const KeyValueEntry &entry = entries_[i];
|
||||
if (entry.IsActive() && !strcmp(entry.GetKey(), key)) {
|
||||
return entry.GetValue();
|
||||
}
|
||||
|
42
thirdparty/breakpad/common/mac/bootstrap_compat.cc
vendored
Normal file
42
thirdparty/breakpad/common/mac/bootstrap_compat.cc
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
#include "common/mac/bootstrap_compat.h"
|
||||
|
||||
namespace breakpad {
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
kern_return_t BootstrapRegister(mach_port_t bp,
|
||||
name_t service_name,
|
||||
mach_port_t sp) {
|
||||
return bootstrap_register(bp, service_name, sp);
|
||||
}
|
||||
#pragma GCC diagnostic warning "-Wdeprecated-declarations"
|
||||
|
||||
} // namesapce breakpad
|
54
thirdparty/breakpad/common/mac/bootstrap_compat.h
vendored
Normal file
54
thirdparty/breakpad/common/mac/bootstrap_compat.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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_MAC_BOOTSTRAP_COMPAT_H_
|
||||
#define COMMON_MAC_BOOTSTRAP_COMPAT_H_
|
||||
|
||||
#include <servers/bootstrap.h>
|
||||
|
||||
namespace breakpad {
|
||||
|
||||
// Wrapper for bootstrap_register to avoid deprecation warnings.
|
||||
//
|
||||
// In 10.6, it's possible to call bootstrap_check_in as the one-stop-shop for
|
||||
// handling what bootstrap_register is used for. In 10.5, bootstrap_check_in
|
||||
// can't check in a service whose name has not yet been registered, despite
|
||||
// bootstrap_register being marked as deprecated in that OS release. Breakpad
|
||||
// needs to register new service names, and in 10.5, calling
|
||||
// bootstrap_register is the only way to achieve that. Attempts to call
|
||||
// bootstrap_check_in for a new service name on 10.5 will result in
|
||||
// BOOTSTRAP_UNKNOWN_SERVICE being returned rather than registration of the
|
||||
// new service name.
|
||||
kern_return_t BootstrapRegister(mach_port_t bp,
|
||||
name_t service_name,
|
||||
mach_port_t sp);
|
||||
|
||||
} // namespace breakpad
|
||||
|
||||
#endif // COMMON_MAC_BOOTSTRAP_COMPAT_H_
|
24
thirdparty/breakpad/common/mac/dump_syms.h
vendored
24
thirdparty/breakpad/common/mac/dump_syms.h
vendored
@@ -1,6 +1,6 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@@ -52,9 +52,9 @@ namespace google_breakpad {
|
||||
|
||||
class DumpSymbols {
|
||||
public:
|
||||
DumpSymbols()
|
||||
DumpSymbols()
|
||||
: input_pathname_(),
|
||||
object_filename_(),
|
||||
object_filename_(),
|
||||
contents_(),
|
||||
selected_object_file_(),
|
||||
selected_object_name_() { }
|
||||
@@ -84,9 +84,9 @@ class DumpSymbols {
|
||||
// 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,
|
||||
|
||||
// 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.
|
||||
//
|
||||
// By default, if this dumper's file contains only one object file, then
|
||||
@@ -94,7 +94,7 @@ class DumpSymbols {
|
||||
// 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);
|
||||
|
||||
|
||||
// Return a pointer to an array of 'struct fat_arch' structures,
|
||||
// describing the object files contained in this dumper's file. Set
|
||||
// *|count| to the number of elements in the array. The returned array is
|
||||
@@ -109,10 +109,10 @@ class DumpSymbols {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read the selected object file's debugging information, and write it
|
||||
// out to |stream|. Return true on success; if an error occurs, report it
|
||||
// and return false.
|
||||
bool WriteSymbolFile(std::ostream &stream);
|
||||
// Read the selected object file's debugging information, and write it out to
|
||||
// |stream|. Write the CFI section if |cfi| is true. Return true on success;
|
||||
// if an error occurs, report it and return false.
|
||||
bool WriteSymbolFile(std::ostream &stream, bool cfi);
|
||||
|
||||
private:
|
||||
// Used internally.
|
||||
@@ -158,7 +158,7 @@ class DumpSymbols {
|
||||
// has exactly one element.
|
||||
vector<struct fat_arch> object_files_;
|
||||
|
||||
// The object file in object_files_ selected to dump, or NULL if
|
||||
// The object file in object_files_ selected to dump, or NULL if
|
||||
// SetArchitecture hasn't been called yet.
|
||||
const struct fat_arch *selected_object_file_;
|
||||
|
||||
|
48
thirdparty/breakpad/common/mac/dump_syms.mm
vendored
48
thirdparty/breakpad/common/mac/dump_syms.mm
vendored
@@ -1,6 +1,6 @@
|
||||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright (c) 2010, Google Inc.
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@@ -79,7 +79,7 @@ namespace google_breakpad {
|
||||
bool DumpSymbols::Read(NSString *filename) {
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
||||
fprintf(stderr, "Object file does not exist: %s\n",
|
||||
[filename fileSystemRepresentation]);
|
||||
[filename fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -101,15 +101,15 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||
// pathForResource:ofType:inDirectory likes.
|
||||
NSString *base_name = [input_pathname_ lastPathComponent];
|
||||
NSString *dwarf_resource;
|
||||
|
||||
|
||||
do {
|
||||
NSString *new_base_name = [base_name stringByDeletingPathExtension];
|
||||
|
||||
// If stringByDeletingPathExtension returned the name unchanged, then
|
||||
// there's nothing more for us to strip off --- lose.
|
||||
if ([new_base_name isEqualToString:base_name]) {
|
||||
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
|
||||
[input_pathname_ fileSystemRepresentation]);
|
||||
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
|
||||
[input_pathname_ fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -141,12 +141,12 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||
// file don't affect memory and vice versa).
|
||||
NSError *error;
|
||||
contents_ = [NSData dataWithContentsOfFile:object_filename_
|
||||
options:0
|
||||
error:&error];
|
||||
options:0
|
||||
error:&error];
|
||||
if (!contents_) {
|
||||
fprintf(stderr, "Error reading object file: %s: %s\n",
|
||||
[object_filename_ fileSystemRepresentation],
|
||||
[[error localizedDescription] UTF8String]);
|
||||
[object_filename_ fileSystemRepresentation],
|
||||
[[error localizedDescription] UTF8String]);
|
||||
return false;
|
||||
}
|
||||
[contents_ retain];
|
||||
@@ -166,7 +166,7 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||
fat_reader.object_files(&object_files_count);
|
||||
if (object_files_count == 0) {
|
||||
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
object_files_.resize(object_files_count);
|
||||
@@ -197,14 +197,14 @@ bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
|
||||
}
|
||||
return arch_set;
|
||||
}
|
||||
|
||||
|
||||
string DumpSymbols::Identifier() {
|
||||
FileID file_id([object_filename_ fileSystemRepresentation]);
|
||||
unsigned char identifier_bytes[16];
|
||||
cpu_type_t cpu_type = selected_object_file_->cputype;
|
||||
if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
|
||||
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::SectionMap &dwarf_sections) const {
|
||||
// Build a byte reader of the appropriate endianness.
|
||||
ByteReader byte_reader(macho_reader.big_endian()
|
||||
ByteReader byte_reader(macho_reader.big_endian()
|
||||
? dwarf2reader::ENDIANNESS_BIG
|
||||
: dwarf2reader::ENDIANNESS_LITTLE);
|
||||
|
||||
@@ -265,10 +265,10 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||
// There had better be a __debug_info section!
|
||||
if (!debug_info_section.first) {
|
||||
fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
|
||||
selected_object_name_.c_str());
|
||||
selected_object_name_.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Build a line-to-module loader for the root handler to use.
|
||||
DumperLineToModule line_to_module(&byte_reader);
|
||||
|
||||
@@ -343,7 +343,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
|
||||
// investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so
|
||||
// this is the only base address the CFI parser will need.
|
||||
byte_reader.SetCFIDataBase(section.address, cfi);
|
||||
|
||||
|
||||
dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_,
|
||||
section.section_name);
|
||||
dwarf2reader::CallFrameInfo parser(cfi, cfi_size,
|
||||
@@ -421,7 +421,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||
bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||
// Select an object file, if SetArchitecture hasn't been called to set one
|
||||
// explicitly.
|
||||
if (!selected_object_file_) {
|
||||
@@ -433,10 +433,10 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||
const NXArchInfo *local_arch = NXGetLocalArchInfo();
|
||||
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
|
||||
fprintf(stderr, "%s: object file contains more than one"
|
||||
" architecture, none of which match the current"
|
||||
" architecture, none of which match the current"
|
||||
" architecture; specify an architecture explicitly"
|
||||
" with '-a ARCH' to resolve the ambiguity\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
" with '-a ARCH' to resolve the ambiguity\n",
|
||||
[object_filename_ fileSystemRepresentation]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -472,7 +472,7 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||
identifier += "0";
|
||||
|
||||
// Create a module to hold the debugging information.
|
||||
Module module([module_name UTF8String], "mac", selected_arch_name,
|
||||
Module module([module_name UTF8String], "mac", selected_arch_name,
|
||||
identifier);
|
||||
|
||||
// Parse the selected object file.
|
||||
@@ -481,8 +481,8 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||
if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
|
||||
+ selected_object_file_->offset,
|
||||
selected_object_file_->size,
|
||||
selected_object_file_->cputype,
|
||||
selected_object_file_->cpusubtype))
|
||||
selected_object_file_->cputype,
|
||||
selected_object_file_->cpusubtype))
|
||||
return false;
|
||||
|
||||
// Walk its load commands, and deal with whatever is there.
|
||||
@@ -490,7 +490,7 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||
if (!reader.WalkLoadCommands(&load_command_dumper))
|
||||
return false;
|
||||
|
||||
return module.Write(stream);
|
||||
return module.Write(stream, cfi);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
45
thirdparty/breakpad/common/mac/macho_id.cc
vendored
45
thirdparty/breakpad/common/mac/macho_id.cc
vendored
@@ -51,18 +51,29 @@ extern "C" { // necessary for Leopard
|
||||
|
||||
namespace MacFileUtilities {
|
||||
|
||||
using google_breakpad::MD5Init;
|
||||
using google_breakpad::MD5Update;
|
||||
using google_breakpad::MD5Final;
|
||||
|
||||
MachoID::MachoID(const char *path)
|
||||
: file_(0),
|
||||
: memory_(0),
|
||||
memory_size_(0),
|
||||
crc_(0),
|
||||
md5_context_(),
|
||||
update_function_(NULL) {
|
||||
strlcpy(path_, path, sizeof(path_));
|
||||
}
|
||||
|
||||
MachoID::MachoID(const char *path, void *memory, size_t size)
|
||||
: memory_(memory),
|
||||
memory_size_(size),
|
||||
crc_(0),
|
||||
md5_context_(),
|
||||
update_function_(NULL) {
|
||||
strlcpy(path_, path, sizeof(path_));
|
||||
file_ = open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
MachoID::~MachoID() {
|
||||
if (file_ != -1)
|
||||
close(file_);
|
||||
}
|
||||
|
||||
// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
|
||||
@@ -144,10 +155,8 @@ void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
|
||||
|
||||
bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
|
||||
struct breakpad_uuid_command uuid_cmd;
|
||||
MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd);
|
||||
|
||||
uuid_cmd.cmd = 0;
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
if (!WalkHeader(cpu_type, UUIDWalkerCB, &uuid_cmd))
|
||||
return false;
|
||||
|
||||
// If we found the command, we'll have initialized the uuid_command
|
||||
@@ -162,10 +171,8 @@ bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
|
||||
|
||||
bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
|
||||
struct dylib_command dylib_cmd;
|
||||
MachoWalker walker(path_, IDWalkerCB, &dylib_cmd);
|
||||
|
||||
dylib_cmd.cmd = 0;
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
if (!WalkHeader(cpu_type, IDWalkerCB, &dylib_cmd))
|
||||
return false;
|
||||
|
||||
// If we found the command, we'll have initialized the dylib_command
|
||||
@@ -204,29 +211,39 @@ bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
|
||||
}
|
||||
|
||||
uint32_t MachoID::Adler32(int cpu_type) {
|
||||
MachoWalker walker(path_, WalkerCB, this);
|
||||
update_function_ = &MachoID::UpdateCRC;
|
||||
crc_ = 0;
|
||||
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
if (!WalkHeader(cpu_type, WalkerCB, this))
|
||||
return 0;
|
||||
|
||||
return crc_;
|
||||
}
|
||||
|
||||
bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
|
||||
MachoWalker walker(path_, WalkerCB, this);
|
||||
update_function_ = &MachoID::UpdateMD5;
|
||||
|
||||
MD5Init(&md5_context_);
|
||||
|
||||
if (!walker.WalkHeader(cpu_type))
|
||||
if (!WalkHeader(cpu_type, WalkerCB, this))
|
||||
return false;
|
||||
|
||||
MD5Final(identifier, &md5_context_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MachoID::WalkHeader(int cpu_type,
|
||||
MachoWalker::LoadCommandCallback callback,
|
||||
void *context) {
|
||||
if (memory_) {
|
||||
MachoWalker walker(memory_, memory_size_, callback, context);
|
||||
return walker.WalkHeader(cpu_type);
|
||||
} else {
|
||||
MachoWalker walker(path_, callback, context);
|
||||
return walker.WalkHeader(cpu_type);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context) {
|
||||
|
17
thirdparty/breakpad/common/mac/macho_id.h
vendored
17
thirdparty/breakpad/common/mac/macho_id.h
vendored
@@ -37,15 +37,15 @@
|
||||
#include <limits.h>
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#include "common/mac/macho_walker.h"
|
||||
#include "common/md5.h"
|
||||
|
||||
namespace MacFileUtilities {
|
||||
|
||||
class MachoWalker;
|
||||
|
||||
class MachoID {
|
||||
public:
|
||||
MachoID(const char *path);
|
||||
MachoID(const char *path, void *memory, size_t size);
|
||||
~MachoID();
|
||||
|
||||
// For the given |cpu_type|, return a UUID from the LC_UUID command.
|
||||
@@ -80,6 +80,10 @@ class MachoID {
|
||||
// Bottleneck for update routines
|
||||
void Update(MachoWalker *walker, off_t offset, size_t size);
|
||||
|
||||
// Factory for the MachoWalker
|
||||
bool WalkHeader(int cpu_type, MachoWalker::LoadCommandCallback callback,
|
||||
void *context);
|
||||
|
||||
// The callback from the MachoWalker for CRC and MD5
|
||||
static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
|
||||
bool swap, void *context);
|
||||
@@ -95,14 +99,17 @@ class MachoID {
|
||||
// File path
|
||||
char path_[PATH_MAX];
|
||||
|
||||
// File descriptor
|
||||
int file_;
|
||||
// Memory region to read from
|
||||
void *memory_;
|
||||
|
||||
// Size of the memory region
|
||||
size_t memory_size_;
|
||||
|
||||
// The current crc value
|
||||
uint32_t crc_;
|
||||
|
||||
// The MD5 context
|
||||
MD5Context md5_context_;
|
||||
google_breakpad::MD5Context md5_context_;
|
||||
|
||||
// The current update to call from the Update callback
|
||||
UpdateFunction update_function_;
|
||||
|
@@ -38,6 +38,11 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Unfortunately, CPU_TYPE_ARM is not define for 10.4.
|
||||
#if !defined(CPU_TYPE_ARM)
|
||||
#define CPU_TYPE_ARM 12
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace mach_o {
|
||||
|
||||
@@ -230,6 +235,7 @@ bool Reader::Read(const uint8_t *buffer,
|
||||
uint32_t expected_magic;
|
||||
// validate that magic matches the expected cpu type
|
||||
switch (expected_cpu_type) {
|
||||
case CPU_TYPE_ARM:
|
||||
case CPU_TYPE_I386:
|
||||
expected_magic = MH_CIGAM;
|
||||
break;
|
||||
|
30
thirdparty/breakpad/common/mac/macho_walker.cc
vendored
30
thirdparty/breakpad/common/mac/macho_walker.cc
vendored
@@ -52,6 +52,8 @@ namespace MacFileUtilities {
|
||||
MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
|
||||
void *context)
|
||||
: file_(0),
|
||||
memory_(NULL),
|
||||
memory_size_(0),
|
||||
callback_(callback),
|
||||
callback_context_(context),
|
||||
current_header_(NULL),
|
||||
@@ -60,6 +62,18 @@ MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
|
||||
file_ = open(path, O_RDONLY);
|
||||
}
|
||||
|
||||
MachoWalker::MachoWalker(void *memory, size_t size,
|
||||
LoadCommandCallback callback, void *context)
|
||||
: file_(0),
|
||||
memory_(memory),
|
||||
memory_size_(size),
|
||||
callback_(callback),
|
||||
callback_context_(context),
|
||||
current_header_(NULL),
|
||||
current_header_size_(0),
|
||||
current_header_offset_(0) {
|
||||
}
|
||||
|
||||
MachoWalker::~MachoWalker() {
|
||||
if (file_ != -1)
|
||||
close(file_);
|
||||
@@ -90,7 +104,21 @@ bool MachoWalker::WalkHeader(int cpu_type) {
|
||||
}
|
||||
|
||||
bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
|
||||
return pread(file_, buffer, size, offset) == (ssize_t)size;
|
||||
if (memory_) {
|
||||
if (offset < 0)
|
||||
return false;
|
||||
bool result = true;
|
||||
if (offset + size > memory_size_) {
|
||||
if (static_cast<size_t>(offset) >= memory_size_)
|
||||
return false;
|
||||
size = memory_size_ - offset;
|
||||
result = false;
|
||||
}
|
||||
memcpy(buffer, static_cast<char *>(memory_) + offset, size);
|
||||
return result;
|
||||
} else {
|
||||
return pread(file_, buffer, size, offset) == (ssize_t)size;
|
||||
}
|
||||
}
|
||||
|
||||
bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
|
||||
|
17
thirdparty/breakpad/common/mac/macho_walker.h
vendored
17
thirdparty/breakpad/common/mac/macho_walker.h
vendored
@@ -52,7 +52,8 @@ class MachoWalker {
|
||||
off_t offset, bool swap, void *context);
|
||||
|
||||
MachoWalker(const char *path, LoadCommandCallback callback, void *context);
|
||||
MachoWalker(int file_descriptor, LoadCommandCallback callback, void *context);
|
||||
MachoWalker(void *memory, size_t size, LoadCommandCallback callback,
|
||||
void *context);
|
||||
~MachoWalker();
|
||||
|
||||
// Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the
|
||||
@@ -68,7 +69,7 @@ class MachoWalker {
|
||||
|
||||
// Read |size| bytes from the opened file at |offset| into |buffer|
|
||||
bool ReadBytes(void *buffer, size_t size, off_t offset);
|
||||
|
||||
|
||||
// Return the current header and header offset
|
||||
bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
|
||||
|
||||
@@ -87,19 +88,25 @@ class MachoWalker {
|
||||
// File descriptor to the opened file
|
||||
int file_;
|
||||
|
||||
// Memory location to read from.
|
||||
void *memory_;
|
||||
|
||||
// Size of the memory segment we can read from.
|
||||
size_t memory_size_;
|
||||
|
||||
// User specified callback & context
|
||||
LoadCommandCallback callback_;
|
||||
void *callback_context_;
|
||||
|
||||
|
||||
// Current header, size, and offset. The mach_header_64 is used for both
|
||||
// 32-bit and 64-bit headers because they only differ in their last field
|
||||
// (reserved). By adding the |current_header_size_| and the
|
||||
// (reserved). By adding the |current_header_size_| and the
|
||||
// |current_header_offset_|, you can determine the offset in the file just
|
||||
// after the header.
|
||||
struct mach_header_64 *current_header_;
|
||||
unsigned long current_header_size_;
|
||||
off_t current_header_offset_;
|
||||
|
||||
|
||||
private:
|
||||
MachoWalker(const MachoWalker &);
|
||||
MachoWalker &operator=(const MachoWalker &);
|
||||
|
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "common/md5.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
#define byteReverse(buf, len) /* Nothing */
|
||||
#else
|
||||
@@ -244,3 +246,6 @@ static void MD5Transform(u32 buf[4], u32 const in[16])
|
||||
buf[2] += c;
|
||||
buf[3] += d;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
10
thirdparty/breakpad/common/md5.h
vendored
10
thirdparty/breakpad/common/md5.h
vendored
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
typedef uint32_t u32;
|
||||
typedef uint8_t u8;
|
||||
|
||||
@@ -14,18 +16,12 @@ struct MD5Context {
|
||||
u8 in[64];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
void MD5Init(struct MD5Context *ctx);
|
||||
|
||||
void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len);
|
||||
|
||||
void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_MD5_H__
|
||||
|
12
thirdparty/breakpad/common/memory.h
vendored
12
thirdparty/breakpad/common/memory.h
vendored
@@ -145,6 +145,18 @@ class wasteful_vector {
|
||||
used_(0) {
|
||||
}
|
||||
|
||||
T& back() {
|
||||
return a_[used_ - 1];
|
||||
}
|
||||
|
||||
const T& back() const {
|
||||
return a_[used_ - 1];
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return used_ == 0;
|
||||
}
|
||||
|
||||
void push_back(const T& new_element) {
|
||||
if (used_ == allocated_)
|
||||
Realloc(allocated_ * 2);
|
||||
|
145
thirdparty/breakpad/common/memory_range.h
vendored
Normal file
145
thirdparty/breakpad/common/memory_range.h
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// memory_range.h: Define the google_breakpad::MemoryRange class, which
|
||||
// is a lightweight wrapper with a pointer and a length to encapsulate
|
||||
// a contiguous range of memory.
|
||||
|
||||
#ifndef COMMON_MEMORY_RANGE_H_
|
||||
#define COMMON_MEMORY_RANGE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A lightweight wrapper with a pointer and a length to encapsulate a
|
||||
// contiguous range of memory. It provides helper methods for checked
|
||||
// access of a subrange of the memory. Its implemementation does not
|
||||
// allocate memory or call into libc functions, and is thus safer to use
|
||||
// in a crashed environment.
|
||||
class MemoryRange {
|
||||
public:
|
||||
MemoryRange() : data_(NULL), length_(0) {}
|
||||
|
||||
MemoryRange(const void* data, size_t length) {
|
||||
Set(data, length);
|
||||
}
|
||||
|
||||
// Returns true if this memory range contains no data.
|
||||
bool IsEmpty() const {
|
||||
// Set() guarantees that |length_| is zero if |data_| is NULL.
|
||||
return length_ == 0;
|
||||
}
|
||||
|
||||
// Resets to an empty range.
|
||||
void Reset() {
|
||||
data_ = NULL;
|
||||
length_ = 0;
|
||||
}
|
||||
|
||||
// Sets this memory range to point to |data| and its length to |length|.
|
||||
void Set(const void* data, size_t length) {
|
||||
data_ = reinterpret_cast<const u_int8_t*>(data);
|
||||
// Always set |length_| to zero if |data_| is NULL.
|
||||
length_ = data ? length : 0;
|
||||
}
|
||||
|
||||
// Returns true if this range covers a subrange of |sub_length| bytes
|
||||
// at |sub_offset| bytes of this memory range, or false otherwise.
|
||||
bool Covers(size_t sub_offset, size_t sub_length) const {
|
||||
// The following checks verify that:
|
||||
// 1. sub_offset is within [ 0 .. length_ - 1 ]
|
||||
// 2. sub_offset + sub_length is within
|
||||
// [ sub_offset .. length_ ]
|
||||
return sub_offset < length_ &&
|
||||
sub_offset + sub_length >= sub_offset &&
|
||||
sub_offset + sub_length <= length_;
|
||||
}
|
||||
|
||||
// Returns a raw data pointer to a subrange of |sub_length| bytes at
|
||||
// |sub_offset| bytes of this memory range, or NULL if the subrange
|
||||
// is out of bounds.
|
||||
const void* GetData(size_t sub_offset, size_t sub_length) const {
|
||||
return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL;
|
||||
}
|
||||
|
||||
// Same as the two-argument version of GetData() but uses sizeof(DataType)
|
||||
// as the subrange length and returns an |DataType| pointer for convenience.
|
||||
template <typename DataType>
|
||||
const DataType* GetData(size_t sub_offset) const {
|
||||
return reinterpret_cast<const DataType*>(
|
||||
GetData(sub_offset, sizeof(DataType)));
|
||||
}
|
||||
|
||||
// Returns a raw pointer to the |element_index|-th element of an array
|
||||
// of elements of length |element_size| starting at |sub_offset| bytes
|
||||
// of this memory range, or NULL if the element is out of bounds.
|
||||
const void* GetArrayElement(size_t element_offset,
|
||||
size_t element_size,
|
||||
unsigned element_index) const {
|
||||
size_t sub_offset = element_offset + element_index * element_size;
|
||||
return GetData(sub_offset, element_size);
|
||||
}
|
||||
|
||||
// Same as the three-argument version of GetArrayElement() but deduces
|
||||
// the element size using sizeof(ElementType) and returns an |ElementType|
|
||||
// pointer for convenience.
|
||||
template <typename ElementType>
|
||||
const ElementType* GetArrayElement(size_t element_offset,
|
||||
unsigned element_index) const {
|
||||
return reinterpret_cast<const ElementType*>(
|
||||
GetArrayElement(element_offset, sizeof(ElementType), element_index));
|
||||
}
|
||||
|
||||
// Returns a subrange of |sub_length| bytes at |sub_offset| bytes of
|
||||
// this memory range, or an empty range if the subrange is out of bounds.
|
||||
MemoryRange Subrange(size_t sub_offset, size_t sub_length) const {
|
||||
return Covers(sub_offset, sub_length) ?
|
||||
MemoryRange(data_ + sub_offset, sub_length) : MemoryRange();
|
||||
}
|
||||
|
||||
// Returns a pointer to the beginning of this memory range.
|
||||
const u_int8_t* data() const { return data_; }
|
||||
|
||||
// Returns the length, in bytes, of this memory range.
|
||||
size_t length() const { return length_; }
|
||||
|
||||
private:
|
||||
// Pointer to the beginning of this memory range.
|
||||
const u_int8_t* data_;
|
||||
|
||||
// Length, in bytes, of this memory range.
|
||||
size_t length_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_MEMORY_RANGE_H_
|
193
thirdparty/breakpad/common/memory_range_unittest.cc
vendored
Normal file
193
thirdparty/breakpad/common/memory_range_unittest.cc
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2011, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// 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 Inc. 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.
|
||||
|
||||
// memory_range_unittest.cc: Unit tests for google_breakpad::MemoryRange.
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/memory_range.h"
|
||||
|
||||
using google_breakpad::MemoryRange;
|
||||
using testing::Message;
|
||||
|
||||
namespace {
|
||||
|
||||
const u_int32_t kBuffer[10] = { 0 };
|
||||
const size_t kBufferSize = sizeof(kBuffer);
|
||||
const u_int8_t* kBufferPointer = reinterpret_cast<const u_int8_t*>(kBuffer);
|
||||
|
||||
// Test vectors for verifying Covers, GetData, and Subrange.
|
||||
const struct {
|
||||
bool valid;
|
||||
size_t offset;
|
||||
size_t length;
|
||||
} kSubranges[] = {
|
||||
{ true, 0, 0 },
|
||||
{ true, 0, 2 },
|
||||
{ true, 0, kBufferSize },
|
||||
{ true, 2, 0 },
|
||||
{ true, 2, 4 },
|
||||
{ true, 2, kBufferSize - 2 },
|
||||
{ true, kBufferSize - 1, 1 },
|
||||
{ false, kBufferSize, 0 },
|
||||
{ false, kBufferSize, -1 },
|
||||
{ false, kBufferSize + 1, 0 },
|
||||
{ false, -1, 2 },
|
||||
{ false, 1, kBufferSize },
|
||||
{ false, kBufferSize - 1, 2 },
|
||||
{ false, 0, -1 },
|
||||
{ false, 1, -1 },
|
||||
};
|
||||
const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]);
|
||||
|
||||
// Test vectors for verifying GetArrayElement.
|
||||
const struct {
|
||||
size_t offset;
|
||||
size_t size;
|
||||
size_t index;
|
||||
const void* const pointer;
|
||||
} kElements[] = {
|
||||
// Valid array elemenets
|
||||
{ 0, 1, 0, kBufferPointer },
|
||||
{ 0, 1, 1, kBufferPointer + 1 },
|
||||
{ 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 },
|
||||
{ 0, 2, 1, kBufferPointer + 2 },
|
||||
{ 0, 4, 2, kBufferPointer + 8 },
|
||||
{ 0, 4, 9, kBufferPointer + 36 },
|
||||
{ kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 },
|
||||
// Invalid array elemenets
|
||||
{ 0, 1, kBufferSize, NULL },
|
||||
{ 0, 4, 10, NULL },
|
||||
{ kBufferSize - 1, 1, 1, NULL },
|
||||
{ kBufferSize - 1, 2, 0, NULL },
|
||||
{ kBufferSize, 1, 0, NULL },
|
||||
};
|
||||
const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]);
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MemoryRangeTest, DefaultConstructor) {
|
||||
MemoryRange range;
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0, range.length());
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, ConstructorWithDataAndLength) {
|
||||
MemoryRange range(kBuffer, kBufferSize);
|
||||
EXPECT_EQ(kBufferPointer, range.data());
|
||||
EXPECT_EQ(kBufferSize, range.length());
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, Reset) {
|
||||
MemoryRange range;
|
||||
range.Reset();
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0, range.length());
|
||||
|
||||
range.Set(kBuffer, kBufferSize);
|
||||
EXPECT_EQ(kBufferPointer, range.data());
|
||||
EXPECT_EQ(kBufferSize, range.length());
|
||||
|
||||
range.Reset();
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0, range.length());
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, Set) {
|
||||
MemoryRange range;
|
||||
range.Set(kBuffer, kBufferSize);
|
||||
EXPECT_EQ(kBufferPointer, range.data());
|
||||
EXPECT_EQ(kBufferSize, range.length());
|
||||
|
||||
range.Set(NULL, 0);
|
||||
EXPECT_EQ(NULL, range.data());
|
||||
EXPECT_EQ(0, range.length());
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, SubrangeOfEmptyMemoryRange) {
|
||||
MemoryRange range;
|
||||
MemoryRange subrange = range.Subrange(0, 10);
|
||||
EXPECT_EQ(NULL, subrange.data());
|
||||
EXPECT_EQ(0, subrange.length());
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, SubrangeAndGetData) {
|
||||
MemoryRange range(kBuffer, kBufferSize);
|
||||
for (size_t i = 0; i < kNumSubranges; ++i) {
|
||||
bool valid = kSubranges[i].valid;
|
||||
size_t sub_offset = kSubranges[i].offset;
|
||||
size_t sub_length = kSubranges[i].length;
|
||||
SCOPED_TRACE(Message() << "offset=" << sub_offset
|
||||
<< ", length=" << sub_length);
|
||||
|
||||
MemoryRange subrange = range.Subrange(sub_offset, sub_length);
|
||||
if (valid) {
|
||||
EXPECT_TRUE(range.Covers(sub_offset, sub_length));
|
||||
EXPECT_EQ(kBufferPointer + sub_offset,
|
||||
range.GetData(sub_offset, sub_length));
|
||||
EXPECT_EQ(kBufferPointer + sub_offset, subrange.data());
|
||||
EXPECT_EQ(sub_length, subrange.length());
|
||||
} else {
|
||||
EXPECT_FALSE(range.Covers(sub_offset, sub_length));
|
||||
EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length));
|
||||
EXPECT_EQ(NULL, subrange.data());
|
||||
EXPECT_EQ(0, subrange.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, GetDataWithTemplateType) {
|
||||
MemoryRange range(kBuffer, kBufferSize);
|
||||
const char* char_pointer = range.GetData<char>(0);
|
||||
EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer);
|
||||
const int* int_pointer = range.GetData<int>(0);
|
||||
EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer);
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, GetArrayElement) {
|
||||
MemoryRange range(kBuffer, kBufferSize);
|
||||
for (size_t i = 0; i < kNumElements; ++i) {
|
||||
size_t element_offset = kElements[i].offset;
|
||||
size_t element_size = kElements[i].size;
|
||||
unsigned element_index = kElements[i].index;
|
||||
const void* const element_pointer = kElements[i].pointer;
|
||||
SCOPED_TRACE(Message() << "offset=" << element_offset
|
||||
<< ", size=" << element_size
|
||||
<< ", index=" << element_index);
|
||||
EXPECT_EQ(element_pointer, range.GetArrayElement(
|
||||
element_offset, element_size, element_index));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MemoryRangeTest, GetArrayElmentWithTemplateType) {
|
||||
MemoryRange range(kBuffer, kBufferSize);
|
||||
const char* char_pointer = range.GetArrayElement<char>(0, 0);
|
||||
EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer);
|
||||
const int* int_pointer = range.GetArrayElement<int>(0, 0);
|
||||
EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer);
|
||||
}
|
@@ -69,6 +69,7 @@ typedef testing::Test WastefulVectorTest;
|
||||
TEST(WastefulVectorTest, Setup) {
|
||||
PageAllocator allocator_;
|
||||
wasteful_vector<int> v(&allocator_);
|
||||
ASSERT_TRUE(v.empty());
|
||||
ASSERT_EQ(v.size(), 0u);
|
||||
}
|
||||
|
||||
@@ -76,8 +77,12 @@ TEST(WastefulVectorTest, Simple) {
|
||||
PageAllocator allocator_;
|
||||
wasteful_vector<unsigned> v(&allocator_);
|
||||
|
||||
for (unsigned i = 0; i < 256; ++i)
|
||||
for (unsigned i = 0; i < 256; ++i) {
|
||||
v.push_back(i);
|
||||
ASSERT_EQ(i, v.back());
|
||||
ASSERT_EQ(&v.back(), &v[i]);
|
||||
}
|
||||
ASSERT_FALSE(v.empty());
|
||||
ASSERT_EQ(v.size(), 256u);
|
||||
for (unsigned i = 0; i < 256; ++i)
|
||||
ASSERT_EQ(v[i], i);
|
||||
|
86
thirdparty/breakpad/common/module.cc
vendored
86
thirdparty/breakpad/common/module.cc
vendored
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2010 Google Inc.
|
||||
// Copyright (c) 2011 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@@ -56,16 +57,17 @@ Module::Module(const string &name, const string &os,
|
||||
load_address_(0) { }
|
||||
|
||||
Module::~Module() {
|
||||
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++)
|
||||
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
|
||||
delete it->second;
|
||||
for (FunctionSet::iterator it = functions_.begin();
|
||||
it != functions_.end(); it++)
|
||||
it != functions_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
|
||||
it != stack_frame_entries_.end(); it++)
|
||||
it != stack_frame_entries_.end(); ++it) {
|
||||
delete *it;
|
||||
for (ExternSet::iterator it = externs_.begin();
|
||||
it != externs_.end(); it++)
|
||||
}
|
||||
for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
|
||||
delete *it;
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ void Module::AddFunction(Function *function) {
|
||||
|
||||
void Module::AddFunctions(vector<Function *>::iterator begin,
|
||||
vector<Function *>::iterator end) {
|
||||
for (vector<Function *>::iterator it = begin; it != end; it++)
|
||||
for (vector<Function *>::iterator it = begin; it != end; ++it)
|
||||
AddFunction(*it);
|
||||
}
|
||||
|
||||
@@ -149,7 +151,7 @@ Module::File *Module::FindExistingFile(const string &name) {
|
||||
|
||||
void Module::GetFiles(vector<File *> *vec) {
|
||||
vec->clear();
|
||||
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++)
|
||||
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
|
||||
vec->push_back(it->second);
|
||||
}
|
||||
|
||||
@@ -160,16 +162,17 @@ void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) {
|
||||
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++)
|
||||
file_it != files_.end(); ++file_it) {
|
||||
file_it->second->source_id = -1;
|
||||
}
|
||||
|
||||
// Next, mark all files actually cited by our functions' line number
|
||||
// info, by setting each one's source id to zero.
|
||||
for (FunctionSet::const_iterator func_it = functions_.begin();
|
||||
func_it != functions_.end(); func_it++) {
|
||||
func_it != functions_.end(); ++func_it) {
|
||||
Function *func = *func_it;
|
||||
for (vector<Line>::iterator line_it = func->lines.begin();
|
||||
line_it != func->lines.end(); line_it++)
|
||||
line_it != func->lines.end(); ++line_it)
|
||||
line_it->file->source_id = 0;
|
||||
}
|
||||
|
||||
@@ -179,9 +182,10 @@ void Module::AssignSourceIds() {
|
||||
// lexicographical order by name, which is neat.
|
||||
int next_source_id = 0;
|
||||
for (FileByNameMap::iterator file_it = files_.begin();
|
||||
file_it != files_.end(); file_it++)
|
||||
file_it != files_.end(); ++file_it) {
|
||||
if (!file_it->second->source_id)
|
||||
file_it->second->source_id = next_source_id++;
|
||||
}
|
||||
}
|
||||
|
||||
bool Module::ReportError() {
|
||||
@@ -192,7 +196,7 @@ bool Module::ReportError() {
|
||||
|
||||
bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
|
||||
for (RuleMap::const_iterator it = rule_map.begin();
|
||||
it != rule_map.end(); it++) {
|
||||
it != rule_map.end(); ++it) {
|
||||
if (it != rule_map.begin())
|
||||
stream << ' ';
|
||||
stream << it->first << ": " << it->second;
|
||||
@@ -200,7 +204,7 @@ bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
|
||||
return stream.good();
|
||||
}
|
||||
|
||||
bool Module::Write(std::ostream &stream) {
|
||||
bool Module::Write(std::ostream &stream, bool cfi) {
|
||||
stream << "MODULE " << os_ << " " << architecture_ << " "
|
||||
<< id_ << " " << name_ << endl;
|
||||
if (!stream.good())
|
||||
@@ -210,7 +214,7 @@ bool Module::Write(std::ostream &stream) {
|
||||
|
||||
// Write out files.
|
||||
for (FileByNameMap::iterator file_it = files_.begin();
|
||||
file_it != files_.end(); file_it++) {
|
||||
file_it != files_.end(); ++file_it) {
|
||||
File *file = file_it->second;
|
||||
if (file->source_id >= 0) {
|
||||
stream << "FILE " << file->source_id << " " << file->name << endl;
|
||||
@@ -221,18 +225,18 @@ bool Module::Write(std::ostream &stream) {
|
||||
|
||||
// Write out functions and their lines.
|
||||
for (FunctionSet::const_iterator func_it = functions_.begin();
|
||||
func_it != functions_.end(); func_it++) {
|
||||
func_it != functions_.end(); ++func_it) {
|
||||
Function *func = *func_it;
|
||||
stream << "FUNC " << hex
|
||||
<< (func->address - load_address_) << " "
|
||||
<< func->size << " "
|
||||
<< func->parameter_size << " "
|
||||
<< func->name << dec << endl;
|
||||
|
||||
|
||||
if (!stream.good())
|
||||
return ReportError();
|
||||
for (vector<Line>::iterator line_it = func->lines.begin();
|
||||
line_it != func->lines.end(); line_it++) {
|
||||
line_it != func->lines.end(); ++line_it) {
|
||||
stream << hex
|
||||
<< (line_it->address - load_address_) << " "
|
||||
<< line_it->size << " "
|
||||
@@ -246,7 +250,7 @@ bool Module::Write(std::ostream &stream) {
|
||||
|
||||
// Write out 'PUBLIC' records.
|
||||
for (ExternSet::const_iterator extern_it = externs_.begin();
|
||||
extern_it != externs_.end(); extern_it++) {
|
||||
extern_it != externs_.end(); ++extern_it) {
|
||||
Extern *ext = *extern_it;
|
||||
stream << "PUBLIC " << hex
|
||||
<< (ext->address - load_address_) << " 0 "
|
||||
@@ -255,34 +259,36 @@ bool Module::Write(std::ostream &stream) {
|
||||
return ReportError();
|
||||
}
|
||||
|
||||
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
||||
vector<StackFrameEntry *>::const_iterator frame_it;
|
||||
for (frame_it = stack_frame_entries_.begin();
|
||||
frame_it != stack_frame_entries_.end(); frame_it++) {
|
||||
StackFrameEntry *entry = *frame_it;
|
||||
stream << "STACK CFI INIT " << hex
|
||||
<< (entry->address - load_address_) << " "
|
||||
<< entry->size << " " << dec;
|
||||
if (!stream.good()
|
||||
|| !WriteRuleMap(entry->initial_rules, stream))
|
||||
return ReportError();
|
||||
|
||||
stream << endl;
|
||||
|
||||
// Write out this entry's delta rules as 'STACK CFI' records.
|
||||
for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
|
||||
delta_it != entry->rule_changes.end(); delta_it++) {
|
||||
stream << "STACK CFI " << hex
|
||||
<< (delta_it->first - load_address_) << " " << dec;
|
||||
if (cfi) {
|
||||
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
||||
vector<StackFrameEntry *>::const_iterator frame_it;
|
||||
for (frame_it = stack_frame_entries_.begin();
|
||||
frame_it != stack_frame_entries_.end(); ++frame_it) {
|
||||
StackFrameEntry *entry = *frame_it;
|
||||
stream << "STACK CFI INIT " << hex
|
||||
<< (entry->address - load_address_) << " "
|
||||
<< entry->size << " " << dec;
|
||||
if (!stream.good()
|
||||
|| !WriteRuleMap(delta_it->second, stream))
|
||||
|| !WriteRuleMap(entry->initial_rules, stream))
|
||||
return ReportError();
|
||||
|
||||
stream << endl;
|
||||
|
||||
// Write out this entry's delta rules as 'STACK CFI' records.
|
||||
for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
|
||||
delta_it != entry->rule_changes.end(); ++delta_it) {
|
||||
stream << "STACK CFI " << hex
|
||||
<< (delta_it->first - load_address_) << " " << dec;
|
||||
if (!stream.good()
|
||||
|| !WriteRuleMap(delta_it->second, stream))
|
||||
return ReportError();
|
||||
|
||||
stream << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
} // namespace google_breakpad
|
||||
|
13
thirdparty/breakpad/common/module.h
vendored
13
thirdparty/breakpad/common/module.h
vendored
@@ -259,14 +259,15 @@ class Module {
|
||||
// breakpad symbol format. Return true if all goes well, or false if
|
||||
// an error occurs. This method writes out:
|
||||
// - a header based on the values given to the constructor,
|
||||
// - the source files added via FindFile, and finally
|
||||
// - the functions added via AddFunctions, each with its lines.
|
||||
// - the source files added via FindFile,
|
||||
// - the functions added via AddFunctions, each with its lines,
|
||||
// - all public records,
|
||||
// - and if CFI is true, all CFI records.
|
||||
// Addresses in the output are all relative to the load address
|
||||
// established by SetLoadAddress.
|
||||
bool Write(std::ostream &stream);
|
||||
bool Write(std::ostream &stream, bool cfi);
|
||||
|
||||
private:
|
||||
|
||||
// Report an error that has occurred writing the symbol file, using
|
||||
// errno to find the appropriate cause. Return false.
|
||||
static bool ReportError();
|
||||
@@ -287,7 +288,7 @@ class Module {
|
||||
// Relation for maps whose keys are strings shared with some other
|
||||
// structure.
|
||||
struct CompareStringPtrs {
|
||||
bool operator()(const string *x, const string *y) { return *x < *y; };
|
||||
bool operator()(const string *x, const string *y) { return *x < *y; }
|
||||
};
|
||||
|
||||
// A map from filenames to File structures. The map's keys are
|
||||
@@ -315,6 +316,6 @@ class Module {
|
||||
ExternSet externs_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_MODULE_H__
|
||||
|
68
thirdparty/breakpad/common/module_unittest.cc
vendored
68
thirdparty/breakpad/common/module_unittest.cc
vendored
@@ -70,7 +70,7 @@ static Module::Function *generate_duplicate_function(const string &name) {
|
||||
TEST(Write, Header) {
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
|
||||
contents.c_str());
|
||||
@@ -91,7 +91,7 @@ TEST(Write, OneLineFunc) {
|
||||
function->lines.push_back(line);
|
||||
m.AddFunction(function);
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 file_name.cc\n"
|
||||
@@ -141,7 +141,7 @@ TEST(Write, RelativeLoadAddress) {
|
||||
// the module must work fine.
|
||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 filename-a.cc\n"
|
||||
@@ -164,7 +164,7 @@ TEST(Write, OmitUnusedFiles) {
|
||||
|
||||
// Create some source files.
|
||||
Module::File *file1 = m.FindFile("filename1");
|
||||
m.FindFile("filename2"); // not used by any line
|
||||
m.FindFile("filename2"); // not used by any line
|
||||
Module::File *file3 = m.FindFile("filename3");
|
||||
|
||||
// Create a function.
|
||||
@@ -197,7 +197,7 @@ TEST(Write, OmitUnusedFiles) {
|
||||
EXPECT_NE(-1, vec[2]->source_id);
|
||||
|
||||
stringstream s;
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 filename1\n"
|
||||
@@ -209,6 +209,52 @@ TEST(Write, OmitUnusedFiles) {
|
||||
contents.c_str());
|
||||
}
|
||||
|
||||
TEST(Write, NoCFI) {
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Some source files. We will expect to see them in lexicographic order.
|
||||
Module::File *file1 = m.FindFile("filename.cc");
|
||||
|
||||
// A function.
|
||||
Module::Function *function = new(Module::Function);
|
||||
function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)";
|
||||
function->address = 0xbec774ea5dd935f3LL;
|
||||
function->size = 0x2922088f98d3f6fcLL;
|
||||
function->parameter_size = 0xe5e9aa008bd5f0d0LL;
|
||||
|
||||
// Some source lines. The module should not sort these.
|
||||
Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL,
|
||||
file1, 41676901 };
|
||||
function->lines.push_back(line1);
|
||||
|
||||
m.AddFunction(function);
|
||||
|
||||
// Some stack information.
|
||||
Module::StackFrameEntry *entry = new Module::StackFrameEntry();
|
||||
entry->address = 0x30f9e5c83323973dULL;
|
||||
entry->size = 0x49fc9ca7c7c13dc2ULL;
|
||||
entry->initial_rules[".cfa"] = "he was a handsome man";
|
||||
entry->initial_rules["and"] = "what i want to know is";
|
||||
entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
|
||||
"do you like your blueeyed boy";
|
||||
entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
|
||||
m.AddStackFrameEntry(entry);
|
||||
|
||||
// Set the load address. Doing this after adding all the data to
|
||||
// the module must work fine.
|
||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||
|
||||
m.Write(s, false);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 filename.cc\n"
|
||||
"FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
|
||||
" A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
|
||||
"9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
||||
TEST(Construct, AddFunctions) {
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
@@ -233,7 +279,7 @@ TEST(Construct, AddFunctions) {
|
||||
|
||||
m.AddFunctions(vec.begin(), vec.end());
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
|
||||
@@ -285,7 +331,7 @@ TEST(Construct, AddFrames) {
|
||||
m.AddStackFrameEntry(entry3);
|
||||
|
||||
// Check that Write writes STACK CFI records properly.
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
||||
@@ -361,7 +407,7 @@ TEST(Construct, DuplicateFunctions) {
|
||||
m.AddFunction(function1);
|
||||
m.AddFunction(function2);
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||
@@ -380,7 +426,7 @@ TEST(Construct, FunctionsWithSameAddress) {
|
||||
m.AddFunction(function1);
|
||||
m.AddFunction(function2);
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||
@@ -407,7 +453,7 @@ TEST(Construct, Externs) {
|
||||
m.AddExtern(extern1);
|
||||
m.AddExtern(extern2);
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||
@@ -434,7 +480,7 @@ TEST(Construct, DuplicateExterns) {
|
||||
m.AddExtern(extern1);
|
||||
m.AddExtern(extern2);
|
||||
|
||||
m.Write(s);
|
||||
m.Write(s, true);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||
|
12
thirdparty/breakpad/common/stabs_reader.cc
vendored
12
thirdparty/breakpad/common/stabs_reader.cc
vendored
@@ -130,7 +130,7 @@ bool StabsReader::ProcessCompilationUnit() {
|
||||
// There may be an N_SO entry whose name ends with a slash,
|
||||
// indicating the directory in which the compilation occurred.
|
||||
// The build directory defaults to NULL.
|
||||
const char *build_directory = NULL;
|
||||
const char *build_directory = NULL;
|
||||
{
|
||||
const char *name = SymbolString();
|
||||
if (name[0] && name[strlen(name) - 1] == '/') {
|
||||
@@ -138,7 +138,7 @@ bool StabsReader::ProcessCompilationUnit() {
|
||||
++iterator_;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// We expect to see an N_SO entry with a filename next, indicating
|
||||
// the start of the compilation unit.
|
||||
{
|
||||
@@ -212,7 +212,7 @@ bool StabsReader::ProcessCompilationUnit() {
|
||||
queued_lines_.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool StabsReader::ProcessFunction() {
|
||||
assert(!iterator_->at_end && iterator_->type == N_FUN);
|
||||
@@ -237,7 +237,7 @@ bool StabsReader::ProcessFunction() {
|
||||
return false;
|
||||
}
|
||||
queued_lines_.clear();
|
||||
|
||||
|
||||
while (!iterator_->at_end) {
|
||||
if (iterator_->type == N_SO || iterator_->type == N_FUN)
|
||||
break;
|
||||
@@ -266,8 +266,8 @@ bool StabsReader::ProcessFunction() {
|
||||
if (!iterator_->at_end) {
|
||||
assert(iterator_->type == N_SO || iterator_->type == N_FUN);
|
||||
if (iterator_->type == N_FUN) {
|
||||
const char *name = SymbolString();
|
||||
if (name[0] == '\0') {
|
||||
const char *symbol_name = SymbolString();
|
||||
if (symbol_name[0] == '\0') {
|
||||
// An N_FUN entry with no name is a terminator for this function;
|
||||
// its value is the function's size.
|
||||
ending_address = function_address + iterator_->value;
|
||||
|
@@ -42,7 +42,7 @@ void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
|
||||
const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
|
||||
const UTF8 *source_end_ptr = source_ptr + source_length;
|
||||
// Erase the contents and zero fill to the expected size
|
||||
out->empty();
|
||||
out->clear();
|
||||
out->insert(out->begin(), source_length, 0);
|
||||
u_int16_t *target_ptr = &(*out)[0];
|
||||
u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
|
||||
@@ -86,7 +86,7 @@ void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out) {
|
||||
const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
|
||||
const UTF32 *source_end_ptr = source_ptr + source_length;
|
||||
// Erase the contents and zero fill to the expected size
|
||||
out->empty();
|
||||
out->clear();
|
||||
out->insert(out->begin(), source_length, 0);
|
||||
u_int16_t *target_ptr = &(*out)[0];
|
||||
u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
|
||||
|
@@ -32,7 +32,7 @@
|
||||
#ifndef COMMON_WINDOWS_GUID_STRING_H__
|
||||
#define COMMON_WINDOWS_GUID_STRING_H__
|
||||
|
||||
#include <guiddef.h>
|
||||
#include <Guiddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@@ -92,13 +92,13 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
|
||||
switch (format) {
|
||||
case PDB_FILE:
|
||||
if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
|
||||
fprintf(stderr, "loadDataFromPdb failed\n");
|
||||
fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case EXE_FILE:
|
||||
if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
|
||||
fprintf(stderr, "loadDataForExe failed\n");
|
||||
fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str());
|
||||
return false;
|
||||
}
|
||||
code_file_ = file;
|
||||
@@ -106,7 +106,7 @@ bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) {
|
||||
case ANY_FILE:
|
||||
if (FAILED(data_source->loadDataFromPdb(file.c_str()))) {
|
||||
if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) {
|
||||
fprintf(stderr, "loadDataForPdb and loadDataFromExe failed\n");
|
||||
fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n", file.c_str());
|
||||
return false;
|
||||
}
|
||||
code_file_ = file;
|
||||
|
Reference in New Issue
Block a user