Introduce sentry for crash data collection

This commit is contained in:
Mark Roszko 2022-04-02 01:21:55 +00:00
parent 0625e20fc0
commit f0f33ef1d3
2266 changed files with 514726 additions and 0 deletions

View File

@ -164,6 +164,10 @@ cmake_dependent_option( KICAD_WIN32_VERIFY_CODESIGN
OFF "WIN32"
OFF )
option( KICAD_USE_SENTRY
"Build KiCad with support for sentry app metrics"
OFF )
if( KICAD_USE_3DCONNEXION )
if( WIN32 )
add_definitions( -DKICAD_USE_3DCONNEXION )
@ -943,6 +947,12 @@ if( APPLE )
)
endif()
if( KICAD_USE_SENTRY )
add_subdirectory( thirdparty/sentry-native )
add_definitions( -DKICAD_USE_SENTRY )
endif()
#================================================
# Add the documentation
#================================================

View File

@ -204,6 +204,12 @@ set( COMMON_DLG_SRCS
dialogs/wx_html_report_panel_base.cpp
)
if( KICAD_USE_SENTRY )
list( APPEND COMMON_DLG_SRCS
dialogs/panel_data_collection.cpp
dialogs/panel_data_collection_base.cpp )
endif()
set( COMMON_WIDGET_SRCS
widgets/app_progress_dialog.cpp
widgets/bitmap_button.cpp
@ -506,6 +512,11 @@ target_link_libraries( common
${Fontconfig_LIBRARIES}
)
if( KICAD_USE_SENTRY )
target_link_libraries( common
sentry )
endif()
target_include_directories( common
PUBLIC
.

View File

@ -0,0 +1,74 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <dialogs/panel_data_collection.h>
#include <advanced_config.h>
#include <bitmaps.h>
#include <dialog_shim.h>
#include <gal/dpi_scaling.h>
#include <kiface_base.h>
#include <kiplatform/ui.h>
#include <pgm_base.h>
#include <id.h>
#include <settings/common_settings.h>
#include <settings/settings_manager.h>
PANEL_DATA_COLLECTION::PANEL_DATA_COLLECTION( PAGED_DIALOG* aDialog, wxWindow* aParent ) :
PANEL_DATA_COLLECTION_BASE( aParent ), m_dialog( aDialog )
{
}
bool PANEL_DATA_COLLECTION::TransferDataToWindow()
{
applySettingsToPanel();
return true;
}
bool PANEL_DATA_COLLECTION::TransferDataFromWindow()
{
Pgm().SetSentryOptIn( m_cbOptIn->GetValue() );
return true;
}
void PANEL_DATA_COLLECTION::ResetPanel()
{
applySettingsToPanel();
}
void PANEL_DATA_COLLECTION::applySettingsToPanel()
{
m_cbOptIn->SetValue( Pgm().IsSentryOptedIn() );
}
void PANEL_DATA_COLLECTION::OnResetIdClick( wxCommandEvent& aEvent )
{
Pgm().ResetSentryId();
}

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "panel_data_collection_base.h"
///////////////////////////////////////////////////////////////////////////
PANEL_DATA_COLLECTION_BASE::PANEL_DATA_COLLECTION_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : RESETTABLE_PANEL( parent, id, pos, size, style, name )
{
wxBoxSizer* bPanelSizer;
bPanelSizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* bSizer8;
bSizer8 = new wxBoxSizer( wxVERTICAL );
m_stExplanation = new wxStaticText( this, wxID_ANY, _("KiCad can anonymously report crashes and special event data to developers in order to aid identifying critical bugs across the user base more effectively and help profile functionality to guide improvements.\n\nTo link automatic reports from the same KiCad install, a unique identifier is generated that is completely random, it is only used for the purposes of crash reporting. No personally identifiable information (PII) including IP address is stored or connected to this identifier. You may reset this id at anytime with the button provided.\n\nIf you choose to voluntarily participate, KiCad will automatically handle sending said reports when crashes or events occur. Your design files such as schematic or PCB are not shared in this process."), wxDefaultPosition, wxDefaultSize, 0 );
m_stExplanation->Wrap( 500 );
bSizer8->Add( m_stExplanation, 0, wxALL, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
m_cbOptIn = new wxCheckBox( this, wxID_ANY, _("I agree to provide anonymous reports"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer3->Add( m_cbOptIn, 0, wxALL, 5 );
m_buttonResetId = new wxButton( this, wxID_ANY, _("Reset Unique Id"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer3->Add( m_buttonResetId, 0, wxALL, 5 );
bSizer8->Add( bSizer3, 1, wxEXPAND, 5 );
bPanelSizer->Add( bSizer8, 1, wxEXPAND, 5 );
this->SetSizer( bPanelSizer );
this->Layout();
bPanelSizer->Fit( this );
// Connect Events
m_buttonResetId->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_DATA_COLLECTION_BASE::OnResetIdClick ), NULL, this );
}
PANEL_DATA_COLLECTION_BASE::~PANEL_DATA_COLLECTION_BASE()
{
// Disconnect Events
m_buttonResetId->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_DATA_COLLECTION_BASE::OnResetIdClick ), NULL, this );
}

View File

@ -0,0 +1,284 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="16" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">panel_data_collection_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">PanelDataCollection</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">1</property>
<property name="use_microsoft_bom">0</property>
<object class="Panel" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">PANEL_DATA_COLLECTION_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="subclass">RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare</property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bPanelSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer8</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">KiCad can anonymously report crashes and special event data to developers in order to aid identifying critical bugs across the user base more effectively and help profile functionality to guide improvements.&#x0A;&#x0A;To link automatic reports from the same KiCad install, a unique identifier is generated that is completely random, it is only used for the purposes of crash reporting. No personally identifiable information (PII) including IP address is stored or connected to this identifier. You may reset this id at anytime with the button provided.&#x0A;&#x0A;If you choose to voluntarily participate, KiCad will automatically handle sending said reports when crashes or events occur. Your design files such as schematic or PCB are not shared in this process.</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_stExplanation</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">500</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer3</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxCheckBox" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="checked">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">I agree to provide anonymous reports</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_cbOptIn</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="auth_needed">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="bitmap"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="current"></property>
<property name="default">0</property>
<property name="default_pane">0</property>
<property name="disabled"></property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="focus"></property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Reset Unique Id</property>
<property name="margins"></property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_buttonResetId</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="position"></property>
<property name="pressed"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnButtonClick">OnResetIdClick</event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,53 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include "widgets/resettable_panel.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/checkbox.h>
#include <wx/button.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/sizer.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class PANEL_DATA_COLLECTION_BASE
///////////////////////////////////////////////////////////////////////////////
class PANEL_DATA_COLLECTION_BASE : public RESETTABLE_PANEL
{
private:
protected:
wxStaticText* m_stExplanation;
wxCheckBox* m_cbOptIn;
wxButton* m_buttonResetId;
// Virtual event handlers, override them in your derived class
virtual void OnResetIdClick( wxCommandEvent& event ) { event.Skip(); }
public:
PANEL_DATA_COLLECTION_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
~PANEL_DATA_COLLECTION_BASE();
};

View File

@ -28,6 +28,7 @@
#include <dialog_shim.h>
#include <dialogs/panel_common_settings.h>
#include <dialogs/panel_mouse_settings.h>
#include <dialogs/panel_data_collection.h>
#include <eda_dde.h>
#include <filehistory.h>
#include <id.h>
@ -994,6 +995,10 @@ void EDA_BASE_FRAME::OnPreferences( wxCommandEvent& event )
book->AddPage( new PANEL_MOUSE_SETTINGS( &dlg, book ), _( "Mouse and Touchpad" ) );
book->AddPage( hotkeysPanel, _( "Hotkeys" ) );
#ifdef KICAD_USE_SENTRY
book->AddPage( new PANEL_DATA_COLLECTION( &dlg, book ), _( "Data Collection" ) );
#endif
#define CREATE_PANEL( key ) kiface->CreateWindow( book, key, &Kiway() )
kiface = Kiway().KiFACE( KIWAY::FACE_SCH );

View File

@ -38,6 +38,7 @@
#include <wx/stdpaths.h>
#include <wx/sysopt.h>
#include <wx/filedlg.h>
#include <wx/ffile.h>
#include <wx/tooltip.h>
#include <advanced_config.h>
@ -59,6 +60,12 @@
#include <trace_helpers.h>
#include <paths.h>
#ifdef KICAD_USE_SENTRY
#include <boost/uuid/uuid_io.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <sentry.h>
#include <kicad_build_version.h>
#endif
/**
* Current list of languages supported by KiCad.
@ -127,6 +134,10 @@ PGM_BASE::~PGM_BASE()
void PGM_BASE::Destroy()
{
#ifdef KICAD_USE_SENTRY
sentry_close();
#endif
// unlike a normal destructor, this is designed to be called more than once safely:
delete m_locale;
m_locale = nullptr;
@ -204,8 +215,146 @@ const wxString PGM_BASE::AskUserForPreferredEditor( const wxString& aDefaultEdit
}
#ifdef KICAD_USE_SENTRY
bool PGM_BASE::IsSentryOptedIn()
{
return m_sentry_optin_fn.Exists();
}
void PGM_BASE::SetSentryOptIn( bool aOptIn )
{
if( aOptIn )
{
if( !m_sentry_uid_fn.Exists() )
{
sentryCreateUid();
}
if( !m_sentry_optin_fn.Exists() )
{
wxFFile sentryInitFile( m_sentry_optin_fn.GetFullPath(), "w" );
sentryInitFile.Write( "" );
sentryInitFile.Close();
}
}
else
{
if( m_sentry_optin_fn.Exists() )
{
wxRemoveFile( m_sentry_optin_fn.GetFullPath() );
sentry_close();
}
}
}
wxString PGM_BASE::sentryCreateUid()
{
boost::uuids::uuid uuid = boost::uuids::random_generator()();
wxString userGuid = boost::uuids::to_string( uuid );
wxFFile sentryInitFile( m_sentry_uid_fn.GetFullPath(), "w" );
sentryInitFile.Write( userGuid );
sentryInitFile.Close();
return userGuid;
}
void PGM_BASE::ResetSentryId()
{
sentryCreateUid();
}
void PGM_BASE::sentryInit()
{
m_sentry_optin_fn = wxFileName( PATHS::GetUserCachePath(), "sentry-opt-in" );
m_sentry_uid_fn = wxFileName( PATHS::GetUserCachePath(), "sentry-uid" );
if( IsSentryOptedIn() )
{
wxString userGuid;
wxFFile sentryInitFile( m_sentry_uid_fn.GetFullPath() );
sentryInitFile.ReadAll( &userGuid );
sentryInitFile.Close();
if( userGuid.IsEmpty() || userGuid.length() != 36 )
{
userGuid = sentryCreateUid();
}
sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(
options,
"https://463925e689c34632b5172436ffb76de5@sentry-relay.kicad.org/6266565" );
wxFileName tmp;
tmp.AssignDir( PATHS::GetUserCachePath() );
tmp.AppendDir( "sentry" );
sentry_options_set_database_pathw( options, tmp.GetPathWithSep().wc_str() );
sentry_options_set_symbolize_stacktraces( options, true );
sentry_options_set_auto_session_tracking( options, false );
#if !KICAD_IS_NIGHTLY
sentry_options_set_release( options, KICAD_SEMANTIC_VERSION );
#else
sentry_options_set_release( options, KICAD_MAJOR_MINOR_VERSION );
#endif
sentry_init( options );
sentry_value_t user = sentry_value_new_object();
sentry_value_set_by_key( user, "id", sentry_value_new_string( userGuid.c_str() ) );
sentry_set_user( user );
sentry_set_tag( "kicad.version", KICAD_VERSION_FULL );
}
}
void PGM_BASE::sentryPrompt()
{
if( !m_settings_manager->GetCommonSettings()->m_DoNotShowAgain.data_collection_prompt )
{
wxMessageDialog optIn = wxMessageDialog(
nullptr,
_( "KiCad can anonymously report crashes and special event "
"data to developers in order to aid identifying critical bugs "
"across the user base more effectively and help profile "
"functionality to guide improvements. \n"
"If you choose to voluntarily participate, KiCad will automatically "
"handle sending said reports when crashes or events occur. \n"
"Your design files such as schematic or PCB are not shared in this process." ),
_( "Data collection opt in request" ), wxYES_NO | wxCENTRE );
int result = optIn.ShowModal();
if( result == wxID_YES )
{
SetSentryOptIn( true );
sentryInit();
}
else
{
SetSentryOptIn( false );
}
m_settings_manager->GetCommonSettings()->m_DoNotShowAgain.data_collection_prompt = true;
}
}
#endif
bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit )
{
#ifdef KICAD_USE_SENTRY
sentryInit();
#endif
wxString pgm_name;
/// Should never happen but boost unit_test isn't playing nicely in some cases
@ -214,6 +363,10 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit )
else
pgm_name = wxFileName( App().argv[0] ).GetName().Lower();
#ifdef KICAD_USE_SENTRY
sentry_set_tag( "kicad.app", pgm_name.c_str() );
#endif
wxInitAllImageHandlers();
#ifndef __WINDOWS__
@ -285,6 +438,10 @@ bool PGM_BASE::InitPgm( bool aHeadless, bool aSkipPyInit )
loadCommonSettings();
#ifdef KICAD_USE_SENTRY
sentryPrompt();
#endif
ReadPdfBrowserInfos(); // needs GetCommonSettings()
// Create the python scripting stuff

View File

@ -318,6 +318,9 @@ COMMON_SETTINGS::COMMON_SETTINGS() :
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.scaled_3d_models_warning",
&m_DoNotShowAgain.scaled_3d_models_warning, false ) );
m_params.emplace_back( new PARAM<bool>( "do_not_show_again.data_collection_prompt",
&m_DoNotShowAgain.data_collection_prompt, false ) );
m_params.emplace_back( new PARAM<bool>( "session.remember_open_files",
&m_Session.remember_open_files, false ) );

View File

@ -0,0 +1,54 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef PANEL_DATA_COLLECTION_H
#define PANEL_DATA_COLLECTION_H
#include "panel_data_collection_base.h"
class COMMON_SETTINGS;
class PAGED_DIALOG;
class PANEL_DATA_COLLECTION : public PANEL_DATA_COLLECTION_BASE
{
public:
PANEL_DATA_COLLECTION( PAGED_DIALOG* aDialog, wxWindow* aParent );
void ResetPanel() override;
protected:
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
virtual void OnResetIdClick( wxCommandEvent& aEvent ) override;
private:
void applySettingsToPanel();
protected:
PAGED_DIALOG* m_dialog;
};
#endif //PANEL_DATA_COLLECTION_H

View File

@ -285,6 +285,12 @@ public:
*/
void SaveCommonSettings();
#ifdef KICAD_USE_SENTRY
bool IsSentryOptedIn();
void SetSentryOptIn( bool aOptIn );
void ResetSentryId();
#endif
/**
* wxWidgets on MSW tends to crash if you spool up more than one print job at a time.
*/
@ -308,6 +314,12 @@ protected:
*/
bool setExecutablePath();
#ifdef KICAD_USE_SENTRY
void sentryInit();
void sentryPrompt();
wxString sentryCreateUid();
#endif
protected:
std::unique_ptr<SETTINGS_MANAGER> m_settings_manager;
@ -323,6 +335,11 @@ protected:
wxString m_pdf_browser; /// Filename of the app selected for browsing PDFs
wxString m_text_editor;
#ifdef KICAD_USE_SENTRY
wxFileName m_sentry_optin_fn;
wxFileName m_sentry_uid_fn;
#endif
};

View File

@ -125,6 +125,7 @@ public:
bool zone_fill_warning;
bool env_var_overwrite_warning;
bool scaled_3d_models_warning;
bool data_collection_prompt;
};
struct NETCLASS_PANEL

View File

@ -0,0 +1,9 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"ms-vscode.cpptools",
"ms-vscode.cmake-tools",
"twxs.cmake"
]
}

View File

@ -0,0 +1,10 @@
{
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
// C++ Extension
"C_Cpp.autoAddFileAssociations": false
}

583
thirdparty/sentry-native/CHANGELOG.md vendored Normal file
View File

@ -0,0 +1,583 @@
# Changelog
## 0.4.15
**Fixes**:
- Fix contexts from the scope not being attached to events correctly.
- Improve performance of event serialization.
## 0.4.14
**Features**:
- The Sentry SDK now has experimental support for performance monitoring.
The performance monitoring API allows manually creating transactions and instrumenting spans, and offers APIs for distributed tracing.
The API is currently disabled by default and needs to be enabled via a compile-time `SENTRY_PERFORMANCE_MONITORING` flag.
For more information, take a look at the more detailed [documentation of performance monitoring](https://docs.sentry.io/platforms/native/performance/).
- Sentry now has an explicit `sentry_flush` method that blocks the calling thread for the given time, waiting for the transport queue to be flushed. Custom transports need to implement a new `flush_hook` for this to work.
**Fixes**:
- Fix Sentry API deadlocking when the SDK was not initialized (or `sentry_init` failed).
- The rate limit handling of the default transports was updated to match the expected behavior.
- The Windows OS version is now read from the Registry and is more accurate.
- The `SENTRY_LIBRARY_TYPE` CMake option is now correctly honored.
- The Linux Modulefinder was once again improved to increase its memory safety and reliability.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@Mixaill](https://github.com/Mixaill)
## 0.4.13
**Features**:
- Add client-side stackwalking on Linux, Windows, and macOS (disabled by default).
- CMake: add ability to set solution folder name.
- Add AIX support.
**Fixes**:
- CMake: check whether libcurl was already found.
- Increment CXX standard version to 14 to allow crashpad to build.
**Internal**:
- Update Crashpad and Breakpad submodules to 2021-12-03.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@Mixaill](https://github.com/Mixaill)
- [@ladislavmacoun](https://github.com/ladislavmacoun)
- [@NattyNarwhal](https://github.com/NattyNarwhal)
- [@mjvankampen](https://github.com/mjvankampen)
## 0.4.12
**Features**:
- Make the shutdown timeout configurable via `sentry_options_set_shutdown_timeout`.
**Fixes**:
- The crashpad backend compiles with mingw again.
- Build System improvements.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@irov](https://github.com/irov)
- [@past-due](https://github.com/past-due)
- [@andrei-mu](https://github.com/andrei-mu)
- [@rpadaki](https://github.com/rpadaki)
## 0.4.11
**Fixes**:
- The crashpad backend now respects the `max_breadcrumbs` setting.
- Hanging HTTP requests will now be canceled on shutdown in the WinHTTP transport.
- The Modulefinder and Android unwinder now use safer memory access.
- Possible races and deadlocks have been fixed in `init`/`close`, and in API related to sessions.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@smibe](https://github.com/smibe)
## 0.4.10
**Fixes**:
- Fix a potential deadlock in macOS modulefinder.
- Lower Stack usage, to lower change of stack overflows.
- Avoid a double-free when parsing an invalid DSN.
- Improvements to Unity Builds and 32-bit Builds.
- Fix infinite recursion in signal handler by correctly cleaning up on shutdown.
**Internal**:
- Update Crashpad and Breakpad submodules to 2021-06-14.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@janisozaur](https://github.com/janisozaur)
- [@bschatt](https://github.com/bschatt)
- [@GenuineAster](https://github.com/GenuineAster)
## 0.4.9
**Features**:
- Rewrote the Linux modulefinder which should now work correctly when encountering gaps in the memory mapping of loaded libraries, and supports libraries loaded from a file offset, such as libraries loaded directly from `.apk` files on Android.
- Invoke the `before_send` hook at time of a hard crash when using the Windows or Linux Crashpad backend.
- Added the following new convenience functions:
- `sentry_value_new_exception`
- `sentry_value_new_thread`
- `sentry_value_new_stacktrace`
- `sentry_event_add_exception`
- `sentry_event_add_thread`
- The `sentry_event_value_add_stacktrace` is deprecated.
- Renamed `sentry_shutdown` to `sentry_close`, though the old function is still available.
- Updated Qt integration to Qt 6.
**Fixes**:
- Optimized and fixed bugs in the JSON parser/serializer.
- Build fixes for PPC and universal macOS.
- Fixes to build using musl libc.
- Correctness fixes around printf and strftime usage.
- Allow building and running on older macOS versions.
**Internal**:
- Update Crashpad and Breakpad submodules to 2021-04-12
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@mastertheknife](https://github.com/mastertheknife)
- [@torarnv](https://github.com/torarnv)
- [@encounter](https://github.com/encounter)
## 0.4.8
**Features**:
- The unwinder on Android was updated to a newer version.
- Experimental support for the Breakpad backend on Android and iOS.
**Fixes**:
- Fixed some memory leaks on Windows.
- Build System improvements.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@Mixaill](https://github.com/Mixaill)
- [@daxpedda](https://github.com/daxpedda)
- [@Amphaal](https://github.com/Amphaal)
## 0.4.7
**Features**:
- Events will automatically get an `os` context with OS version information.
- Added a new `max_breadcrumbs` option.
**Fixes**:
- Fixed some memory leaks related to bounded breadcrumbs.
## 0.4.6
**Fixes**:
- Restore compatibility with CMake 3.10 (as used in Android NDK Tools)
**Internal**:
- Update Crashpad and Breakpad submodules to 2021-01-25
## 0.4.5
**Features**:
- The Breakpad backend is now supported on macOS, although the crashpad backend is recommended on that platform.
- Added a new `sentry_reinstall_backend` function which can be used in case a third-party library is overriding the signal/exception handler.
- Add a Qt integration that hooks into Qt logging (opt-in CMake option).
- Expose the sentry-native version via CMake.
**Fixes**:
- Install `.pdb` files correctly.
- Improve macOS runtime version detection.
- Fixed a potential segfault when doing concurrent scope modification.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@Mixaill](https://github.com/Mixaill)
- [@eakoli](https://github.com/eakoli)
- [@GenuineAster](https://github.com/GenuineAster)
- [@daxpedda](https://github.com/daxpedda)
- [@torarnv](https://github.com/torarnv)
## 0.4.4
**Features**:
- The `sentry_get_modules_list` function was made public, which will return a list of loaded libraries that will be sent to sentry with each event.
- A new `sentry_options_set_transport_thread_name` function was added to set an explicit name for sentries http transport thread.
**Fixes**:
- The session duration is now printed in a locale-independent way, avoiding invalid session payloads.
- Correctly clean up locks and pass the Windows Application Verifier.
- Build fixes for MinGW and better documentation for universal MacOS builds.
- Crashes captured by the `crashpad` backend _after_ calling `sentry_shutdown` will now have the full metadata.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@Mixaill](https://github.com/Mixaill)
## 0.4.3
**Caution**:
- The representation of `sentry_value_t` was changed to avoid problems with the newly introduced Memory Tagging Extension (MTE) on ARM / Android.
Implementation details of `sentry_value_t` were never considered public, and it should always be treated as an opaque type.
**Fixes**:
- Fix corrupted breadcrumb data when using the crashpad backend on Windows.
- Avoid sending empty envelopes when using the crashpad backend.
- Correctly encode the signal number when using the Windows inproc backend, avoiding a processing Error.
- Unwind from the local call-stack, fixing empty stacktraces when using the inproc backend on Linux.
- Improvements to the Build configuration.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@4diekmann](https://github.com/4diekmann)
- [@variar](https://github.com/variar)
- [@Mixaill](https://github.com/Mixaill)
## 0.4.2
**Fixes**:
- Sampled (discarded) events still contribute to a sessions `errors` count.
- Initialize all static data structures.
## 0.4.1
**Fixes**:
- Fix parsing rate limit headers with multiple categories.
## 0.4.0
**Breaking Changes**:
- The minimum CMake version required to build on windows was raised to `3.16.4` to avoid potential build failures on older versions.
- The `sentry_get_options` function was removed, as it was unsafe to use after a `sentry_shutdown` call.
- The `sentry_options_set_logger` function now accepts a `userdata` parameter.
- The `name` parameter of `sentry_options_add_attachment(w)` was removed, it will now be inferred from the filename of `path`.
- The transport startup hook that is set via `sentry_transport_set_startup_func` now needs to return an `int`, and a failure will propagate to `sentry_init`.
- The return value of the transport shutdown hook set via `sentry_transport_set_shutdown_func` was also changed to return an `int`.
- Both functions should return _0_ on success, and a non-zero error code on failure, as does `sentry_init`.
- Similarly, the return value of `sentry_shutdown` was also changed to an `int`, and will return _0_ on success and a non-zero error code on unclean shutdown.
- Documentation for custom transports was updated to highlight the ordering requirements of submitted envelopes, which is important for release health.
```c
// before
sentry_options_set_logger(options, my_custom_logger);
sentry_options_add_attachment(options, "some-attachment", "/path/to/some-attachment.txt");
void transport_startup(sentry_options_t *options, void*state) {
}
sentry_transport_set_startup_func(transport, transport_startup);
bool transport_shutdown(uint64_t timeout, void*state) {
return true;
}
sentry_transport_set_shutdown_func(transport, transport_shutdown);
// after
sentry_options_set_logger(options, my_custom_logger, NULL);
sentry_options_add_attachment(options, "/path/to/some-attachment.txt");
int transport_startup(sentry_options_t *options, void*state) {
return 0;
}
sentry_transport_set_startup_func(transport, transport_startup);
int transport_shutdown(uint64_t timeout, void*state) {
return 0;
}
sentry_transport_set_shutdown_func(transport, transport_shutdown);
```
**Features**:
- [Release Health](https://docs.sentry.io/workflow/releases/health/) support is now stable and enabled by default. After the update, you will see the number of crash free sessions and crash free users on the Releases page in Sentry. To disable automatic session tracking, use `sentry_options_set_auto_session_tracking`.
- Breakpad support for Windows. This allows you to use `sentry-native` even on Windows XP! ([#278](https://github.com/getsentry/sentry-native/pull/278))
- Add an in-process backend for Windows. As opposed to Breakpad, stack traces are generated on the device and sent to Sentry for symbolication. ([#287](https://github.com/getsentry/sentry-native/pull/287))
- Support for the Crashpad backend was fixed and enabled for Linux. ([#320](https://github.com/getsentry/sentry-native/pull/320))
- A new `SENTRY_BREAKPAD_SYSTEM` CMake option was added to link to the system-installed breakpad client instead of building it as part of sentry.
**Fixes**:
- Reworked thread synchronization code and logic in `sentry_shutdown`, avoiding an abort in case of an unclean shutdown. ([#323](https://github.com/getsentry/sentry-native/pull/323))
- Similarly, reworked global options handling, avoiding thread safety issues. ([#333](https://github.com/getsentry/sentry-native/pull/333))
- Fixed errors not being properly recorded in sessions. ([#317](https://github.com/getsentry/sentry-native/pull/317))
- Fixed some potential memory leaks and other issues. ([#304](https://github.com/getsentry/sentry-native/pull/304) and others)
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@eakoli](https://github.com/eakoli)
- [@Mixaill](https://github.com/Mixaill)
- [@irov](https://github.com/irov)
- [@jblazquez](https://github.com/jblazquez)
- [@daxpedda](https://github.com/daxpedda)
## 0.3.4
**Fixes**:
- Invalid memory access when `sentry_options_set_debug(1)` is set, leading to an application crash. This bug was introduced in version `0.3.3`. ([#310](https://github.com/getsentry/sentry-native/pull/310)).
## 0.3.3
**Fixes**:
- Fix a memory unsafety issue when calling `sentry_value_remove_by_key`. ([#297](https://github.com/getsentry/sentry-native/pull/297))
- Improvements to internal logging. ([#301](https://github.com/getsentry/sentry-native/pull/301), [#302](https://github.com/getsentry/sentry-native/pull/302))
- Better handling of timeouts. ([#284](https://github.com/getsentry/sentry-native/pull/284))
- Better 32-bit build support. ([#291](https://github.com/getsentry/sentry-native/pull/291))
- Run more checks on CI. ([#299](https://github.com/getsentry/sentry-native/pull/299))
**Thank you**:
Fixes in this release have been contributed by:
- [@eakoli](https://github.com/eakoli)
## 0.3.2
**Features**:
- Implement a new logger hook. ([#267](https://github.com/getsentry/sentry-native/pull/267))
This adds the new `sentry_options_set_logger` function, which can be used to customize the sentry-internal logging, for example to integrate into an apps own logging system, or to stream logs to a file.
- New CMake options: `SENTRY_LINK_PTHREAD`, `SENTRY_BUILD_RUNTIMESTATIC` and `SENTRY_EXPORT_SYMBOLS` along with other CMake improvements.
**Fixes**:
- Avoid memory unsafety when loading session from disk. ([#270](https://github.com/getsentry/sentry-native/pull/270))
- Avoid Errors in Crashpad Backend without prior scope changes. ([#272](https://github.com/getsentry/sentry-native/pull/272))
- Fix absolute paths on Windows, and allow using forward-slashes as directory separators. ([#266](https://github.com/getsentry/sentry-native/pull/266), [#289](https://github.com/getsentry/sentry-native/pull/289))
- Various fixes uncovered by static analysis tools, notably excessive allocations by the page-allocator used inside signal handlers.
- Build fixes for MinGW and other compilers.
**Thank you**:
Features, fixes and improvements in this release have been contributed by:
- [@Mixaill](https://github.com/Mixaill)
- [@blinkov](https://github.com/blinkov)
- [@eakoli](https://github.com/eakoli)
## 0.3.1
- Add support for on-device symbolication, which is enabled by default on
Android. Use `sentry_options_set_symbolize_stacktraces` to customize.
- Enable gzip compressed crashpad minidumps on windows.
- Correctly 0-pad short `build-id`s.
- Fix build for 32bit Apple targets.
## 0.3.0
- Always send the newer `x-sentry-envelope` format, which makes this
incompatible with older on-premise installations.
- Better document and handle non-ASCII paths. Users on windows should use the
`w` version of the appropriate APIs.
- Avoid segfaults due to failed sentry initialization.
- Avoid creating invalid sessions without a `release`.
- Make `sentry_transport_t` opaque, and instead expose APIs to configure it.
More functionality related to creating custom transports will be exposed in
future versions.
### Breaking changes
- The `sentry_backend_free` function was removed.
- The `sentry_backend_t` type was removed.
- The `sentry_transport_t` type is now opaque. Use the following new API to
create a custom transport.
### New API
- `sentry_transport_new`
- `sentry_transport_set_state`
- `sentry_transport_set_free_func`
- `sentry_transport_set_startup_func`
- `sentry_transport_set_shutdown_func`
See `sentry.h` for more documentation.
### Deprecations
- `sentry_new_function_transport` has been deprecated in favor of the new
transport builder functions.
## 0.2.6
- Avoid crash with invalid crashpad handler path.
## 0.2.5
- Send sessions to the correct sentry endpoint and make sure they work.
- Smaller cleanups.
## 0.2.4
- Avoid unsafe reads in the linux module finder.
- Update to latest crashpad snapshot.
- Yet more CMake improvements (thanks @madebr and @Amphaal).
## 0.2.3
### Important upgrade notice
All `0.2.x` versions prior to this one were affected by a bug that could
potentially lead to serious data-loss on Windows platforms. We encourage
everyone to update as quickly as possible.
See [#220](https://github.com/getsentry/sentry-native/issues/220) for details.
### Deprecations
- `sentry_transport_t` will be replaced by an opaque struct with setter methods
in a future release.
- `sentry_backend_free` and `sentry_backend_t` are deprecated and will be
removed in a future release.
### Other changes
- Further improvements to the cmake build system (huge thanks to @madebr
[#207](https://github.com/getsentry/sentry-native/pull/207))
- Improved support for older Windows versions, as low as Windows XP SP3 (thanks
to @Mixaill [#203](https://github.com/getsentry/sentry-native/pull/203),
@cammm [#202](https://github.com/getsentry/sentry-native/pull/202) and
@jblazquez [#212](https://github.com/getsentry/sentry-native/pull/212))
- Improved documentation
- Cleaned up sentry database handling
- Added new `sentry_handle_exception` function to explicitly capture a crash
(thanks @cammm [#201](https://github.com/getsentry/sentry-native/pull/201))
- Added new `sentry_clear_modulecache` function to clear the list of loaded
modules. Use this function when dynamically loading libraries at runtime.
## 0.2.2
- Implement experimental Session handling
- Implement more fine grained Rate Limiting for HTTP requests
- Implement `sample_rate` option
- In-process and Breakpad backend will not lose events queued for HTTP
submission on crash
- `sentry_shutdown` will better clean up after itself
- Add Experimental MinGW build support (thanks @Amphaal
[#189](https://github.com/getsentry/sentry-native/pull/189))
- Various other fixes and improvements
## 0.2.1
- Added Breakpad support on Linux
- Implemented fallback `debug-id` on Linux and Android for modules that are
built without a `build-id`
- Fixes issues and added CI for more platforms/compilers, including 32-bit Linux
and 32-bit VS2017
- Further improvements to the CMake configuration (thanks @madebr
[#168](https://github.com/getsentry/sentry-native/pull/168))
- Added a new `SENTRY_TRANSPORT` CMake option to customize the default HTTP transport
## 0.2.0
- Complete rewrite in C
- Build system was switched to CMake
- Add attachment support
- Better support for custom transports
- The crashpad backend will automatically look for a `crashpad_handler`
executable next to the running program if no `handler_path` is set.
### Breaking Changes
- The `sentry_uuid_t` struct is now always a `char bytes[16]` instead of a
platform specific type.
- `sentry_remove_context`: The second parameter was removed.
- `sentry_options_set_transport`:
This function now takes a pointer to the new `sentry_transport_t` type.
Migrating from the old API can be done by wrapping with
`sentry_new_function_transport`, like this:
```c
sentry_options_set_transport(
options, sentry_new_function_transport(send_envelope_func, &closure_data));
```
### Other API Additions
- `size_t sentry_value_refcount(sentry_value_t value)`
- `void sentry_envelope_free(sentry_envelope_t *envelope)`
- `void sentry_backend_free(sentry_backend_t *backend)`
## 0.1.4
- Add an option to enable the system crash reporter
- Fix compilation warnings
## 0.1.3
- Stack unwinding on Android
- Fix UUID generation on Android
- Fix concurrently captured events leaking data in some cases
- Fix crashes when the database path contains both slashes and backslashes
- More robust error handling when creating the database folder
- Fix wrong initialization of CA info for the curl backend
- Disable the system crash handler on macOS for faster crashes
## 0.1.2
- Fix SafeSEH builds on Win32
- Fix a potential error when shutting down after unloading libsentry on macOS
## 0.1.1
- Update Crashpad
- Fix compilation on Windows with VS 2019
- Fix a bug in the JSON serializer causing invalid escapes
- Fix a bug in the Crashpad backend causing invalid events
- Reduce data event data sent along with minidumps
- Experimental support for Android NDK
## 0.1.0
- Support for capturing messages
- Add an API to capture arbitrary contexts (`sentry_set_context`)
- Fix scope information being lost in some cases
- Experimental on-device unwinding support
- Experimental on-device symbolication support
## 0.0.4
- Breakpad builds on all platforms
- Add builds for Windows (x86)
- Add builds for Linux
## 0.0.3
- Fix debug information generation on macOS
## 0.0.2
- Crashpad builds on macOS
- Crashpad builds on Windows (x64)
## 0.0.1
Initial Release

578
thirdparty/sentry-native/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,578 @@
if(WIN32)
cmake_minimum_required (VERSION 3.16.4)
# enables support for CMAKE_MSVC_RUNTIME_LIBRARY
cmake_policy(SET CMP0091 NEW)
else()
# The Android tools ship with this ancient version, which we need to support.
cmake_minimum_required (VERSION 3.10)
endif()
#read sentry-native version
file(READ "include/sentry.h" _SENTRY_HEADER_CONTENT)
string(REGEX MATCH "#define SENTRY_SDK_VERSION \"([0-9\.]+)\"" _SENTRY_VERSION_MATCH "${_SENTRY_HEADER_CONTENT}")
set(SENTRY_VERSION "${CMAKE_MATCH_1}")
unset(_SENTRY_HEADER_CONTENT)
unset(_SENTRY_VERSION_MATCH)
project(Sentry-Native
LANGUAGES C CXX ASM
VERSION ${SENTRY_VERSION}
)
set(SENTRY_MAIN_PROJECT OFF)
if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
set(SENTRY_MAIN_PROJECT ON)
endif()
if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD 11)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
include(GNUInstallDirs)
set(CMAKE_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/sentry")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(LINUX TRUE)
elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400")
set(AIX TRUE)
endif()
#setup sentry library type
if(SENTRY_MAIN_PROJECT AND NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON)
endif()
option(SENTRY_BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ${BUILD_SHARED_LIBS})
if(SENTRY_BUILD_SHARED_LIBS)
set(SENTRY_LIBRARY_TYPE SHARED)
else()
set(SENTRY_LIBRARY_TYPE STATIC)
endif()
option(SENTRY_PIC "Build sentry (and dependent) libraries as position independent libraries" ON)
option(SENTRY_BUILD_TESTS "Build sentry-native tests" "${SENTRY_MAIN_PROJECT}")
option(SENTRY_BUILD_EXAMPLES "Build sentry-native example(s)" "${SENTRY_MAIN_PROJECT}")
option(SENTRY_LINK_PTHREAD "Link platform threads library" ON)
if(SENTRY_LINK_PTHREAD)
find_package(Threads REQUIRED)
endif()
if(MSVC)
option(SENTRY_BUILD_RUNTIMESTATIC "Build sentry-native with static runtime" OFF)
endif()
if(LINUX)
option(SENTRY_BUILD_FORCE32 "Force a 32bit compile on a 64bit host" OFF)
if(SENTRY_BUILD_FORCE32)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE")
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE")
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS OFF)
endif()
endif()
# CMAKE_POSITION_INDEPENDENT_CODE must be set BEFORE adding any libraries (including subprojects)
if(SENTRY_PIC)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
else()
set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
endif()
if(WIN32)
set(SENTRY_DEFAULT_TRANSPORT "winhttp")
elseif((APPLE AND NOT IOS) OR LINUX OR AIX)
set(SENTRY_DEFAULT_TRANSPORT "curl")
else()
set(SENTRY_DEFAULT_TRANSPORT "none")
endif()
set(SENTRY_TRANSPORT ${SENTRY_DEFAULT_TRANSPORT} CACHE STRING
"The HTTP transport that sentry uses to submit events to the sentry server, can be either 'none', 'curl' or 'winhttp' on windows.")
if(SENTRY_TRANSPORT STREQUAL "winhttp")
set(SENTRY_TRANSPORT_WINHTTP TRUE)
elseif(SENTRY_TRANSPORT STREQUAL "curl")
set(SENTRY_TRANSPORT_CURL TRUE)
elseif(SENTRY_TRANSPORT STREQUAL "none")
set(SENTRY_TRANSPORT_NONE TRUE)
else()
message(FATAL_ERROR "SENTRY_TRANSPORT must be one of 'none', 'curl' or 'winhttp'")
endif()
if(SENTRY_TRANSPORT_WINHTTP AND NOT WIN32)
message(FATAL_ERROR "The winhttp transport is only supported on Windows.")
endif()
if(SENTRY_BUILD_TESTS OR SENTRY_BUILD_EXAMPLES)
enable_testing()
endif()
if("${CMAKE_SOURCE_DIR}" STREQUAL "${PROJECT_SOURCE_DIR}")
set(SENTRY_MAIN_PROJECT ON)
endif()
option(SENTRY_ENABLE_INSTALL "Enable sentry installation" "${SENTRY_MAIN_PROJECT}")
if(MSVC AND CMAKE_GENERATOR_TOOLSET MATCHES "_xp$")
message(WARNING "Crashpad is not supported for MSVC with XP toolset. Default backend was switched to 'breakpad'")
set(SENTRY_DEFAULT_BACKEND "breakpad")
elseif((APPLE AND NOT IOS) OR WIN32)
set(SENTRY_DEFAULT_BACKEND "crashpad")
elseif(LINUX)
set(SENTRY_DEFAULT_BACKEND "breakpad")
else()
set(SENTRY_DEFAULT_BACKEND "inproc")
endif()
if(NOT DEFINED SENTRY_BACKEND)
set(SENTRY_BACKEND ${SENTRY_DEFAULT_BACKEND} CACHE STRING
"The sentry backend responsible for reporting crashes, can be either 'none', 'inproc', 'breakpad' or 'crashpad'.")
endif()
if(SENTRY_BACKEND STREQUAL "crashpad")
set(SENTRY_BACKEND_CRASHPAD TRUE)
elseif(SENTRY_BACKEND STREQUAL "inproc")
set(SENTRY_BACKEND_INPROC TRUE)
elseif(SENTRY_BACKEND STREQUAL "breakpad")
set(SENTRY_BACKEND_BREAKPAD TRUE)
elseif(SENTRY_BACKEND STREQUAL "none")
set(SENTRY_BACKEND_NONE TRUE)
else()
message(FATAL_ERROR "SENTRY_BACKEND must be one of 'crashpad', 'inproc', 'breakpad' or 'none'")
endif()
if(SENTRY_BACKEND_CRASHPAD AND ANDROID)
message(FATAL_ERROR "The Crashpad backend is not currently supported on Android")
endif()
message(STATUS "SENTRY_TRANSPORT=${SENTRY_TRANSPORT}")
message(STATUS "SENTRY_BACKEND=${SENTRY_BACKEND}")
message(STATUS "SENTRY_LIBRARY_TYPE=${SENTRY_LIBRARY_TYPE}")
if(ANDROID)
set(SENTRY_WITH_LIBUNWINDSTACK TRUE)
elseif(NOT WIN32)
set(SENTRY_WITH_LIBBACKTRACE TRUE)
endif()
option(WITH_ASAN_OPTION "Build sentry-native with address sanitizer" OFF)
if(WITH_ASAN_OPTION)
add_compile_options(-g -fsanitize=address -fno-omit-frame-pointer)
link_libraries(-fsanitize=address)
endif()
option(WITH_TSAN_OPTION "Build sentry-native with thread sanitizer" OFF)
if(WITH_TSAN_OPTION)
add_compile_options(-g -fsanitize=thread -fno-omit-frame-pointer)
link_libraries(-fsanitize=thread)
endif()
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo")
endif()
# use -O3 when doing `RelWithDebInfo` builds
if(NOT MSVC)
foreach(lang ASM C CXX)
string(REPLACE "-O2" "-O3" CMAKE_${lang}_FLAGS_RELWITHDEBINFO "${CMAKE_${lang}_FLAGS_RELWITHDEBINFO}")
endforeach()
endif()
# https://gitlab.kitware.com/cmake/cmake/issues/20256
if(APPLE)
find_program(DSYMUTIL_PROGRAM dsymutil)
if(DSYMUTIL_PROGRAM)
foreach(lang C CXX)
foreach(var LINK_EXECUTABLE CREATE_SHARED_LIBRARY)
set(CMAKE_${lang}_${var} "${CMAKE_${lang}_${var}}" "${DSYMUTIL_PROGRAM} <TARGET>")
endforeach()
endforeach()
endif()
endif()
function(sentry_install)
if(SENTRY_ENABLE_INSTALL)
install(${ARGN})
endif()
endfunction()
# helper function to add sources to existing TARGET prepended with ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}
function(sentry_target_sources_cwd TARGET)
cmake_parse_arguments(STSC "" "SUBDIR" "" ${ARGN})
foreach(src ${STSC_UNPARSED_ARGUMENTS})
if(IS_ABSOLUTE "${src}")
target_sources(${TARGET} PRIVATE ${src})
else()
target_sources(${TARGET} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/${STSC_SUBDIR}/${src}")
endif()
endforeach()
endfunction()
# ===== sentry library =====
add_library(sentry ${SENTRY_LIBRARY_TYPE} "${PROJECT_SOURCE_DIR}/vendor/mpack.c")
target_sources(sentry PRIVATE "${PROJECT_SOURCE_DIR}/include/sentry.h")
add_library(sentry::sentry ALIAS sentry)
add_subdirectory(src)
# we do not need this on android, only linux
if(LINUX)
target_sources(sentry PRIVATE
"${PROJECT_SOURCE_DIR}/vendor/stb_sprintf.c"
"${PROJECT_SOURCE_DIR}/vendor/stb_sprintf.h"
)
endif()
set_target_properties(sentry PROPERTIES PUBLIC_HEADER "include/sentry.h")
if(DEFINED SENTRY_FOLDER)
set_target_properties(sentry PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()
# check size type
include(CheckTypeSize)
check_type_size("long" CMAKE_SIZEOF_LONG)
# https://gitlab.kitware.com/cmake/cmake/issues/18393
if(SENTRY_BUILD_SHARED_LIBS)
if(APPLE)
sentry_install(FILES "$<TARGET_FILE:sentry>.dSYM" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
elseif(MSVC)
sentry_install(FILES "$<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:$<TARGET_PDB_FILE:sentry>>"
DESTINATION "${CMAKE_INSTALL_BINDIR}")
endif()
endif()
if(SENTRY_BUILD_SHARED_LIBS)
target_compile_definitions(sentry PRIVATE SENTRY_BUILD_SHARED)
else()
target_compile_definitions(sentry PUBLIC SENTRY_BUILD_STATIC)
endif()
target_compile_definitions(sentry PRIVATE SIZEOF_LONG=${CMAKE_SIZEOF_LONG})
# AIX needs libm for isnan used in test suite
if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR CMAKE_SYSTEM_NAME STREQUAL "OS400")
target_link_libraries(sentry PRIVATE m)
endif()
# On IBM i PASE, flock is in libutil. Here because "sentry" exists now.
if(CMAKE_SYSTEM_NAME STREQUAL "OS400")
target_link_libraries(sentry PRIVATE util)
endif()
if(SENTRY_TRANSPORT_CURL)
if(NOT CURL_FOUND) # Some other lib might bring libcurl already
find_package(CURL REQUIRED)
endif()
if(TARGET CURL::libcurl) # Only available in cmake 3.12+
target_link_libraries(sentry PRIVATE CURL::libcurl)
else()
# Needed for cmake < 3.12 support (cmake 3.12 introduced the target CURL::libcurl)
target_include_directories(sentry PRIVATE ${CURL_INCLUDE_DIR})
# The exported sentry target must not contain any path of the build machine, therefore use generator expressions
string(REPLACE ";" "$<SEMICOLON>" GENEX_CURL_LIBRARIES "${CURL_LIBRARIES}")
string(REPLACE ";" "$<SEMICOLON>" GENEX_CURL_COMPILE_DEFINITIONS "${CURL_COMPILE_DEFINITIONS}")
target_link_libraries(sentry PRIVATE $<BUILD_INTERFACE:${GENEX_CURL_LIBRARIES}>)
target_compile_definitions(sentry PRIVATE $<BUILD_INTERFACE:${GENEX_CURL_COMPILE_DEFINITIONS}>)
endif()
endif()
set_property(TARGET sentry PROPERTY C_VISIBILITY_PRESET hidden)
if(MSVC)
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
set(CMAKE_ASM_MASM_FLAGS "${CMAKE_ASM_MASM_FLAGS} /safeseh")
endif()
# using `/Wall` is not feasible, as it spews tons of warnings from windows headers
# supress C5105, introduced in VS 16.8, which breaks on the Windows SDKs own `winbase.h` header
target_compile_options(sentry PRIVATE $<BUILD_INTERFACE:/W4 /wd5105>)
# ignore all warnings for mpack
set_source_files_properties(
"${PROJECT_SOURCE_DIR}/vendor/mpack.c"
PROPERTIES
COMPILE_FLAGS
"/W0"
)
# set static runtime if enabled
if(SENTRY_BUILD_RUNTIMESTATIC)
set_property(TARGET sentry PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
else()
target_compile_options(sentry PRIVATE $<BUILD_INTERFACE:-Wall -Wextra -Wpedantic>)
# The crashpad and breakpad headers generate the following warnings that we
# ignore specifically
target_compile_options(sentry PRIVATE $<BUILD_INTERFACE:-Wno-variadic-macros -Wno-gnu-include-next -Wno-multichar>)
# ignore all warnings for mpack
set_source_files_properties(
"${PROJECT_SOURCE_DIR}/vendor/mpack.c"
PROPERTIES
COMPILE_FLAGS
"-w"
)
endif()
target_include_directories(sentry
PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
PRIVATE
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>"
)
# The modulefinder and symbolizer need these two settings, and they are exported
# as `PUBLIC`, so libraries that depend on sentry get these too:
# `-E`: To have all symbols in the dynamic symbol table.
# `--build-id`: To have a build-id in the ELF object.
# FIXME: cmake 3.13 introduced target_link_options
option(SENTRY_EXPORT_SYMBOLS "Export symbols for modulefinder and symbolizer" ON)
if(SENTRY_EXPORT_SYMBOLS)
target_link_libraries(sentry PUBLIC
"$<$<OR:$<PLATFORM_ID:Linux>,$<PLATFORM_ID:Android>>:-Wl,-E,--build-id=sha1>")
endif()
#respect CMAKE_SYSTEM_VERSION
if(WIN32)
if(MSVC AND CMAKE_GENERATOR_TOOLSET MATCHES "_xp$")
#force WINNT to 5.1 for Windows XP toolchain
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0501")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^10")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0A00")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^6.3")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0603")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^6.2")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0602")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^6.1")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0601")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^6.0")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0600")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^5.2")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0502")
elseif(${CMAKE_SYSTEM_VERSION} MATCHES "^5.1")
target_compile_definitions(sentry PRIVATE "_WIN32_WINNT=0x0501")
endif()
# crashpad does not support Windows XP toolset
if(MSVC AND CMAKE_GENERATOR_TOOLSET MATCHES "_xp$" AND SENTRY_BACKEND_CRASHPAD)
message(FATAL_ERROR "MSVC XP toolset does not support Crashpad")
endif()
endif()
# handle platform libraries
if(ANDROID)
set(_SENTRY_PLATFORM_LIBS "dl" "log")
elseif(LINUX)
set(_SENTRY_PLATFORM_LIBS "dl" "rt")
elseif(WIN32)
set(_SENTRY_PLATFORM_LIBS "dbghelp" "shlwapi" "version")
endif()
if(SENTRY_TRANSPORT_WINHTTP)
list(APPEND _SENTRY_PLATFORM_LIBS "winhttp")
endif()
# handle platform threads library
if(SENTRY_LINK_PTHREAD)
list(APPEND _SENTRY_PLATFORM_LIBS "Threads::Threads")
endif()
# apply platform libraries to sentry library
if(SENTRY_LIBRARY_TYPE STREQUAL "STATIC")
target_link_libraries(sentry PUBLIC ${_SENTRY_PLATFORM_LIBS})
else()
target_link_libraries(sentry PRIVATE ${_SENTRY_PLATFORM_LIBS})
endif()
# suppress some errors and warnings for MinGW target
if(MINGW)
target_compile_options(sentry PRIVATE
-Wno-unused-variable
-Wno-unused-parameter
-Wno-format
-Wno-incompatible-pointer-types
-Wno-incompatible-function-pointer-types
)
endif()
if(SENTRY_WITH_LIBUNWINDSTACK)
target_include_directories(sentry PRIVATE
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/external/libunwindstack-ndk/include>")
add_subdirectory("${PROJECT_SOURCE_DIR}/external/libunwindstack-ndk/cmake")
target_link_libraries(sentry PRIVATE unwindstack)
if(NOT SENTRY_BUILD_SHARED_LIBS)
sentry_install(TARGETS unwindstack EXPORT sentry
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
endif()
endif()
if(SENTRY_BACKEND_CRASHPAD)
option(SENTRY_CRASHPAD_SYSTEM "Use system crashpad" OFF)
if(SENTRY_CRASHPAD_SYSTEM)
find_package(crashpad REQUIRED)
target_link_libraries(sentry PUBLIC crashpad::client)
else()
# FIXME: required for cmake 3.12 and lower:
# - NEW behavior lets normal variable override option
cmake_policy(SET CMP0077 NEW)
if(SENTRY_BUILD_SHARED_LIBS)
set(CRASHPAD_ENABLE_INSTALL OFF CACHE BOOL "Enable crashpad installation" FORCE)
else()
set(CRASHPAD_ENABLE_INSTALL ON CACHE BOOL "Enable crashpad installation" FORCE)
endif()
add_subdirectory(external/crashpad crashpad_build)
# set static runtime if enabled
if(SENTRY_BUILD_RUNTIMESTATIC AND MSVC)
set_property(TARGET crashpad_client PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_compat PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_getopt PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_handler PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_handler_lib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_minidump PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_snapshot PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_tools PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_util PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET crashpad_zlib PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
set_property(TARGET mini_chromium PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
if(DEFINED SENTRY_FOLDER)
set_target_properties(crashpad_client PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_compat PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_getopt PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_handler PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_handler_lib PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_minidump PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_snapshot PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_tools PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_util PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(crashpad_zlib PROPERTIES FOLDER ${SENTRY_FOLDER})
set_target_properties(mini_chromium PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()
target_link_libraries(sentry PRIVATE
$<BUILD_INTERFACE:crashpad::client>
$<INSTALL_INTERFACE:sentry_crashpad::client>
)
install(EXPORT crashpad_export NAMESPACE sentry_crashpad:: FILE sentry_crashpad-targets.cmake
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}"
)
if(WIN32 AND MSVC)
sentry_install(FILES $<TARGET_PDB_FILE:crashpad_handler>
DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL)
endif()
endif()
add_dependencies(sentry crashpad::handler)
elseif(SENTRY_BACKEND_BREAKPAD)
option(SENTRY_BREAKPAD_SYSTEM "Use system breakpad" OFF)
if(SENTRY_BREAKPAD_SYSTEM)
# system breakpad is using pkg-config, see `external/breakpad/breakpad-client.pc.in`
find_package(PkgConfig REQUIRED)
pkg_check_modules(BREAKPAD REQUIRED IMPORTED_TARGET breakpad-client)
target_link_libraries(sentry PUBLIC PkgConfig::BREAKPAD)
else()
add_subdirectory(external)
target_include_directories(sentry PRIVATE
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/external/breakpad/src>"
)
target_link_libraries(sentry PRIVATE
breakpad_client
)
if(DEFINED SENTRY_FOLDER)
set_target_properties(breakpad_client PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()
if(NOT SENTRY_BUILD_SHARED_LIBS)
sentry_install(TARGETS breakpad_client EXPORT sentry
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)
endif()
endif()
elseif(SENTRY_BACKEND_INPROC)
target_compile_definitions(sentry PRIVATE SENTRY_WITH_INPROC_BACKEND)
endif()
option(SENTRY_INTEGRATION_QT "Build Qt integration")
if(SENTRY_INTEGRATION_QT)
if(QT_DEFAULT_MAJOR_VERSION)
# Let user choose major version
set(Qt_VERSION_MAJOR ${QT_DEFAULT_MAJOR_VERSION})
else()
# Find best match, prioritizing Qt 6 if available
find_package(Qt NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
endif()
find_package(Qt${Qt_VERSION_MAJOR} COMPONENTS Core REQUIRED)
message(STATUS "Found Qt: ${Qt${Qt_VERSION_MAJOR}_DIR} "
"(found version \"${Qt${Qt_VERSION_MAJOR}_VERSION}\")")
target_link_libraries(sentry PRIVATE Qt${Qt_VERSION_MAJOR}::Core)
endif()
include(CMakePackageConfigHelpers)
configure_package_config_file(sentry-config.cmake.in sentry-config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
# generate package version file
# We would have liked to use `SameMinorVersion`, but that is only supported on
# CMake >= 3.11.
write_basic_package_version_file(sentry-config-version.cmake
VERSION ${SENTRY_VERSION}
COMPATIBILITY SameMajorVersion)
sentry_install(TARGETS sentry EXPORT sentry
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
sentry_install(EXPORT sentry NAMESPACE sentry:: FILE sentry-targets.cmake
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
sentry_install(
FILES
"${PROJECT_BINARY_DIR}/sentry-config.cmake"
"${PROJECT_BINARY_DIR}/sentry-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
if(WIN32 AND MSVC AND SENTRY_BUILD_SHARED_LIBS)
sentry_install(FILES $<TARGET_PDB_FILE:sentry>
DESTINATION "${CMAKE_INSTALL_BINDIR}" OPTIONAL)
endif()
# ===== tests =====
if(SENTRY_BUILD_TESTS)
add_subdirectory(tests/unit)
endif()
# ===== example, also used as integration test =====
if(SENTRY_BUILD_EXAMPLES)
add_executable(sentry_example examples/example.c)
target_link_libraries(sentry_example PRIVATE sentry)
target_compile_definitions(sentry_example PRIVATE SENTRY_PERFORMANCE_MONITORING)
if(MSVC)
target_compile_options(sentry_example PRIVATE $<BUILD_INTERFACE:/wd5105>)
endif()
# set static runtime if enabled
if(SENTRY_BUILD_RUNTIMESTATIC AND MSVC)
set_property(TARGET sentry_example PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
if(DEFINED SENTRY_FOLDER)
set_target_properties(sentry_example PROPERTIES FOLDER ${SENTRY_FOLDER})
endif()
add_test(NAME sentry_example COMMAND sentry_example)
endif()

140
thirdparty/sentry-native/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,140 @@
# Contribution guidelines
We love and welcome contributions!
In order to maintain a high quality, we run a number of checks on
different OS / Compiler combinations, and using different analysis tools.
## Prerequisites
Building and testing `sentry-native` currently requires the following tools:
- **CMake** and a supported C/C++ compiler, to actually build the code.
- **python** and **pytest**, to run integration tests.
- **clang-format** and **black**, to format the C/C++ and python code respectively.
`pytest` and `black` are installed as virtualenv dependencies automatically.
## Setting up Environment
$ make setup
This sets up both git, including a pre-commit hook and submodules, and installs
a python virtualenv which is used to run tests and formatting.
## Formatting Code
$ make format
This should be done automatically as part of the pre-commit hook, but can also
be done manually.
$ black tests
## Running Tests
$ make test
Creates a python virtualenv, and runs all the tests through `pytest`.
**Running integration tests manually**:
$ pytest --verbose --maxfail=1 --capture=no tests/
When all the python dependencies have been installed, the integration test suite
can also be invoked directly.
The `maxfail` parameter will abort after the first failure, and `capture=no`
will print the complete compiler output, and test log.
**Running unit tests**:
$ make test-unit
Unit tests also have a dedicated `make` target, if they need to be run separately
from the integration tests.
**Running unit tests manually**:
$ cmake -B build -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=$(pwd)/build
$ cmake --build build --target sentry_test_unit
$ ./build/sentry_test_unit
The unit tests are a separate executable target and can be built and run on
their own.
## How to interpret CI failures
The way that tests are run unfortunately does not make it immediately obvious from
the summary what the actual failure is, especially for compile-time failures.
In such cases, it is good to scan the test output _from top to bottom_ and find
the offending compile error.
When running tests locally, one can use the `--maxfail=1` / `-x` parameter to
abort after the first failure.
## Integration Test Parameters
The integration test suite runs the `sentry_example` target using a variety of
different compile-time parameters, and asserts different use-cases.
Some of its behavior is controlled by env-variables:
- `ERROR_ON_WARNINGS`: Turns on `-Werror` for gcc compatible compilers.
This is also the default for `MSVC` on windows.
- `RUN_ANALYZER`: Runs the code with/through one or more of the given analyzers.
This accepts a comma-separated list, and currently has support for:
- `asan`: Uses clangs AddressSanitizer and runs integration tests with the
`detect_leaks` flag.
- `scan-build`: Runs the build through the `scan-build` tool.
- `code-checker`: Uses the [`CodeChecker`](https://github.com/Ericsson/codechecker)
tool for builds.
- `kcov`: Uses [`kcov`](https://github.com/SimonKagstrom/kcov) to collect
code-coverage statistics.
- `valgrind`: Uses [`valgrind`](https://valgrind.org/) to check for memory
issues such as leaks.
- `gcc`: Use the `-fanalyzer` flag of `gcc > 10`.
This is currently not stable enough to use, as it leads to false positives
and internal compiler errors.
- `TEST_X86`: Passes flags to CMake to enable a 32-bit (cross-)compile.
- `ANDROID_API` / `ANDROID_NDK` / `ANDROID_ARCH`: Instructs the test runner to
build using the given Android `NDK` version, targeting the given `API` and
`ARCH`. The test runner assumes an already running simulator matching the
`ARCH`, and will run the tests on that.
**Analyzer Requirements**:
Some tools, such as `kcov` and `valgrind` have their own distribution packages.
Clang-based tools may require an up-to-date clang, and a separate `clang-tools`
packages.
`CodeChecker` has its own
[install instructions](https://github.com/Ericsson/codechecker#install-guide)
with a list of needed dependencies.
**Running examples manually**:
$ cmake -B build -D CMAKE_RUNTIME_OUTPUT_DIRECTORY=$(pwd)/build
$ cmake --build build --target sentry_example
$ ./build/sentry_example log capture-event
The example can be run manually with a variety of commands to test different
scenarios. Additionally, it will use the `SENTRY_DSN` env-variable, and can thus
also be used to capture events/crashes directly to sentry.
The example currently supports the following commends:
- `capture-event`: Captures an event.
- `crash`: Triggers a crash to be captured.
- `log`: Enables debug logging.
- `release-env`: Uses the `SENTRY_RELEASE` env-variable for the release,
instead of a hardcoded value.
- `attachment`: Adds an attachment, which is currently defined as the
`CMakeCache.txt` file, which is part of the CMake build folder.
- `stdout`: Uses a custom transport which dumps all envelopes to `stdout`.
- `no-setup`: Skips all scope and breadcrumb initialization code.
- `start-session`: Starts a new release-health session.
- `overflow-breadcrumbs`: Creates a large number of breadcrumbs that overflow
the maximum allowed number.
- `capture-multiple`: Captures a number of events.
- `sleep`: Introduces a 10 second sleep.
- `add-stacktrace`: Adds the current thread stacktrace to the captured event.

20
thirdparty/sentry-native/LICENSE vendored Normal file
View File

@ -0,0 +1,20 @@
Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors.
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

316
thirdparty/sentry-native/README.md vendored Normal file
View File

@ -0,0 +1,316 @@
<p align="center">
<a href="https://sentry.io" target="_blank" align="center">
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
</a>
<br />
</p>
# Official Sentry SDK for C/C++ <!-- omit in toc -->
The _Sentry Native SDK_ is an error and crash reporting client for native
applications, optimized for C and C++. Sentry allows to add tags, breadcrumbs
and arbitrary custom context to enrich error reports. Supports Sentry _20.6.0_
and later.
**Note**: This SDK is being actively developed and still in Beta. We recommend
to check for updates regularly to benefit from latest features and bug fixes.
Please see [Known Limitations](#known-limitations).
## Resources <!-- omit in toc -->
- [Discord](https://discord.gg/ez5KZN7) server for project discussions.
- Follow [@getsentry](https://twitter.com/getsentry) on Twitter for updates
## Table of Contents <!-- omit in toc -->
- [Downloads](#downloads)
- [What is Inside](#what-is-inside)
- [Platform and Feature Support](#platform-and-feature-support)
- [Building and Installation](#building-and-installation)
- [Compile-Time Options](#compile-time-options)
- [Build Targets](#build-targets)
- [Runtime Configuration](#runtime-configuration)
- [Known Limitations](#known-limitations)
- [Development](#development)
## Downloads
The SDK can be downloaded from the [Releases] page, which also lists the
changelog of every version.
[releases]: https://github.com/getsentry/sentry-native/releases
### What is Inside
The SDK bundle contains the following folders:
- `external`: These are external projects which are consumed via
`git submodules`.
- `include`: Contains the Sentry header file. Set the include path to this
directory or copy the header file to your source tree so that it is available
during the build.
- `src`: Sources of the Sentry SDK required for building.
## Platform and Feature Support
The SDK currently supports and is tested on the following OS/Compiler variations:
- 64bit Linux with GCC 9
- 64bit Linux with clang 9
- 32bit Linux with GCC 7 (cross compiled from 64bit host)
- 64bit Windows with MSVC 2019
- 32bit Windows with MSVC 2017
- macOS Catalina with most recent Compiler toolchain
- Android API29 built by NDK21 toolchain
- Android API16 built by NDK19 toolchain
Additionally, the SDK should support the following platforms, although they are
not automatically tested, so breakage may occur:
- Windows Versions lower than Windows 10 / Windows Server 2016
- Windows builds with the MSYS2 + MinGW + Clang toolchain
The SDK supports different features on the target platform:
- **HTTP Transport** is currently only supported on Windows and platforms that
have the `curl` library available. On other platforms, library users need to
implement their own transport, based on the `function transport` API.
- **Crashpad Backend** is currently only supported on Linux, Windows and macOS.
- **Client-side stackwalking** is currently only supported on Linux, Windows, and macOS.
## Building and Installation
The SDK is developed and shipped as a [CMake] project.
CMake will pick an appropriate compiler and buildsystem toolchain automatically
per platform, and can also be configured for cross-compilation.
System-wide installation of the resulting sentry library is also possible via
CMake.
Building the Crashpad Backend requires a `C++14` compatible compiler.
**Build example**:
```sh
# configure the cmake build into the `build` directory, with crashpad (on macOS)
$ cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
# build the project
$ cmake --build build --parallel
# install the resulting artifacts into a specific prefix (use the correct config on windows)
$ cmake --install build --prefix install --config RelWithDebInfo
# which will result in the following (on macOS):
$ exa --tree install
install
├── bin
│ └── crashpad_handler
├── include
│ └── sentry.h
└── lib
├── cmake
│ └── sentry
├── libsentry.dylib
└── libsentry.dylib.dSYM
```
Please refer to the CMake Manual for more details.
**Android**:
The CMake project can also be configured to correctly work with the Android NDK,
see the dedicated [CMake Guide] for details on how to integrate it with gradle
or use it on the command line.
[cmake]: https://cmake.org/cmake/help/latest/
[cmake guide]: https://developer.android.com/ndk/guides/cmake
**MinGW**:
64-bits is the only platform supported for now.
LLVM + Clang are mandatory here : they are required to generate .pdb files, used by Crashpad for the report generation.
For your application to generate the appropriate .pdb output, you need to activate CodeView file format generation on your application target. To do so, update your own CMakeLists.txt with something like `target_compile_options(${yourApplicationTarget} PRIVATE -gcodeview)`.
If you use a MSYS2 environement to compile with MinGW, make sure to :
- Create an environement variable `MINGW_ROOT` (ex : `C:/msys64/mingw64`)
- Run from `mingw64.exe` : `pacman -S --needed - < ./toolchains/msys2-mingw64-pkglist.txt`
- Build as :
```sh
# Configure with Ninja as generator and use the MSYS2 toolchain file
$ cmake -GNinja -Bbuild -H. -DCMAKE_TOOLCHAIN_FILE=toolchains/msys2.cmake
# build with Ninja
$ ninja -C build
```
**MacOS**:
Building universal binaries/libraries is possible out of the box when using the
[`CMAKE_OSX_ARCHITECTURES`](https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html) define, both with the `Xcode` generator as well
as the default generator:
```sh
# using xcode generator:
$ cmake -B xcodebuild -GXcode -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
$ xcodebuild build -project xcodebuild/Sentry-Native.xcodeproj
$ lipo -info xcodebuild/Debug/libsentry.dylib
Architectures in the fat file: xcodebuild/Debug/libsentry.dylib are: x86_64 arm64
# using default generator:
$ cmake -B defaultbuild -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
$ cmake --build defaultbuild --parallel
$ lipo -info defaultbuild/libsentry.dylib
Architectures in the fat file: defaultbuild/libsentry.dylib are: x86_64 arm64
```
Make sure that MacOSX SDK 11 or later is used. It is possible that this requires
manually overriding the `SDKROOT`:
```sh
$ export SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
```
### Compile-Time Options
The following options can be set when running the cmake generator, for example
using `cmake -D BUILD_SHARED_LIBS=OFF ..`.
- `SENTRY_BUILD_SHARED_LIBS` (Default: ON):
By default, `sentry` is built as a shared library. Setting this option to
`OFF` will build `sentry` as a static library instead.
If sentry is used as a subdirectory of another project, the value `BUILD_SHARED_LIBS` will be inherited by default.
When using `sentry` as a static library, make sure to `#define SENTRY_BUILD_STATIC 1` before including the sentry header.
- `SENTRY_PIC` (Default: ON):
By default, `sentry` is built as a position independent library.
- `SENTRY_EXPORT_SYMBOLS` (Default: ON):
By default, `sentry` exposes all symbols in the dynamic symbol table. You might want to disable it in case the program intends to `dlopen` third-party shared libraries and avoid symbol collisions.
- `SENTRY_BUILD_RUNTIMESTATIC` (Default: OFF):
Enables linking with the static MSVC runtime. Has no effect if the compiler is not MSVC.
- `SENTRY_LINK_PTHREAD` (Default: ON):
Links platform threads library like `pthread` on unix targets.
- `SENTRY_BUILD_FORCE32` (Default: OFF):
Forces cross-compilation from 64-bit host to 32-bit target. Only has an effect on Linux.
- `CMAKE_SYSTEM_VERSION` (Default: depending on Windows SDK version):
Sets up a minimal version of Windows where sentry-native can be guaranteed to run.
Possible values:
- `5.1` (Windows XP)
- `5.2` (Windows XP 64-bit / Server 2003 / Server 2003 R2)
- `6.0` (Windows Vista / Server 2008)
- `6.1` (Windows 7 / Server 2008 R2)
- `6.2` (Windows 8.0 / Server 2012)
- `6.3` (Windows 8.1 / Server 2012 R2)
- `10` (Windows 10 / Server 2016 / Server 2019)
For Windows versions below than `6.0` it is also necessary to use XP toolchain
in case of MSVC compiler (pass `-T v141_xp` to CMake command line).
- `SENTRY_TRANSPORT` (Default: depending on platform):
Sentry can use different http libraries to send reports to the server.
- **curl**: This uses the `curl` library for HTTP handling. This requires
that the development version of the package is available.
- **winhttp**: This uses the `winhttp` system library, is only supported on
Windows and is the default there.
- **none**: Do not build any http transport. This should be used if users
want to handle uploads themselves
- `SENTRY_BACKEND` (Default: depending on platform):
Sentry can use different backends depending on platform.
- **crashpad**: This uses the out-of-process crashpad handler. It is currently
only supported on Desktop OSs, and used as the default on Windows and macOS.
- **breakpad**: This uses the in-process breakpad handler. It is currently
only supported on Desktop OSs, and used as the default on Linux.
- **inproc**: A small in-process handler which is supported on all platforms,
and is used as default on Android.
- **none**: This builds `sentry-native` without a backend, so it does not handle
crashes at all. It is primarily used for tests.
- `SENTRY_INTEGRATION_QT` (Default: OFF):
Builds the Qt integration, which turns Qt log messages into breadcrumbs.
- `SENTRY_BREAKPAD_SYSTEM` / `SENTRY_CRASHPAD_SYSTEM` (Default: OFF):
This instructs the build system to use system-installed breakpad or crashpad
libraries instead of using the in-tree version. This is generally not recommended
for crashpad, as sentry uses a patched version that has attachment support.
This is being worked on upstream as well, and a future version might work with
an unmodified crashpad version as well.
| Feature | Windows | macOS | Linux | Android | iOS |
| ---------- | ------- | ----- | ----- | ------- | --- |
| Transports | | | | | |
| - curl | | ☑ | ☑ | (✓) | |
| - winhttp | ☑ | | | | |
| - none | ✓ | ✓ | ✓ | ☑ | ☑ |
| | | | | | |
| Backends | | | | | |
| - inproc | ✓ | ✓ | ✓ | ☑ | |
| - crashpad | ☑ | ☑ | ✓ | | |
| - breakpad | ✓ | ✓ | ☑ | (✓) | (✓) |
| - none | ✓ | ✓ | ✓ | ✓ | |
Legend:
- ☑ default
- ✓ supported
- unsupported
- `SENTRY_FOLDER` (Default: not defined):
Sets the sentry-native projects folder name for generators which support project hierarchy (like Microsoft Visual Studio).
To use this feature you need to enable hierarchy via [`USE_FOLDERS` property](https://cmake.org/cmake/help/latest/prop_gbl/USE_FOLDERS.html)
- `CRASHPAD_ENABLE_STACKTRACE` (Default: OFF):
This enables client-side stackwalking when using the crashpad backend. Stack unwinding will happen on the client's machine
and the result will be submitted to Sentry attached to the generated minidump.
Note that this feature is still experimental.
### Build Targets
- `sentry`: This is the main library and the only default build target.
- `crashpad_handler`: When configured with the `crashpad` backend, this is
the out of process crash handler, which will need to be installed along with
the projects executable.
- `sentry_test_unit`: These are the main unit-tests, which are conveniently built
also by the toplevel makefile.
- `sentry_example`: This is a small example program highlighting the API, which
can be controlled via command-line parameters, and is also used for
integration tests.
## Runtime Configuration
A minimal working example looks like this. For a more elaborate example see the [example.c](examples/example.c) file which is also used to run sentries integration tests.
```c
sentry_options_t *options = sentry_options_new();
sentry_options_set_dsn(options, "https://YOUR_KEY@oORG_ID.ingest.sentry.io/PROJECT_ID");
sentry_init(options);
// your application code …
sentry_close();
```
Other important configuration options include:
- `sentry_options_set_database_path`: Sentry needs to persist some cache data across application restarts, especially for proper handling of release health sessions. It is recommended to set an explicit absolute path corresponding to the applications cache directory (equivalent to `AppData/Local` on Windows, and `XDG_CACHE_HOME` on Linux). Sentry should be given its own directory which is not shared with other application data, as the SDK will enumerate and possibly delete files in that directory. An example might be `$XDG_CACHE_HOME/your-app/sentry`.
When not set explicitly, sentry will create and use the `.sentry-native` directory inside of the current working directory.
- `sentry_options_set_handler_path`: When using the crashpad backend, sentry will look for a `crashpad_handler` executable in the same directory as the running executable. It is recommended to set this as an explicit absolute path based on the applications install location.
- `sentry_options_set_release`: Some features in sentry, including release health, need to have a release version set. This corresponds to the applications version and needs to be set explicitly. See [Releases](https://docs.sentry.io/product/releases/) for more information.
## Known Limitations
- The crashpad backend on macOS currently has no support for notifying the crashing
process, and can thus not properly terminate sessions or call the registered
`before_send` hook. It will also lose any events that have been queued for
sending at time of crash.
## Development
Please see the [contribution guide](./CONTRIBUTING.md).

View File

@ -0,0 +1,268 @@
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# define NOMINMAX
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "sentry.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef NDEBUG
# undef NDEBUG
#endif
#include <assert.h>
#ifdef SENTRY_PLATFORM_WINDOWS
# include <synchapi.h>
# define sleep_s(SECONDS) Sleep((SECONDS)*1000)
#else
# include <signal.h>
# include <unistd.h>
# define sleep_s(SECONDS) sleep(SECONDS)
#endif
static void
print_envelope(sentry_envelope_t *envelope, void *unused_state)
{
(void)unused_state;
size_t size_out = 0;
char *s = sentry_envelope_serialize(envelope, &size_out);
printf("%s", s);
sentry_free(s);
sentry_envelope_free(envelope);
}
static bool
has_arg(int argc, char **argv, const char *arg)
{
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], arg) == 0) {
return true;
}
}
return false;
}
#ifdef SENTRY_PLATFORM_AIX
// AIX has a null page mapped to the bottom of memory, which means null derefs
// don't segfault. try dereferencing the top of memory instead; the top nibble
// seems to be unusable.
static void *invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset
#else
static void *invalid_mem = (void *)1;
#endif
static void
trigger_crash()
{
memset((char *)invalid_mem, 1, 100);
}
int
main(int argc, char **argv)
{
sentry_options_t *options = sentry_options_new();
// this is an example. for real usage, make sure to set this explicitly to
// an app specific cache location.
sentry_options_set_database_path(options, ".sentry-native");
sentry_options_set_auto_session_tracking(options, false);
sentry_options_set_symbolize_stacktraces(options, true);
sentry_options_set_environment(options, "development");
// sentry defaults this to the `SENTRY_RELEASE` env variable
if (!has_arg(argc, argv, "release-env")) {
sentry_options_set_release(options, "test-example-release");
}
if (has_arg(argc, argv, "log")) {
sentry_options_set_debug(options, 1);
}
if (has_arg(argc, argv, "attachment")) {
// assuming the example / test is run directly from the cmake build
// directory
sentry_options_add_attachment(options, "./CMakeCache.txt");
}
if (has_arg(argc, argv, "stdout")) {
sentry_options_set_transport(
options, sentry_transport_new(print_envelope));
}
#ifdef SENTRY_PERFORMANCE_MONITORING
if (has_arg(argc, argv, "capture-transaction")) {
sentry_options_set_traces_sample_rate(options, 1.0);
}
if (has_arg(argc, argv, "child-spans")) {
sentry_options_set_max_spans(options, 5);
}
#endif
sentry_init(options);
if (!has_arg(argc, argv, "no-setup")) {
sentry_set_transaction("test-transaction");
sentry_set_level(SENTRY_LEVEL_WARNING);
sentry_set_extra("extra stuff", sentry_value_new_string("some value"));
sentry_set_extra("…unicode key…",
// https://xkcd.com/1813/ :-)
sentry_value_new_string("őá…–🤮🚀¿ 한글 테스트"));
sentry_set_tag("expected-tag", "some value");
sentry_set_tag("not-expected-tag", "some value");
sentry_remove_tag("not-expected-tag");
sentry_value_t context = sentry_value_new_object();
sentry_value_set_by_key(
context, "type", sentry_value_new_string("runtime"));
sentry_value_set_by_key(
context, "name", sentry_value_new_string("testing-runtime"));
sentry_set_context("runtime", context);
sentry_value_t user = sentry_value_new_object();
sentry_value_set_by_key(user, "id", sentry_value_new_int32(42));
sentry_value_set_by_key(
user, "username", sentry_value_new_string("some_name"));
sentry_set_user(user);
sentry_value_t default_crumb
= sentry_value_new_breadcrumb(NULL, "default level is info");
sentry_add_breadcrumb(default_crumb);
sentry_value_t debug_crumb
= sentry_value_new_breadcrumb("http", "debug crumb");
sentry_value_set_by_key(
debug_crumb, "category", sentry_value_new_string("example!"));
sentry_value_set_by_key(
debug_crumb, "level", sentry_value_new_string("debug"));
sentry_add_breadcrumb(debug_crumb);
sentry_value_t nl_crumb
= sentry_value_new_breadcrumb(NULL, "lf\ncrlf\r\nlf\n...");
sentry_value_set_by_key(
nl_crumb, "category", sentry_value_new_string("something else"));
sentry_add_breadcrumb(nl_crumb);
}
if (has_arg(argc, argv, "start-session")) {
sentry_start_session();
}
if (has_arg(argc, argv, "overflow-breadcrumbs")) {
for (size_t i = 0; i < 101; i++) {
char buffer[4];
snprintf(buffer, 4, "%zu", i);
sentry_add_breadcrumb(sentry_value_new_breadcrumb(0, buffer));
}
}
if (has_arg(argc, argv, "capture-multiple")) {
for (size_t i = 0; i < 10; i++) {
char buffer[10];
snprintf(buffer, 10, "Event #%zu", i);
sentry_value_t event = sentry_value_new_message_event(
SENTRY_LEVEL_INFO, NULL, buffer);
sentry_capture_event(event);
}
}
if (has_arg(argc, argv, "reinstall")) {
sentry_reinstall_backend();
}
if (has_arg(argc, argv, "sleep")) {
sleep_s(10);
}
if (has_arg(argc, argv, "crash")) {
trigger_crash();
}
if (has_arg(argc, argv, "assert")) {
assert(0);
}
if (has_arg(argc, argv, "abort")) {
abort();
}
#ifdef SENTRY_PLATFORM_UNIX
if (has_arg(argc, argv, "raise")) {
raise(SIGSEGV);
}
if (has_arg(argc, argv, "kill")) {
kill(getpid(), SIGSEGV);
}
#endif
if (has_arg(argc, argv, "capture-event")) {
sentry_value_t event = sentry_value_new_message_event(
SENTRY_LEVEL_INFO, "my-logger", "Hello World!");
if (has_arg(argc, argv, "add-stacktrace")) {
sentry_event_value_add_stacktrace(event, NULL, 0);
}
sentry_capture_event(event);
}
if (has_arg(argc, argv, "capture-exception")) {
sentry_value_t exc = sentry_value_new_exception(
"ParseIntError", "invalid digit found in string");
if (has_arg(argc, argv, "add-stacktrace")) {
sentry_value_t stacktrace = sentry_value_new_stacktrace(NULL, 0);
sentry_value_set_by_key(exc, "stacktrace", stacktrace);
}
sentry_value_t event = sentry_value_new_event();
sentry_event_add_exception(event, exc);
sentry_capture_event(event);
}
#ifdef SENTRY_PERFORMANCE_MONITORING
if (has_arg(argc, argv, "capture-transaction")) {
sentry_transaction_context_t *tx_ctx
= sentry_transaction_context_new("little.teapot",
"Short and stout here is my handle and here is my spout");
if (has_arg(argc, argv, "unsample-tx")) {
sentry_transaction_context_set_sampled(tx_ctx, 0);
}
sentry_transaction_t *tx
= sentry_transaction_start(tx_ctx, sentry_value_new_null());
if (has_arg(argc, argv, "error-status")) {
sentry_transaction_set_status(
tx, SENTRY_SPAN_STATUS_INTERNAL_ERROR);
}
if (has_arg(argc, argv, "child-spans")) {
sentry_span_t *child
= sentry_transaction_start_child(tx, "littler.teapot", NULL);
sentry_span_t *grandchild
= sentry_span_start_child(child, "littlest.teapot", NULL);
if (has_arg(argc, argv, "error-status")) {
sentry_span_set_status(child, SENTRY_SPAN_STATUS_NOT_FOUND);
sentry_span_set_status(
grandchild, SENTRY_SPAN_STATUS_ALREADY_EXISTS);
}
sentry_span_finish(grandchild);
sentry_span_finish(child);
}
sentry_transaction_finish(tx);
}
#endif
// make sure everything flushes
sentry_close();
if (has_arg(argc, argv, "sleep-after-shutdown")) {
sleep_s(1);
}
if (has_arg(argc, argv, "crash-after-shutdown")) {
trigger_crash();
}
}

View File

@ -0,0 +1,174 @@
# The list of files is drived from: breakpad/Makefile.am
set(BREAKPAD_SOURCES_COMMON
breakpad/src/common/convert_UTF.cc
breakpad/src/common/convert_UTF.h
breakpad/src/common/md5.cc
breakpad/src/common/md5.h
breakpad/src/common/string_conversion.cc
breakpad/src/common/string_conversion.h
)
set(BREAKPAD_SOURCES_COMMON_LINUX
breakpad/src/common/linux/elf_core_dump.cc
breakpad/src/common/linux/elfutils.cc
breakpad/src/common/linux/elfutils.h
breakpad/src/common/linux/file_id.cc
breakpad/src/common/linux/file_id.h
breakpad/src/common/linux/guid_creator.cc
breakpad/src/common/linux/guid_creator.h
breakpad/src/common/linux/linux_libc_support.cc
breakpad/src/common/linux/memory_mapped_file.cc
breakpad/src/common/linux/safe_readlink.cc
)
set(BREAKPAD_SOURCES_COMMON_LINUX_GETCONTEXT
breakpad/src/common/linux/breakpad_getcontext.S
)
set(BREAKPAD_SOURCES_COMMON_ANDROID
breakpad/src/common/android/include/sys/procfs.h
)
set(BREAKPAD_SOURCES_COMMON_WINDOWS
breakpad/src/common/windows/guid_string.cc
breakpad/src/common/windows/guid_string.h
)
set(BREAKPAD_SOURCES_COMMON_APPLE
breakpad/src/common/mac/file_id.cc
breakpad/src/common/mac/file_id.h
breakpad/src/common/mac/macho_id.cc
breakpad/src/common/mac/macho_id.h
breakpad/src/common/mac/macho_utilities.cc
breakpad/src/common/mac/macho_utilities.h
breakpad/src/common/mac/macho_walker.cc
breakpad/src/common/mac/macho_walker.h
breakpad/src/common/mac/string_utilities.cc
breakpad/src/common/mac/string_utilities.h
)
set(BREAKPAD_SOURCES_COMMON_MAC
breakpad/src/common/mac/MachIPC.mm
breakpad/src/common/mac/bootstrap_compat.cc
breakpad/src/common/mac/bootstrap_compat.h
)
set(BREAKPAD_SOURCES_CLIENT_LINUX
breakpad/src/client/minidump_file_writer-inl.h
breakpad/src/client/minidump_file_writer.cc
breakpad/src/client/minidump_file_writer.h
breakpad/src/client/linux/crash_generation/crash_generation_client.cc
breakpad/src/client/linux/crash_generation/crash_generation_server.cc
breakpad/src/client/linux/dump_writer_common/thread_info.cc
breakpad/src/client/linux/dump_writer_common/ucontext_reader.cc
breakpad/src/client/linux/handler/exception_handler.cc
breakpad/src/client/linux/handler/exception_handler.h
breakpad/src/client/linux/handler/minidump_descriptor.cc
breakpad/src/client/linux/handler/minidump_descriptor.h
breakpad/src/client/linux/log/log.cc
breakpad/src/client/linux/log/log.h
breakpad/src/client/linux/microdump_writer/microdump_writer.cc
breakpad/src/client/linux/microdump_writer/microdump_writer.h
breakpad/src/client/linux/minidump_writer/linux_core_dumper.cc
breakpad/src/client/linux/minidump_writer/linux_dumper.cc
breakpad/src/client/linux/minidump_writer/linux_ptrace_dumper.cc
breakpad/src/client/linux/minidump_writer/minidump_writer.cc
)
set(BREAKPAD_SOURCES_CLIENT_WINDOWS
breakpad/src/client/windows/crash_generation/crash_generation_client.cc
breakpad/src/client/windows/crash_generation/crash_generation_client.h
breakpad/src/client/windows/handler/exception_handler.cc
breakpad/src/client/windows/handler/exception_handler.h
)
set(BREAKPAD_SOURCES_CLIENT_APPLE
breakpad/src/client/minidump_file_writer-inl.h
breakpad/src/client/minidump_file_writer.cc
breakpad/src/client/minidump_file_writer.h
breakpad/src/client/mac/handler/breakpad_nlist_64.cc
breakpad/src/client/mac/handler/breakpad_nlist_64.h
breakpad/src/client/mac/handler/dynamic_images.cc
breakpad/src/client/mac/handler/dynamic_images.h
breakpad/src/client/mac/handler/exception_handler.cc
breakpad/src/client/mac/handler/exception_handler.h
breakpad/src/client/mac/handler/minidump_generator.cc
breakpad/src/client/mac/handler/minidump_generator.h
)
set(BREAKPAD_SOURCES_CLIENT_MAC
breakpad/src/client/mac/crash_generation/crash_generation_client.cc
breakpad/src/client/mac/crash_generation/crash_generation_client.h
)
set(BREAKPAD_SOURCES_CLIENT_IOS
breakpad/src/client/ios/exception_handler_no_mach.cc
breakpad/src/client/ios/exception_handler_no_mach.h
breakpad/src/client/ios/handler/ios_exception_minidump_generator.h
breakpad/src/client/ios/handler/ios_exception_minidump_generator.mm
breakpad/src/client/mac/crash_generation/ConfigFile.h
breakpad/src/client/mac/crash_generation/ConfigFile.mm
breakpad/src/client/mac/handler/mach_vm_compat.h
breakpad/src/client/mac/handler/protected_memory_allocator.cc
breakpad/src/client/mac/handler/protected_memory_allocator.h
breakpad/src/client/mac/handler/ucontext_compat.h
)
add_library(breakpad_client STATIC)
target_sources(breakpad_client PRIVATE ${BREAKPAD_SOURCES_COMMON})
if(LINUX OR ANDROID)
target_sources(breakpad_client PRIVATE ${BREAKPAD_SOURCES_COMMON_LINUX} ${BREAKPAD_SOURCES_CLIENT_LINUX})
if(ANDROID)
target_sources(breakpad_client PRIVATE ${BREAKPAD_SOURCES_COMMON_ANDROID})
target_include_directories(breakpad_client PRIVATE breakpad/src/common/android/include)
endif(ANDROID)
include(CheckFunctionExists)
check_function_exists(getcontext HAVE_GETCONTEXT)
if(HAVE_GETCONTEXT)
target_compile_definitions(breakpad_client PRIVATE HAVE_GETCONTEXT)
else()
target_sources(breakpad_client PRIVATE ${BREAKPAD_SOURCES_COMMON_LINUX_GETCONTEXT})
endif()
set_property(TARGET breakpad_client PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
if(APPLE)
target_sources(breakpad_client PRIVATE
${BREAKPAD_SOURCES_COMMON_APPLE}
${BREAKPAD_SOURCES_CLIENT_APPLE})
if(NOT IOS)
target_sources(breakpad_client PRIVATE
${BREAKPAD_SOURCES_COMMON_MAC}
${BREAKPAD_SOURCES_CLIENT_MAC})
else()
target_sources(breakpad_client PRIVATE
${BREAKPAD_SOURCES_CLIENT_IOS})
endif()
target_link_libraries(breakpad_client PRIVATE "-framework CoreFoundation")
endif()
if(WIN32)
target_sources(breakpad_client PRIVATE ${BREAKPAD_SOURCES_COMMON_WINDOWS} ${BREAKPAD_SOURCES_CLIENT_WINDOWS})
target_compile_definitions(breakpad_client PRIVATE _UNICODE UNICODE)
# set static runtime if enabled
if(SENTRY_BUILD_RUNTIMESTATIC AND MSVC)
set_property(TARGET breakpad_client PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
endif()
# breakpad has includes directly to `third_party/lss/...`,
# which are being resolved correctly when we add the current directory to
# the include directories. A giant hack, yes, but it works
target_include_directories(breakpad_client
PRIVATE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/breakpad/src/>"
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)

View File

@ -0,0 +1,9 @@
# Defines the Chromium style for automatic reformatting.
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
BasedOnStyle: Chromium
# This defaults to 'Auto'. Explicitly set it for a while, so that
# 'vector<vector<int> >' in existing files gets formatted to
# 'vector<vector<int>>'. ('Auto' means that clang-format will only use
# 'int>>' if the file already contains at least one such instance.)
Standard: Cpp11

View File

@ -0,0 +1,22 @@
# GitHub actions workflow.
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
# https://github.com/superbrothers/close-pull-request
name: Close Pull Request
on:
pull_request_target:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: superbrothers/close-pull-request@v3
with:
comment: >
Thanks for your contribution!
Unfortunately, we don't use GitHub pull requests to manage code
contributions to this repository.
Instead, please see [README.md](../blob/HEAD/README.md) which
provides full instructions on how to get involved.

View File

@ -0,0 +1,44 @@
# GitHub actions workflow.
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
# https://scan.coverity.com/projects/gentoo-pax-utils
name: Coverity Scan
on:
push:
branches: [main]
schedule:
# The GH mirroring from Google GoB does not trigger push actions.
# Fire it once a week to provide some coverage.
- cron: '39 2 * * WED'
# Allow for manual triggers from the web.
workflow_dispatch:
jobs:
coverity:
runs-on: ubuntu-latest
env:
CC: clang
CXX: clang++
steps:
- name: Checkout depot_tools
run: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git ../depot_tools
- name: Checkout breakpad
run: |
set -xe
PATH+=:$PWD/../depot_tools
gclient config --unmanaged --name=src https://github.com/${{ github.repository }}
gclient sync --no-history --nohooks
- run: ./configure --disable-silent-rules
working-directory: src
- uses: vapier/coverity-scan-action@v0
with:
project: google%2Fbreakpad
command: make -C src -O -j$(getconf _NPROCESSORS_CONF)
email: google-breakpad-dev@googlegroups.com
token: ${{ secrets.COVERITY_SCAN_TOKEN }}

View File

@ -0,0 +1,92 @@
# Copyright 2014 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.
# Ignore other VCSs.
.repo/
.svn/
# Ignore common compiled artifacts.
*~
*.dwo
*.o
lib*.a
/breakpad.pc
/breakpad-client.pc
/src/client/linux/linux_client_unittest_shlib
/src/client/linux/linux_dumper_unittest_helper
/src/common/linux/google_crashdump_uploader_test
/src/processor/microdump_stackwalk
/src/processor/minidump_dump
/src/processor/minidump_stackwalk
/src/tools/linux/core2md/core2md
/src/tools/linux/core_handler/core_handler
/src/tools/linux/dump_syms/dump_syms
/src/tools/linux/md2core/minidump-2-core
/src/tools/linux/pid2md/pid2md
/src/tools/linux/symupload/minidump_upload
/src/tools/linux/symupload/sym_upload
/src/tools/mac/dump_syms/dump_syms
/src/tools/mac/dump_syms/dump_syms_mac
# Ignore unit test artifacts.
*_unittest
*.log
*.trs
# Ignore autotools generated artifacts.
.deps
.dirstamp
autom4te.cache/
/config.cache
config.h
/config.log
/config.status
/Makefile
stamp-h1
# Ignore GYP generated Visual Studio artifacts.
*.filters
*.sdf
*.sln
*.suo
*.vcproj
*.vcxproj
# Ignore GYP generated Makefiles
src/Makefile
*.Makefile
*.target.mk
# Ignore compiled Python files.
*.pyc
# Ignore directories gclient syncs.
src/testing
src/third_party/lss
src/third_party/protobuf
src/tools/gyp

View File

@ -0,0 +1 @@
opensource@google.com

View File

View File

@ -0,0 +1,84 @@
# Copyright 2010 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.
# This is used to mimic the svn:externals mechanism for gclient (both Git and
# SVN) based checkouts of Breakpad. As such, its use is entirely optional. If
# using a manually managed SVN checkout as opposed to a gclient managed checkout
# you can still use the hooks mechanism for generating project files by calling
# 'gclient runhooks' rather than 'gclient sync'.
deps = {
# Testing libraries and utilities.
"src/src/testing":
"https://github.com/google/googletest.git" +
"@release-1.11.0",
# Protobuf.
"src/src/third_party/protobuf/protobuf":
"https://github.com/google/protobuf.git" +
"@cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac",
# GYP project generator.
"src/src/tools/gyp":
"https://chromium.googlesource.com/external/gyp/" +
"@324dd166b7c0b39d513026fa52d6280ac6d56770",
# Linux syscall support.
"src/src/third_party/lss":
"https://chromium.googlesource.com/linux-syscall-support/" +
"@e1e7b0ad8ee99a875b272c8e33e308472e897660",
}
hooks = [
{
# Keep the manifest up to date.
"action": ["python", "src/src/tools/python/deps-to-manifest.py",
"src/DEPS", "src/default.xml"],
},
]
hooks_os = {
'win': [
{
# TODO(chrisha): Fix the GYP files so that they work without
# --no-circular-check.
"pattern": ".",
"action": ["python",
"src/src/tools/gyp/gyp_main.py",
"--no-circular-check",
"src/src/client/windows/breakpad_client.gyp"],
},
{
# XXX: this and above should all be wired into build/all.gyp ?
"action": ["python",
"src/src/tools/gyp/gyp_main.py",
"--no-circular-check",
"src/src/tools/windows/tools_windows.gyp"],
},
],
}

View File

@ -0,0 +1,13 @@
# Metadata information for this directory.
#
# For more information on DIR_METADATA files, see:
# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/README.md
#
# For the schema of this file, see Metadata message:
# https://source.chromium.org/chromium/infra/infra/+/HEAD:go/src/infra/tools/dirmd/proto/dir_metadata.proto
monorail {
project: "google-breakpad"
}
team_email: "google-breakpad-dev@googlegroups.com"

View File

@ -0,0 +1,370 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell commands `./configure; make; make install' should
configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View File

@ -0,0 +1,132 @@
Copyright (c) 2006, 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.
--------------------------------------------------------------------
Copyright 2001-2004 Unicode, Inc.
Disclaimer
This source code is provided as is by Unicode, Inc. No claims are
made as to fitness for any particular purpose. No warranties of any
kind are expressed or implied. The recipient agrees to determine
applicability of information provided. If this file has been
purchased on magnetic or optical media from Unicode, Inc., the
sole remedy for any claim will be exchange of defective media
within 90 days of receipt.
Limitations on Rights to Redistribute This Code
Unicode, Inc. hereby grants the right to freely use the information
supplied in this file in the creation of products supporting the
Unicode Standard, and to make copies of this file in any form
for internal or external distribution as long as this notice
remains attached.
--------------------------------------------------------------------
libunwind - a platform-independent unwind library
Copyright (C) 2008 Google, Inc
Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
--------------------------------------------------------------------
Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
@APPLE_LICENSE_HEADER_START@
This file contains Original Code and/or Modifications of Original Code
as defined in and that are subject to the Apple Public Source License
Version 2.0 (the 'License'). You may not use this file except in
compliance with the License. Please obtain a copy of the License at
http://www.opensource.apple.com/apsl/ and read it before using this
file.
The Original Code and all software distributed under the License are
distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
Please see the License for the specific language governing rights and
limitations under the License.
@APPLE_LICENSE_HEADER_END@
--------------------------------------------------------------------
Copyright (c) 1989, 1993
The Regents of the University of California. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. 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.
3. All advertising materials mentioning features or use of this software
must display the following acknowledgement:
This product includes software developed by the University of
California, Berkeley and its contributors.
4. Neither the name of the University 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 REGENTS 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 REGENTS 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.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

View File

@ -0,0 +1,13 @@
# Sorted alphabetically.
# Please see README.md for contact info.
ivanpe@chromium.org
jperaza@chromium.org
mark@chromium.org
nbilling@google.com
primiano@chromium.org
saugustine@google.com
rsesek@chromium.org
ted@mielczarek.org
thestig@chromium.org
vapier@chromium.org

View File

@ -0,0 +1,139 @@
Google Breakpad for Android
===========================
This document explains how to use the Google Breakpad client library
on Android, and later generate valid stack traces from the minidumps
it generates.
This release supports ARM, x86 and MIPS based Android systems.
This release requires NDK release r11c or higher.
I. Building the client library:
===============================
The Android client is built as a static library that you can
link into your own Android native code. There are two ways to
build it:
I.1. Building with ndk-build:
-----------------------------
If you're using the ndk-build build system, you can follow
these simple steps:
1/ Include android/google_breakpad/Android.mk from your own
project's Android.mk
This can be done either directly, or using ndk-build's
import-module feature.
2/ Link the library to one of your modules by using:
LOCAL_STATIC_LIBRARIES += breakpad_client
NOTE: The client library requires a C++ STL implementation,
which you can select with APP_STL in your Application.mk
It has been tested succesfully with both STLport and GNU libstdc++
I.2. Building with a standalone Android toolchain:
--------------------------------------------------
All you need to do is configure your build with the right 'host'
value, and disable the processor and tools, as in:
$GOOGLE_BREAKPAD_PATH/configure --host=arm-linux-androideabi \
--disable-processor \
--disable-tools
make -j4
The library will be under src/client/linux/libbreakpad_client.a
You can also use 'make check' to run the test suite on a connected
Android device. This requires the Android 'adb' tool to be in your
path.
II. Using the client library in Android:
========================================
The usage instructions are very similar to the Linux ones that are
found at https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md
1/ You need to include "client/linux/handler/exception_handler.h" from a C++
source file.
2/ If you're not using ndk-build, you also need to:
- add the following to your compiler include search paths:
$GOOGLE_BREAKPAD_PATH/src
$GOOGLE_BREAKPAD_PATH/src/common/android/include
- add -llog to your linker flags
Note that ndk-build does that for your automatically.
3/ Keep in mind that there is no /tmp directory on Android.
If you use the library from a regular Android applications, specify a
path under your app-specific storage directory. An alternative is to
store them on the SDCard, but this requires a specific permission.
For a concrete example, see the sample test application under
android/sample_app. See its README for more information.
III. Getting a stack trace on the host:
=======================================
This process is similar to other platforms, but here's a quick example:
1/ Retrieve the minidumps on your development machine.
2/ Dump the symbols for your native libraries with the 'dump_syms' tool.
This first requires building the host version of Google Breakpad, then
calling:
dump_syms $PROJECT_PATH/obj/local/$ABI/libfoo.so > libfoo.so.sym
3/ Create the symbol directory hierarchy.
The first line of the generated libfoo.so.sym will have a "MODULE"
entry that carries a hexadecimal version number, e.g.:
MODULE Linux arm D51B4A5504974FA6ECC1869CAEE3603B0 test_google_breakpad
Note: The second field could be either 'Linux' or 'Android'.
Extract the version number, and a 'symbol' directory, for example:
$PROJECT_PATH/symbols/libfoo.so/$VERSION/
Copy/Move your libfoo.sym file there.
4/ Invoke minidump_stackwalk to create the stack trace:
minidump_stackwalk $MINIDUMP_FILE $PROJECT_PATH/symbols
Note that various helper scripts can be found on the web to automate these
steps.
IV. Verifying the Android build library:
========================================
If you modify Google Breakpad and want to check that it still works correctly
on Android, please run the android/run-checks.sh script which will do all
necessary verifications for you. This includes:
- Rebuilding the full host binaries.
- Rebuilding the full Android binaries with configure/make.
- Rebuilding the client library unit tests, and running them on a device.
- Rebuilding the client library with ndk-build.
- Building, installing and running a test crasher program on a device.
- Extracting the corresponding minidump, dumping the test program symbols
and generating a stack trace.
- Checking the generated stack trace for valid source locations.
For more details, please run:
android/run-checks.sh --help-all

View File

@ -0,0 +1,82 @@
# Breakpad
Breakpad is a set of client and server components which implement a
crash-reporting system.
* [Homepage](https://chromium.googlesource.com/breakpad/breakpad/)
* [Documentation](./docs/)
* [Bugs](https://bugs.chromium.org/p/google-breakpad/)
* Discussion/Questions: [google-breakpad-discuss@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-discuss)
* Developer/Reviews: [google-breakpad-dev@googlegroups.com](https://groups.google.com/d/forum/google-breakpad-dev)
* Tests: [![Build+Test CI](https://github.com/google/breakpad/actions/workflows/build-test-ci.yml/badge.svg)](https://github.com/google/breakpad/actions/workflows/build-test-ci.yml) [![Build status](https://ci.appveyor.com/api/projects/status/eguv4emv2rhq68u2?svg=true)](https://ci.appveyor.com/project/vapier/breakpad)
* Coverage [![Coverity Status](https://scan.coverity.com/projects/9215/badge.svg)](https://scan.coverity.com/projects/google-breakpad)
## Getting started (from main)
1. First, [download depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)
and ensure that theyre in your `PATH`.
2. Create a new directory for checking out the source code (it must be named
breakpad).
```sh
mkdir breakpad && cd breakpad
```
3. Run the `fetch` tool from depot_tools to download all the source repos.
```sh
fetch breakpad
cd src
```
4. Build the source.
```sh
./configure && make
```
You can also cd to another directory and run configure from there to build
outside the source tree.
This will build the processor tools (`src/processor/minidump_stackwalk`,
`src/processor/minidump_dump`, etc), and when building on Linux it will
also build the client libraries and some tools
(`src/tools/linux/dump_syms/dump_syms`,
`src/tools/linux/md2core/minidump-2-core`, etc).
5. Optionally, run tests.
```sh
make check
```
6. Optionally, install the built libraries
```sh
make install
```
If you need to reconfigure your build be sure to run `make distclean` first.
To update an existing checkout to a newer revision, you can
`git pull` as usual, but then you should run `gclient sync` to ensure that the
dependent repos are up-to-date.
## To request change review
1. Follow the steps above to get the source and build it.
2. Make changes. Build and test your changes.
For core code like processor use methods above.
For linux/mac/windows, there are test targets in each project file.
3. Commit your changes to your local repo and upload them to the server.
http://dev.chromium.org/developers/contributing-code
e.g. `git commit ... && git cl upload ...`
You will be prompted for credential and a description.
4. At https://chromium-review.googlesource.com/ you'll find your issue listed;
click on it, then “Add reviewer”, and enter in the code reviewer. Depending
on your settings, you may not see an email, but the reviewer has been
notified with google-breakpad-dev@googlegroups.com always CCd.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,372 @@
# 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.
# Collection of common shell functions for 'run-checks.sh' et 'test-shell.sh'
# All internal variables and functions use an underscore as a prefix
# (e.g. _VERBOSE, _ALL_CLEANUPS, etc..).
# Sanitize the environment
export LANG=C
export LC_ALL=C
if [ "$BASH_VERSION" ]; then
set -o posix
fi
# Utility functions
_ALL_CLEANUPS=
# Register a function to be called when the script exits, even in case of
# Ctrl-C, logout, etc.
# $1: function name.
atexit () {
if [ -z "$_ALL_CLEANUPS" ]; then
_ALL_CLEANUPS=$1
# Ensure a clean exit when the script is:
# - Exiting normally (EXIT)
# - Interrupted by Ctrl-C (INT)
# - Interrupted by log out (HUP)
# - Being asked to quit nicely (TERM)
# - Being asked to quit and dump core (QUIT)
trap "_exit_cleanups \$?" EXIT INT HUP QUIT TERM
else
_ALL_CLEANUPS="$_ALL_CLEANUPS $1"
fi
}
# Called on exit if at least one function was registered with atexit
# $1: final exit status code
_exit_cleanups () {
local CLEANUP CLEANUPS
# Ignore calls to atexit during cleanups
CLEANUPS=$_ALL_CLEANUPS
_ALL_CLEANUPS=
for CLEANUP in $CLEANUPS; do
($CLEANUP)
done
exit "$@"
}
# Dump a panic message then exit.
# $1+: message
panic () {
echo "ERROR: $@" >&2
exit 1
}
# If the previous command failed, dump a panic message then exit.
# $1+: message.
fail_panic () {
if [ $? != 0 ]; then
panic "$@"
fi;
}
_VERBOSE=0
# Increase verbosity for dump/log/run/run2 functions
increase_verbosity () {
_VERBOSE=$(( $_VERBOSE + 1 ))
}
# Decrease verbosity
decrease_verbosity () {
_VERBOSE=$(( $_VERBOSE - 1 ))
}
# Returns success iff verbosity level is higher than a specific value
# $1: verbosity level
verbosity_is_higher_than () {
[ "$_VERBOSE" -gt "$1" ]
}
# Returns success iff verbosity level is lower than a specific value
# $1: verbosity level
verbosity_is_lower_than () {
[ "$_VERBOSE" -le "$1" ]
}
# Dump message to stdout, unless verbosity is < 0, i.e. --quiet was called
# $1+: message
dump () {
if [ "$_VERBOSE" -ge 0 ]; then
printf "%s\n" "$*"
fi
}
# If --verbose was used, dump a message to stdout.
# $1+: message
log () {
if [ "$_VERBOSE" -ge 1 ]; then
printf "%s\n" "$*"
fi
}
_RUN_LOG=
# Set a run log file that can be used to collect the output of commands that
# are not displayed.
set_run_log () {
_RUN_LOG=$1
}
# Run a command. Output depends on $_VERBOSE:
# $_VERBOSE <= 0: Run command, store output into the run log
# $_VERBOSE >= 1: Dump command, run it, output goest to stdout
# Note: Ideally, the command's output would go to the run log for $_VERBOSE >= 1
# but the 'tee' tool doesn't preserve the status code of its input pipe
# in case of error.
run () {
local LOGILE
if [ "$_RUN_LOG" ]; then
LOGFILE=$_RUN_LOG
else
LOGFILE=/dev/null
fi
if [ "$_VERBOSE" -ge 1 ]; then
echo "COMMAND: $@"
"$@"
else
"$@" >>$LOGFILE 2>&1
fi
}
# Same as run(), but only dump command output for $_VERBOSE >= 2
run2 () {
local LOGILE
if [ "$_RUN_LOG" ]; then
LOGFILE=$_RUN_LOG
else
LOGFILE=/dev/null
fi
if [ "$_VERBOSE" -ge 1 ]; then
echo "COMMAND: $@"
fi
if [ "$_VERBOSE" -ge 2 ]; then
"$@"
else
"$@" >>$LOGFILE 2>&1
fi
}
# Extract number of cores to speed up the builds
# Out: number of CPU cores
get_core_count () {
case $(uname -s) in
Linux)
grep -c -e '^processor' /proc/cpuinfo
;;
Darwin)
sysctl -n hw.ncpu
;;
CYGWIN*|*_NT-*)
echo $NUMBER_OF_PROCESSORS
;;
*)
echo 1
;;
esac
}
# Check for the Android ADB program.
#
# On success, return nothing, but updates internal variables so later calls to
# adb_shell, adb_push, etc.. will work. You can get the path to the ADB program
# with adb_get_program if needed.
#
# On failure, returns 1, and updates the internal adb error message, which can
# be retrieved with adb_get_error.
#
# $1: optional ADB program path.
# Return: success or failure.
_ADB=
_ADB_STATUS=
_ADB_ERROR=
adb_check () {
# First, try to find the executable in the path, or the SDK install dir.
_ADB=$1
if [ -z "$_ADB" ]; then
_ADB=$(which adb 2>/dev/null)
if [ -z "$_ADB" -a "$ANDROID_SDK_ROOT" ]; then
_ADB=$ANDROID_SDK_ROOT/platform-tools/adb
if [ ! -f "$_ADB" ]; then
_ADB=
fi
fi
if [ -z "$_ADB" ]; then
_ADB_STATUS=1
_ADB_ERROR="The Android 'adb' tool is not in your path."
return 1
fi
fi
log "Found ADB program: $_ADB"
# Check that it works correctly
local ADB_VERSION
ADB_VERSION=$("$_ADB" version 2>/dev/null)
case $ADB_VERSION in
"Android Debug Bridge "*) # Pass
log "Found ADB version: $ADB_VERSION"
;;
*) # Fail
_ADB_ERROR="Your ADB binary reports a bad version ($ADB_VERSION): $_ADB"
_ADB_STATUS=1
return 1
esac
_ADB_STATUS=0
return 0
}
# Return the path to the Android ADB program, if correctly detected.
# On failure, return the empty string.
# Out: ADB program path (or empty on failure)
# Return: success or failure.
adb_get_program () {
# Return cached value as soon as possible.
if [ -z "$_ADB_STATUS" ]; then
adb_check $1
fi
echo "$_ADB"
return $_ADB_STATUS
}
# Return the error corresponding to the last ADB function failure.
adb_get_error () {
echo "$_ADB_ERROR"
}
# Check that there is one device connected through ADB.
# In case of failure, use adb_get_error to know why this failed.
# $1: Optional adb program path
# Return: success or failure.
_ADB_DEVICE=
_ADB_DEVICE_STATUS=
adb_check_device () {
if [ "$_ADB_DEVICE_STATUS" ]; then
return $_ADB_DEVICE_STATUS
fi
# Check for ADB.
if ! adb_check $1; then
_ADB_DEVICE_STATUS=$_ADB_STATUS
return 1
fi
local ADB_DEVICES NUM_DEVICES FINGERPRINT
# Count the number of connected devices.
ADB_DEVICES=$("$_ADB" devices 2>/dev/null | awk '$2 == "device" { print $1; }')
NUM_DEVICES=$(echo "$ADB_DEVICES" | wc -l)
case $NUM_DEVICES in
0)
_ADB_ERROR="No Android device connected. Please connect one to your machine."
_ADB_DEVICE_STATUS=1
return 1
;;
1) # Pass
# Ensure the same device will be called in later adb_shell calls.
export ANDROID_SERIAL=$ADB_DEVICES
;;
*) # 2 or more devices.
if [ "$ANDROID_SERIAL" ]; then
ADB_DEVICES=$ANDROID_SERIAL
NUM_DEVICES=1
else
_ADB_ERROR="More than one Android device connected. \
Please define ANDROID_SERIAL in your environment"
_ADB_DEVICE_STATUS=1
return 1
fi
;;
esac
_ADB_DEVICE_STATUS=0
_ADB_DEVICE=$ADB_DEVICES
FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
log "Using ADB device: $ANDROID_SERIAL ($FINGERPRINT)"
return 0
}
# The 'adb shell' command is pretty hopeless, try to make sense of it by:
# 1/ Removing trailing \r from line endings.
# 2/ Ensuring the function returns the command's status code.
#
# $1+: Command
# Out: command output (stdout + stderr combined)
# Return: command exit status
adb_shell () {
local RET ADB_LOG
# Check for ADB device.
adb_check_device || return 1
ADB_LOG=$(mktemp "${TMPDIR:-/tmp}/adb-XXXXXXXX")
"$_ADB" shell "$@" ";" echo \$? > "$ADB_LOG" 2>&1
sed -i -e 's![[:cntrl:]]!!g' "$ADB_LOG" # Remove \r.
RET=$(sed -e '$!d' "$ADB_LOG") # Last line contains status code.
sed -e '$d' "$ADB_LOG" # Print everything except last line.
rm -f "$ADB_LOG"
return $RET
}
# Push a file to a device.
# $1: source file path
# $2: device target file path
# Return: success or failure.
adb_push () {
adb_check_device || return 1
run "$_ADB" push "$1" "$2"
}
# Pull a file from a device
# $1: device file path
# $2: target host file path
# Return: success or failure.
adb_pull () {
adb_check_device || return 1
run "$_ADB" pull "$1" "$2"
}
# Same as adb_push, but will panic if the operations didn't succeed.
adb_install () {
adb_push "$@"
fail_panic "Failed to install $1 to the Android device at $2"
}

View File

@ -0,0 +1,104 @@
# 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.
# ndk-build module definition for the Google Breakpad client library
#
# To use this file, do the following:
#
# 1/ Include this file from your own Android.mk, either directly
# or with through the NDK's import-module function.
#
# 2/ Use the client static library in your project with:
#
# LOCAL_STATIC_LIBRARIES += breakpad_client
#
# 3/ In your source code, include "src/client/linux/exception_handler.h"
# and use the Linux instructions to use it.
#
# This module works with either the STLport or GNU libstdc++, but you need
# to select one in your Application.mk
#
# The top Google Breakpad directory.
# We assume this Android.mk to be under 'android/google_breakpad'
LOCAL_PATH := $(call my-dir)/../..
# Defube the client library module, as a simple static library that
# exports the right include path / linker flags to its users.
include $(CLEAR_VARS)
LOCAL_MODULE := breakpad_client
LOCAL_CPP_EXTENSION := .cc
# Breakpad uses inline ARM assembly that requires the library
# to be built in ARM mode. Otherwise, the build will fail with
# cryptic assembler messages like:
# Compile++ thumb : google_breakpad_client <= crash_generation_client.cc
# /tmp/cc8aMSoD.s: Assembler messages:
# /tmp/cc8aMSoD.s:132: Error: invalid immediate: 288 is out of range
# /tmp/cc8aMSoD.s:244: Error: invalid immediate: 296 is out of range
LOCAL_ARM_MODE := arm
# List of client source files, directly taken from Makefile.am
LOCAL_SRC_FILES := \
src/client/linux/crash_generation/crash_generation_client.cc \
src/client/linux/dump_writer_common/thread_info.cc \
src/client/linux/dump_writer_common/ucontext_reader.cc \
src/client/linux/handler/exception_handler.cc \
src/client/linux/handler/minidump_descriptor.cc \
src/client/linux/log/log.cc \
src/client/linux/microdump_writer/microdump_writer.cc \
src/client/linux/minidump_writer/linux_dumper.cc \
src/client/linux/minidump_writer/linux_ptrace_dumper.cc \
src/client/linux/minidump_writer/minidump_writer.cc \
src/client/minidump_file_writer.cc \
src/common/convert_UTF.cc \
src/common/md5.cc \
src/common/string_conversion.cc \
src/common/linux/breakpad_getcontext.S \
src/common/linux/elfutils.cc \
src/common/linux/file_id.cc \
src/common/linux/guid_creator.cc \
src/common/linux/linux_libc_support.cc \
src/common/linux/memory_mapped_file.cc \
src/common/linux/safe_readlink.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)/src/common/android/include \
$(LOCAL_PATH)/src \
$(LSS_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)
# Done.

View File

@ -0,0 +1,555 @@
#!/bin/sh
# 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.
# Sanitize the environment
export LANG=C
export LC_ALL=C
if [ "$BASH_VERSION" ]; then
set -o posix
fi
PROGDIR=$(dirname "$0")
PROGDIR=$(cd "$PROGDIR" && pwd)
PROGNAME=$(basename "$0")
. $PROGDIR/common-functions.sh
DEFAULT_ABI="armeabi"
VALID_ABIS="armeabi armeabi-v7a x86 mips"
ABI=
ADB=
ALL_TESTS=
ENABLE_M32=
HELP=
HELP_ALL=
NDK_DIR=
NO_CLEANUP=
NO_DEVICE=
NUM_JOBS=$(get_core_count)
TMPDIR=
for opt do
# The following extracts the value if the option is like --name=<value>.
optarg=$(expr -- $opt : '^--[^=]*=\(.*\)$')
case $opt in
--abi=*) ABI=$optarg;;
--adb=*) ADB=$optarg;;
--all-tests) ALL_TESTS=true;;
--enable-m32) ENABLE_M32=true;;
--help|-h|-?) HELP=TRUE;;
--help-all) HELP_ALL=true;;
--jobs=*) NUM_JOBS=$optarg;;
--ndk-dir=*) NDK_DIR=$optarg;;
--tmp-dir=*) TMPDIR=$optarg;;
--no-cleanup) NO_CLEANUP=true;;
--no-device) NO_DEVICE=true;;
--quiet) decrease_verbosity;;
--verbose) increase_verbosity;;
-*) panic "Invalid option '$opt', see --help for details.";;
*) panic "This script doesn't take any parameters. See --help for details."
;;
esac
done
if [ "$HELP" -o "$HELP_ALL" ]; then
echo "\
Usage: $PROGNAME [options]
This script is used to check that your Google Breakpad source tree can
be properly built for Android, and that the client library and host tools
work properly together.
"
if [ "$HELP_ALL" ]; then
echo "\
In more details, this script will:
- Rebuild the host version of Google Breakpad in a temporary
directory (with the Auto-tools based build system).
- Rebuild the Android client library with the Google Breakpad build
system (using autotools/configure). This requires that you define
ANDROID_NDK_ROOT in your environment to point to a valid Android NDK
installation directory, or use the --ndk-dir=<path> option.
- Rebuild the Android client library and a test crashing program with the
Android NDK build system (ndk-build).
- Require an Android device connected to your machine, and the 'adb'
tool in your path. They are used to:
- Install and run a test crashing program.
- Extract the corresponding minidump from the device.
- Dump the symbols from the test program on the host with 'dump_syms'
- Generate a stack trace with 'minidump_stackwalk'
- Check the stack trace content for valid source file locations.
You can however skip this requirement and only test the builds by using
the --no-device flag.
By default, all generated files will be created in a temporary directory
that is removed when the script completion. If you want to inspect the
files, use the --no-cleanup option.
Finally, use --verbose to increase the verbosity level, this will help
you see which exact commands are being issues and their result. Use the
flag twice for even more output. Use --quiet to decrease verbosity
instead and run the script silently.
If you have a device connected, the script will probe it to determine
its primary CPU ABI, and build the test program for it. You can however
use the --abi=<name> option to override this (this can be useful to check
the secondary ABI, e.g. using --abi=armeabi to check that such a program
works correctly on an ARMv7-A device).
If you don't have a device connected, the test program will be built (but
not run) with the default '$DEFAULT_ABI' ABI. Again, you can use
--abi=<name> to override this. Valid ABI names are:
$VALID_ABIS
The script will only run the client library unit test on the device
by default. You can use --all-tests to also build and run the unit
tests for the Breakpad tools and processor, but be warned that this
adds several minutes of testing time. --all-tests will also run the
host unit tests suite.
"
fi # HELP_ALL
echo "\
Valid options:
--help|-h|-? Display this message.
--help-all Display extended help.
--enable-m32 Build 32-bit version of host tools.
--abi=<name> Specify target CPU ABI [auto-detected].
--jobs=<count> Run <count> build tasks in parallel [$NUM_JOBS].
--ndk-dir=<path> Specify NDK installation directory.
--tmp-dir=<path> Specify temporary directory (will be wiped-out).
--adb=<path> Specify adb program path.
--no-cleanup Don't remove temporary directory after completion.
--no-device Do not try to detect devices, nor run crash test.
--all-tests Run all unit tests (i.e. tools and processor ones too).
--verbose Increase verbosity.
--quiet Decrease verbosity."
exit 0
fi
TESTAPP_DIR=$PROGDIR/sample_app
# Select NDK install directory.
if [ -z "$NDK_DIR" ]; then
if [ -z "$ANDROID_NDK_ROOT" ]; then
panic "Please define ANDROID_NDK_ROOT in your environment, or use \
--ndk-dir=<path>."
fi
NDK_DIR="$ANDROID_NDK_ROOT"
log "Found NDK directory: $NDK_DIR"
else
log "Using NDK directory: $NDK_DIR"
fi
# Small sanity check.
NDK_BUILD="$NDK_DIR/ndk-build"
if [ ! -f "$NDK_BUILD" ]; then
panic "Your NDK directory is not valid (missing ndk-build): $NDK_DIR"
fi
# Ensure the temporary directory is deleted on exit, except if the --no-cleanup
# option is used.
clean_tmpdir () {
if [ "$TMPDIR" ]; then
if [ -z "$NO_CLEANUP" ]; then
log "Cleaning up: $TMPDIR"
rm -rf "$TMPDIR"
else
dump "Temporary directory contents preserved: $TMPDIR"
fi
fi
exit "$@"
}
atexit clean_tmpdir
# If --tmp-dir=<path> is not used, create a temporary directory.
# Otherwise, start by cleaning up the user-provided path.
if [ -z "$TMPDIR" ]; then
TMPDIR=$(mktemp -d /tmp/$PROGNAME.XXXXXXXX)
fail_panic "Can't create temporary directory!"
log "Using temporary directory: $TMPDIR"
else
if [ ! -d "$TMPDIR" ]; then
mkdir -p "$TMPDIR"
fail_panic "Can't create temporary directory: $TMPDIR"
else
log "Cleaning up temporary directory: $TMPDIR"
rm -rf "$TMPDIR"/*
fail_panic "Cannot cleanup temporary directory!"
fi
fi
if [ -z "$NO_DEVICE" ]; then
if ! adb_check_device $ADB; then
echo "$(adb_get_error)"
echo "Use --no-device to build the code without running any tests."
exit 1
fi
fi
BUILD_LOG="$TMPDIR/build.log"
RUN_LOG="$TMPDIR/run.log"
CRASH_LOG="$TMPDIR/crash.log"
set_run_log "$RUN_LOG"
TMPHOST="$TMPDIR/host-local"
cd "$TMPDIR"
# Build host version of the tools
dump "Building host binaries."
CONFIGURE_FLAGS=
if [ "$ENABLE_M32" ]; then
CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-m32"
fi
(
run mkdir "$TMPDIR/build-host" &&
run cd "$TMPDIR/build-host" &&
run2 "$PROGDIR/../configure" --prefix="$TMPHOST" $CONFIGURE_FLAGS &&
run2 make -j$NUM_JOBS install
)
fail_panic "Can't build host binaries!"
if [ "$ALL_TESTS" ]; then
dump "Running host unit tests."
(
run cd "$TMPDIR/build-host" &&
run2 make -j$NUM_JOBS check
)
fail_panic "Host unit tests failed!!"
fi
TMPBIN=$TMPHOST/bin
# Generate a stand-alone NDK toolchain
# Extract CPU ABI and architecture from device, if any.
if adb_check_device; then
DEVICE_ABI=$(adb_shell getprop ro.product.cpu.abi)
DEVICE_ABI2=$(adb_shell getprop ro.product.cpu.abi2)
if [ -z "$DEVICE_ABI" ]; then
panic "Can't extract ABI from connected device!"
fi
if [ "$DEVICE_ABI2" ]; then
dump "Found device ABIs: $DEVICE_ABI $DEVICE_ABI2"
else
dump "Found device ABI: $DEVICE_ABI"
DEVICE_ABI2=$DEVICE_ABI
fi
# If --abi=<name> is used, check that the device supports it.
if [ "$ABI" -a "$DEVICE_ABI" != "$ABI" -a "$DEVICE_ABI2" != "$ABI" ]; then
dump "ERROR: Device ABI(s) do not match --abi command-line value ($ABI)!"
panic "Please use --no-device to skip device tests."
fi
if [ -z "$ABI" ]; then
ABI=$DEVICE_ABI
dump "Using CPU ABI: $ABI (device)"
else
dump "Using CPU ABI: $ABI (command-line)"
fi
else
if [ -z "$ABI" ]; then
# No device connected, choose default ABI
ABI=$DEFAULT_ABI
dump "Using CPU ABI: $ABI (default)"
else
dump "Using CPU ABI: $ABI (command-line)"
fi
fi
# Check the ABI value
VALID=
for VALID_ABI in $VALID_ABIS; do
if [ "$ABI" = "$VALID_ABI" ]; then
VALID=true
break
fi
done
if [ -z "$VALID" ]; then
panic "Unknown CPU ABI '$ABI'. Valid values are: $VALID_ABIS"
fi
# Extract architecture name from ABI
case $ABI in
armeabi*) ARCH=arm;;
*) ARCH=$ABI;;
esac
# Extract GNU configuration name
case $ARCH in
arm)
GNU_CONFIG=arm-linux-androideabi
;;
x86)
GNU_CONFIG=i686-linux-android
;;
mips)
GNU_CONFIG=mipsel-linux-android
;;
*)
GNU_CONFIG="$ARCH-linux-android"
;;
esac
# Generate standalone NDK toolchain installation
NDK_STANDALONE="$TMPDIR/ndk-$ARCH-toolchain"
echo "Generating NDK standalone toolchain installation"
mkdir -p "$NDK_STANDALONE"
# NOTE: The --platform=android-9 is required to provide <regex.h> for GTest.
run "$NDK_DIR/build/tools/make-standalone-toolchain.sh" \
--arch="$ARCH" \
--platform=android-9 \
--install-dir="$NDK_STANDALONE"
fail_panic "Can't generate standalone NDK toolchain installation!"
# Rebuild the client library, processor and tools with the auto-tools based
# build system. Even though it's not going to be used, this checks that this
# still works correctly.
echo "Building full Android binaries with configure/make"
TMPTARGET="$TMPDIR/target-local"
(
PATH="$NDK_STANDALONE/bin:$PATH"
run mkdir "$TMPTARGET" &&
run mkdir "$TMPDIR"/build-target &&
run cd "$TMPDIR"/build-target &&
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
--host="$GNU_CONFIG" &&
run2 make -j$NUM_JOBS install
)
fail_panic "Could not rebuild Android binaries!"
# Build and/or run unit test suite.
# If --no-device is used, only rebuild it, otherwise, run in on the
# connected device.
if [ "$NO_DEVICE" ]; then
ACTION="Building"
# This is a trick to force the Makefile to ignore running the scripts.
TESTS_ENVIRONMENT="TESTS_ENVIRONMENT=true"
else
ACTION="Running"
TESTS_ENVIRONMENT=
fi
(
PATH="$NDK_STANDALONE/bin:$PATH"
run cd "$TMPDIR"/build-target &&
# Reconfigure to only run the client unit test suite.
# This one should _never_ fail.
dump "$ACTION Android client library unit tests."
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
--host="$GNU_CONFIG" \
--disable-tools \
--disable-processor &&
run make -j$NUM_JOBS check $TESTS_ENVIRONMENT || exit $?
if [ "$ALL_TESTS" ]; then
dump "$ACTION Tools and processor unit tests."
# Reconfigure to run the processor and tools tests.
# Most of these fail for now, so do not worry about it.
run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
--host="$GNU_CONFIG" &&
run make -j$NUM_JOBS check $TESTS_ENVIRONMENT
if [ $? != 0 ]; then
dump "Tools and processor unit tests failed as expected. \
Use --verbose for results."
fi
fi
)
fail_panic "Client library unit test suite failed!"
# Copy sources to temporary directory
PROJECT_DIR=$TMPDIR/project
dump "Copying test program sources to: $PROJECT_DIR"
run cp -r "$TESTAPP_DIR" "$PROJECT_DIR" &&
run rm -rf "$PROJECT_DIR/obj" &&
run rm -rf "$PROJECT_DIR/libs"
fail_panic "Could not copy test program sources to: $PROJECT_DIR"
# Build the test program with ndk-build.
dump "Building test program with ndk-build"
export NDK_MODULE_PATH="$PROGDIR"
NDK_BUILD_FLAGS="-j$NUM_JOBS"
if verbosity_is_higher_than 1; then
NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS NDK_LOG=1 V=1"
fi
run "$NDK_DIR/ndk-build" -C "$PROJECT_DIR" $NDK_BUILD_FLAGS APP_ABI=$ABI
fail_panic "Can't build test program!"
# Unless --no-device was used, stop right here if ADB isn't in the path,
# or there is no connected device.
if [ "$NO_DEVICE" ]; then
dump "Done. Please connect a device to run all tests!"
clean_exit 0
fi
# Push the program to the device.
TESTAPP=test_google_breakpad
TESTAPP_FILE="$PROJECT_DIR/libs/$ABI/test_google_breakpad"
if [ ! -f "$TESTAPP_FILE" ]; then
panic "Device requires '$ABI' binaries. None found!"
fi
# Run the program there
dump "Installing test program on device"
DEVICE_TMP=/data/local/tmp
adb_push "$TESTAPP_FILE" "$DEVICE_TMP/"
fail_panic "Cannot push test program to device!"
dump "Running test program on device"
adb_shell cd "$DEVICE_TMP" "&&" ./$TESTAPP > "$CRASH_LOG" 2>/dev/null
if [ $? = 0 ]; then
panic "Test program did *not* crash as expected!"
fi
if verbosity_is_higher_than 0; then
echo -n "Crash log: "
cat "$CRASH_LOG"
fi
# Extract minidump from device
MINIDUMP_NAME=$(awk '$1 == "Dump" && $2 == "path:" { print $3; }' "$CRASH_LOG")
MINIDUMP_NAME=$(basename "$MINIDUMP_NAME")
if [ -z "$MINIDUMP_NAME" ]; then
panic "Test program didn't write minidump properly!"
fi
dump "Extracting minidump: $MINIDUMP_NAME"
adb_pull "$DEVICE_TMP/$MINIDUMP_NAME" .
fail_panic "Can't extract minidump!"
dump "Parsing test program symbols"
if verbosity_is_higher_than 1; then
log "COMMAND: $TMPBIN/dump_syms \
$PROJECT_DIR/obj/local/$ABI/$TESTAPP >$TESTAPP.sym"
fi
"$TMPBIN/dump_syms" "$PROJECT_DIR/obj/local/$ABI/$TESTAPP" > $TESTAPP.sym
fail_panic "dump_syms doesn't work!"
VERSION=$(awk '$1 == "MODULE" { print $4; }' $TESTAPP.sym)
dump "Found module version: $VERSION"
if [ -z "$VERSION" ]; then
echo "ERROR: Can't find proper module version from symbol dump!"
head -n5 $TESTAPP.sym
clean_exit 1
fi
run mkdir -p "$TMPDIR/symbols/$TESTAPP/$VERSION"
run mv $TESTAPP.sym "$TMPDIR/symbols/$TESTAPP/$VERSION/"
dump "Generating stack trace"
# Don't use 'run' to be able to send stdout and stderr to two different files.
log "COMMAND: $TMPBIN/minidump_stackwalk $MINIDUMP_NAME symbols"
"$TMPBIN/minidump_stackwalk" $MINIDUMP_NAME \
"$TMPDIR/symbols" \
> "$BUILD_LOG" 2>>"$RUN_LOG"
fail_panic "minidump_stackwalk doesn't work!"
dump "Checking stack trace content"
if verbosity_is_higher_than 1; then
cat "$BUILD_LOG"
fi
# The generated stack trace should look like the following:
#
# Thread 0 (crashed)
# 0 test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4]
# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
# sp = 0xbea2cb50 lr = 0x00009025 pc = 0x00008f84
# Found by: given as instruction pointer in context
# 1 test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3]
# r4 = 0x00015530 r5 = 0xbea2cbe4 r6 = 0xffffff38 r7 = 0xbea2cb5c
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
# sp = 0xbea2cb50 pc = 0x00009025
# Found by: call frame info
# 2 libc.so + 0x164e5
# r4 = 0x00008f64 r5 = 0xbea2cc34 r6 = 0x00000001 r7 = 0xbea2cc3c
# r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 fp = 0x00000000
# sp = 0xbea2cc18 pc = 0x400c34e7
# Found by: call frame info
# ...
#
# The most important part for us is ensuring that the source location could
# be extracted, so look at the 'test_breakpad.cpp' references here.
#
# First, extract all the lines with test_google_breakpad! in them, and
# dump the corresponding crash location.
#
# Note that if the source location can't be extracted, the second field
# will only be 'test_google_breakpad' without the exclamation mark.
#
LOCATIONS=$(awk '$2 ~ "^test_google_breakpad!.*" { print $3; }' "$BUILD_LOG")
if [ -z "$LOCATIONS" ]; then
if verbosity_is_lower_than 1; then
cat "$BUILD_LOG"
fi
panic "No source location found in stack trace!"
fi
# Now check that they all match "[<source file>"
BAD_LOCATIONS=
for LOCATION in $LOCATIONS; do
case $LOCATION in
# Escape the opening bracket, or some shells like Dash will not
# match them properly.
\[*.cpp|\[*.cc|\[*.h) # These are valid source locations in our executable
;;
*) # Everything else is not!
BAD_LOCATIONS="$BAD_LOCATIONS $LOCATION"
;;
esac
done
if [ "$BAD_LOCATIONS" ]; then
dump "ERROR: Generated stack trace doesn't contain valid source locations:"
cat "$BUILD_LOG"
echo "Bad locations are: $BAD_LOCATIONS"
exit 1
fi
echo "All clear! Congratulations."

View File

@ -0,0 +1,32 @@
This is a sample Android executable that can be used to test the
Google Breakpad client library on Android.
Its purpose is simply to crash and generate a minidump under /data/local/tmp.
Build instructions:
cd android/sample_app
$NDK/ndk-build
Where $NDK points to a valid Android NDK installation.
Usage instructions:
After buildind the test program, send it to a device, then run it as
the shell UID:
adb push libs/armeabi/test_google_breakpad /data/local/tmp
adb shell /data/local/tmp/test_google_breakpad
This will simply crash after dumping the name of the generated minidump
file.
See jni/test_breakpad.cpp for details.
Use 'armeabi-v7a' instead of 'armeabi' above to test the ARMv7-A version
of the binary.
Note:
If you plan to use the library in a regular Android application, store
the minidump files either to your app-specific directory, or to the SDCard
(the latter requiring a specific permission).

View File

@ -0,0 +1,44 @@
# 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test_google_breakpad
LOCAL_SRC_FILES := test_breakpad.cpp
LOCAL_STATIC_LIBRARIES += breakpad_client
include $(BUILD_EXECUTABLE)
# If NDK_MODULE_PATH is defined, import the module, otherwise do a direct
# includes. This allows us to build in all scenarios easily.
ifneq ($(NDK_MODULE_PATH),)
$(call import-module,google_breakpad)
else
include $(LOCAL_PATH)/../../google_breakpad/Android.mk
endif

View File

@ -0,0 +1,32 @@
# 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.
APP_STL := stlport_static
APP_ABI := all
APP_CXXFLAGS := -std=c++11 -D__STDC_LIMIT_MACROS

View File

@ -0,0 +1,57 @@
// 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 <stdio.h>
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
namespace {
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
void Crash() {
volatile int* a = reinterpret_cast<volatile int*>(NULL);
*a = 1;
}
} // namespace
int main(int argc, char* argv[]) {
google_breakpad::MinidumpDescriptor descriptor(".");
google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback,
NULL, true, -1);
Crash();
return 0;
}

View File

@ -0,0 +1,131 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
# Slightly modified for Android, see ANDROID comment below.
scriptversion=2012-06-27.10; # UTC
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--] TEST-SCRIPT
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END
}
# TODO: better error handling in option parsing (in particular, ensure
# TODO: $log_file, $trs_file and $test_name are defined).
test_name= # Used for reporting.
log_file= # Where to save the output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=no
color_tests=no
enable_hard_errors=yes
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "test-driver $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) enable_hard_errors=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
esac
shift
done
if test $color_tests = yes; then
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
red='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # No color.
else
red= grn= lgn= blu= mgn= std=
fi
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
trap "st=129; $do_exit" 1
trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
# Test script is run here.
# ANDROID: old line was: "$@" > $log_file 2>&1
progdir=$(dirname "$0")
"$progdir/test-shell.sh" "$@" > $log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
estatus=1
fi
case $estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -0,0 +1,131 @@
#!/bin/sh
#
# 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.
# A special shell wrapper that can be used to run the Google Breakpad unit
# tests on a connected Android device.
#
# This is designed to be called from the Makefile during 'make check'
#
PROGDIR=$(dirname "$0")
PROGNAME=$(basename "$0")
. $PROGDIR/common-functions.sh
# Extract test program name first.
TEST_PROGRAM=$1
shift
if [ -z "$TEST_PROGRAM" ]; then
panic "No test program/script name on the command-line!"
fi
if [ ! -f "$TEST_PROGRAM" ]; then
panic "Can't find test program/script: $TEST_PROGRAM"
fi
# Create test directory on the device
TEST_DIR=/data/local/tmp/test-google-breakpad-$$
adb_shell mkdir "$TEST_DIR" ||
panic "Can't create test directory on device: $TEST_DIR"
# Ensure that it is always removed when the script exits.
clean_test_dir () {
# Don't care about success/failure, use '$ADB shell' directly.
adb_shell rm -r "$TEST_DIR"
}
atexit clean_test_dir
TEST_PROGRAM_NAME=$(basename "$TEST_PROGRAM")
TEST_PROGRAM_DIR=$(dirname "$TEST_PROGRAM")
# Handle special case(s) here.
DATA_FILES=
case $TEST_PROGRAM_NAME in
linux_client_unittest)
# linux_client_unittest will call another executable at runtime, ensure
# it is installed too.
adb_install "$TEST_PROGRAM_DIR/linux_dumper_unittest_helper" "$TEST_DIR"
# linux_client_unittest loads a shared library at runtime, ensure it is
# installed too.
adb_install "$TEST_PROGRAM_DIR/linux_client_unittest_shlib" "$TEST_DIR"
;;
basic_source_line_resolver_unittest)
DATA_FILES="module1.out \
module2.out \
module3_bad.out \
module4_bad.out"
;;
exploitability_unittest)
DATA_FILES="scii_read_av.dmp \
ascii_read_av_block_write.dmp \
ascii_read_av_clobber_write.dmp \
ascii_read_av_conditional.dmp \
ascii_read_av_non_null.dmp \
ascii_read_av_then_jmp.dmp \
ascii_read_av_xchg_write.dmp \
ascii_write_av.dmp \
ascii_write_av_arg_to_call.dmp \
exec_av_on_stack.dmp \
null_read_av.dmp \
null_write_av.dmp \
read_av.dmp \
null_read_av.dmp \
write_av_non_null.dmp"
;;
fast_source_line_resolver_unittest)
DATA_FILES="module0.out \
module1.out \
module2.out \
module3_bad.out \
module4_bad.out"
;;
minidump_processor_unittest|minidump_unittest)
DATA_FILES="src/processor/testdata/minidump2.dmp"
;;
esac
# Install the data files, their path is relative to the environment
# variable 'srcdir'
for FILE in $DATA_FILES; do
FILEDIR=src/processor/testdata/$(dirname "$FILE")
adb_shell mkdir -p "$TEST_DIR/$FILEDIR"
adb_install "${srcdir:-.}/$FILE" "$TEST_DIR"/"$FILE"
done
# Copy test program to device
adb_install "$TEST_PROGRAM" "$TEST_DIR"
# Run it
adb_shell "cd $TEST_DIR && LD_LIBRARY_PATH=. ./$TEST_PROGRAM_NAME $@"
# Note: exiting here will call cleanup_exit which will remove the temporary
# files from the device.

View File

@ -0,0 +1,42 @@
version: '{build}'
environment:
GYP_MSVS_VERSION: 2013
platform:
- Win32
configuration:
- Debug
- Release
# Use the source dir expected by gclient.
clone_folder: c:\projects\breakpad\src
# Before checkout.
init:
- cd %APPVEYOR_BUILD_FOLDER%\..\..
- appveyor DownloadFile https://storage.googleapis.com/chrome-infra/depot_tools.zip
- 7z -bd x depot_tools.zip -odepot_tools
- depot_tools\update_depot_tools
- cd %APPVEYOR_BUILD_FOLDER%
# After checkout.
install:
- PATH C:\projects\depot_tools;%PATH%
- cd %APPVEYOR_BUILD_FOLDER%\..
- gclient config https://%APPVEYOR_REPO_PROVIDER%.com/%APPVEYOR_REPO_NAME% --unmanaged --name=src
- gclient sync
build_script:
- cd %APPVEYOR_BUILD_FOLDER%
- msbuild src\client\windows\breakpad_client.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m /verbosity:normal
- msbuild src\tools\windows\tools_windows.sln /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m /verbosity:normal
test_script:
- src\client\windows\%CONFIGURATION%\client_tests.exe
- src\tools\windows\%CONFIGURATION%\dump_syms_unittest.exe
artifacts:
- path: '**\*.exe'
- path: '**\*.lib'

View File

@ -0,0 +1,270 @@
#! /bin/sh
# Wrapper for Microsoft lib.exe
me=ar-lib
scriptversion=2012-03-01.08; # UTC
# Copyright (C) 2010-2014 Free Software Foundation, Inc.
# Written by Peter Rosin <peda@lysator.liu.se>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# func_error message
func_error ()
{
echo "$me: $1" 1>&2
exit 1
}
file_conv=
# func_file_conv build_file
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv in
mingw)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin)
file=`cygpath -m "$file" || echo "$file"`
;;
wine)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_at_file at_file operation archive
# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
# for each of them.
# When interpreting the content of the @FILE, do NOT use func_file_conv,
# since the user would need to supply preconverted file names to
# binutils ar, at least for MinGW.
func_at_file ()
{
operation=$2
archive=$3
at_file_contents=`cat "$1"`
eval set x "$at_file_contents"
shift
for member
do
$AR -NOLOGO $operation:"$member" "$archive" || exit $?
done
}
case $1 in
'')
func_error "no command. Try '$0 --help' for more information."
;;
-h | --h*)
cat <<EOF
Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
Members may be specified in a file named with @FILE.
EOF
exit $?
;;
-v | --v*)
echo "$me, version $scriptversion"
exit $?
;;
esac
if test $# -lt 3; then
func_error "you must specify a program, an action and an archive"
fi
AR=$1
shift
while :
do
if test $# -lt 2; then
func_error "you must specify a program, an action and an archive"
fi
case $1 in
-lib | -LIB \
| -ltcg | -LTCG \
| -machine* | -MACHINE* \
| -subsystem* | -SUBSYSTEM* \
| -verbose | -VERBOSE \
| -wx* | -WX* )
AR="$AR $1"
shift
;;
*)
action=$1
shift
break
;;
esac
done
orig_archive=$1
shift
func_file_conv "$orig_archive"
archive=$file
# strip leading dash in $action
action=${action#-}
delete=
extract=
list=
quick=
replace=
index=
create=
while test -n "$action"
do
case $action in
d*) delete=yes ;;
x*) extract=yes ;;
t*) list=yes ;;
q*) quick=yes ;;
r*) replace=yes ;;
s*) index=yes ;;
S*) ;; # the index is always updated implicitly
c*) create=yes ;;
u*) ;; # TODO: don't ignore the update modifier
v*) ;; # TODO: don't ignore the verbose modifier
*)
func_error "unknown action specified"
;;
esac
action=${action#?}
done
case $delete$extract$list$quick$replace,$index in
yes,* | ,yes)
;;
yesyes*)
func_error "more than one action specified"
;;
*)
func_error "no action specified"
;;
esac
if test -n "$delete"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
for member
do
case $1 in
@*)
func_at_file "${1#@}" -REMOVE "$archive"
;;
*)
func_file_conv "$1"
$AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
;;
esac
done
elif test -n "$extract"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
if test $# -gt 0; then
for member
do
case $1 in
@*)
func_at_file "${1#@}" -EXTRACT "$archive"
;;
*)
func_file_conv "$1"
$AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
;;
esac
done
else
$AR -NOLOGO -LIST "$archive" | sed -e 's/\\/\\\\/g' | while read member
do
$AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
done
fi
elif test -n "$quick$replace"; then
if test ! -f "$orig_archive"; then
if test -z "$create"; then
echo "$me: creating $orig_archive"
fi
orig_archive=
else
orig_archive=$archive
fi
for member
do
case $1 in
@*)
func_file_conv "${1#@}"
set x "$@" "@$file"
;;
*)
func_file_conv "$1"
set x "$@" "$file"
;;
esac
shift
shift
done
if test -n "$orig_archive"; then
$AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
else
$AR -NOLOGO -OUT:"$archive" "$@" || exit $?
fi
elif test -n "$list"; then
if test ! -f "$orig_archive"; then
func_error "archive not found"
fi
$AR -NOLOGO -LIST "$archive" || exit $?
fi

View File

@ -0,0 +1,347 @@
#! /bin/sh
# Wrapper for compilers which do not understand '-c -o'.
scriptversion=2012-10-14.11; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# Written by Tom Tromey <tromey@cygnus.com>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
nl='
'
# We need space, tab and new line, in precisely that order. Quoting is
# there to prevent tools from complaining about whitespace usage.
IFS=" "" $nl"
file_conv=
# func_file_conv build_file lazy
# Convert a $build file to $host form and store it in $file
# Currently only supports Windows hosts. If the determined conversion
# type is listed in (the comma separated) LAZY, no conversion will
# take place.
func_file_conv ()
{
file=$1
case $file in
/ | /[!/]*) # absolute file, and not a UNC file
if test -z "$file_conv"; then
# lazily determine how to convert abs files
case `uname -s` in
MINGW*)
file_conv=mingw
;;
CYGWIN*)
file_conv=cygwin
;;
*)
file_conv=wine
;;
esac
fi
case $file_conv/,$2, in
*,$file_conv,*)
;;
mingw/*)
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
;;
cygwin/*)
file=`cygpath -m "$file" || echo "$file"`
;;
wine/*)
file=`winepath -w "$file" || echo "$file"`
;;
esac
;;
esac
}
# func_cl_dashL linkdir
# Make cl look for libraries in LINKDIR
func_cl_dashL ()
{
func_file_conv "$1"
if test -z "$lib_path"; then
lib_path=$file
else
lib_path="$lib_path;$file"
fi
linker_opts="$linker_opts -LIBPATH:$file"
}
# func_cl_dashl library
# Do a library search-path lookup for cl
func_cl_dashl ()
{
lib=$1
found=no
save_IFS=$IFS
IFS=';'
for dir in $lib_path $LIB
do
IFS=$save_IFS
if $shared && test -f "$dir/$lib.dll.lib"; then
found=yes
lib=$dir/$lib.dll.lib
break
fi
if test -f "$dir/$lib.lib"; then
found=yes
lib=$dir/$lib.lib
break
fi
if test -f "$dir/lib$lib.a"; then
found=yes
lib=$dir/lib$lib.a
break
fi
done
IFS=$save_IFS
if test "$found" != yes; then
lib=$lib.lib
fi
}
# func_cl_wrapper cl arg...
# Adjust compile command to suit cl
func_cl_wrapper ()
{
# Assume a capable shell
lib_path=
shared=:
linker_opts=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
eat=1
case $2 in
*.o | *.[oO][bB][jJ])
func_file_conv "$2"
set x "$@" -Fo"$file"
shift
;;
*)
func_file_conv "$2"
set x "$@" -Fe"$file"
shift
;;
esac
;;
-I)
eat=1
func_file_conv "$2" mingw
set x "$@" -I"$file"
shift
;;
-I*)
func_file_conv "${1#-I}" mingw
set x "$@" -I"$file"
shift
;;
-l)
eat=1
func_cl_dashl "$2"
set x "$@" "$lib"
shift
;;
-l*)
func_cl_dashl "${1#-l}"
set x "$@" "$lib"
shift
;;
-L)
eat=1
func_cl_dashL "$2"
;;
-L*)
func_cl_dashL "${1#-L}"
;;
-static)
shared=false
;;
-Wl,*)
arg=${1#-Wl,}
save_ifs="$IFS"; IFS=','
for flag in $arg; do
IFS="$save_ifs"
linker_opts="$linker_opts $flag"
done
IFS="$save_ifs"
;;
-Xlinker)
eat=1
linker_opts="$linker_opts $2"
;;
-*)
set x "$@" "$1"
shift
;;
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
func_file_conv "$1"
set x "$@" -Tp"$file"
shift
;;
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
func_file_conv "$1" mingw
set x "$@" "$file"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -n "$linker_opts"; then
linker_opts="-link$linker_opts"
fi
exec "$@" $linker_opts
exit 1
}
eat=
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: compile [--help] [--version] PROGRAM [ARGS]
Wrapper for compilers which do not understand '-c -o'.
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
arguments, and rename the output as expected.
If you are trying to build a whole package this is not the
right script to run: please start by reading the file 'INSTALL'.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "compile $scriptversion"
exit $?
;;
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
func_cl_wrapper "$@" # Doesn't return...
;;
esac
ofile=
cfile=
for arg
do
if test -n "$eat"; then
eat=
else
case $1 in
-o)
# configure might choose to run compile as 'compile cc -o foo foo.c'.
# So we strip '-o arg' only if arg is an object.
eat=1
case $2 in
*.o | *.obj)
ofile=$2
;;
*)
set x "$@" -o "$2"
shift
;;
esac
;;
*.c)
cfile=$1
set x "$@" "$1"
shift
;;
*)
set x "$@" "$1"
shift
;;
esac
fi
shift
done
if test -z "$ofile" || test -z "$cfile"; then
# If no '-o' option was seen then we might have been invoked from a
# pattern rule where we don't need one. That is ok -- this is a
# normal compilation that the losing compiler can handle. If no
# '.c' file was seen then we are probably linking. That is also
# ok.
exec "$@"
fi
# Name of file we expect compiler to create.
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
# Create the lock directory.
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
# that we are using for the .o file. Also, base the name on the expected
# object file name, since that is what matters with a parallel build.
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
while true; do
if mkdir "$lockdir" >/dev/null 2>&1; then
break
fi
sleep 1
done
# FIXME: race condition here if user kills between mkdir and trap.
trap "rmdir '$lockdir'; exit 1" 1 2 15
# Run the compile.
"$@"
ret=$?
if test -f "$cofile"; then
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
elif test -f "${cofile}bj"; then
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
fi
rmdir "$lockdir"
exit $ret
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,791 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
scriptversion=2013-05-30.07; # UTC
# Copyright (C) 1999-2014 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
case $1 in
'')
echo "$0: No command. Try '$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
Run PROGRAMS ARGS to compile a file, generating dependencies
as side-effects.
Environment variables:
depmode Dependency tracking mode.
source Source file read by 'PROGRAMS ARGS'.
object Object file output by 'PROGRAMS ARGS'.
DEPDIR directory where to store dependencies.
depfile Dependency file to output.
tmpdepfile Temporary file to use when outputting dependencies.
libtool Whether libtool is used (yes/no).
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "depcomp $scriptversion"
exit $?
;;
esac
# Get the directory component of the given path, and save it in the
# global variables '$dir'. Note that this directory component will
# be either empty or ending with a '/' character. This is deliberate.
set_dir_from ()
{
case $1 in
*/*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
*) dir=;;
esac
}
# Get the suffix-stripped basename of the given path, and save it the
# global variable '$base'.
set_base_from ()
{
base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
}
# If no dependency file was actually created by the compiler invocation,
# we still have to create a dummy depfile, to avoid errors with the
# Makefile "include basename.Plo" scheme.
make_dummy_depfile ()
{
echo "#dummy" > "$depfile"
}
# Factor out some common post-processing of the generated depfile.
# Requires the auxiliary global variable '$tmpdepfile' to be set.
aix_post_process_depfile ()
{
# If the compiler actually managed to produce a dependency file,
# post-process it.
if test -f "$tmpdepfile"; then
# Each line is of the form 'foo.o: dependency.h'.
# Do two passes, one to just change these to
# $object: dependency.h
# and one to simply output
# dependency.h:
# which is needed to avoid the deleted-header problem.
{ sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
} > "$depfile"
rm -f "$tmpdepfile"
else
make_dummy_depfile
fi
}
# A tabulation character.
tab=' '
# A newline character.
nl='
'
# Character ranges might be problematic outside the C locale.
# These definitions help.
upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower=abcdefghijklmnopqrstuvwxyz
digits=0123456789
alpha=${upper}${lower}
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
echo "depcomp: Variables source, object and depmode must be set" 1>&2
exit 1
fi
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
depfile=${depfile-`echo "$object" |
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
rm -f "$tmpdepfile"
# Avoid interferences from the environment.
gccflag= dashmflag=
# Some modes work just like other modes, but use different flags. We
# parameterize here, but still list the modes in the big case below,
# to make depend.m4 easier to write. Note that we *cannot* use a case
# here, because this file can only contain one case statement.
if test "$depmode" = hp; then
# HP compiler uses -M and no extra arg.
gccflag=-M
depmode=gcc
fi
if test "$depmode" = dashXmstdout; then
# This is just like dashmstdout with a different argument.
dashmflag=-xM
depmode=dashmstdout
fi
cygpath_u="cygpath -u -f -"
if test "$depmode" = msvcmsys; then
# This is just like msvisualcpp but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvisualcpp
fi
if test "$depmode" = msvc7msys; then
# This is just like msvc7 but w/o cygpath translation.
# Just convert the backslash-escaped backslashes to single forward
# slashes to satisfy depend.m4
cygpath_u='sed s,\\\\,/,g'
depmode=msvc7
fi
if test "$depmode" = xlc; then
# IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
gccflag=-qmakedep=gcc,-MF
depmode=gcc
fi
case "$depmode" in
gcc3)
## gcc 3 implements dependency tracking that does exactly what
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
## it if -MD -MP comes after the -MF stuff. Hmm.
## Unfortunately, FreeBSD c89 acceptance of flags depends upon
## the command line argument order; so add the flags where they
## appear in depend2.am. Note that the slowdown incurred here
## affects only configure: in makefiles, %FASTDEP% shortcuts this.
for arg
do
case $arg in
-c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
*) set fnord "$@" "$arg" ;;
esac
shift # fnord
shift # $arg
done
"$@"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
mv "$tmpdepfile" "$depfile"
;;
gcc)
## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
## (see the conditional assignment to $gccflag above).
## There are various ways to get dependency output from gcc. Here's
## why we pick this rather obscure method:
## - Don't want to use -MD because we'd like the dependencies to end
## up in a subdir. Having to rename by hand is ugly.
## (We might end up doing this anyway to support other compilers.)
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
## -MM, not -M (despite what the docs say). Also, it might not be
## supported by the other compilers which use the 'gcc' depmode.
## - Using -M directly means running the compiler twice (even worse
## than renaming).
if test -z "$gccflag"; then
gccflag=-MD,
fi
"$@" -Wp,"$gccflag$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The second -e expression handles DOS-style file names with drive
# letters.
sed -e 's/^[^:]*: / /' \
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
## This next piece of magic avoids the "deleted header file" problem.
## The problem is that when a header file which appears in a .P file
## is deleted, the dependency causes make to die (because there is
## typically no way to rebuild the header). We avoid this by adding
## dummy dependencies for each header file. Too bad gcc doesn't do
## this for us directly.
## Some versions of gcc put a space before the ':'. On the theory
## that the space means something, we add a space to the output as
## well. hp depmode also adds that space, but also prefixes the VPATH
## to the object. Take care to not repeat it in the output.
## Some versions of the HPUX 10.20 sed can't process this invocation
## correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
sgi)
if test "$libtool" = yes; then
"$@" "-Wp,-MDupdate,$tmpdepfile"
else
"$@" -MDupdate "$tmpdepfile"
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
echo "$object : \\" > "$depfile"
# Clip off the initial element (the dependent). Don't try to be
# clever and replace this with sed code, as IRIX sed won't handle
# lines with more than a fixed number of characters (4096 in
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
# the IRIX cc adds comments like '#:fec' to the end of the
# dependency line.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
| tr "$nl" ' ' >> "$depfile"
echo >> "$depfile"
# The second pass generates a dummy entry for each header file.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
>> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile"
;;
xlc)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts '$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.u
tmpdepfile2=$base.u
tmpdepfile3=$dir.libs/$base.u
"$@" -Wc,-M
else
tmpdepfile1=$dir$base.u
tmpdepfile2=$dir$base.u
tmpdepfile3=$dir$base.u
"$@" -M
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
aix_post_process_depfile
;;
tcc)
# tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
# FIXME: That version still under development at the moment of writing.
# Make that this statement remains true also for stable, released
# versions.
# It will wrap lines (doesn't matter whether long or short) with a
# trailing '\', as in:
#
# foo.o : \
# foo.c \
# foo.h \
#
# It will put a trailing '\' even on the last line, and will use leading
# spaces rather than leading tabs (at least since its commit 0394caf7
# "Emit spaces for -MD").
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
# We have to change lines of the first kind to '$object: \'.
sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
# And for each line of the second kind, we have to emit a 'dep.h:'
# dummy dependency, to avoid the deleted-header problem.
sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
rm -f "$tmpdepfile"
;;
## The order of this option in the case statement is important, since the
## shell code in configure will try each of these formats in the order
## listed in this file. A plain '-MD' option would be understood by many
## compilers, so we must ensure this comes after the gcc and icc options.
pgcc)
# Portland's C compiler understands '-MD'.
# Will always output deps to 'file.d' where file is the root name of the
# source file under compilation, even if file resides in a subdirectory.
# The object file name does not affect the name of the '.d' file.
# pgcc 10.2 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using '\' :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
set_dir_from "$object"
# Use the source, not the object, to determine the base name, since
# that's sadly what pgcc will do too.
set_base_from "$source"
tmpdepfile=$base.d
# For projects that build the same source file twice into different object
# files, the pgcc approach of using the *source* file root name can cause
# problems in parallel builds. Use a locking strategy to avoid stomping on
# the same $tmpdepfile.
lockdir=$base.d-lock
trap "
echo '$0: caught signal, cleaning up...' >&2
rmdir '$lockdir'
exit 1
" 1 2 13 15
numtries=100
i=$numtries
while test $i -gt 0; do
# mkdir is a portable test-and-set.
if mkdir "$lockdir" 2>/dev/null; then
# This process acquired the lock.
"$@" -MD
stat=$?
# Release the lock.
rmdir "$lockdir"
break
else
# If the lock is being held by a different process, wait
# until the winning process is done or we timeout.
while test -d "$lockdir" && test $i -gt 0; do
sleep 1
i=`expr $i - 1`
done
fi
i=`expr $i - 1`
done
trap - 1 2 13 15
if test $i -le 0; then
echo "$0: failed to acquire lock after $numtries attempts" >&2
echo "$0: check lockdir '$lockdir'" >&2
exit 1
fi
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
hp2)
# The "hp" stanza above does not work with aCC (C++) and HP's ia64
# compilers, which have integrated preprocessors. The correct option
# to use with these is +Maked; it writes dependencies to a file named
# 'foo.d', which lands next to the object file, wherever that
# happens to be.
# Much of this is similar to the tru64 case; see comments there.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir.libs/$base.d
"$@" -Wc,+Maked
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
"$@" +Maked
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
do
test -f "$tmpdepfile" && break
done
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
# Add 'dependent.h:' lines.
sed -ne '2,${
s/^ *//
s/ \\*$//
s/$/:/
p
}' "$tmpdepfile" >> "$depfile"
else
make_dummy_depfile
fi
rm -f "$tmpdepfile" "$tmpdepfile2"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
# dependencies in 'foo.d' instead, so we check for that too.
# Subdirectories are respected.
set_dir_from "$object"
set_base_from "$object"
if test "$libtool" = yes; then
# Libtool generates 2 separate objects for the 2 libraries. These
# two compilations output dependencies in $dir.libs/$base.o.d and
# in $dir$base.o.d. We have to check for both files, because
# one of the two compilations can be disabled. We should prefer
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
# automatically cleaned when .libs/ is deleted, while ignoring
# the former would cause a distcleancheck panic.
tmpdepfile1=$dir$base.o.d # libtool 1.5
tmpdepfile2=$dir.libs/$base.o.d # Likewise.
tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
"$@" -Wc,-MD
else
tmpdepfile1=$dir$base.d
tmpdepfile2=$dir$base.d
tmpdepfile3=$dir$base.d
"$@" -MD
fi
stat=$?
if test $stat -ne 0; then
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
exit $stat
fi
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
do
test -f "$tmpdepfile" && break
done
# Same post-processing that is required for AIX mode.
aix_post_process_depfile
;;
msvc7)
if test "$libtool" = yes; then
showIncludes=-Wc,-showIncludes
else
showIncludes=-showIncludes
fi
"$@" $showIncludes > "$tmpdepfile"
stat=$?
grep -v '^Note: including file: ' "$tmpdepfile"
if test $stat -ne 0; then
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
echo "$object : \\" > "$depfile"
# The first sed program below extracts the file names and escapes
# backslashes for cygpath. The second sed program outputs the file
# name when reading, but also accumulates all include files in the
# hold buffer in order to output them again at the end. This only
# works with sed implementations that can handle large buffers.
sed < "$tmpdepfile" -n '
/^Note: including file: *\(.*\)/ {
s//\1/
s/\\/\\\\/g
p
}' | $cygpath_u | sort -u | sed -n '
s/ /\\ /g
s/\(.*\)/'"$tab"'\1 \\/p
s/.\(.*\) \\/\1:/
H
$ {
s/.*/'"$tab"'/
G
p
}' >> "$depfile"
echo >> "$depfile" # make sure the fragment doesn't end with a backslash
rm -f "$tmpdepfile"
;;
msvc7msys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
#nosideeffect)
# This comment above is used by automake to tell side-effect
# dependency tracking mechanisms from slower ones.
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for ':'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
"$@" $dashmflag |
sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this sed invocation
# correctly. Breaking it into two sed invocations is a workaround.
tr ' ' "$nl" < "$tmpdepfile" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
dashXmstdout)
# This case only exists to satisfy depend.m4. It is never actually
# run, as this mode is specially recognized in the preamble.
exit 1
;;
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no eat=no
for arg
do
case $cleared in
no)
set ""; shift
cleared=yes ;;
esac
if test $eat = yes; then
eat=no
continue
fi
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-arch)
eat=yes ;;
-*|$object)
;;
*)
set fnord "$@" "$arg"; shift ;;
esac
done
obj_suffix=`echo "$object" | sed 's/^.*\././'`
touch "$tmpdepfile"
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
rm -f "$depfile"
# makedepend may prepend the VPATH from the source file name to the object.
# No need to regex-escape $object, excess matching of '.' is harmless.
sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process the last invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed '1,2d' "$tmpdepfile" \
| tr ' ' "$nl" \
| sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
| sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile" "$tmpdepfile".bak
;;
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
# Remove '-o $object'.
IFS=" "
for arg
do
case $arg in
-o)
shift
;;
$object)
shift
;;
*)
set fnord "$@" "$arg"
shift # fnord
shift # $arg
;;
esac
done
"$@" -E \
| sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
| sed '$ s: \\$::' > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
cat < "$tmpdepfile" >> "$depfile"
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
if test "$libtool" = yes; then
while test "X$1" != 'X--mode=compile'; do
shift
done
shift
fi
IFS=" "
for arg
do
case "$arg" in
-o)
shift
;;
$object)
shift
;;
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
set fnord "$@"
shift
shift
;;
*)
set fnord "$@" "$arg"
shift
shift
;;
esac
done
"$@" -E 2>/dev/null |
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
rm -f "$depfile"
echo "$object : \\" > "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
echo "$tab" >> "$depfile"
sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
rm -f "$tmpdepfile"
;;
msvcmsys)
# This case exists only to let depend.m4 do its work. It works by
# looking at the text of this script. This case will never be run,
# since it is checked for above.
exit 1
;;
none)
exec "$@"
;;
*)
echo "Unknown depmode $depmode" 1>&2
exit 1
;;
esac
exit 0
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -0,0 +1,501 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2013-12-25.23; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
tab=' '
nl='
'
IFS=" $tab$nl"
# Set DOITPROG to "echo" to test this script.
doit=${DOITPROG-}
doit_exec=${doit:-exec}
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
is_target_a_directory=possibly
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t)
is_target_a_directory=always
dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) is_target_a_directory=never;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
# We allow the use of options -d and -T together, by making -d
# take the precedence; this is for compatibility with GNU install.
if test -n "$dir_arg"; then
if test -n "$dst_arg"; then
echo "$0: target directory not allowed when installing a directory." >&2
exit 1
fi
fi
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
if test $# -gt 1 || test "$is_target_a_directory" = always; then
if test ! -d "$dst_arg"; then
echo "$0: $dst_arg: Is not a directory." >&2
exit 1
fi
fi
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test "$is_target_a_directory" = never; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
dstdir=`dirname "$dst"`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
oIFS=$IFS
IFS=/
set -f
set fnord $dstdir
shift
set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,215 @@
#! /bin/sh
# Common wrapper for a few potentially missing GNU programs.
scriptversion=2013-10-28.13; # UTC
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try '$0 --help' for more information"
exit 1
fi
case $1 in
--is-lightweight)
# Used by our autoconf macros to check whether the available missing
# script is modern enough.
exit 0
;;
--run)
# Back-compat with the calling convention used by older automake.
shift
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
to PROGRAM being missing or too old.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
Supported PROGRAM values:
aclocal autoconf autoheader autom4te automake makeinfo
bison yacc flex lex help2man
Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
'g' are ignored when checking the name.
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: unknown '$1' option"
echo 1>&2 "Try '$0 --help' for more information"
exit 1
;;
esac
# Run the given program, remember its exit status.
"$@"; st=$?
# If it succeeded, we are done.
test $st -eq 0 && exit 0
# Also exit now if we it failed (or wasn't found), and '--version' was
# passed; such an option is passed most likely to detect whether the
# program is present and works.
case $2 in --version|--help) exit $st;; esac
# Exit code 63 means version mismatch. This often happens when the user
# tries to use an ancient version of a tool on a file that requires a
# minimum version.
if test $st -eq 63; then
msg="probably too old"
elif test $st -eq 127; then
# Program was missing.
msg="missing on your system"
else
# Program was found and executed, but failed. Give up.
exit $st
fi
perl_URL=http://www.perl.org/
flex_URL=http://flex.sourceforge.net/
gnu_software_URL=http://www.gnu.org/software
program_details ()
{
case $1 in
aclocal|automake)
echo "The '$1' program is part of the GNU Automake package:"
echo "<$gnu_software_URL/automake>"
echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/autoconf>"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
autoconf|autom4te|autoheader)
echo "The '$1' program is part of the GNU Autoconf package:"
echo "<$gnu_software_URL/autoconf/>"
echo "It also requires GNU m4 and Perl in order to run:"
echo "<$gnu_software_URL/m4/>"
echo "<$perl_URL>"
;;
esac
}
give_advice ()
{
# Normalize program name to check for.
normalized_program=`echo "$1" | sed '
s/^gnu-//; t
s/^gnu//; t
s/^g//; t'`
printf '%s\n' "'$1' is $msg."
configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
case $normalized_program in
autoconf*)
echo "You should only need it if you modified 'configure.ac',"
echo "or m4 files included by it."
program_details 'autoconf'
;;
autoheader*)
echo "You should only need it if you modified 'acconfig.h' or"
echo "$configure_deps."
program_details 'autoheader'
;;
automake*)
echo "You should only need it if you modified 'Makefile.am' or"
echo "$configure_deps."
program_details 'automake'
;;
aclocal*)
echo "You should only need it if you modified 'acinclude.m4' or"
echo "$configure_deps."
program_details 'aclocal'
;;
autom4te*)
echo "You might have modified some maintainer files that require"
echo "the 'autom4te' program to be rebuilt."
program_details 'autom4te'
;;
bison*|yacc*)
echo "You should only need it if you modified a '.y' file."
echo "You may want to install the GNU Bison package:"
echo "<$gnu_software_URL/bison/>"
;;
lex*|flex*)
echo "You should only need it if you modified a '.l' file."
echo "You may want to install the Fast Lexical Analyzer package:"
echo "<$flex_URL>"
;;
help2man*)
echo "You should only need it if you modified a dependency" \
"of a man page."
echo "You may want to install the GNU Help2man package:"
echo "<$gnu_software_URL/help2man/>"
;;
makeinfo*)
echo "You should only need it if you modified a '.texi' file, or"
echo "any other file indirectly affecting the aspect of the manual."
echo "You might want to install the Texinfo package:"
echo "<$gnu_software_URL/texinfo/>"
echo "The spurious makeinfo call might also be the consequence of"
echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
echo "want to install GNU make:"
echo "<$gnu_software_URL/make/>"
;;
*)
echo "You might have modified some files without having the proper"
echo "tools for further handling them. Check the 'README' file, it"
echo "often tells you about the needed prerequisites for installing"
echo "this package. You may also peek at any GNU archive site, in"
echo "case some other package contains this missing '$1' program."
;;
esac
}
give_advice "$1" | sed -e '1s/^/WARNING: /' \
-e '2,$s/^/ /' >&2
# Propagate the correct exit status (expected to be 127 for a program
# not found, 63 for a program that failed due to version mismatch).
exit $st
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -0,0 +1,3 @@
#!/bin/sh
# -E to keep the environment variables needed to run the tests.
exec sudo -E "$@"

View File

@ -0,0 +1,148 @@
#! /bin/sh
# test-driver - basic testsuite driver script.
scriptversion=2013-07-13.22; # UTC
# Copyright (C) 2011-2014 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
usage_error ()
{
echo "$0: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--]
TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
The '--test-name', '--log-file' and '--trs-file' options are mandatory.
END
}
test_name= # Used for reporting.
log_file= # Where to save the output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=no
color_tests=no
enable_hard_errors=yes
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "test-driver $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) enable_hard_errors=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
*) break;;
esac
shift
done
missing_opts=
test x"$test_name" = x && missing_opts="$missing_opts --test-name"
test x"$log_file" = x && missing_opts="$missing_opts --log-file"
test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
if test x"$missing_opts" != x; then
usage_error "the following mandatory options are missing:$missing_opts"
fi
if test $# -eq 0; then
usage_error "missing argument"
fi
if test $color_tests = yes; then
# Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
red='' # Red.
grn='' # Green.
lgn='' # Light green.
blu='' # Blue.
mgn='' # Magenta.
std='' # No color.
else
red= grn= lgn= blu= mgn= std=
fi
do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
trap "st=129; $do_exit" 1
trap "st=130; $do_exit" 2
trap "st=141; $do_exit" 13
trap "st=143; $do_exit" 15
# Test script is run here.
"$@" >$log_file 2>&1
estatus=$?
if test $enable_hard_errors = no && test $estatus -eq 99; then
tweaked_estatus=1
else
tweaked_estatus=$estatus
fi
case $tweaked_estatus:$expect_failure in
0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
0:*) col=$grn res=PASS recheck=no gcopy=no;;
77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
*:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
*:*) col=$red res=FAIL recheck=yes gcopy=yes;;
esac
# Report the test outcome and exit status in the logs, so that one can
# know whether the test passed or failed simply by looking at the '.log'
# file, without the need of also peaking into the corresponding '.trs'
# file (automake bug#11814).
echo "$res $test_name (exit status: $estatus)" >>$log_file
# Report outcome to console.
echo "${col}${res}${std}: $test_name"
# Register the test result, and other relevant metadata.
echo ":test-result: $res" > $trs_file
echo ":global-test-result: $res" >> $trs_file
echo ":recheck: $recheck" >> $trs_file
echo ":copy-in-global-log: $gcopy" >> $trs_file
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View File

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@/@PACKAGE_NAME@
Name: google-breakpad-client
Description: An open-source multi-platform crash reporting system
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lbreakpad_client @PTHREAD_LIBS@
Cflags: -I${includedir} @PTHREAD_CFLAGS@

View File

@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@/@PACKAGE_NAME@
Name: google-breakpad
Description: An open-source multi-platform crash reporting system
Version: @PACKAGE_VERSION@
Libs: -L${libdir} -lbreakpad @PTHREAD_LIBS@
Cflags: -I${includedir} @PTHREAD_CFLAGS@

View File

@ -0,0 +1,3 @@
GERRIT_HOST: True
CODE_REVIEW_SERVER: chromium-review.googlesource.com
VIEW_VC: https://chromium.googlesource.com/breakpad/breakpad/+/

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,272 @@
# Copyright (c) 2006, 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.
AC_PREREQ(2.64)
AC_INIT(breakpad, 0.1, google-breakpad-dev@googlegroups.com)
dnl Sanity check: the argument is just a file that should exist.
AC_CONFIG_SRCDIR(README.md)
AC_CONFIG_AUX_DIR(autotools)
AC_CONFIG_MACRO_DIR([m4])
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE(subdir-objects tar-ustar 1.11.1)
AM_CONFIG_HEADER(src/config.h)
AM_MAINTAINER_MODE
AM_PROG_AR
AM_PROG_AS
AC_PROG_CC
AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_RANLIB
dnl This must come before all the feature tests below.
AC_ARG_ENABLE(m32,
AS_HELP_STRING([--enable-m32],
[Compile/build with -m32]
[(default is no)]),
[case "${enableval}" in
yes)
CFLAGS="${CFLAGS} -m32"
CXXFLAGS="${CXXFLAGS} -m32"
usem32=true
;;
no)
usem32=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-m32)
;;
esac],
[usem32=false])
AC_HEADER_STDC
AC_SYS_LARGEFILE
AX_PTHREAD
AC_CHECK_HEADERS([a.out.h sys/mman.h sys/random.h])
AC_CHECK_FUNCS([arc4random getcontext getrandom memfd_create])
AM_CONDITIONAL([HAVE_GETCONTEXT], [test "x$ac_cv_func_getcontext" = xyes])
AM_CONDITIONAL([HAVE_MEMFD_CREATE], [test "x$ac_cv_func_memfd_create" = xyes])
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
dnl Test supported warning flags.
WARN_CXXFLAGS=
dnl This warning flag is used by clang. Its default behavior is to warn when
dnl given an unknown flag rather than error out.
AC_LANG_PUSH([C++])
AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[
ax_compiler_flags_test="-Werror=unknown-warning-option"
],[
ax_compiler_flags_test=""
])
AX_APPEND_COMPILE_FLAGS(m4_flatten([
-Wmissing-braces
-Wnon-virtual-dtor
-Woverloaded-virtual
-Wreorder
-Wsign-compare
-Wunused-local-typedefs
-Wunused-variable
-Wvla
]), [WARN_CXXFLAGS], [${ax_compiler_flags_test}])
AS_VAR_APPEND([WARN_CXXFLAGS], " -Werror")
AC_LANG_POP([C++])
AC_SUBST([WARN_CXXFLAGS])
dnl Test support for O_CLOEXEC
AX_CHECK_DEFINE([fcntl.h], [O_CLOEXEC], [],
[AC_DEFINE([O_CLOEXEC], [0], [Fallback definition for old systems])])
# Only build Linux client libs when compiling for Linux
case $host in
*-*-linux* | *-android* )
LINUX_HOST=true
;;
esac
AM_CONDITIONAL(LINUX_HOST, test x$LINUX_HOST = xtrue)
# Only use Android support headers when compiling for Android
case $host in
*-android*)
ANDROID_HOST=true
;;
esac
AM_CONDITIONAL(ANDROID_HOST, test x$ANDROID_HOST = xtrue)
# Some tools (like mac ones) only support x86 currently.
case $host_cpu in
i?86|x86_64)
X86_HOST=true
;;
esac
AM_CONDITIONAL(X86_HOST, test x$X86_HOST = xtrue)
AC_ARG_ENABLE(processor,
AS_HELP_STRING([--disable-processor],
[Don't build processor library]
[(default is no)]),
[case "${enableval}" in
yes)
disable_processor=false
;;
no)
disable_processor=true
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --disable-processor)
;;
esac],
[disable_processor=false])
AM_CONDITIONAL(DISABLE_PROCESSOR, test x$disable_processor = xtrue)
AC_ARG_ENABLE(tools,
AS_HELP_STRING([--disable-tools],
[Don't build tool binaries]
[(default is no)]),
[case "${enableval}" in
yes)
disable_tools=false
;;
no)
disable_tools=true
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --disable-tools)
;;
esac],
[disable_tools=false])
AM_CONDITIONAL(DISABLE_TOOLS, test x$disable_tools = xtrue)
if test x$LINUX_HOST = xfalse -a x$disable_processor = xtrue -a x$disable_tools = xtrue; then
AC_MSG_ERROR([--disable-processor and --disable-tools were specified, and not building for Linux. Nothing to build!])
fi
AC_ARG_ENABLE(system-test-libs,
AS_HELP_STRING([--enable-system-test-libs],
[Use gtest/gmock/etc... from the system instead ]
[of the local copies (default is local)]),
[case "${enableval}" in
yes)
system_test_libs=true
;;
no)
system_test_libs=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-system-test-libs)
;;
esac],
[system_test_libs=false])
AM_CONDITIONAL(SYSTEM_TEST_LIBS, test x$system_test_libs = xtrue)
AC_ARG_VAR([GMOCK_CFLAGS], [Compiler flags for gmock])
AC_ARG_VAR([GMOCK_LIBS], [Linker flags for gmock])
AC_ARG_VAR([GTEST_CFLAGS], [Compiler flags for gtest])
AC_ARG_VAR([GTEST_LIBS], [Linker flags for gtest])
if test x$system_test_libs = xtrue; then
: "${GMOCK_CFLAGS:=-pthread}"
: "${GMOCK_LIBS:=-lgmock -lgtest -pthread -lpthread}"
: "${GTEST_CFLAGS:=-pthread}"
: "${GTEST_LIBS:=-lgtest -pthread -lpthread}"
fi
AC_ARG_ENABLE(selftest,
AS_HELP_STRING([--enable-selftest],
[Run extra tests with "make check" ]
[(may conflict with optimizations) ]
[(default is no)]),
[case "${enableval}" in
yes)
selftest=true
;;
no)
selftest=false
;;
*)
AC_MSG_ERROR(bad value ${enableval} for --enable-selftest)
;;
esac],
[selftest=false])
AM_CONDITIONAL(SELFTEST, test x$selftest = xtrue)
AC_ARG_WITH(rustc-demangle,
AS_HELP_STRING([--with-rustc-demangle=/path/to/rustc-demangle],
[Link against the rustc-demangle library]
[to demangle Rust language symbols during]
[symbol dumping (default is no)]
[Pass the path to the crate root.]),
[case "${withval}" in
yes)
AC_MSG_ERROR(You must pass the path to the rustc-demangle crate for --with-rustc-demangle)
;;
no)
rustc_demangle=false
;;
*)
if ! test -f "${withval}/Cargo.toml"; then
AC_MSG_ERROR(You must pass the path to the rustc-demangle crate for --with-rustc-demangle)
fi
RUSTC_DEMANGLE_CFLAGS="-DHAVE_RUSTC_DEMANGLE -I${withval}/crates/capi/include"
RUSTC_DEMANGLE_LIBS="-L${withval}/target/release -lrustc_demangle -lpthread -ldl"
;;
esac],
[rustc_demangle=false])
AC_ARG_VAR([RUSTC_DEMANGLE_CFLAGS], [Compiler flags for rustc-demangle])
AC_ARG_VAR([RUSTC_DEMANGLE_LIBS], [Linker flags for rustc-demangle])
AC_ARG_WITH(tests-as-root,
AS_HELP_STRING([--with-tests-as-root],
[Run the tests as root. Use this on platforms]
[like travis-ci.org that require root privileges]
[to use ptrace (default is no)]),
[case "${withval}" in
yes)
tests_as_root=true
;;
no)
tests_as_root=false
;;
*)
AC_MSG_ERROR(--with-tests-as-root can only be "yes" or "no")
;;
esac],
[tests_as_root=false])
AM_CONDITIONAL(TESTS_AS_ROOT, test x$tests_as_root = xtrue)
AC_CONFIG_FILES(m4_flatten([
breakpad.pc
breakpad-client.pc
Makefile
]))
AC_OUTPUT

View File

@ -0,0 +1,43 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- AUTOGENERATED BY deps-to-manifest.py; DO NOT EDIT -->
<manifest>
<default revision='refs/heads/main'
remote='chromium'
sync-c='true'
sync-j='8' />
<remote name='github'
fetch='https://github.com/'
review='' />
<remote name='chromium'
fetch='https://chromium.googlesource.com/'
review='https://chromium-review.googlesource.com' />
<project path='src'
name='breakpad/breakpad'
revision='refs/heads/main'
remote='chromium' />
<project path='src/src/tools/gyp'
name='external/gyp/'
revision='324dd166b7c0b39d513026fa52d6280ac6d56770'
remote='chromium' />
<project path='src/src/testing'
name='google/googletest.git'
revision='refs/tags/release-1.11.0'
remote='github' />
<project path='src/src/third_party/lss'
name='linux-syscall-support/'
revision='e1e7b0ad8ee99a875b272c8e33e308472e897660'
remote='chromium' />
<project path='src/src/third_party/protobuf/protobuf'
name='google/protobuf.git'
revision='cb6dd4ef5f82e41e06179dcd57d3b1d9246ad6ac'
remote='github' />
</manifest>

View File

@ -0,0 +1 @@
*

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -0,0 +1,223 @@
# Breakpad Client Libraries
## Objective
The Breakpad client libraries are responsible for monitoring an application for
crashes (exceptions), handling them when they occur by generating a dump, and
providing a means to upload dumps to a crash reporting server. These tasks are
divided between the “handler” (short for “exception handler”) library linked in
to an application being monitored for crashes, and the “sender” library,
intended to be linked in to a separate external program.
## Background
As one of the chief tasks of the client handler is to generate a dump, an
understanding of [dump files](processor_design.md) will aid in understanding the
handler.
## Overview
Breakpad provides client libraries for each of its target platforms. Currently,
these exist for Windows on x86 and Mac OS X on both x86 and PowerPC. A Linux
implementation has been written and is currently under review.
Because the mechanisms for catching exceptions and the methods for obtaining the
information that a dump contains vary between operating systems, each target
operating system requires a completely different handler implementation. Where
multiple CPUs are supported for a single operating system, the handler
implementation will likely also require separate code for each processor type to
extract CPU-specific information. One of the goals of the Breakpad handler is to
provide a prepackaged cross-platform system that masks many of these
system-level differences and quirks from the application developer. Although the
underlying implementations differ, the handler library for each system follows
the same set of principles and exposes a similar interface.
Code that wishes to take advantage of Breakpad should be linked against the
handler library, and should, at an appropriate time, install a Breakpad handler.
For applications, it is generally desirable to install the handler as early in
the start-up process as possible. Developers of library code using Breakpad to
monitor itself may wish to install a Breakpad handler when the library is
loaded, or may only want to install a handler when calls are made in to the
library.
The handler can be triggered to generate a dump either by catching an exception
or at the request of the application itself. The latter case may be useful in
debugging assertions or other conditions where developers want to know how a
program got in to a specific non-crash state. After generating a dump, the
handler calls a user-specified callback function. The callback function may
collect additional data about the programs state, quit the program, launch a
crash reporter application, or perform other tasks. Allowing for this
functionality to be dictated by a callback function preserves flexibility.
The sender library is also has a separate implementation for each supported
platform, because of the varying interfaces for accessing network resources on
different operating systems. The sender transmits a dump along with other
application-defined information to a crash report server via HTTP. Because dumps
may contain sensitive data, the sender allows for the use of HTTPS.
The canonical example of the entire client system would be for a monitored
application to link against the handler library, install a Breakpad handler from
its main function, and provide a callback to launch a small crash reporter
program. The crash reporter program would be linked against the sender library,
and would send the crash dump when launched. A separate process is recommended
for this function because of the unreliability inherent in doing any significant
amount of work from a crashed process.
## Detailed Design
### Exception Handler Installation
The mechanisms for installing an exception handler vary between operating
systems. On Windows, its a relatively simple matter of making one call to
register a [top-level exception
filter](http://msdn.microsoft.com/library/en-us/debug/base/setunhandledexceptionfilter.asp)
callback function. On most Unix-like systems such as Linux, processes are
informed of exceptions by the delivery of a signal, so an exception handler
takes the form of a signal handler. The native mechanism to catch exceptions on
Mac OS X requires a large amount of code to set up a Mach port, identify it as
the exception port, and assign a thread to listen for an exception on that port.
Just as the preparation of exception handlers differ, the manner in which they
are called differs as well. On Windows and most Unix-like systems, the handler
is called on the thread that caused the exception. On Mac OS X, the thread
listening to the exception port is notified that an exception has occurred. The
different implementations of the Breakpad handler libraries perform these tasks
in the appropriate ways on each platform, while exposing a similar interface on
each.
A Breakpad handler is embodied in an `ExceptionHandler` object. Because its a
C++ object, `ExceptionHandler`s may be created as local variables, allowing them
to be installed and removed as functions are called and return. This provides
one possible way for a developer to monitor only a portion of an application for
crashes.
### Exception Basics
Once an application encounters an exception, it is in an indeterminate and
possibly hazardous state. Consequently, any code that runs after an exception
occurs must take extreme care to avoid performing operations that might fail,
hang, or cause additional exceptions. This task is not at all straightforward,
and the Breakpad handler library seeks to do it properly, accounting for all of
the minute details while allowing other application developers, even those with
little systems programming experience, to reap the benefits. All of the Breakpad
handler code that executes after an exception occurs has been written according
to the following guidelines for safety at exception time:
* Use of the application heap is forbidden. The heap may be corrupt or
otherwise unusable, and allocators may not function.
* Resource allocation must be severely limited. The handler may create a new
file to contain the dump, and it may attempt to launch a process to continue
handling the crash.
* Execution on the thread that caused the exception is significantly limited.
The only code permitted to execute on this thread is the code necessary to
transition handling to a dedicated preallocated handler thread, and the code
to return from the exception handler.
* Handlers shouldnt handle crashes by attempting to walk stacks themselves,
as stacks may be in inconsistent states. Dump generation should be performed
by interfacing with the operating systems memory manager and code module
manager.
* Library code, including runtime library code, must be avoided unless it
provably meets the above guidelines. For example, this means that the STL
string class may not be used, because it performs operations that attempt to
allocate and use heap memory. It also means that many C runtime functions
must be avoided, particularly on Windows, because of heap operations that
they may perform.
A dedicated handler thread is used to preserve the state of the exception thread
when an exception occurs: during dump generation, it is difficult if not
impossible for a thread to accurately capture its own state. Performing all
exception-handling functions on a separate thread is also critical when handling
stack-limit-exceeded exceptions. It would be hazardous to run out of stack space
while attempting to handle an exception. Because of the rule against allocating
resources at exception time, the Breakpad handler library creates its handler
thread when it installs its exception handler. On Mac OS X, this handler thread
is created during the normal setup of the exception handler, and the handler
thread will be signaled directly in the event of an exception. On Windows and
Linux, the handler thread is signaled by a small amount of code that executes on
the exception thread. Because the code that executes on the exception thread in
this case is small and safe, this does not pose a problem. Even when an
exception is caused by exceeding stack size limits, this code is sufficiently
compact to execute entirely within the stacks guard page without causing an
exception.
The handler thread may also be triggered directly by a user call, even when no
exception occurs, to allow dumps to be generated at any point deemed
interesting.
### Filter Callback
When the handler thread begins handling an exception, it calls an optional
user-defined filter callback function, which is responsible for judging whether
Breakpads handler should continue handling the exception or not. This mechanism
is provided for the benefit of library or plug-in code, whose developers may not
be interested in reports of crashes that occur outside of their modules but
within processes hosting their code. If the filter callback indicates that it is
not interested in the exception, the Breakpad handler arranges for it to be
delivered to any previously-installed handler.
### Dump Generation
Assuming that the filter callback approves (or does not exist), the handler
writes a dump in a directory specified by the application developer when the
handler was installed, using a previously generated unique identifier to avoid
name collisions. The mechanics of dump generation also vary between platforms,
but in general, the process involves enumerating each thread of execution, and
capturing its state, including processor context and the active portion of its
stack area. The dump also includes a list of the code modules loaded in to the
application, and an indicator of which thread generated the exception or
requested the dump. In order to avoid allocating memory during this process, the
dump is written in place on disk.
### Post-Dump Behavior
Upon completion of writing the dump, a second callback function is called. This
callback may be used to launch a separate crash reporting program or to collect
additional data from the application. The callback may also be used to influence
whether Breakpad will treat the exception as handled or unhandled. Even after a
dump is successfully generated, Breakpad can be made to behave as though it
didnt actually handle an exception. This function may be useful for developers
who want to test their applications with Breakpad enabled but still retain the
ability to use traditional debugging techniques. It also allows a
Breakpad-enabled application to coexist with a platforms native crash reporting
system, such as Mac OS X [CrashReporter](http://developer.apple.com/technotes/tn2004/tn2123.html)
and [Windows Error Reporting](http://msdn.microsoft.com/isv/resources/wer/).
Typically, when Breakpad handles an exception fully and no debuggers are
involved, the crashed process will terminate.
Authors of both callback functions that execute within a Breakpad handler are
cautioned that their code will be run at exception time, and that as a result,
they should observe the same programming practices that the Breakpad handler
itself adheres to. Notably, if a callback is to be used to collect additional
data from an application, it should take care to read only “safe” data. This
might involve accessing only static memory locations that are updated
periodically during the course of normal program execution.
### Sender Library
The Breakpad sender library provides a single function to send a crash report to
a crash server. It accepts a crash servers URL, a map of key-value parameters
that will accompany the dump, and the path to a dump file itself. Each of the
key-value parameters and the dump file are sent as distinct parts of a multipart
HTTP POST request to the specified URL using the platforms native HTTP
facilities. On Linux, [libcurl](http://curl.haxx.se/) is used for this function,
as it is the closest thing to a standard HTTP library available on that
platform.
## Future Plans
Although weve had great success with in-process dump generation by following
our guidelines for safe code at exception time, we are exploring options for
allowing dumps to be generated in a separate process, to further enhance the
handler librarys robustness.
On Windows, we intend to offer tools to make it easier for Breakpads settings
to be managed by the native group policy management system.
We also plan to offer tools that many developers would find desirable in the
context of handling crashes, such as a mechanism to determine at launch if the
program last terminated in a crash, and a way to calculate “crashiness” in terms
of crashes over time or the number of application launches between crashes.
We are also investigating methods to capture crashes that occur early in an
applications launch sequence, including crashes that occur before a programs
main function begins executing.

View File

@ -0,0 +1,35 @@
# Introduction
Thanks for thinking of contributing to Breakpad! Unfortunately there are some
pesky legal issues to get out of the way, but they're quick and painless.
## Legal
If you're doing work individually, not as part of any employment, you'll need to
sign the <a
href='http://code.google.com/legal/individual-cla-v1.0.html'>Individual
Contributor License Agreement</a>. This agreement can be completed
electronically.
If you're contributing to Breakpad as part of your employment with another
organization, you'll need to sign a <a
href='http://code.google.com/legal/corporate-cla-v1.0.html'> Corporate
Contributor License Agreement</a>. Once completed this document will need to be
faxed.
**_IMPORTANT_**: The authors(you!) of the contributions will maintain all
copyrights; the agreements you sign will grant rights to Google to use your
work.
Thanks, and if you have any questions let me know and I'll loop in the legal guy
here to get you an answer.
## Technical
Once you have signed the agreement you can be added to our contributors list and
have write access to code. For full details on getting started see our trunk
`README`.
## List of people who have signed contributor agreements
None so far.

View File

@ -0,0 +1,128 @@
The goal of this document is to give an overview of the exception handling
options in breakpad.
# Basics
Exception handling is a mechanism designed to handle the occurrence of
exceptions, special conditions that change the normal flow of program execution.
`SetUnhandledExceptionFilter` replaces all unhandled exceptions when Breakpad is
enabled. TODO: More on first and second change and vectored v. try/catch.
There are two main types of exceptions across all platforms: in-process and
out-of-process.
# In-Process
In process exception handling is relatively simple since the crashing process
handles crash reporting. It is generally considered unsafe to write a minidump
from a crashed process. For example, key data structures could be corrupted or
the stack on which the exception handler runs could have been overwritten. For
this reason all platforms also support some level of out-of-process exception
handling.
## Windows
In-process exception handling Breakpad creates a 'handler head' that waits
infinitely on a semaphore at start up. When this thread is woken it writes the
minidump and signals to the excepting thread that it may continue. A filter will
tell the OS to kill the process if the minidump is written successfully.
Otherwise it continues.
# Out-of-Process
Out-of-process exception handling is more complicated than in-process exception
handling because of the need to set up a separate process that can read the
state of the crashing process.
## Windows
Breakpad uses two abstractions around the exception handler to make things work:
`CrashGenerationServer` and `CrashGenerationClient`. The constructor for these
takes a named pipe name.
During server start up a named pipe and registers callbacks for client
connections are created. The named pipe is used for registration and all IO on
the pipe is done asynchronously. `OnPipeConnected` is called when a client
attempts to connect (call `CreateFile` on the pipe). `OnPipeConnected` does the
state machine transition from `Initial` to `Connecting` and on through
`Reading`, `Reading_Done`, `Writing`, `Writing_Done`, `Reading_ACK`, and
`Disconnecting`.
When registering callbacks, the client passes in two pointers to pointers: 1. A
pointer to the `EXCEPTION_INFO` pointer 1. A pointer to the `MDRawAssertionInfo`
which handles various non-exception failures like assertions
The essence of registration is adding a "`ClientInfo`" object that contains
handles used for synchronization with the crashing process to an array
maintained by the server. This is how we can keep track of all the clients on
the system that have registered for minidumps. These handles are: *
`server_died(mutex)` * `dump_requested(Event)` * `dump_generated(Event)`
The server registers asynchronous waits on these events with the `ClientInfo`
object as the callback context. When the `dump_requested` event is set by the
client, the `OnDumpRequested()` callback is called. The server uses the handles
inside `ClientInfo` to communicate with the child process. Once the child sets
the event, it waits for two objects: 1. the `dump_generated` event 1. the
`server_died` mutex
In the end handles are "duped" into the client process, and the clients use
`SetEvent` to request events, wait on the other event, or the `server_died`
mutex.
## Linux
### Current Status
As of July 2011, Linux had a minidump generator that is not entirely
out-of-process. The minidump was generated from a separate process, but one that
shared an address space, file descriptors, signal handles and much else with the
crashing process. It worked by using the `clone()` system call to duplicate the
crashing process, and then uses `ptrace()` and the `/proc` file system to
retrieve the information required to write the minidump. Since then Breakpad has
updated Linux exception handling to provide more benefits of out-of-process
report generation.
### Proposed Design
#### Overview
Breakpad would use a per-user daemon to write out a minidump that does not have,
interact with or depend on the crashing process. We don't want to start a new
separate process every time a user launches a Breakpad-enabled process. Doing
one daemon per machine is unacceptable for security concerns around one user
being able to initiate a minidump generation for another user's process.
#### Client/Server Communication
On Breakpad initialization in a process, the initializer would check if the
daemon is running and, if not, start it. The race condition between the check
and the initialization is not a problem because multiple daemons can check if
the IPC endpoint already exists and if a server is listening. Even if multiple
copies of the daemon try to `bind()` the filesystem to name the socket, all but
one will fail and can terminate.
This point is relevant for error handling conditions. Linux does not clean the
file system representation of a UNIX domain socket even if both endpoints
terminate, so checking for existence is not strong enough. However checking the
process list or sending a ping on the socket can handle this.
Breakpad uses UNIX domain sockets since they support full duplex communication
(unlike Windows, named pipes on Linux are half) and the kernal automatically
creates a private channel between the client and server once the client calls
`connect()`.
#### Minidump Generation
Breakpad could use the current system with `ptrace()` and `/proc` within the
daemon executable.
Overall the operations look like: 1. Signal from OS indicating crash 1. Signal
Handler suspends all threads except itself 1. Signal Handler sends
`CRASH_DUMP_REQUEST` message to server and waits for response 1. Server inspects
1. Minidump is asynchronously written to disk by the server 1. Server responds
indicating inspection is done
## Mac OSX
Out-of-process exception handling is fully supported on Mac.

View File

@ -0,0 +1,115 @@
# Introduction
Breakpad is a library and tool suite that allows you to distribute an
application to users with compiler-provided debugging information removed,
record crashes in compact "minidump" files, send them back to your server, and
produce C and C++ stack traces from these minidumps. Breakpad can also write
minidumps on request for programs that have not crashed.
Breakpad is currently used by Google Chrome, Firefox, Google Picasa, Camino,
Google Earth, and other projects.
![Workflow](breakpad.png)
Breakpad has three main components:
* The **client** is a library that you include in your application. It can
write minidump files capturing the current threads' state and the identities
of the currently loaded executable and shared libraries. You can configure
the client to write a minidump when a crash occurs, or when explicitly
requested.
* The **symbol dumper** is a program that reads the debugging information
produced by the compiler and produces a **symbol file**, in [Breakpad's own
format](symbol_files.md).
* The **processor** is a program that reads a minidump file, finds the
appropriate symbol files for the versions of the executables and shared
libraries the minidump mentions, and produces a human-readable C/C++ stack
trace.
# The minidump file format
The minidump file format is similar to core files but was developed by Microsoft
for its crash-uploading facility. A minidump file contains:
* A list of the executable and shared libraries that were loaded in the
process at the time the dump was created. This list includes both file names
and identifiers for the particular versions of those files that were loaded.
* A list of threads present in the process. For each thread, the minidump
includes the state of the processor registers, and the contents of the
threads' stack memory. These data are uninterpreted byte streams, as the
Breakpad client generally has no debugging information available to produce
function names or line numbers, or even identify stack frame boundaries.
* Other information about the system on which the dump was collected:
processor and operating system versions, the reason for the dump, and so on.
Breakpad uses Windows minidump files on all platforms, instead of the
traditional core files, for several reasons:
* Core files can be very large, making them impractical to send across a
network to the collector for processing. Minidumps are smaller, as they were
designed to be used this way.
* The core file format is poorly documented. For example, the Linux Standards
Base does not describe how registers are stored in `PT_NOTE` segments.
* It is harder to persuade a Windows machine to produce a core dump file than
it is to persuade other machines to write a minidump file.
* It simplifies the Breakpad processor to support only one file format.
# Overview/Life of a minidump
A minidump is generated via calls into the Breakpad library. By default,
initializing Breakpad installs an exception/signal handler that writes a
minidump to disk at exception time. On Windows, this is done via
`SetUnhandledExceptionFilter()`; on OS X, this is done by creating a thread that
waits on the Mach exception port; and on Linux, this is done by installing a
signal handler for various exceptions like `SIGILL, SIGSEGV` etc.
Once the minidump is generated, each platform has a slightly different way of
uploading the crash dump. On Windows & Linux, a separate library of functions is
provided that can be called into to do the upload. On OS X, a separate process
is spawned that prompts the user for permission, if configured to do so, and
sends the file.
# Terminology
**In-process vs. out-of-process exception handling** - it's generally considered
that writing the minidump from within the crashed process is unsafe - key
process data structures could be corrupted, or the stack on which the exception
handler runs could have been overwritten, etc. All 3 platforms support what's
known as "out-of-process" exception handling.
# Integration overview
## Breakpad Code Overview
All the client-side code is found by visiting the Google Project at
https://chromium.googlesource.com/breakpad/breakpad. The following directory structure is
present in the `src` directory:
* `processor` Contains minidump-processing code that is used on the server
side and isn't of use on the client side
* `client` Contains client minidump-generation libraries for all platforms
* `tools` Contains source code & projects for building various tools on each
platform.
(Among other directories)
* [Windows Integration Guide](windows_client_integration.md)
* [Mac Integration Guide](mac_breakpad_starter_guide.md)
* [Linux Integration Guide](linux_starter_guide.md)
## Build process specifics(symbol generation)
This applies to all platforms. Inside `src/tools/{platform}/dump_syms` is a tool
that can read debugging information for each platform (e.g. for OS X/Linux,
DWARF and STABS, and for Windows, PDB files) and generate a Breakpad symbol
file. This tool should be run on your binary before it's stripped(in the case of
OS X/Linux) and the symbol files need to be stored somewhere that the minidump
processor can find. There is another tool, `symupload`, that can be used to
upload symbol files if you have written a server that can accept them.

View File

@ -0,0 +1,39 @@
# How To Use Breakpad As a Coredump Handler on Linux
This document presents a way to use Breakpad in order to generate
minidumps system wide on Linux.
Please refer to [Linux starter guide](./linux_starter_guide.md) if
instead you want to integrate breakpad into your application.
## Motivation
When working on an embedded system, disk and memory space is often
limited and when a process crashes it must be restarted as soon as
possible. Sometime saving a full coredump takes to much time or
consumes too much space.
## Breakpad Core Handler
In such case the program `core_handler` can be use to generate
minidumps instead of coredumps. `core_handler` reads the firsts
sections of the coredump (where the various threads are described)
generated by Linux from the standard input and then directly reads
`/proc/<pid>/mem` to reconstruct the stacktraces.
One can test it with:
```
# echo "|/usr/libexec/core_handler %P /var/lib/minidump/%e-%i.md" >
/proc/sys/kernel/core_pattern
# echo 1 > /proc/sys/kernel/core_pipe_limit
```
Be aware that a real world integration would likely require further
customization and so `core_handler` can be wrapped into a script (for
example to change the permission of the minidump file or to signal the
presence of the minidump to another service).
Please refer to
[core(5)](https://man7.org/linux/man-pages/man5/core.5.html) for more
details.

View File

@ -0,0 +1,110 @@
# How To Add Breakpad To Your Linux Application
This document is an overview of using the Breakpad client libraries on Linux.
## Building the Breakpad libraries
Breakpad provides an Autotools build system that will build both the Linux
client libraries and the processor libraries. Running `./configure && make` in
the Breakpad source directory will produce
**src/client/linux/libbreakpad\_client.a**, which contains all the code
necessary to produce minidumps from an application.
## Integrating Breakpad into your Application
First, configure your build process to link **libbreakpad\_client.a** into your
binary, and set your include paths to include the **src** directory in the
**google-breakpad** source tree. Next, include the exception handler header:
```cpp
#include "client/linux/handler/exception_handler.h"
```
Now you can instantiate an `ExceptionHandler` object. Exception handling is active for the lifetime of the `ExceptionHandler` object, so you should instantiate it as early as possible in your application's startup process, and keep it alive for as close to shutdown as possible. To do anything useful, the `ExceptionHandler` constructor requires a path where it can write minidumps, as well as a callback function to receive information about minidumps that were written:
```cpp
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context, bool succeeded) {
printf("Dump path: %s\n", descriptor.path());
return succeeded;
}
void crash() { volatile int* a = (int*)(NULL); *a = 1; }
int main(int argc, char* argv[]) {
google_breakpad::MinidumpDescriptor descriptor("/tmp");
google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
crash();
return 0;
}
```
Compiling and running this example should produce a minidump file in /tmp, and
it should print the minidump filename before exiting. You can read more about
the other parameters to the `ExceptionHandler` constructor [in the exception_handler.h source file][1].
[1]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/client/linux/handler/exception_handler.h
**Note**: You should do as little work as possible in the callback function.
Your application is in an unsafe state. It may not be safe to allocate memory or
call functions from other shared libraries. The safest thing to do is `fork` and
`exec` a new process to do any work you need to do. If you must do some work in
the callback, the Breakpad source contains [some simple reimplementations of libc functions][2], to avoid calling directly into
libc, as well as [a header file for making Linux system calls][3] (in **src/third\_party/lss**) to avoid calling into other shared libraries.
[2]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/common/linux/linux_libc_support.h
[3]: https://chromium.googlesource.com/linux-syscall-support/+/master
## Sending the minidump file
In a real application, you would want to handle the minidump in some way, likely
by sending it to a server for analysis. The Breakpad source tree contains [some
HTTP upload source][4] that you might find useful, as well as [a minidump upload tool][5].
[4]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/common/linux/http_upload.h
[5]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/tools/linux/symupload/minidump_upload.cc
## Producing symbols for your application
To produce useful stack traces, Breakpad requires you to convert the debugging
symbols in your binaries to [text-format symbol files][6]. First, ensure that you've compiled your binaries with `-g` to
include debugging symbols. Next, compile the `dump_syms` tool by running
`configure && make` in the Breakpad source directory. Next, run `dump_syms` on
your binaries to produce the text-format symbols. For example, if your main
binary was named `test`:
[6]: https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/symbol_files.md
```
$ google-breakpad/src/tools/linux/dump_syms/dump_syms ./test > test.sym
```
In order to use these symbols with the `minidump_stackwalk` tool, you will need
to place them in a specific directory structure. The first line of the symbol
file contains the information you need to produce this directory structure, for
example (your output will vary):
```
$ head -n1 test.sym MODULE Linux x86_64 6EDC6ACDB282125843FD59DA9C81BD830 test
$ mkdir -p ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
$ mv test.sym ./symbols/test/6EDC6ACDB282125843FD59DA9C81BD830
```
You may also find the [symbolstore.py][7] script in the Mozilla repository useful, as it encapsulates these steps.
[7]: https://dxr.mozilla.org/mozilla-central/source/toolkit/crashreporter/tools/symbolstore.py
## Processing the minidump to produce a stack trace
Breakpad includes a tool called `minidump_stackwalk` which can take a minidump
plus its corresponding text-format symbols and produce a symbolized stacktrace.
It should be in the **google-breakpad/src/processor** directory if you compiled
the Breakpad source using the directions above. Simply pass it the minidump and
the symbol path as commandline parameters:
```
$ google-breakpad/src/processor/minidump_stackwalk minidump.dmp ./symbols
```
It produces verbose output on stderr, and the stacktrace on stdout, so you may
want to redirect stderr.

View File

@ -0,0 +1,47 @@
# Introduction
Linux implements its userland-to-kernel transition using a special library
called linux-gate.so that is mapped by the kernel into every process. For more
information, see
http://www.trilithium.com/johan/2005/08/linux-gate/
In a nutshell, the problem is that the system call gate function,
kernel\_vsyscall does not use EBP to point to the frame pointer.
However, the Breakpad processor supports special frames like this via STACK
lines in the symbol file. If you look in src/client/linux/data you will see
symbol files for linux-gate.so for both Intel & AMD(the implementation of
kernel\_vsyscall changes depending on the CPU manufacturer). When processing
minidumps from Linux 2.6, having these symbol files is necessary for walking the
stack for crashes that happen while a thread is in a system call.
If you're just interested in processing minidumps, those two symbol files should
be all you need!
# Details
The particular details of understanding the linux-gate.so symbol files can be
found by reading about STACK lines inside
src/common/windows/pdb\_source\_line\_writer.cc, and the above link. To
summarize briefly, we just have to inform the processor how to get to the
previous frame when the EIP is inside kernel\_vsyscall, and we do that by
telling the processor how many bytes kernel\_vsyscall has pushed onto the stack
in it's prologue. For example, one of the symbol files looks somewhat like the
following:
MODULE Linux x86 random\_debug\_id linux-gate.so PUBLIC 400 0 kernel\_vsyscall
STACK WIN 4 100 1 1 0 0 0 0 0 1
The PUBLIC line indicates that kernel\_vsyscall is at offset 400 (in bytes) from
the beginning of linux-gate.so. The STACK line indicates the size of the
function(100), how many bytes it pushes(1), and how many bytes it pops(1). The
last 1 indicates that EBP is pushed onto the stack before being used by the
function.
# Warnings
These functions might change significantly depending on kernel version. In my
opinion, the actual function stack information is unlikely to change frequently,
but the Linux kernel might change the address of kernel\_vsyscall w.r.t the
beginning of linux-gate.so, which would cause these symbol files to be invalid.

View File

@ -0,0 +1,184 @@
# How To Add Breakpad To Your Mac Client Application
This document is a step-by-step recipe to get your Mac client app to build with
Breakpad.
## Preparing a binary build of Breakpad for use in your tree
You can either check in a binary build of the Breakpad framework & tools or
build it as a dependency of your project. The former is recommended, and
detailed here, since building dependencies through other projects is
problematic(matching up configuration names), and the Breakpad code doesn't
change nearly often enough as your application's will.
## Building the requisite targets
All directories are relative to the `src` directory of the Breakpad checkout.
* Build the 'All' target of `client/mac/Breakpad.xcodeproj` in Release mode.
* Execute `cp -R client/mac/build/Release/Breakpad.framework <location in your
source tree>`
* Inside `tools/mac/dump_syms` directory, build dump\_syms.xcodeproj, and copy
tools/mac/dump\_syms/build/Release/dump\_syms to a safe location where it
can be run during the build process.
## Adding Breakpad.framework
Inside your application's framework, add the Breakpad.Framework to your
project's framework settings. When you select it from the file chooser, it will
let you pick a target to add it to; go ahead and check the one that's relevant
to your application.
## Copy Breakpad into your Application Package
Copy Breakpad into your Application Package, so it will be around at run time.
Go to the Targets section of your Xcode Project window. Hit the disclosure
triangle to reveal the build phases of your application. Add a new Copy Files
phase using the Contextual menu (Control Click). On the General panel of the new
'Get Info' of this new phase, set the destination to 'Frameworks' Close the
'Info' panel. Use the Contextual Menu to Rename your new phase 'Copy Frameworks'
Now drag Breakpad again into this Copy Frameworks phase. Drag it from whereever
it appears in the project file tree.
## Add a New Run Script build phase
Near the end of the build phases, add a new Run Script build phase. This will be
run before Xcode calls /usr/bin/strip on your project. This is where you'll be
calling dump\_sym to output the symbols for each architecture of your build. In
my case, the relevant lines read:
```
#!/bin/sh
$TOOL_DIR=<location of dump_syms from step 3 above>
"$TOOL_DIR/dump_syms" -a ppc "$PROD" > "$TARGET_NAME ppc.breakpad"
"$TOOL_DIR/dump_syms" -a i386 "$PROD" > "$TARGET_NAME i386.breakpad"
```
## Adjust the Project Settings
* Turn on Separate Strip,
* Set the Strip Style to Non-Global Symbols.
## Write Code!
You'll need to have an object that acts as the delegate for NSApplication.
Inside this object's header, you'll need to add
1. add an ivar for Breakpad and
2. a declaration for the applicationShouldTerminate:(NSApplication`*` sender)
message.
```
#import <Breakpad/Breakpad.h>
@interface BreakpadTest : NSObject {
.
.
.
BreakpadRef breakpad;
.
.
.
}
.
.
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
.
.
@end
```
Inside your object's implementation file,
1. add the following method InitBreakpad
2. modify your awakeFromNib method to look like the one below,
3. modify/add your application's delegate method to look like the one below
```
static BreakpadRef InitBreakpad(void) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
BreakpadRef breakpad = 0;
NSDictionary *plist = [[NSBundle mainBundle] infoDictionary];
if (plist) {
// Note: version 1.0.0.4 of the framework changed the type of the argument
// from CFDictionaryRef to NSDictionary * on the next line:
breakpad = BreakpadCreate(plist);
}
[pool release];
return breakpad;
}
- (void)awakeFromNib {
breakpad = InitBreakpad();
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
BreakpadRelease(breakpad);
return NSTerminateNow;
}
```
## Configure Breakpad
Configure Breakpad for your application.
1. Take a look inside the Breakpad.framework at the Breakpad.h file for the
keys, default values, and descriptions to be passed to BreakpadCreate().
2. Add/Edit the Breakpad specific entries in the dictionary passed to
BreakpadCreate() -- typically your application's info plist.
Example from the Notifier Info.plist:
`<key>BreakpadProduct</key><string>Google_Notifier_Mac</string>
<key>BreakpadProductDisplay</key><string>${PRODUCT_NAME}</string>
`
## Build Your Application
Almost done!
## Verify
Double-check:
Your app should have in its package contents:
myApp.app/Contents/Frameworks/Breakpad.framework.
The symbol files have reasonable contents (you can look at them with a text
editor.)
Look again at the Copy Frameworks phase of your project. Are you leaking .h
files? Select them and delete them. (If you drag a bunch of files into your
project, Xcode often wants to copy your .h files into the build, revealing
Google secrets. Be vigilant!)
## Upload the symbol file
You'll need to configure your build process to store symbols in a location that
is accessible by the minidump processor. There is a tool in tools/mac/symupload
that can be used to send the symbol file via HTTP post.
1. Test
Configure breakpad to send reports to a URL by adding to your app's Info.plist:
```
<key>BreakpadURL</key>
<string>upload URL</string>
<key>BreakpadReportInterval</key>
<string>30</string>
```
## Final Notes
Breakpad checks whether it is being run under a debugger, and if so, normally
does nothing. But, you can force Breakpad to function under a debugger by
setting the Unix shell variable BREAKPAD\_IGNORE\_DEBUGGER to a non-zero value.
You can bracket the source code in the above Write The Code step with #if DEBUG
to completely eliminate it from Debug builds. See
//depot/googlemac/GoogleNotifier/main.m for an example. FYI, when your process
forks(), exception handlers are reset to the default for child processes. So
they must reinitialize Breakpad, otherwise exceptions will be handled by Apple's
Crash Reporter.

View File

@ -0,0 +1,82 @@
# Breakpad Crash Reporting for Mozilla
* January 24, 2007
* Links updated February 14, 2007
* Mozilla HQ
* Mark Mentovai
* Brian Ryner
## What is a crash reporter?
* Enables developers to analyze crashes that occur in the wild
* Produces stack backtraces that help identify how a program failed
* Offers higher-level data aggregation (topcrashes, MTBF statistics)
## Motivation
* Talkback is proprietary and unmaintained
* Smaller open-source projects have few options
* Larger projects need flexibility and scalability
## Design Options
* Stackwalking done on client
* Apple CrashReporter
* GNOME BugBuddy
* Client sends memory dump
* Talkback
* Windows Error Reporting
* Breakpad
## Goals
* Provide libraries around which systems can be based
* Open-source
* Cross-platform
* Mac OS X x86, PowerPC
* Linux x86
* Windows x86
* No requirement to distribute symbols
## Client Libraries
* Exception handler installed at application startup
* Spawns a separate thread
* Minidump file written at crash time
* Format used by Windows debuggers
* Separate application invoked to send
* HTTP[S](S.md) POST, can include additional parameters
## Symbols
* Cross-platform symbol file format
* Contents
* Function names
* Source file names and line numbers
* Windows: Frame pointer omission data
* Future: parameters and local variables
* Symbol conversion methods
## Processor
* Examines minidump file and invokes stackwalker
* Symbol files requested from a SymbolSupplier
* Produces stack trace
* Output may be placed where convenient
## Intergation
* Breakpad client present in Gran Paradiso Alpha 1 for Windows
* Disabled by default
* Enable with `MOZ_AIRBAG`
* Proof-of-concept collector
* http://mavra.perilith.com/~luser/airbag-collector/list.pl
* Other platforms coming soon
## More Information
* Project home: https://chromium.googlesource.com/breakpad/breakpad
* Mailing lists
* [google-breakpad-dev@googlegroups.com](http://groups.google.com/group/google-breakpad-dev/)
* [google-breakpad-discuss@googlegroups.com](http://groups.google.com/group/google-breakpad-discuss/)
* Ask me (irc.mozilla.org: mento)

View File

@ -0,0 +1,231 @@
# Breakpad Processor Library
## Objective
The Breakpad processor library is an open-source framework to access the the
information contained within crash dumps for multiple platforms, and to use that
information to produce stack traces showing the call chain of each thread in a
process. After processing, this data is made available to users of the library.
## Background
The Breakpad processor is intended to sit at the core of a comprehensive
crash-reporting system that does not require debugging information to be
provided to those running applications being monitored. Some existing
crash-reporting systems, such as [GNOME](http://www.gnome.org/)s Bug-Buddy and
[Apple](http://www.apple.com/)s
[CrashReporter](http://developer.apple.com/technotes/tn2004/tn2123.html),
require symbolic
information to be present on the end users computer; in the case of
CrashReporter, the reports are transmitted only to Apple, not to third-party
developers. Other systems, such as [Microsoft](http://www.microsoft.com/)s
[Windows Error Reporting](http://msdn.microsoft.com/isv/resources/wer/) and
SupportSofts Talkback, transmit only a snapshot of a crashed process state,
which can later be combined with symbolic debugging information without the need
for it to be present on end users computers. Because symbolic debugging
information consumes a large amount of space and is otherwise not needed during
the normal operation of software, and because some developers are reluctant to
release debugging symbols to their customers, Breakpad follows the latter
approach.
We know of no currently-maintained crash-reporting systems that meet our
requirements, which are to: * allow for symbols to be separate from the
application, * handle crash reports from multiple platforms, * allow developers
to operate their own crash-reporting platform, and to * be open-source. Windows
Error Reporting only functions for Microsoft products, and requires the
involvement of Microsofts servers. Talkback, while cross-platform, has not been
maintained and at this point does not support Mac OS X on x86, which we consider
to be a significant platform. Talkback is also closed-source commercial
software, and has very specific requirements for its server platform.
We are aware of Windows-only crash-reporting systems that leverage Microsofts
debugging interfaces. Such systems, even if extended to support dumps from other
platforms, are tied to using Windows for at least a portion of the processor
platform.
## Overview
The Breakpad processor itself is written in standard C++ and will work on a
variety of platforms. The dumps it accepts may also have been created on a
variety of systems. The library is able to combine dumps with symbolic debugging
information to create stack traces that include function signatures. The
processor library includes simple command-line tools to examine dumps and
process them, producing stack traces. It also exposes several layers of APIs
enabling crash-reporting systems to be built around the Breakpad processor.
## Detailed Design
### Dump Files
In the processor, the dump data is of primary significance. Dumps typically
contain:
* CPU context (register data) as it was at the time the crash occurred, and an
indication of which thread caused the crash. General-purpose registers are
included, as are special-purpose registers such as the instruction pointer
(program counter).
* Information about each thread of execution within a crashed process,
including:
* The memory region used for each threads stack.
* CPU context for each thread, which for various reasons is not the same
as the crash context in the case of the crashed thread.
* A list of loaded code segments (or modules), including:
* The name of the file (`.so`, `.exe`, `.dll`, etc.) which provides the
code.
* The boundaries of the memory region in which the code segment is visible
to the process.
* A reference to the debugging information for the code module, when such
information is available.
Ordinarily, dumps are produced as a result of a crash, but other triggers may be
set to produce dumps at any time a developer deems appropriate. The Breakpad
processor can handle dumps in the minidump format, either generated by an
[Breakpad client “handler”](client_design.md) implementation, or by another
implementation that produces dumps in this format. The
[DbgHelp.dll!MiniDumpWriteDump](http://msdn2.microsoft.com/en-us/library/ms680360.aspx)
function on Windows
produces dumps in this format, and is the basis for the Breakpad handler
implementation on that platform.
The [minidump format](http://msdn.microsoft.com/en-us/library/ms679293%28VS.85%29.aspx) is
essentially a simple container format, organized as a series of streams. Each
stream contains some type of data relevant to the crash. A typical “normal”
minidump contains streams for the thread list, the module list, the CPU context
at the time of the crash, and various bits of additional system information.
Other types of minidump can be generated, such as a full-memory minidump, which
in addition to stack memory contains snapshots of all of a process mapped
memory regions.
The minidump format was chosen as Breakpads dump format because it has an
established track record on Windows, and it can be adapted to meet the needs of
the other platforms that Breakpad supports. Most other operating systems use
“core” files as their native dump formats, but the capabilities of core files
vary across platforms, and because core files are usually presented in a
platforms native executable format, there are complications involved in
accessing the data contained therein without the benefit of the header files
that define an executable formats entire structure. Because minidumps are
leaner than a typical executable format, a redefinition of the format in a
cross-platform header file, `minidump_format.h`, was a straightforward task.
Similarly, the capabilities of the minidump format are understood, and because
it provides an extensible container, any of Breakpads needs that could not be
met directly by the standard minidump format could likely be met by extending it
as needed. Finally, using this format means that the dump file is compatible
with native debugging tools at least on Windows. A possible future avenue for
exploration is the conversion of minidumps to core files, to enable this same
benefit on other platforms.
We have already provided an extension to the minidump format that allows it to
carry dumps generated on systems with PowerPC processors. The format already
allows for variable CPUs, so our work in this area was limited to defining a
context structure sufficient to represent the execution state of a PowerPC. We
have also defined an extension that allows minidumps to indicate which thread of
execution requested a dump be produced for non-crash dumps.
Often, the information contained within a dump alone is sufficient to produce a
full stack backtrace for each thread. Certain optimizations that compilers
employ in producing code frustrate this process. Specifically, the “frame
pointer omission” optimization of x86 compilers can make it impossible to
produce useful stack traces given only a stack snapshot and CPU context. In
these cases, however, compiler-emitted debugging information can aid in
producing useful stack traces. The Breakpad processor is able to take advantage
of this debugging information as supplied by Microsofts C/C++ compiler, the
only compiler to apply such optimizations by default. As a result, the Breakpad
processor can produce useful stack traces even from code with frame pointer
omission optimizations as produced by this compiler.
### Symbol Files
The [symbol files](symbol_files.md) that the Breakpad processor accepts allow
for frame pointer omission data, but this is only one of their capabilities.
Each symbol file also includes information about the functions, source files,
and source code line numbers for a single module of code. A module is an
individually-loadble chunk of code: these can be executables containing a main
program (`exe` files on Windows) or shared libraries (`.so` files on Linux,
`.dylib` files, frameworks, and bundles on Mac OS X, and `.dll` files on
Windows). Dumps contain information about which of these modules were loaded at
the time the dump was produced, and given this information, the Breakpad
processor attempts to locate debugging symbols for the module through a
user-supplied function embodied in a “symbol supplier.” Breakpad includes a
sample symbol supplier, called `SimpleSymbolSupplier`, that is used by its
command-line tools; this supplier locates symbol files by pathname.
`SimpleSymbolSupplier` is also available to other users of the Breakpad
processor library. This allows for the use of a simple reference implementation,
but preserves flexibility for users who may have more demanding symbol file
storage needs.
Breakpads symbol file format is text-based, and was defined to be fairly
human-readable and to encompass the needs of multiple platforms. The Breakpad
processor itself does not operate directly with native symbol formats
([DWARF](http://dwarf.freestandards.org/) and
[STABS](http://sourceware.org/gdb/current/onlinedocs/stabs.html)
on most Unix-like systems,
[.pdb files](http://msdn2.microsoft.com/en-us/library/yd4f8bd1(VS.80).aspx)
on Windows),
because of the complications in accessing potentially complex symbol formats
with slight variations between platforms, stored within different types of
binary formats. In the case of `.pdb` files, the debugging format is not even
documented. Instead, Breakpads symbol files are produced on each platform,
using specific debugging APIs where available, to convert native symbols to
Breakpads cross-platform format.
### Processing
Most commonly, a developer will enable an application to use Breakpad by
building it with a platform-specific [client “handler”](client_design.md)
library. After building the application, the developer will create symbol files
for Breakpads use using the included `dump_syms` or `symupload` tools, or
another suitable tool, and place the symbol files where the processors symbol
supplier will be able to locate them.
When a dump file is given to the processors `MinidumpProcessor` class, it will
read it using its included minidump reader, contained in the `Minidump` family
of classes. It will collect information about the operating system and CPU that
produced the dump, and determine whether the dump was produced as a result of a
crash or at the direct request of the application itself. It then loops over all
of the threads in a process, attempting to walk the stack associated with each
thread. This process is achieved by the processors `Stackwalker` components, of
which there are a slightly different implementations for each CPU type that the
processor is able to handle dumps from. Beginning with a threads context, and
possibly using debugging data, the stackwalker produces a list of stack frames,
containing each instruction executed in the chain. These instructions are
matched up with the modules that contributed them to a process, and the
`SymbolSupplier` is invoked to locate a symbol file. The symbol file is given to
a `SourceLineResolver`, which matches the instruction up with a specific
function name, source file, and line number, resulting in a representation of a
stack frame that can easily be used to identify which code was executing.
The results of processing are made available in a `ProcessState` object, which
contains a vector of threads, each containing a vector of stack frames.
For small-scale use of the Breakpad processor, and for testing and debugging,
the `minidump_stackwalk` tool is provided. It invokes the processor and displays
the full results of processing, optionally allowing symbols to be provided to
the processor by a pathname-based symbol supplier, `SimpleSymbolSupplier`.
For lower-level testing and debugging, the processor library also includes a
`minidump_dump` tool, which walks through an entire minidump file and displays
its contents in somewhat readable form.
### Platform Support
The Breakpad processor library is able to process dumps produced on Mac OS X
systems running on x86, x86-64, and PowerPC processors, on Windows and Linux
systems running on x86 or x86-64 processors, and on Android systems running ARM
or x86 processors. The processor library itself is written in standard C++, and
should function properly in most Unix-like environments. It has been tested on
Linux and Mac OS X.
## Future Plans
There are currently no firm plans or timetables to implement any of these
features, although they are possible avenues for future exploration.
The symbol file format can be extended to carry information about the locations
of parameters and local variables as stored in stack frames and registers, and
the processor can use this information to provide enhanced stack traces showing
function arguments and variable values.
On Mac OS X and Linux, we can provide tools to convert files from the minidump
format into the native core format. This will enable developers to open dump
files in a native debugger, just as they are presently able to do with minidumps
on Windows.

View File

@ -0,0 +1,144 @@
# Introduction
This page aims to provide a detailed description of how Breakpad produces stack
traces from the information contained within a minidump file.
# Details
## Starting the Process
Typically the stack walking process is initiated by instantiating the
[MinidumpProcessor](../src/processor/minidump_processor.cc)
class and calling the [MinidumpProcessor::Process](../src/processor/minidump_processor.cc#61)
method, providing it a minidump file to process. To produce a useful stack
trace, the MinidumpProcessor requires two other objects which are passed in its
constructor: a [SymbolSupplier](../src/google_breakpad/processor/symbol_supplier.h)
and a [SourceLineResolverInterface](../src/google_breakpad/processor/source_line_resolver_interface.h).
The SymbolSupplier object is responsible for locating and providing SymbolFiles
that match modules from the minidump. The SourceLineResolverInterface is
responsible for loading the symbol files and using the information contained
within to provide function and source information for stack frames, as well as
information on how to unwind from a stack frame to its caller. More detail will
be provided on these interactions later.
A number of data streams are extracted from the minidump to begin stack walking:
the list of threads from the process
([MinidumpThreadList](../src/google_breakpad/processor/minidump.h#335)),
the list of modules loaded in the process
([MinidumpModuleList](../src/google_breakpad/processor/minidump.h#501)),
and information about the exception that caused the process to crash
([MinidumpException](../src/google_breakpad/processor/minidump.h#615)).
## Enumerating Threads
For each thread in the thread list
([MinidumpThread](../src/google_breakpad/processor/minidump.h#299)),
the thread memory containing the stack for the thread
([MinidumpMemoryRegion](../src/google_breakpad/processor/minidump.h#236))
and the CPU context representing the CPU state of the thread at the time the
dump was written ([MinidumpContext](../src/google_breakpad/processor/minidump.h#171))
are extracted from the minidump. If the thread being processed is the thread
that produced the exception then a CPU context is obtained from the
MinidumpException object instead, which represents the CPU state of the thread
at the point of the exception. A stack walker is then instantiated by calling
the [Stackwalker::StackwalkerForCPU](../src/google_breakpad/processor/stackwalker.h#77)
method and passing it the CPU context, the thread memory, the module list, as
well as the SymbolSupplier and SourceLineResolverInterface. This method selects
the specific !Stackwalker subclass based on the CPU architecture of the provided
CPU context and returns an instance of that subclass.
## Walking a thread's stack
Once a !Stackwalker instance has been obtained, the processor calls the
[Stackwalker::Walk](../src/google_breakpad/processor/source_line_resolver_interface.h)
method to obtain a list of frames representing the stack of this thread. The
!Stackwalker starts by calling the GetContextFrame method which returns a
StackFrame representing the top of the stack, with CPU state provided by the
initial CPU context. From there, the stack walker repeats the following steps
for each frame in turn:
### Finding the Module
The address of the instruction pointer of the current frame is used to determine
which module contains the current frame by calling the module list's
[GetModuleForAddress](../src/google_breakpad/processor/code_modules.h#56) method.
### Locating Symbols
If a module is located, the SymbolSupplier is asked to locate symbols
corresponding to the module by calling its
[GetCStringSymbolData](../src/google_breakpad/processor/symbol_supplier.h#87)
method. Typically this is implemented by using the module's debug filename (the
PDB filename for Windows dumps) and debug identifier (a GUID plus one extra
digit) as a lookup key. The [SimpleSymbolSupplier](../src/processor/simple_symbol_supplier.cc)
class simply uses these as parts of a file path to locate a flat file on disk.
### Loading Symbols
If a symbol file is located, the SourceLineResolverInterface is then asked to
load the symbol file by calling its
[LoadModuleUsingMemoryBuffer](../src/google_breakpad/processor/source_line_resolver_interface.h#71)
method. The [BasicSourceLineResolver](../src/processor/basic_source_line_resolver.cc)
implementation parses the text-format [symbol file](symbol_files.md) into
in-memory data structures to make lookups by address of function names, source
line information, and unwind information easy.
### Getting source line information
If a symbol file has been successfully loaded, the SourceLineResolverInterface's
[FillSourceLineInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#89)
method is called to provide a function name and source line information for the
current frame. This is done by subtracting the base address of the module
containing the current frame from the instruction pointer of the current frame
to obtain a relative virtual address (RVA), which is a code offset relative to
the start of the module. This RVA is then used as a lookup into a table of
functions ([FUNC lines](SymbolFiles#FUNC_records.md) from the symbol file), each
of which has an associated address range (function start address, function
size). If a function is found whose address range contains the RVA, then its
name is used. The RVA is then used as a lookup into a table of source lines
([line records](SymbolFiles#Line_records.md) from the symbol file), each of
which also has an associated address range. If a match is found it will provide
the file name and source line associated with the current frame. If no match was
found in the function table, another table of publicly exported symbols may be
consulted ([PUBLIC lines](SymbolFiles#PUBLIC_records.md) from the symbol file).
Public symbols contain only a start address, so the lookup simply looks for the
nearest symbol that is less than the provided RVA.
### Finding the caller frame
To find the next frame in the stack, the !Stackwalker calls its
[GetCallerFrame](../src/google_breakpad/processor/stackwalker.h#186)
method, passing in the current frame. Each !Stackwalker subclass implements
GetCallerFrame differently, but there are common patterns.
Typically the first step is to query the SourceLineResolverInterface for the
presence of detailed unwind information. This is done using its
[FindWindowsFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#96)
and [FindCFIFrameInfo](../src/google_breakpad/processor/source_line_resolver_interface.h#102)
methods. These methods look for Windows unwind info extracted from a PDB file
([STACK WIN](SymbolFiles#STACK_WIN_records.md) lines from the symbol file), or
DWARF CFI extracted from a binary ([STACK CFI](SymbolFiles#STACK_CFI_records.md)
lines from the symbol file) respectively. The information covers address ranges,
so the RVA of the current frame is used for lookup as with function and source
line information.
If unwind info is found it provides a set of rules to recover the register state
of the caller frame given the current register state as well as the thread's
stack memory. The rules are evaluated to produce the caller frame.
If unwind info is not found then the !Stackwalker may resort to other methods.
Typically on architectures which specify a frame pointer unwinding by
dereferencing the frame pointer is tried next. If that is successful it is used
to produce the caller frame.
If no caller frame was found by any other method most !Stackwalker
implementations resort to stack scanning by looking at each word on the stack
down to a fixed depth (implemented in the
[Stackwalker::ScanForReturnAddress](../src/google_breakpad/processor/stackwalker.h#131)
method) and using a heuristic to attempt to find a reasonable return address
(implemented in the
[Stackwalker::InstructionAddressSeemsValid](../src/google_breakpad/processor/stackwalker.h#111) method).
If no caller frame is found or the caller frame seems invalid, stack walking
stops. If a caller frame was found then these steps repeat using the new frame
as the current frame.

View File

@ -0,0 +1,214 @@
# Introduction
The `sym_upload` tool is able to operate in `sym-upload-v2` protocol mode, in
addition to the legacy protocol (which will be referred to as `sym-upload-v1`
for the rest of this document). For now `sym-upload-v2` is HTTP/REST-based but
it could be extended to operate over gRPC instead, in the future.
# Table of Contents
* [Why](#why)
* [How](#how)
* [Uploading](#uploading)
* [Uploading with `sym_upload`](#uploading-with-sym_upload)
* [Uploading with curl](#uploading-with-curl)
* [Serving the `sym-upload-v2` protocol](#serving-the-sym-upload-v2-protocol)
* [Authenticate using `key`](#authenticate-using-key)
* [Symbol `checkStatus`](#symbol-checkstatus)
* [Upload `create`](#upload-create)
* [Uploading the symbol file](#uploading-the-symbol-file)
* [Upload complete](#upload-complete)
# Why
Using `sym_upload` in `sym-upload-v2` protocol mode has the following features
beyond `sym-upload-v1`:
* Authentication via `key` (arbitrary secret).
* Symbol identifier (product of `debug_file` and `debug_id`, as recorded in
output from `dump_syms`) can be checked against existing symbol information on
server. If it's present, then the upload is skipped entirely.
# How
## Uploading
### Uploading with `sym_upload`
Uploading in `sym-upload-v2` protocol mode is easy. Invoke `sym_upload` like
```
$ ./sym_upload -p sym-upload-v2 [-k <API-key>] <symbol-file> <API-URL>
```
Where `symbol-file` is a symbol file created by `dump_syms`, `API-URL` is the
URL of your `sym-upload-v2` API service (see next section for details), and
`API-key` is a secret known to your uploader and server.
For more options see `sym_upload --help`.
### Uploading with curl
As an example, if:
* Your API's URL was "https://sym-upload-api".
* Your service has assigned you `key` "myfancysecret123".
* You wanted to upload the symbol file at "path/to/file_name", with
`debug_file` being "file_name" and `debug_id` being
"123123123123123123123123123". Normally you would read these values from
"path/to/file_name", which in turn was generated by `dump_syms`.
Then you might run:
```
$ curl https://sym-upload-api/symbols/file_name/123123123123123123123123123:checkStatus?key=myfancysecret123
```
And, upon seeing that this `debug_file`/`debug_id` combo is missing from symbol
storage then you could run:
```
$ curl --request POST https://sym-upload-api/uploads:create?key=myfancysecret123
```
Which returns `upload_url` "https://upload-server/42?creds=shhhhh" and
`upload_key` "42". Next you upload the file directly like:
```
$ curl -T path/to/file_name "https://upload-server/42?creds=shhhhh"
```
Once the HTTP PUT is complete, run:
```
$ curl --header "Content-Type: application/json" \
--request POST \
--data '{symbol_id:{"debugFile":"file_name",'\
'"debugId":"123123123123123123123123123"}}' \
https://sym-upload-api/uploads/42:complete?key=myfancysecret123
```
### Serving the `sym-upload-v2` Protocol
The protocol is currently defined only in HTTP/REST. There are three necessary
REST operations to implement in your service:
* `/symbols/<debug_file>/<debug_id>:checkStatus?key=<key>`
* `/uploads:create?key=<key>`
* `/uploads/<upload_key>:complete?key=<key>`
#### Authenticate Using `key`
The query string arg `key` contains some secret that both the uploader and
server understand. It is up to the service implementer to decide on what
constitutes a valid `key`, how the uploader acquires one, and how to handle
requests made with invalid ones.
#### Symbol `checkStatus`
```
/symbols/<debug_file>/<debug_id>:checkStatus?key=<key>
```
This operation expects an empty (or no) JSON payload in the request.
This operation should return the status of the symbol file uniquely identified
by the given `debug_file` and `debug_id`. JSON schema:
```
{
"type": object",
"properties": {
"status": {
"type": "string",
"enum": ["STATUS_UNSPECIFIED", "MISING", "FOUND"],
"required": true
}
}
}
```
Where `MISSING` denotes that the symbol file does not exist on the server and
`FOUND` denotes that the symbol file exists on the server.
#### Upload `create`
```
/uploads:create?key=<key>
```
This operation expects an empty (or no) JSON payload in the request.
This operation should return a URL that uploader can HTTP PUT their symbol file
to, along with an "upload key" that can be used to notify the service once the
file upload is completed. JSON schema:
```
{
"type": "object",
"properties": {
"upload_url": {
"type: "string",
"required": true
},
"upload_key": {
"type": "string",
"required": true
}
}
}
```
Since this REST API operation can be authenticated via the `key` query string
arg, the service can return a URL that encodes permission delegation to the
upload endpoint resource and thereby constrain the ability to upload to those
with valid `key`s.
#### Uploading the Symbol File
Note that the actual symbol upload step is _not_ part of the REST API. The
upload URL obtained in the above operation is meant to be used as the endpoint
for a normal HTTP PUT request for the contents of the symbol file. Once that
HTTP PUT request is completed use the upload `complete` operation.
#### Upload `complete`
```
/uploads/<upload_key>:complete?key=<key>
```
This operation expects a JSON payload in the HTTP request body with the
following schema:
```
{
"type": "object",
"properties": {
"symbol_id": {
"type": "object",
"properties": {
"debug_file": {
"type": "string",
"required": true
},
"debug_id": {
"type": "string",
"required": true
}
}
}
}
}
```
This operation should cause the symbol storage back-end (however implemented)
to consume the symbol file identified by `upload_key`. It is up to the service
implementation to decide how uploads are assigned `upload_key`s and how to
retrieve a completed upload by its `upload_key`. If the symbol file cannot be
found, is malformed, or the operation cannot be completed for any other reason
then an HTTP error will be returned. JSON schema of non-error responses:
```
{
"type": "object",
"properties": {
"result": {
"type": string,
"enum": ["RESULT_UNSPECIFIED", "OK", "DUPLICATE_DATA"],
"required": true
}
}
}
```
Where `OK` denotes that the symbol storage was updated with the new symbol file
and `DUPLICATE_DATA` denotes that the symbol file data was identical to data
already in symbol storage and therefore nothing changed.

View File

@ -0,0 +1,506 @@
# Introduction
Given a minidump file, the Breakpad processor produces stack traces that include
function names and source locations. However, minidump files contain only the
byte-by-byte contents of threads' registers and stacks, without function names
or machine-code-to-source mapping data. The processor consults Breakpad symbol
files for the information it needs to produce human-readable stack traces from
the binary-only minidump file.
The platform-specific symbol dumping tools parse the debugging information the
compiler provides (whether as DWARF or STABS sections in an ELF file or as
stand-alone PDB files), and write that information back out in the Breakpad
symbol file format. This format is much simpler and less detailed than compiler
debugging information, and values legibility over compactness.
# Overview
Breakpad symbol files are ASCII text files, with lines delimited as appropriate
for the host platform. Each line is a _record_, divided into fields by single
spaces; in some cases, the last field of the record can contain spaces. The
first field is a string indicating what sort of record the line represents
(except for line records; these are very common, making them the default saves
space). Some fields hold decimal or hexadecimal numbers; hexadecimal numbers
have no "0x" prefix, and use lower-case letters.
Breakpad symbol files contain the following record types. With some
restrictions, these may appear in any order.
* A `MODULE` record describes the executable file or shared library from which
this data was derived, for use by symbol suppliers. A `MODULE' record should
be the first record in the file.
* A `FILE` record gives a source file name, and assigns it a number by which
other records can refer to it.
* A `FUNC` record describes a function present in the source code.
* A line record indicates to which source file and line a given range of
machine code should be attributed. The line is attributed to the function
defined by the most recent `FUNC` record.
* A `PUBLIC` record gives the address of a linker symbol.
* A `STACK` record provides information necessary to produce stack traces.
# `MODULE` records
A `MODULE` record provides meta-information about the module the symbol file
describes. It has the form:
> `MODULE` _operatingsystem_ _architecture_ _id_ _name_
For example: `MODULE Linux x86 D3096ED481217FD4C16B29CD9BC208BA0 firefox-bin
` These records provide meta-information about the executable or shared library
from which this symbol file was generated. A symbol supplier might use this
information to find the correct symbol files to use to interpret a given
minidump, or to perform other sorts of validation. If present, a `MODULE` record
should be the first line in the file.
The fields are separated by spaces, and cannot contain spaces themselves, except
for _name_.
* The _operatingsystem_ field names the operating system on which the
executable or shared library was intended to run. This field should have one
of the following values: | **Value** | **Meaning** |
|:----------|:--------------------| | Linux | Linux | | mac | Macintosh OSX
| | windows | Microsoft Windows |
* The _architecture_ field indicates what processor architecture the
executable or shared library contains machine code for. This field should
have one of the following values: | **Value** | **Instruction Set
Architecture** | |:----------|:---------------------------------| | x86 |
Intel IA-32 | | x86\_64 | AMD64/Intel 64 | | ppc | 32-bit PowerPC | | ppc64
| 64-bit PowerPC | | unknown | unknown |
* The _id_ field is a sequence of hexadecimal digits that identifies the exact
executable or library whose contents the symbol file describes. The way in
which it is computed varies from platform to platform.
* The _name_ field contains the base name (the final component of the
directory path) of the executable or library. It may contain spaces, and
extends to the end of the line.
# `FILE` records
A `FILE` record holds a source file name for other records to refer to. It has
the form:
> `FILE` _number_ _name_
For example: `FILE 2 /home/jimb/mc/in/browser/app/nsBrowserApp.cpp
`
A `FILE` record provides the name of a source file, and assigns it a number
which other records (line records, in particular) can use to refer to that file
name. The _number_ field is a decimal number. The _name_ field is the name of
the file; it may contain spaces.
# `FUNC` records
A `FUNC` record describes a source-language function. It has the form:
> `FUNC` _[m]_ _address_ _size_ _parameter\_size_ _name_
For example: `FUNC m c184 30 0 nsQueryInterfaceWithError::operator()(nsID const&,
void**) const
`
The _m_ field is optional. If present it indicates that multiple symbols
reference this function's instructions. (In which case, only one symbol name is
mentioned within the breakpad file.) Multiple symbols referencing the same
instructions may occur due to identical code folding by the linker.
The _address_ and _size_ fields are hexadecimal numbers indicating the start
address and length in bytes of the machine code instructions the function
occupies. (Breakpad symbol files cannot accurately describe functions whose code
is not contiguous.) The start address is relative to the module's load address.
The _parameter\_size_ field is a hexadecimal number indicating the size, in
bytes, of the arguments pushed on the stack for this function. Some calling
conventions, like the Microsoft Windows `stdcall` convention, require the called
function to pop parameters passed to it on the stack from its caller before
returning. The stack walker uses this value, along with data from `STACK`
records, to step from the called function's frame to the caller's frame.
The _name_ field is the name of the function. In languages that use linker
symbol name mangling like C++, this should be the source language name (the
"unmangled" form). This field may contain spaces.
# Line records
A line record describes the source file and line number to which a given range
of machine code should be attributed. It has the form:
> _address_ _size_ _line_ _filenum_
For example: `c184 7 59 4
`
Because they are so common, line records do not begin with a string indicating
the record type. All other record types' names use upper-case letters;
hexadecimal numbers, like a line record's _address_, use lower-case letters.
The _address_ and _size_ fields are hexadecimal numbers indicating the start
address and length in bytes of the machine code. The address is relative to the
module's load address.
The _line_ field is the line number to which the machine code should be
attributed, in decimal; the first line of the source file is line number 1. The
_filenum_ field is a decimal number appearing in a prior `FILE` record; the name
given in that record is the source file name for the machine code.
The line is assumed to belong to the function described by the last preceding
`FUNC` record. Line records may not appear before the first `FUNC' record.
No two line records in a symbol file cover the same range of addresses. However,
there may be many line records with identical line and file numbers, as a given
source line may contribute many non-contiguous blocks of machine code.
# `PUBLIC` records
A `PUBLIC` record describes a publicly visible linker symbol, such as that used
to identify an assembly language entry point or region of memory. It has the
form:
> PUBLIC _[m]_ _address_ _parameter\_size_ _name_
For example: `PUBLIC m 2160 0 Public2_1
`
The Breakpad processor essentially treats a `PUBLIC` record as defining a
function with no line number data and an indeterminate size: the code extends to
the next address mentioned. If a given address is covered by both a `PUBLIC`
record and a `FUNC` record, the processor uses the `FUNC` data.
The _m_ field is optional. If present it indicates that multiple symbols
reference this function's instructions. (In which case, only one symbol name is
mentioned within the breakpad file.) Multiple symbols referencing the same
instructions may occur due to identical code folding by the linker.
The _address_ field is a hexadecimal number indicating the symbol's address,
relative to the module's load address.
The _parameter\_size_ field is a hexadecimal number indicating the size of the
parameters passed to the code whose entry point the symbol marks, if known. This
field has the same meaning as the _parameter\_size_ field of a `FUNC` record;
see that description for more details.
The _name_ field is the name of the symbol. In languages that use linker symbol
name mangling like C++, this should be the source language name (the "unmangled"
form). This field may contain spaces.
# `STACK WIN` records
Given a stack frame, a `STACK WIN` record indicates how to find the frame that
called it. It has the form:
> STACK WIN _type_ _rva_ _code\_size_ _prologue\_size_ _epilogue\_size_
> _parameter\_size_ _saved\_register\_size_ _local\_size_ _max\_stack\_size_
> _has\_program\_string_ _program\_string\_OR\_allocates\_base\_pointer_
For example: `STACK WIN 4 2170 14 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + =
$ebp $ebp ^ =
`
All fields of a `STACK WIN` record, except for the last, are hexadecimal
numbers.
The _type_ field indicates what sort of stack frame data this record holds. Its
value should be one of the values of the
[StackFrameTypeEnum](http://msdn.microsoft.com/en-us/library/bc5207xw%28VS.100%29.aspx)
type in Microsoft's
[Debug Interface Access (DIA)](http://msdn.microsoft.com/en-us/library/x93ctkx8%28VS.100%29.aspx) API.
Breakpad uses only records of type 4 (`FrameTypeFrameData`) and 0
(`FrameTypeFPO`); it ignores others. These types differ only in whether the last
field is an _allocates\_base\_pointer_ flag (`FrameTypeFPO`) or a program string
(`FrameTypeFrameData`). If more than one record covers a given address, Breakpad
prefers `FrameTypeFrameData` records over `FrameTypeFPO` records.
The _rva_ and _code\_size_ fields give the starting address and length in bytes
of the machine code covered by this record. The starting address is relative to
the module's load address.
The _prologue\_size_ and _epilogue\_size_ fields give the length, in bytes, of
the prologue and epilogue machine code within the record's range. Breakpad does
not use these values.
The _parameter\_size_ field gives the number of argument bytes this function
expects to have been passed. This field has the same meaning as the
_parameter\_size_ field of a `FUNC` record; see that description for more
details.
The _saved\_register\_size_ field gives the number of bytes in the stack frame
dedicated to preserving the values of any callee-saves registers used by this
function.
The _local\_size_ field gives the number of bytes in the stack frame dedicated
to holding the function's local variables and temporary values.
The _max\_stack\_size_ field gives the maximum number of bytes pushed on the
stack in the frame. Breakpad does not use this value.
If the _has\_program\_string_ field is zero, then the `STACK WIN` record's final
field is an _allocates\_base\_pointer_ flag, as a hexadecimal number; this is
expected for records whose _type_ is 0. Otherwise, the final field is a program
string.
## Interpreting a `STACK WIN` record
Given the register values for a frame F, we can find the calling frame as
follows:
* If the _has\_program\_string_ field of a `STACK WIN` record is zero, then
the final field is _allocates\_base\_pointer_, a flag indicating whether the
frame uses the frame pointer register, `%ebp`, as a general-purpose
register.
* If _allocates\_base\_pointer_ is true, then `%ebp` does not point to the
frame's base address. Instead,
* Let _next\_parameter\_size_ be the parameter size of the function
frame F called (**not** this record's _parameter\_size_ field), or
zero if F is the youngest frame on the stack. You must find this
value in F's callee's `FUNC`, `STACK WIN`, or `PUBLIC` records.
* Let _frame\_size_ be the sum of the _local\_size_ field, the
_saved\_register\_size_ field, and _next\_parameter\_size_. > > With
those definitions in place, we can recover the calling frame as
follows:
* F's return address is at `%esp +`_frame\_size_,
* the caller's value of `%ebp` is saved at `%esp
+`_next\_parameter\_size_`+`_saved\_register\_size_`- 8`, and
* the caller's value of `%esp` just before the call instruction was
`%esp +`_frame\_size_`+ 4`. > > (Why do we include
_next\_parameter\_size_ in the sum when computing _frame\_size_ and
the address of the saved `%ebp`? When a function A has called a
function B, the arguments that A pushed for B are considered part of
A's stack frame: A's value for `%esp` points at the last argument
pushed for B. Thus, we must include the size of those arguments
(given by the debugging info for B) along with the size of A's
register save area and local variable area (given by the debugging
info for A) when computing the overall size of A's frame.)
* If _allocates\_base\_pointer_ is false, then F's function doesn't use
`%ebp` at all. You may recover the calling frame as above, except that
the caller's value of `%ebp` is the same as F's value for `%ebp`, so no
steps are necessary to recover it.
* If the _has\_program\_string_ field of a `STACK WIN` record is not zero,
then the record's final field is a string containing a program to be
interpreted to recover the caller's frame. The comments in the
[postfix\_evaluator.h](../src/processor/postfix_evaluator.h#40)
header file explain the language in which the program is written. You should
place the following variables in the dictionary before interpreting the
program:
* `$ebp` and `$esp` should be the values of the `%ebp` and `%esp`
registers in F.
* `.cbParams`, `.cbSavedRegs`, and `.cbLocals`, should be the values of
the `STACK WIN` record's _parameter\_size_, _saved\_register\_size_, and
_local\_size_ fields.
* `.raSearchStart` should be set to the address on the stack to begin
scanning for a return address, if necessary. The Breakpad processor sets
this to the value of `%esp` in F, plus the _frame\_size_ value mentioned
above.
> If the program stores values for `$eip`, `$esp`, `$ebp`, `$ebx`, `$esi`, or
> `$edi`, then those are the values of the given registers in the caller. If the
> value of `$eip` is zero, that indicates that the end of the stack has been
> reached.
The Breakpad processor checks that the value yielded by the above for the
calling frame's instruction address refers to known code; if the address seems
to be bogus, then it uses a heuristic search to find F's return address and
stack base.
# `STACK CFI` records
`STACK CFI` ("Call Frame Information") records describe how to walk the stack
when execution is at a given machine instruction. These records take one of two
forms:
> `STACK CFI INIT` _address_ _size_ _register<sub>1</sub>_:
> _expression<sub>1</sub>_ _register<sub>2</sub>_: _expression<sub>2</sub>_ ...
>
> `STACK CFI` _address_ _register<sub>1</sub>_: _expression<sub>1</sub>_
> _register<sub>2</sub>_: _expression<sub>2</sub>_ ...
For example:
```
STACK CFI INIT 804c4b0 40 .cfa: $esp 4 + $eip: .cfa 4 - ^
STACK CFI 804c4b1 .cfa: $esp 8 + $ebp: .cfa 8 - ^
```
The _address_ and _size_ fields are hexadecimal numbers. Each
_register_<sub>i</sub> is the name of a register or pseudoregister. Each
_expression_ is a Breakpad postfix expression, which may contain spaces, but
never ends with a colon. (The appropriate register names for a given
architecture are determined when `STACK CFI` records are first enabled for that
architecture, and should be documented in the appropriate
`stackwalker_`_architecture_`.cc` source file.)
STACK CFI records describe, at each machine instruction in a given function, how
to recover the values the machine registers had in the function's caller.
Naturally, some registers' values are simply lost, but there are three cases in
which they can be recovered:
* You can always recover the program counter, because that's the function's
return address. If the function is ever going to return, the PC must be
saved somewhere.
* You can always recover the stack pointer. The function is responsible for
popping its stack frame before it returns to the caller, so it must be able
to restore this, as well.
* You should be able to recover the values of callee-saves registers. These
are registers whose values the callee must preserve, either by saving them
in its own stack frame before using them and re-loading them before
returning, or by not using them at all.
(As an exception, note that functions which never return may not save any of
this data. It may not be possible to walk the stack past such functions' stack
frames.)
Given rules for recovering the values of a function's caller's registers, we can
walk up the stack. Starting with the current set of registers --- the PC of the
instruction we're currently executing, the current stack pointer, etc. --- we
use CFI to recover the values those registers had in the caller of the current
frame. This gives us a PC in the caller whose CFI we can look up; we apply the
process again to find that function's caller; and so on.
Concretely, CFI records represent a table with a row for each machine
instruction address and a column for each register. The table entry for a given
address and register contains a rule describing how, when the PC is at that
address, to restore the value that register had in the caller.
There are some special columns:
* A column named `.cfa`, for "Canonical Frame Address", tells how to compute
the base address of the frame; other entries can refer to the CFA in their
rules.
* A column named `.ra` represents the return address.
For example, suppose we have a machine with 32-bit registers, one-byte
instructions, a stack that grows downwards, and an assembly language that
resembles C. Suppose further that we have a function whose machine code looks
like this:
```
func: ; entry point; return address at sp
func+0: sp -= 16 ; allocate space for stack frame
func+1: sp[12] = r0 ; save 4-byte r0 at sp+12
... ; stuff that doesn't affect stack
func+10: sp -= 4; *sp = x ; push some 4-byte x on the stack
... ; stuff that doesn't affect stack
func+20: r0 = sp[16] ; restore saved r0
func+21: sp += 20 ; pop whole stack frame
func+22: pc = *sp; sp += 4 ; pop return address and jump to it
```
The following table would describe the function above:
**code address** | **.cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **.ra**
:--------------- | :------- | :---------------------- | :---------------------- | :-- | :-------
func+0 | sp | | | | `cfa[0]`
func+1 | sp+16 | | | | `cfa[0]`
func+2 | sp+16 | `cfa[-4]` | | | `cfa[0]`
func+11 | sp+20 | `cfa[-4]` | | | `cfa[0]`
func+21 | sp+20 | | | | `cfa[0]`
func+22 | sp | | | | `cfa[0]`
Some things to note here:
* Each row describes the state of affairs **before** executing the instruction
at the given address. Thus, the row for func+0 describes the state before we
execute the first instruction, which allocates the stack frame. In the next
row, the formula for computing the CFA has changed, reflecting the
allocation.
* The other entries are written in terms of the CFA; this allows them to
remain unchanged as the stack pointer gets bumped around. For example, to
find the caller's value for r0 (on Google Code) at func+2, we would first
compute the CFA by adding 16 to the sp, and then subtract four from that to
find the address at which r0 (on Google Code) was saved.
* Although the example doesn't show this, most calling conventions designate
"callee-saves" and "caller-saves" registers. The callee must restore the
values of "callee-saves" registers before returning (if it uses them at
all), whereas the callee is free to use "caller-saves" registers without
restoring their values. A function that uses caller-saves registers
typically does not save their original values at all; in this case, the CFI
marks such registers' values as "unrecoverable".
* Exactly where the CFA points in the frame --- at the return address? below
it? At some fixed point within the frame? --- is a question of definition
that depends on the architecture and ABI in use. But by definition, the CFA
remains constant throughout the lifetime of the frame. It's up to
architecture- specific code to know what significance to assign the CFA, if
any.
To save space, the most common type of CFI record only mentions the table
entries at which changes take place. So for the above, the CFI data would only
actually mention the non-blank entries here:
**insn** | **cfa** | **r0 (on Google Code)** | **r1 (on Google Code)** | ... | **ra**
:------- | :------ | :---------------------- | :---------------------- | :-- | :-------
func+0 | sp | | | | `cfa[0]`
func+1 | sp+16 | | | |
func+2 | | `cfa[-4]` | | |
func+11 | sp+20 | | | |
func+21 | | r0 (on Google Code) | | |
func+22 | sp | | | |
A `STACK CFI INIT` record indicates that, at the machine instruction at
_address_, belonging to some function, the value that _register<sub>n</sub>_ had
in that function's caller can be recovered by evaluating
_expression<sub>n</sub>_. The values of any callee-saves registers not mentioned
are assumed to be unchanged. (`STACK CFI` records never mention caller-saves
registers.) These rules apply starting at _address_ and continue up to, but not
including, the address given in the next `STACK CFI` record. The _size_ field is
the total number of bytes of machine code covered by this record and any
subsequent `STACK CFI` records (until the next `STACK CFI INIT` record). The
_address_ field is relative to the module's load address.
A `STACK CFI` record (no `INIT`) is the same, except that it mentions only those
registers whose recovery rules have changed from the previous CFI record. There
must be a prior `STACK CFI INIT` or `STACK CFI` record in the symbol file. The
_address_ field of this record must be greater than that of the previous record,
and it must not be at or beyond the end of the range given by the most recent
`STACK CFI INIT` record. The address is relative to the module's load address.
Each expression is a breakpad-style postfix expression. Expressions may contain
spaces, but their tokens may not end with colons. When an expression mentions a
register, it refers to the value of that register in the callee, even if a prior
name/expression pair gives that register's value in the caller. The exception is
`.cfa`, which refers to the canonical frame address computed by the .cfa rule in
force at the current instruction.
The special expression `.undef` indicates that the given register's value cannot
be recovered.
The register names preceding the expressions are always followed by colons. The
expressions themselves never contain tokens ending with colons.
There are two special register names:
* `.cfa` ("Canonical Frame Address") is the base address of the stack frame.
Other registers' rules may refer to this. If no rule is provided for the
stack pointer, the value of `.cfa` is the caller's stack pointer.
* `.ra` is the return address. This is the value of the restored program
counter. We use `.ra` instead of the architecture-specific name for the
program counter.
The Breakpad stack walker requires that there be rules in force for `.cfa` and
`.ra` at every code address from which it unwinds. If those rules are not
present, the stack walker will ignore the `STACK CFI` data, and try to use a
different strategy.
So the CFI for the example function above would be as follows, if `func` were at
address 0x1000 (relative to the module's load address):
```
STACK CFI INIT 1000 .cfa: $sp .ra: .cfa ^
STACK CFI 1001 .cfa: $sp 16 +
STACK CFI 1002 $r0: .cfa 4 - ^
STACK CFI 100b .cfa: $sp 20 +
STACK CFI 1015 $r0: $r0
STACK CFI 1016 .cfa: $sp
```

View File

@ -0,0 +1,70 @@
# Windows Integration overview
## Windows Client Code
The Windows client code is in the `src/client/windows` directory of the tree.
Since the header files are fairly well commented some specifics are purposely
omitted from this document.
## Integration of minidump-generation
Once you build the solution inside `src/client/windows`, an output file of
`exception_handler.lib` will be generated. You can either check this into your
project's directory or build directly from the source, as the project itself
does.
Enabling Breakpad in your application requires you to `#include
"exception_handler.h"` and instantiate the `ExceptionHandler` object like so:
```
handler = new ExceptionHandler(const wstring& dump_path,
FilterCallback filter,
MinidumpCallback callback,
void* callback_context,
int handler_types,
MINIDUMP_TYPE dump_type,
const wchar_t* pipe_name,
const CustomClientInfo* custom_info);
```
The parameters, in order, are:
* pathname for minidumps to be written to - this is ignored if OOP dump
generation is used
* A callback that is called when the exception is first handled - you can
return true/false here to continue/stop exception processing
* A callback that is called after minidumps have been written
* Context for the callbacks
* Which exceptions to handle - see `HandlerType` enumeration in
exception\_handler.h
* The type of minidump to generate, using the `MINIDUMP_TYPE` definitions in
`DbgHelp.h`
* A pipe name that can be used to communicate with a crash generation server
* A pointer to a CustomClientInfo class that can be used to send custom data
along with the minidump when using OOP generation
You can also see `src/client/windows/tests/crash_generation_app/*` for a sample
app that uses OOP generation.
## OOP Minidump Generation
For out of process minidump generation, more work is needed. If you look inside
`src/client/windows/crash_generation`, you will see a file called
`crash_generation_server.h`. This file is the interface for a crash generation
server, which must be instantiated with the same pipe name that is passed to the
client above. The logistics of running a separate process that instantiates the
crash generation server is left up to you, however.
## Build process specifics(symbol generation, upload)
The symbol creation step is talked about in the general overview doc, since it
doesn't vary much by platform. You'll need to make sure that the symbols are
available wherever minidumps are uploaded to for processing.
## Out in the field - uploading the minidump
Inside `src/client/windows/sender` is a class implementation called
`CrashReportSender`. This class can be compiled into a separate standalone CLI
or in the crash generation server and used to upload the report; it can know
when to do so via one of the callbacks provided by the `CrashGenerationServer`
or the `ExceptionHandler` object for in-process generation.

View File

@ -0,0 +1,67 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the compiler works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. During the check the flag is always added to the
# current language's flags.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
# AX_APPEND_LINK_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 5
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
for flag in $1; do
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
done
])dnl AX_APPEND_COMPILE_FLAGS

View File

@ -0,0 +1,71 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
#
# DESCRIPTION
#
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
# added in between.
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
# FLAG.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AC_DEFUN([AX_APPEND_FLAG],
[dnl
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
AS_VAR_SET_IF(FLAGS,[
AS_CASE([" AS_VAR_GET(FLAGS) "],
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
[
AS_VAR_APPEND(FLAGS,[" $1"])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
],
[
AS_VAR_SET(FLAGS,[$1])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_APPEND_FLAG

View File

@ -0,0 +1,74 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 4
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

View File

@ -0,0 +1,92 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_define.html
# ===========================================================================
#
# SYNOPSIS
#
# AC_CHECK_DEFINE([symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT])
# AX_CHECK_DEFINE([includes],[symbol], [ACTION-IF-FOUND], [ACTION-IF-NOT])
#
# DESCRIPTION
#
# Complements AC_CHECK_FUNC but it does not check for a function but for a
# define to exist. Consider a usage like:
#
# AC_CHECK_DEFINE(__STRICT_ANSI__, CFLAGS="$CFLAGS -D_XOPEN_SOURCE=500")
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 9
AU_ALIAS([AC_CHECK_DEFINED], [AC_CHECK_DEFINE])
AC_DEFUN([AC_CHECK_DEFINE],[
AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$1])dnl
AC_CACHE_CHECK([for $1 defined], ac_var,
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
#ifdef $1
int ok;
#else
choke me
#endif
]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)]))
AS_IF([test AS_VAR_GET(ac_var) != "no"], [$2], [$3])dnl
AS_VAR_POPDEF([ac_var])dnl
])
AU_ALIAS([AX_CHECK_DEFINED], [AX_CHECK_DEFINE])
AC_DEFUN([AX_CHECK_DEFINE],[
AS_VAR_PUSHDEF([ac_var],[ac_cv_defined_$2_$1])dnl
AC_CACHE_CHECK([for $2 defined in $1], ac_var,
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <$1>]], [[
#ifdef $2
int ok;
#else
choke me
#endif
]])],[AS_VAR_SET(ac_var, yes)],[AS_VAR_SET(ac_var, no)]))
AS_IF([test AS_VAR_GET(ac_var) != "no"], [$3], [$4])dnl
AS_VAR_POPDEF([ac_var])dnl
])
AC_DEFUN([AX_CHECK_FUNC],
[AS_VAR_PUSHDEF([ac_var], [ac_cv_func_$2])dnl
AC_CACHE_CHECK([for $2], ac_var,
dnl AC_LANG_FUNC_LINK_TRY
[AC_LINK_IFELSE([AC_LANG_PROGRAM([$1
#undef $2
char $2 ();],[
char (*f) () = $2;
return f != $2; ])],
[AS_VAR_SET(ac_var, yes)],
[AS_VAR_SET(ac_var, no)])])
AS_IF([test AS_VAR_GET(ac_var) = yes], [$3], [$4])dnl
AS_VAR_POPDEF([ac_var])dnl
])# AC_CHECK_FUNC

View File

@ -0,0 +1,558 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
#
# DESCRIPTION
#
# Check for baseline language coverage in the compiler for the specified
# version of the C++ standard. If necessary, add switches to CXXFLAGS to
# enable support. VERSION may be '11' (for the C++11 standard) or '14'
# (for the C++14 standard).
#
# The second argument, if specified, indicates whether you insist on an
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
# -std=c++11). If neither is specified, you get whatever works, with
# preference for an extended mode.
#
# The third argument, if specified 'mandatory' or if left unspecified,
# indicates that baseline support for the specified C++ standard is
# required and that the macro should error out if no mode with that
# support is found. If specified 'optional', then configuration proceeds
# regardless, after defining HAVE_CXX${VERSION} if and only if a
# supporting mode is found.
#
# LICENSE
#
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
dnl (serial version number 13).
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
m4_if([$1], [11], [],
[$1], [14], [],
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$2], [], [],
[$2], [ext], [],
[$2], [noext], [],
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
AC_LANG_PUSH([C++])dnl
ac_success=no
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
ax_cv_cxx_compile_cxx$1,
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[ax_cv_cxx_compile_cxx$1=yes],
[ax_cv_cxx_compile_cxx$1=no])])
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
ac_success=yes
fi
m4_if([$2], [noext], [], [dnl
if test x$ac_success = xno; then
for switch in -std=gnu++$1 -std=gnu++0x; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
m4_if([$2], [ext], [], [dnl
if test x$ac_success = xno; then
dnl HP's aCC needs +std=c++11 according to:
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
dnl Cray's crayCC needs "-h std=c++11"
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
$cachevar,
[ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS="$CXXFLAGS $switch"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
[eval $cachevar=yes],
[eval $cachevar=no])
CXXFLAGS="$ac_save_CXXFLAGS"])
if eval test x\$$cachevar = xyes; then
CXXFLAGS="$CXXFLAGS $switch"
ac_success=yes
break
fi
done
fi])
AC_LANG_POP([C++])
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
if test x$ac_success = xno; then
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
fi
else
if test x$ac_success = xno; then
HAVE_CXX$1=0
AC_MSG_NOTICE([No compiler with C++$1 support was found])
else
HAVE_CXX$1=1
AC_DEFINE(HAVE_CXX$1,1,
[define if the compiler supports basic C++$1 syntax])
fi
AC_SUBST(HAVE_CXX$1)
fi
])
dnl Test body for checking C++11 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
)
dnl Test body for checking C++14 support
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
)
dnl Tests for new features in C++11
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
// If the compiler admits that it is not ready for C++11, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201103L
#error "This is not a C++11 compiler"
#else
namespace cxx11
{
namespace test_static_assert
{
template <typename T>
struct check
{
static_assert(sizeof(int) <= sizeof(T), "not big enough");
};
}
namespace test_final_override
{
struct Base
{
virtual void f() {}
};
struct Derived : public Base
{
virtual void f() override {}
};
}
namespace test_double_right_angle_brackets
{
template < typename T >
struct check {};
typedef check<void> single_type;
typedef check<check<void>> double_type;
typedef check<check<check<void>>> triple_type;
typedef check<check<check<check<void>>>> quadruple_type;
}
namespace test_decltype
{
int
f()
{
int a = 1;
decltype(a) b = 2;
return a + b;
}
}
namespace test_type_deduction
{
template < typename T1, typename T2 >
struct is_same
{
static const bool value = false;
};
template < typename T >
struct is_same<T, T>
{
static const bool value = true;
};
template < typename T1, typename T2 >
auto
add(T1 a1, T2 a2) -> decltype(a1 + a2)
{
return a1 + a2;
}
int
test(const int c, volatile int v)
{
static_assert(is_same<int, decltype(0)>::value == true, "");
static_assert(is_same<int, decltype(c)>::value == false, "");
static_assert(is_same<int, decltype(v)>::value == false, "");
auto ac = c;
auto av = v;
auto sumi = ac + av + 'x';
auto sumf = ac + av + 1.0;
static_assert(is_same<int, decltype(ac)>::value == true, "");
static_assert(is_same<int, decltype(av)>::value == true, "");
static_assert(is_same<int, decltype(sumi)>::value == true, "");
static_assert(is_same<int, decltype(sumf)>::value == false, "");
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
return (sumf > 0.0) ? sumi : add(c, v);
}
}
namespace test_noexcept
{
int f() { return 0; }
int g() noexcept { return 0; }
static_assert(noexcept(f()) == false, "");
static_assert(noexcept(g()) == true, "");
}
namespace test_constexpr
{
template < typename CharT >
unsigned long constexpr
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
{
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
}
template < typename CharT >
unsigned long constexpr
strlen_c(const CharT *const s) noexcept
{
return strlen_c_r(s, 0UL);
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("1") == 1UL, "");
static_assert(strlen_c("example") == 7UL, "");
static_assert(strlen_c("another\0example") == 7UL, "");
}
namespace test_rvalue_references
{
template < int N >
struct answer
{
static constexpr int value = N;
};
answer<1> f(int&) { return answer<1>(); }
answer<2> f(const int&) { return answer<2>(); }
answer<3> f(int&&) { return answer<3>(); }
void
test()
{
int i = 0;
const int c = 0;
static_assert(decltype(f(i))::value == 1, "");
static_assert(decltype(f(c))::value == 2, "");
static_assert(decltype(f(0))::value == 3, "");
}
}
namespace test_uniform_initialization
{
struct test
{
static const int zero {};
static const int one {1};
};
static_assert(test::zero == 0, "");
static_assert(test::one == 1, "");
}
namespace test_lambdas
{
void
test1()
{
auto lambda1 = [](){};
auto lambda2 = lambda1;
lambda1();
lambda2();
}
int
test2()
{
auto a = [](int i, int j){ return i + j; }(1, 2);
auto b = []() -> int { return '0'; }();
auto c = [=](){ return a + b; }();
auto d = [&](){ return c; }();
auto e = [a, &b](int x) mutable {
const auto identity = [](int y){ return y; };
for (auto i = 0; i < a; ++i)
a += b--;
return x + identity(a + b);
}(0);
return a + b + c + d + e;
}
int
test3()
{
const auto nullary = [](){ return 0; };
const auto unary = [](int x){ return x; };
using nullary_t = decltype(nullary);
using unary_t = decltype(unary);
const auto higher1st = [](nullary_t f){ return f(); };
const auto higher2nd = [unary](nullary_t f1){
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
};
return higher1st(nullary) + higher2nd(nullary)(unary);
}
}
namespace test_variadic_templates
{
template <int...>
struct sum;
template <int N0, int... N1toN>
struct sum<N0, N1toN...>
{
static constexpr auto value = N0 + sum<N1toN...>::value;
};
template <>
struct sum<>
{
static constexpr auto value = 0;
};
static_assert(sum<>::value == 0, "");
static_assert(sum<1>::value == 1, "");
static_assert(sum<23>::value == 23, "");
static_assert(sum<1, 2>::value == 3, "");
static_assert(sum<5, 5, 11>::value == 21, "");
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
}
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
// because of this.
namespace test_template_alias_sfinae
{
struct foo {};
template<typename T>
using member = typename T::member_type;
template<typename T>
void func(...) {}
template<typename T>
void func(member<T>*) {}
void test();
void test() { func<foo>(0); }
}
} // namespace cxx11
#endif // __cplusplus >= 201103L
]])
dnl Tests for new features in C++14
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
// If the compiler admits that it is not ready for C++14, why torture it?
// Hopefully, this will speed up the test.
#ifndef __cplusplus
#error "This is not a C++ compiler"
#elif __cplusplus < 201402L
#error "This is not a C++14 compiler"
#else
namespace cxx14
{
namespace test_polymorphic_lambdas
{
int
test()
{
const auto lambda = [](auto&&... args){
const auto istiny = [](auto x){
return (sizeof(x) == 1UL) ? 1 : 0;
};
const int aretiny[] = { istiny(args)... };
return aretiny[0];
};
return lambda(1, 1L, 1.0f, '1');
}
}
namespace test_binary_literals
{
constexpr auto ivii = 0b0000000000101010;
static_assert(ivii == 42, "wrong value");
}
namespace test_generalized_constexpr
{
template < typename CharT >
constexpr unsigned long
strlen_c(const CharT *const s) noexcept
{
auto length = 0UL;
for (auto p = s; *p; ++p)
++length;
return length;
}
static_assert(strlen_c("") == 0UL, "");
static_assert(strlen_c("x") == 1UL, "");
static_assert(strlen_c("test") == 4UL, "");
static_assert(strlen_c("another\0test") == 7UL, "");
}
namespace test_lambda_init_capture
{
int
test()
{
auto x = 0;
const auto lambda1 = [a = x](int b){ return a + b; };
const auto lambda2 = [a = lambda1(x)](){ return a; };
return lambda2();
}
}
namespace test_digit_seperators
{
constexpr auto ten_million = 100'000'000;
static_assert(ten_million == 100000000, "");
}
namespace test_return_type_deduction
{
auto f(int& x) { return x; }
decltype(auto) g(int& x) { return x; }
template < typename T1, typename T2 >
struct is_same
{
static constexpr auto value = false;
};
template < typename T >
struct is_same<T, T>
{
static constexpr auto value = true;
};
int
test()
{
auto x = 0;
static_assert(is_same<int, decltype(f(x))>::value, "");
static_assert(is_same<int&, decltype(g(x))>::value, "");
return x;
}
}
} // namespace cxx14
#endif // __cplusplus >= 201402L
]])

View File

@ -0,0 +1,283 @@
# ===========================================================================
# http://www.nongnu.org/autoconf-archive/ax_pthread.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro figures out how to build C programs using POSIX threads. It
# sets the PTHREAD_LIBS output variable to the threads library and linker
# flags, and the PTHREAD_CFLAGS output variable to any special C compiler
# flags that are needed. (The user can also force certain compiler
# flags/libs to be tested by setting these environment variables.)
#
# Also sets PTHREAD_CC to any special C compiler that is needed for
# multi-threaded programs (defaults to the value of CC otherwise). (This
# is necessary on AIX to use the special cc_r compiler alias.)
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well. e.g. you should link with
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
#
# If you are only building threads programs, you may wish to use these
# variables in your default LIBS, CFLAGS, and CC:
#
# LIBS="$PTHREAD_LIBS $LIBS"
# CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# CC="$PTHREAD_CC"
#
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
#
# ACTION-IF-FOUND is a list of shell commands to run if a threads library
# is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
# is not found. If ACTION-IF-FOUND is not specified, the default action
# will define HAVE_PTHREAD.
#
# Please let the authors know if this macro fails on any platform, or if
# you have any other suggestions or comments. This macro was based on work
# by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
# from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
# Alejandro Forero Cuervo to the autoconf macro repository. We are also
# grateful for the helpful feedback of numerous users.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
AC_REQUIRE([AC_CANONICAL_HOST])
AC_LANG_SAVE
AC_LANG_C
ax_pthread_ok=no
# We used to check for pthread.h first, but this fails if pthread.h
# requires special compiler flags (e.g. on True64 or Sequent).
# It gets checked for in the link test anyway.
# First of all, check if the user has set any of the PTHREAD_LIBS,
# etcetera environment variables, and if threads linking works using
# them:
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
AC_TRY_LINK_FUNC(pthread_join, ax_pthread_ok=yes)
AC_MSG_RESULT($ax_pthread_ok)
if test x"$ax_pthread_ok" = xno; then
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
# We must check for the threads library under a number of different
# names; the ordering is very important because some systems
# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
# libraries is broken (non-POSIX).
# Create a list of thread flags to try. Items starting with a "-" are
# C compiler flags, and other items are library names, except for "none"
# which indicates that we try without any flags at all, and "pthread-config"
# which is a program returning the flags for the Pth emulation library.
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
# The ordering *is* (sometimes) important. Some notes on the
# individual items follow:
# pthreads: AIX (must check this before -lpthread)
# none: in case threads are in libc; should be tried before -Kthread and
# other compiler flags to prevent continual compiler warnings
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
# -pthreads: Solaris/gcc
# -mthreads: Mingw32/gcc, Lynx/gcc
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
# doesn't hurt to check since this sometimes defines pthreads too;
# also defines -D_REENTRANT)
# ... -mt is also the pthreads flag for HP/aCC
# pthread: Linux, etcetera
# --thread-safe: KAI C++
# pthread-config: use pthread-config program (for GNU Pth library)
case "${host_cpu}-${host_os}" in
*solaris*)
# On Solaris (at least, for some versions), libc contains stubbed
# (non-functional) versions of the pthreads routines, so link-based
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
# a function called by this macro, so we could check for that, but
# who knows whether they'll stub that too in a future libc.) So,
# we'll just look for -pthreads and -lpthread first:
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
;;
*-darwin*)
acx_pthread_flags="-pthread $acx_pthread_flags"
;;
esac
if test x"$ax_pthread_ok" = xno; then
for flag in $ax_pthread_flags; do
case $flag in
none)
AC_MSG_CHECKING([whether pthreads work without any flags])
;;
-*)
AC_MSG_CHECKING([whether pthreads work with $flag])
PTHREAD_CFLAGS="$flag"
;;
pthread-config)
AC_CHECK_PROG(ax_pthread_config, pthread-config, yes, no)
if test x"$ax_pthread_config" = xno; then continue; fi
PTHREAD_CFLAGS="`pthread-config --cflags`"
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
;;
*)
AC_MSG_CHECKING([for the pthreads library -l$flag])
PTHREAD_LIBS="-l$flag"
;;
esac
save_LIBS="$LIBS"
save_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for various functions. We must include pthread.h,
# since some functions may be macros. (On the Sequent, we
# need a special flag -Kthread to make this header compile.)
# We check for pthread_join because it is in -lpthread on IRIX
# while pthread_create is in libc. We check for pthread_attr_init
# due to DEC craziness with -lpthreads. We check for
# pthread_cleanup_push because it is one of the few pthread
# functions on Solaris that doesn't have a non-functional libc stub.
# We try pthread_create on general principles.
AC_TRY_LINK([#include <pthread.h>
static void routine(void* a) {a=0;}
static void* start_routine(void* a) {return a;}],
[pthread_t th; pthread_attr_t attr;
pthread_join(th, 0);
pthread_attr_init(&attr);
pthread_cleanup_push(routine, 0);
pthread_create(&th,0,start_routine,0);
pthread_cleanup_pop(0); ],
[ax_pthread_ok=yes])
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
AC_MSG_RESULT($ax_pthread_ok)
if test "x$ax_pthread_ok" = xyes; then
break;
fi
PTHREAD_LIBS=""
PTHREAD_CFLAGS=""
done
fi
# Various other checks:
if test "x$ax_pthread_ok" = xyes; then
save_LIBS="$LIBS"
LIBS="$PTHREAD_LIBS $LIBS"
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
AC_MSG_CHECKING([for joinable pthread attribute])
attr_name=unknown
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
[attr_name=$attr; break])
done
AC_MSG_RESULT($attr_name)
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
[Define to necessary symbol if this constant
uses a non-standard name on your system.])
fi
AC_MSG_CHECKING([if more special flags are required for pthreads])
flag=no
case "${host_cpu}-${host_os}" in
*-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
*solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
esac
AC_MSG_RESULT(${flag})
if test "x$flag" != xno; then
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
fi
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
# More AIX lossage: must compile with xlc_r or cc_r
if test x"$GCC" != xyes; then
AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
else
PTHREAD_CC=$CC
fi
else
PTHREAD_CC="$CC"
fi
AC_SUBST(PTHREAD_LIBS)
AC_SUBST(PTHREAD_CFLAGS)
AC_SUBST(PTHREAD_CC)
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
if test x"$ax_pthread_ok" = xyes; then
ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
:
else
ax_pthread_ok=no
$2
fi
AC_LANG_RESTORE
])dnl AX_PTHREAD

View File

@ -0,0 +1,37 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 1
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,368 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option `$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl `shared' nor `disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [0], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the `shared' and
# `disable-shared' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the `static' and
# `disable-static' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the `fast-install'
# and `disable-fast-install' LT_INIT options.
# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
for pkg in $enableval; do
IFS="$lt_save_ifs"
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS="$lt_save_ifs"
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the `disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the `pic-only' and `no-pic'
# LT_INIT options.
# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[pic_mode="$withval"],
[pic_mode=default])
test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the `pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

View File

@ -0,0 +1,123 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

View File

@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# Generated from ltversion.in.
# serial 3017 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.2.6b])
m4_define([LT_PACKAGE_REVISION], [1.3017])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.2.6b'
macro_revision='1.3017'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

View File

@ -0,0 +1,92 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 4 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])

View File

@ -0,0 +1,57 @@
// Copyright (c) 2009, 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 BREAKPAD_GOOGLETEST_INCLUDES_H__
#define BREAKPAD_GOOGLETEST_INCLUDES_H__
#include "gtest/gtest.h"
#include "gmock/gmock.h"
// If AddressSanitizer is used, NULL pointer dereferences generate SIGILL
// (illegal instruction) instead of SIGSEGV (segmentation fault). Also,
// the number of memory regions differs, so there is no point in running
// this test if AddressSanitizer is used.
//
// Ideally we'd use this attribute to disable ASAN on a per-func basis,
// but this doesn't seem to actually work, and it's changed names over
// time. So just stick with disabling the actual tests.
// http://crbug.com/304575
//#define NO_ASAN __attribute__((no_sanitize_address))
#if defined(__clang__) && defined(__has_feature)
// Have to keep this check sep from above as newer gcc will barf on it.
# if __has_feature(address_sanitizer)
# define ADDRESS_SANITIZER
# endif
#elif defined(__GNUC__) && defined(__SANITIZE_ADDRESS__)
# define ADDRESS_SANITIZER
#else
# undef ADDRESS_SANITIZER
#endif
#endif // BREAKPAD_GOOGLETEST_INCLUDES_H__

View File

@ -0,0 +1,73 @@
// 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.
// Keys for configuration file
#define kReporterMinidumpDirectoryKey "MinidumpDir"
#define kReporterMinidumpIDKey "MinidumpID"
// Filename for recording uploaded IDs
#define kReporterLogFilename "uploads.log"
// The default subdirectory of the Library to put crash dumps in
// The subdirectory is
// ~/Library/<kDefaultLibrarySubdirectory>/<GoogleBreakpadProduct>
#define kDefaultLibrarySubdirectory "Breakpad"
// Specify some special keys to be used in the configuration file that is
// generated by Breakpad and consumed by the crash_sender.
#define BREAKPAD_PRODUCT "BreakpadProduct"
#define BREAKPAD_PRODUCT_DISPLAY "BreakpadProductDisplay"
#define BREAKPAD_VERSION "BreakpadVersion"
#define BREAKPAD_VENDOR "BreakpadVendor"
#define BREAKPAD_URL "BreakpadURL"
#define BREAKPAD_REPORT_INTERVAL "BreakpadReportInterval"
#define BREAKPAD_SKIP_CONFIRM "BreakpadSkipConfirm"
#define BREAKPAD_CONFIRM_TIMEOUT "BreakpadConfirmTimeout"
#define BREAKPAD_SEND_AND_EXIT "BreakpadSendAndExit"
#define BREAKPAD_DUMP_DIRECTORY "BreakpadMinidumpLocation"
#define BREAKPAD_INSPECTOR_LOCATION "BreakpadInspectorLocation"
#define BREAKPAD_REPORTER_EXE_LOCATION \
"BreakpadReporterExeLocation"
#define BREAKPAD_LOGFILES "BreakpadLogFiles"
#define BREAKPAD_LOGFILE_UPLOAD_SIZE "BreakpadLogFileTailSize"
#define BREAKPAD_REQUEST_COMMENTS "BreakpadRequestComments"
#define BREAKPAD_COMMENTS "BreakpadComments"
#define BREAKPAD_REQUEST_EMAIL "BreakpadRequestEmail"
#define BREAKPAD_EMAIL "BreakpadEmail"
#define BREAKPAD_SERVER_TYPE "BreakpadServerType"
#define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters"
#define BREAKPAD_IN_PROCESS "BreakpadInProcess"
// The keys below are NOT user supplied, and are used internally.
#define BREAKPAD_PROCESS_START_TIME "BreakpadProcStartTime"
#define BREAKPAD_PROCESS_UP_TIME "BreakpadProcessUpTime"
#define BREAKPAD_PROCESS_CRASH_TIME "BreakpadProcessCrashTime"
#define BREAKPAD_LOGFILE_KEY_PREFIX "BreakpadAppLogFile"
#define BREAKPAD_SERVER_PARAMETER_PREFIX "BreakpadServerParameterPrefix_"
#define BREAKPAD_ON_DEMAND "BreakpadOnDemand"

View File

@ -0,0 +1,260 @@
// 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.
// Framework to provide a simple C API to crash reporting for
// applications. By default, if any machine-level exception (e.g.,
// EXC_BAD_ACCESS) occurs, it will be handled by the BreakpadRef
// object as follows:
//
// 1. Create a minidump file (see Breakpad for details)
// 2. Create a config file.
//
// These files can then be uploaded to a server.
typedef void* BreakpadRef;
#ifdef __cplusplus
extern "C" {
#endif
#include <Foundation/Foundation.h>
#include <client/apple/Framework/BreakpadDefines.h>
// The keys in the dictionary returned by |BreakpadGenerateReport|.
#define BREAKPAD_OUTPUT_DUMP_FILE "BreakpadDumpFile"
#define BREAKPAD_OUTPUT_CONFIG_FILE "BreakpadConfigFile"
// Optional user-defined function to decide if we should handle this crash or
// forward it along.
// Return true if you want Breakpad to handle it.
// Return false if you want Breakpad to skip it
// The exception handler always returns false, as if SEND_AND_EXIT were false
// (which means the next exception handler will take the exception)
typedef bool (*BreakpadFilterCallback)(int exception_type,
int exception_code,
mach_port_t crashing_thread,
void* context);
// Optional user-defined function that will be called after a network upload
// of a crash report.
// |report_id| will be the id returned by the server, or "ERR" if an error
// occurred.
// |error| will contain the error, or nil if no error occured.
typedef void (*BreakpadUploadCompletionCallback)(NSString* report_id,
NSError* error);
// Create a new BreakpadRef object and install it as an exception
// handler. The |parameters| will typically be the contents of your
// bundle's Info.plist.
//
// You can also specify these additional keys for customizable behavior:
// Key: Value:
// BREAKPAD_PRODUCT Product name (e.g., "MyAwesomeProduct")
// This one is used as the key to identify
// the product when uploading. Falls back to
// CFBundleName if not specified.
// REQUIRED
//
// BREAKPAD_PRODUCT_DISPLAY This is the display name, e.g. a pretty
// name for the product when the crash_sender
// pops up UI for the user. Falls back first to
// CFBundleDisplayName and then to
// BREAKPAD_PRODUCT if not specified.
//
// BREAKPAD_VERSION Product version (e.g., 1.2.3), used
// as metadata for crash report. Falls back to
// CFBundleVersion if not specified.
// REQUIRED
//
// BREAKPAD_VENDOR Vendor name, used in UI (e.g. "A report has
// been created that you can send to <vendor>")
//
// BREAKPAD_URL URL destination for reporting
// REQUIRED
//
// BREAKPAD_DUMP_DIRECTORY The directory to store crash-dumps
// in. By default, we use
// ~/Library/Cache/Breakpad/<BREAKPAD_PRODUCT>
// The path you specify here is tilde-expanded.
//
// BREAKPAD_SERVER_TYPE A parameter that tells Breakpad how to
// rewrite the upload parameters for a specific
// server type. The currently valid values are
// 'socorro' or 'google'. If you want to add
// other types, see the function in
// crash_report_sender.m that maps parameters to
// URL parameters. Defaults to 'google'.
//
// BREAKPAD_SERVER_PARAMETER_DICT A plist dictionary of static
// parameters that are uploaded to the
// server. The parameters are sent as
// is to the crash server. Their
// content isn't added to the minidump
// but pass as URL parameters when
// uploading theminidump to the crash
// server.
//=============================================================================
// The BREAKPAD_PRODUCT, BREAKPAD_VERSION and BREAKPAD_URL are
// required to have non-NULL values. By default, the BREAKPAD_PRODUCT
// will be the CFBundleName and the BREAKPAD_VERSION will be the
// CFBundleVersion when these keys are present in the bundle's
// Info.plist, which is usually passed in to BreakpadCreate() as an
// NSDictionary (you could also pass in another dictionary that had
// the same keys configured). If the BREAKPAD_PRODUCT or
// BREAKPAD_VERSION are ultimately undefined, BreakpadCreate() will
// fail. You have been warned.
//
// If you are running in a debugger, Breakpad will not install, unless the
// BREAKPAD_IGNORE_DEBUGGER envionment variable is set and/or non-zero.
//
//=============================================================================
// The following are NOT user-supplied but are documented here for
// completeness. They are calculated by Breakpad during initialization &
// crash-dump generation, or entered in by the user.
//
// BREAKPAD_PROCESS_START_TIME The time, in seconds since the Epoch, the
// process started
//
// BREAKPAD_PROCESS_CRASH_TIME The time, in seconds since the Epoch, the
// process crashed.
//
// BREAKPAD_PROCESS_UP_TIME The total time in milliseconds the process
// has been running. This parameter is not
// set until the crash-dump-generation phase.
//
// BREAKPAD_SERVER_PARAMETER_PREFIX This prefix is used by Breakpad
// internally, because Breakpad uses
// the same dictionary internally to
// track both its internal
// configuration parameters and
// parameters meant to be uploaded
// to the server. This string is
// used internally by Breakpad to
// prefix user-supplied parameter
// names so those can be sent to the
// server without leaking Breakpad's
// internal values.
// Returns a new BreakpadRef object on success, NULL otherwise.
BreakpadRef BreakpadCreate(NSDictionary* parameters);
// Uninstall and release the data associated with |ref|.
void BreakpadRelease(BreakpadRef ref);
// User defined key and value string storage. Generally this is used
// to configure Breakpad's internal operation, such as whether the
// crash_sender should prompt the user, or the filesystem location for
// the minidump file. See Breakpad.h for some parameters that can be
// set. Anything longer than 255 bytes will be truncated. Note that
// the string is converted to UTF8 before truncation, so any multibyte
// character that straddles the 255(256 - 1 for terminator) byte limit
// will be mangled.
//
// A maximum number of 64 key/value pairs are supported. An assert()
// will fire if more than this number are set. Unfortunately, right
// now, the same dictionary is used for both Breakpad's parameters AND
// the Upload parameters.
//
// TODO (nealsid): Investigate how necessary this is if we don't
// automatically upload parameters to the server anymore.
// TODO (nealsid): separate server parameter dictionary from the
// dictionary used to configure Breakpad, and document limits for each
// independently.
void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value);
NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key);
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key);
// You can use this method to specify parameters that will be uploaded
// to the crash server. They will be automatically encoded as
// necessary. Note that as mentioned above there are limits on both
// the number of keys and their length.
void BreakpadAddUploadParameter(BreakpadRef ref, NSString* key,
NSString* value);
// This method will remove a previously-added parameter from the
// upload parameter set.
void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString* key);
// Method to handle uploading data to the server
// Returns the number of crash reports waiting to send to the server.
int BreakpadGetCrashReportCount(BreakpadRef ref);
// Returns the next upload configuration. The report file is deleted.
NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref);
// Returns the date of the most recent crash report.
NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref);
// Upload next report to the server.
void BreakpadUploadNextReport(BreakpadRef ref);
// Upload next report to the server.
// |server_parameters| is additional server parameters to send.
void BreakpadUploadNextReportWithParameters(
BreakpadRef ref,
NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback);
// Upload a report to the server.
// |server_parameters| is additional server parameters to send.
// |configuration| is the configuration of the breakpad report to send.
void BreakpadUploadReportWithParametersAndConfiguration(
BreakpadRef ref,
NSDictionary* server_parameters,
NSDictionary* configuration,
BreakpadUploadCompletionCallback callback);
// Handles the network response of a breakpad upload. This function is needed if
// the actual upload is done by the Breakpad client.
// |configuration| is the configuration of the upload. It must contain the same
// fields as the configuration passed to
// BreakpadUploadReportWithParametersAndConfiguration.
// |data| and |error| contain the network response.
void BreakpadHandleNetworkResponse(BreakpadRef ref,
NSDictionary* configuration,
NSData* data,
NSError* error);
// Upload a file to the server. |data| is the content of the file to sent.
// |server_parameters| is additional server parameters to send.
void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name,
NSDictionary* server_parameters);
// Generate a breakpad minidump and configuration file in the dump directory.
// The report will be available for uploading. The paths of the created files
// are returned in the dictionary. |server_parameters| is additional server
// parameters to add in the config file.
NSDictionary* BreakpadGenerateReport(BreakpadRef ref,
NSDictionary* server_parameters);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,987 @@
// 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.
#define IGNORE_DEBUGGER "BREAKPAD_IGNORE_DEBUGGER"
#import "client/ios/Breakpad.h"
#include <assert.h>
#import <Foundation/Foundation.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <TargetConditionals.h>
#include <string>
#import "client/ios/handler/ios_exception_minidump_generator.h"
#import "client/mac/crash_generation/ConfigFile.h"
#import "client/mac/handler/minidump_generator.h"
#import "client/mac/handler/protected_memory_allocator.h"
#import "client/mac/sender/uploader.h"
#import "common/long_string_dictionary.h"
#if !TARGET_OS_TV && !TARGET_OS_WATCH
#import "client/mac/handler/exception_handler.h"
#else
#import "client/ios/exception_handler_no_mach.h"
#endif // !TARGET_OS_TV && !TARGET_OS_WATCH
#if !defined(__EXCEPTIONS) || (__clang__ && !__has_feature(cxx_exceptions))
// This file uses C++ try/catch (but shouldn't). Duplicate the macros from
// <c++/4.2.1/exception_defines.h> allowing this file to work properly with
// exceptions disabled even when other C++ libraries are used. #undef the try
// and catch macros first in case libstdc++ is in use and has already provided
// its own definitions.
#undef try
#define try if (true)
#undef catch
#define catch(X) if (false)
#endif // __EXCEPTIONS
using google_breakpad::ConfigFile;
using google_breakpad::EnsureDirectoryPathExists;
using google_breakpad::LongStringDictionary;
//=============================================================================
// We want any memory allocations which are used by breakpad during the
// exception handling process (after a crash has happened) to be read-only
// to prevent them from being smashed before a crash occurs. Unfortunately
// we cannot protect against smashes to our exception handling thread's
// stack.
//
// NOTE: Any memory allocations which are not used during the exception
// handling process may be allocated in the normal ways.
//
// The ProtectedMemoryAllocator class provides an Allocate() method which
// we'll using in conjunction with placement operator new() to control
// allocation of C++ objects. Note that we don't use operator delete()
// but instead call the objects destructor directly: object->~ClassName();
//
ProtectedMemoryAllocator* gMasterAllocator = NULL;
ProtectedMemoryAllocator* gKeyValueAllocator = NULL;
ProtectedMemoryAllocator* gBreakpadAllocator = NULL;
// Mutex for thread-safe access to the key/value dictionary used by breakpad.
// It's a global instead of an instance variable of Breakpad
// since it can't live in a protected memory area.
pthread_mutex_t gDictionaryMutex;
//=============================================================================
// Stack-based object for thread-safe access to a memory-protected region.
// It's assumed that normally the memory block (allocated by the allocator)
// is protected (read-only). Creating a stack-based instance of
// ProtectedMemoryLocker will unprotect this block after taking the lock.
// Its destructor will first re-protect the memory then release the lock.
class ProtectedMemoryLocker {
public:
ProtectedMemoryLocker(pthread_mutex_t* mutex,
ProtectedMemoryAllocator* allocator)
: mutex_(mutex),
allocator_(allocator) {
// Lock the mutex
__attribute__((unused)) int rv = pthread_mutex_lock(mutex_);
assert(rv == 0);
// Unprotect the memory
allocator_->Unprotect();
}
~ProtectedMemoryLocker() {
// First protect the memory
allocator_->Protect();
// Then unlock the mutex
__attribute__((unused)) int rv = pthread_mutex_unlock(mutex_);
assert(rv == 0);
}
private:
ProtectedMemoryLocker();
ProtectedMemoryLocker(const ProtectedMemoryLocker&);
ProtectedMemoryLocker& operator=(const ProtectedMemoryLocker&);
pthread_mutex_t* mutex_;
ProtectedMemoryAllocator* allocator_;
};
//=============================================================================
class Breakpad {
public:
// factory method
static Breakpad* Create(NSDictionary* parameters) {
// Allocate from our special allocation pool
Breakpad* breakpad =
new (gBreakpadAllocator->Allocate(sizeof(Breakpad)))
Breakpad();
if (!breakpad)
return NULL;
if (!breakpad->Initialize(parameters)) {
// Don't use operator delete() here since we allocated from special pool
breakpad->~Breakpad();
return NULL;
}
return breakpad;
}
~Breakpad();
void SetKeyValue(NSString* key, NSString* value);
NSString* KeyValue(NSString* key);
void RemoveKeyValue(NSString* key);
NSArray* CrashReportsToUpload();
NSString* NextCrashReportToUpload();
NSDictionary* NextCrashReportConfiguration();
NSDictionary* FixedUpCrashReportConfiguration(NSDictionary* configuration);
NSDate* DateOfMostRecentCrashReport();
void UploadNextReport(NSDictionary* server_parameters);
void UploadReportWithConfiguration(NSDictionary* configuration,
NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback);
void UploadData(NSData* data, NSString* name,
NSDictionary* server_parameters);
void HandleNetworkResponse(NSDictionary* configuration,
NSData* data,
NSError* error);
NSDictionary* GenerateReport(NSDictionary* server_parameters);
private:
Breakpad()
: handler_(NULL),
config_params_(NULL) {}
bool Initialize(NSDictionary* parameters);
bool ExtractParameters(NSDictionary* parameters);
// Dispatches to HandleMinidump()
static bool HandleMinidumpCallback(const char* dump_dir,
const char* minidump_id,
void* context, bool succeeded);
bool HandleMinidump(const char* dump_dir,
const char* minidump_id);
// NSException handler
static void UncaughtExceptionHandler(NSException* exception);
// Handle an uncaught NSException.
void HandleUncaughtException(NSException* exception);
// Since ExceptionHandler (w/o namespace) is defined as typedef in OSX's
// MachineExceptions.h, we have to explicitly name the handler.
google_breakpad::ExceptionHandler* handler_; // The actual handler (STRONG)
LongStringDictionary* config_params_; // Create parameters (STRONG)
ConfigFile config_file_;
// A static reference to the current Breakpad instance. Used for handling
// NSException.
static Breakpad* current_breakpad_;
};
Breakpad* Breakpad::current_breakpad_ = NULL;
#pragma mark -
#pragma mark Helper functions
//=============================================================================
// Helper functions
//=============================================================================
static BOOL IsDebuggerActive() {
BOOL result = NO;
NSUserDefaults* stdDefaults = [NSUserDefaults standardUserDefaults];
// We check both defaults and the environment variable here
BOOL ignoreDebugger = [stdDefaults boolForKey:@IGNORE_DEBUGGER];
if (!ignoreDebugger) {
char* ignoreDebuggerStr = getenv(IGNORE_DEBUGGER);
ignoreDebugger =
(ignoreDebuggerStr ? strtol(ignoreDebuggerStr, NULL, 10) : 0) != 0;
}
if (!ignoreDebugger) {
pid_t pid = getpid();
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
int mibSize = sizeof(mib) / sizeof(int);
size_t actualSize;
if (sysctl(mib, mibSize, NULL, &actualSize, NULL, 0) == 0) {
struct kinfo_proc* info = (struct kinfo_proc*)malloc(actualSize);
if (info) {
// This comes from looking at the Darwin xnu Kernel
if (sysctl(mib, mibSize, info, &actualSize, NULL, 0) == 0)
result = (info->kp_proc.p_flag & P_TRACED) ? YES : NO;
free(info);
}
}
}
return result;
}
//=============================================================================
bool Breakpad::HandleMinidumpCallback(const char* dump_dir,
const char* minidump_id,
void* context, bool succeeded) {
Breakpad* breakpad = (Breakpad*)context;
// If our context is damaged or something, just return false to indicate that
// the handler should continue without us.
if (!breakpad || !succeeded)
return false;
return breakpad->HandleMinidump(dump_dir, minidump_id);
}
//=============================================================================
void Breakpad::UncaughtExceptionHandler(NSException* exception) {
NSSetUncaughtExceptionHandler(NULL);
if (current_breakpad_) {
current_breakpad_->HandleUncaughtException(exception);
BreakpadRelease(current_breakpad_);
}
}
//=============================================================================
#pragma mark -
//=============================================================================
bool Breakpad::Initialize(NSDictionary* parameters) {
// Initialize
current_breakpad_ = this;
config_params_ = NULL;
handler_ = NULL;
// Gather any user specified parameters
if (!ExtractParameters(parameters)) {
return false;
}
// Check for debugger
if (IsDebuggerActive()) {
return true;
}
// Create the handler (allocating it in our special protected pool)
handler_ =
new (gBreakpadAllocator->Allocate(
sizeof(google_breakpad::ExceptionHandler)))
google_breakpad::ExceptionHandler(
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY),
0, &HandleMinidumpCallback, this, true, 0);
NSSetUncaughtExceptionHandler(&Breakpad::UncaughtExceptionHandler);
return true;
}
//=============================================================================
Breakpad::~Breakpad() {
NSSetUncaughtExceptionHandler(NULL);
current_breakpad_ = NULL;
// Note that we don't use operator delete() on these pointers,
// since they were allocated by ProtectedMemoryAllocator objects.
//
if (config_params_) {
config_params_->~LongStringDictionary();
}
if (handler_)
handler_->~ExceptionHandler();
}
//=============================================================================
bool Breakpad::ExtractParameters(NSDictionary* parameters) {
NSString* serverType = [parameters objectForKey:@BREAKPAD_SERVER_TYPE];
NSString* display = [parameters objectForKey:@BREAKPAD_PRODUCT_DISPLAY];
NSString* product = [parameters objectForKey:@BREAKPAD_PRODUCT];
NSString* version = [parameters objectForKey:@BREAKPAD_VERSION];
NSString* urlStr = [parameters objectForKey:@BREAKPAD_URL];
NSString* vendor =
[parameters objectForKey:@BREAKPAD_VENDOR];
// We check both parameters and the environment variable here.
char* envVarDumpSubdirectory = getenv(BREAKPAD_DUMP_DIRECTORY);
NSString* dumpSubdirectory = envVarDumpSubdirectory ?
[NSString stringWithUTF8String:envVarDumpSubdirectory] :
[parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
NSDictionary* serverParameters =
[parameters objectForKey:@BREAKPAD_SERVER_PARAMETER_DICT];
if (!product)
product = [parameters objectForKey:@"CFBundleName"];
if (!display) {
display = [parameters objectForKey:@"CFBundleDisplayName"];
if (!display) {
display = product;
}
}
if (!version.length) // Default nil or empty string to CFBundleVersion
version = [parameters objectForKey:@"CFBundleVersion"];
if (!vendor) {
vendor = @"Vendor not specified";
}
if (!dumpSubdirectory) {
NSString* cachePath =
[NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
NSUserDomainMask,
YES)
objectAtIndex:0];
dumpSubdirectory =
[cachePath stringByAppendingPathComponent:@kDefaultLibrarySubdirectory];
EnsureDirectoryPathExists(dumpSubdirectory);
}
// The product, version, and URL are required values.
if (![product length]) {
return false;
}
if (![version length]) {
return false;
}
if (![urlStr length]) {
return false;
}
config_params_ =
new (gKeyValueAllocator->Allocate(sizeof(LongStringDictionary)))
LongStringDictionary();
LongStringDictionary& dictionary = *config_params_;
dictionary.SetKeyValue(BREAKPAD_SERVER_TYPE, [serverType UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT_DISPLAY, [display UTF8String]);
dictionary.SetKeyValue(BREAKPAD_PRODUCT, [product UTF8String]);
dictionary.SetKeyValue(BREAKPAD_VERSION, [version UTF8String]);
dictionary.SetKeyValue(BREAKPAD_URL, [urlStr UTF8String]);
dictionary.SetKeyValue(BREAKPAD_VENDOR, [vendor UTF8String]);
dictionary.SetKeyValue(BREAKPAD_DUMP_DIRECTORY,
[dumpSubdirectory UTF8String]);
struct timeval tv;
gettimeofday(&tv, NULL);
char timeStartedString[32];
sprintf(timeStartedString, "%zd", tv.tv_sec);
dictionary.SetKeyValue(BREAKPAD_PROCESS_START_TIME, timeStartedString);
if (serverParameters) {
// For each key-value pair, call BreakpadAddUploadParameter()
NSEnumerator* keyEnumerator = [serverParameters keyEnumerator];
NSString* aParameter;
while ((aParameter = [keyEnumerator nextObject])) {
BreakpadAddUploadParameter(this, aParameter,
[serverParameters objectForKey:aParameter]);
}
}
return true;
}
//=============================================================================
void Breakpad::SetKeyValue(NSString* key, NSString* value) {
// We allow nil values. This is the same as removing the keyvalue.
if (!config_params_ || !key)
return;
config_params_->SetKeyValue([key UTF8String], [value UTF8String]);
}
//=============================================================================
NSString* Breakpad::KeyValue(NSString* key) {
if (!config_params_ || !key)
return nil;
const std::string value = config_params_->GetValueForKey([key UTF8String]);
return value.empty() ? nil : [NSString stringWithUTF8String:value.c_str()];
}
//=============================================================================
void Breakpad::RemoveKeyValue(NSString* key) {
if (!config_params_ || !key) return;
config_params_->RemoveKey([key UTF8String]);
}
//=============================================================================
NSArray* Breakpad::CrashReportsToUpload() {
NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory)
return nil;
NSArray* dirContents = [[NSFileManager defaultManager]
contentsOfDirectoryAtPath:directory error:nil];
NSArray* configs = [dirContents filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"self BEGINSWITH 'Config-'"]];
return configs;
}
//=============================================================================
NSString* Breakpad::NextCrashReportToUpload() {
NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory)
return nil;
NSString* config = [CrashReportsToUpload() lastObject];
if (!config)
return nil;
return [NSString stringWithFormat:@"%@/%@", directory, config];
}
//=============================================================================
NSDictionary* Breakpad::NextCrashReportConfiguration() {
NSDictionary* configuration = [Uploader readConfigurationDataFromFile:NextCrashReportToUpload()];
return FixedUpCrashReportConfiguration(configuration);
}
//=============================================================================
NSDictionary* Breakpad::FixedUpCrashReportConfiguration(NSDictionary* configuration) {
NSMutableDictionary* fixedConfiguration = [[configuration mutableCopy] autorelease];
// kReporterMinidumpDirectoryKey can become stale because the app's data container path includes
// an UUID that is not guaranteed to stay the same over time.
[fixedConfiguration setObject:KeyValue(@BREAKPAD_DUMP_DIRECTORY)
forKey:@kReporterMinidumpDirectoryKey];
return fixedConfiguration;
}
//=============================================================================
NSDate* Breakpad::DateOfMostRecentCrashReport() {
NSString* directory = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!directory) {
return nil;
}
NSFileManager* fileManager = [NSFileManager defaultManager];
NSArray* dirContents = [fileManager contentsOfDirectoryAtPath:directory error:nil];
NSArray* dumps = [dirContents filteredArrayUsingPredicate:[NSPredicate
predicateWithFormat:@"self ENDSWITH '.dmp'"]];
NSDate* mostRecentCrashReportDate = nil;
for (NSString* dump in dumps) {
NSString* filePath = [directory stringByAppendingPathComponent:dump];
NSDate* crashReportDate =
[[fileManager attributesOfItemAtPath:filePath error:nil] fileCreationDate];
if (!mostRecentCrashReportDate) {
mostRecentCrashReportDate = crashReportDate;
} else if (crashReportDate) {
mostRecentCrashReportDate = [mostRecentCrashReportDate laterDate:crashReportDate];
}
}
return mostRecentCrashReportDate;
}
//=============================================================================
void Breakpad::HandleNetworkResponse(NSDictionary* configuration,
NSData* data,
NSError* error) {
Uploader* uploader = [[[Uploader alloc]
initWithConfig:configuration] autorelease];
[uploader handleNetworkResponse:data withError:error];
}
//=============================================================================
void Breakpad::UploadReportWithConfiguration(
NSDictionary* configuration,
NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback) {
Uploader* uploader = [[[Uploader alloc]
initWithConfig:configuration] autorelease];
if (!uploader)
return;
for (NSString* key in server_parameters) {
[uploader addServerParameter:[server_parameters objectForKey:key]
forKey:key];
}
if (callback) {
[uploader setUploadCompletionBlock:^(NSString* report_id, NSError* error) {
dispatch_async(dispatch_get_main_queue(), ^{
callback(report_id, error);
});
}];
}
[uploader report];
}
//=============================================================================
void Breakpad::UploadNextReport(NSDictionary* server_parameters) {
NSDictionary* configuration = NextCrashReportConfiguration();
if (configuration) {
return UploadReportWithConfiguration(configuration, server_parameters,
nullptr);
}
}
//=============================================================================
void Breakpad::UploadData(NSData* data, NSString* name,
NSDictionary* server_parameters) {
NSMutableDictionary* config = [NSMutableDictionary dictionary];
LongStringDictionary::Iterator it(*config_params_);
while (const LongStringDictionary::Entry* next = it.Next()) {
[config setValue:[NSString stringWithUTF8String:next->value]
forKey:[NSString stringWithUTF8String:next->key]];
}
Uploader* uploader =
[[[Uploader alloc] initWithConfig:config] autorelease];
for (NSString* key in server_parameters) {
[uploader addServerParameter:[server_parameters objectForKey:key]
forKey:key];
}
[uploader uploadData:data name:name];
}
//=============================================================================
NSDictionary* Breakpad::GenerateReport(NSDictionary* server_parameters) {
NSString* dumpDirAsNSString = KeyValue(@BREAKPAD_DUMP_DIRECTORY);
if (!dumpDirAsNSString)
return nil;
const char* dumpDir = [dumpDirAsNSString UTF8String];
google_breakpad::MinidumpGenerator generator(mach_task_self(),
MACH_PORT_NULL);
std::string dumpId;
std::string dumpFilename = generator.UniqueNameInDirectory(dumpDir, &dumpId);
bool success = generator.Write(dumpFilename.c_str());
if (!success)
return nil;
LongStringDictionary params = *config_params_;
for (NSString* key in server_parameters) {
params.SetKeyValue([key UTF8String],
[[server_parameters objectForKey:key] UTF8String]);
}
ConfigFile config_file;
config_file.WriteFile(dumpDir, &params, dumpDir, dumpId.c_str());
// Handle results.
NSMutableDictionary* result = [NSMutableDictionary dictionary];
NSString* dumpFullPath = [NSString stringWithUTF8String:dumpFilename.c_str()];
[result setValue:dumpFullPath
forKey:@BREAKPAD_OUTPUT_DUMP_FILE];
[result setValue:[NSString stringWithUTF8String:config_file.GetFilePath()]
forKey:@BREAKPAD_OUTPUT_CONFIG_FILE];
return result;
}
//=============================================================================
bool Breakpad::HandleMinidump(const char* dump_dir,
const char* minidump_id) {
config_file_.WriteFile(dump_dir,
config_params_,
dump_dir,
minidump_id);
// Return true here to indicate that we've processed things as much as we
// want.
return true;
}
//=============================================================================
void Breakpad::HandleUncaughtException(NSException* exception) {
// Generate the minidump.
google_breakpad::IosExceptionMinidumpGenerator generator(exception);
const std::string minidump_path =
config_params_->GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
std::string minidump_id;
std::string minidump_filename = generator.UniqueNameInDirectory(minidump_path,
&minidump_id);
generator.Write(minidump_filename.c_str());
// Copy the config params and our custom parameter. This is necessary for 2
// reasons:
// 1- config_params_ is protected.
// 2- If the application crash while trying to handle this exception, a usual
// report will be generated. This report must not contain these special
// keys.
LongStringDictionary params = *config_params_;
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "type", "exception");
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionName",
[[exception name] UTF8String]);
params.SetKeyValue(BREAKPAD_SERVER_PARAMETER_PREFIX "exceptionReason",
[[exception reason] UTF8String]);
// And finally write the config file.
ConfigFile config_file;
config_file.WriteFile(minidump_path.c_str(),
&params,
minidump_path.c_str(),
minidump_id.c_str());
}
//=============================================================================
#pragma mark -
#pragma mark Public API
//=============================================================================
BreakpadRef BreakpadCreate(NSDictionary* parameters) {
try {
// This is confusing. Our two main allocators for breakpad memory are:
// - gKeyValueAllocator for the key/value memory
// - gBreakpadAllocator for the Breakpad, ExceptionHandler, and other
// breakpad allocations which are accessed at exception handling time.
//
// But in order to avoid these two allocators themselves from being smashed,
// we'll protect them as well by allocating them with gMasterAllocator.
//
// gMasterAllocator itself will NOT be protected, but this doesn't matter,
// since once it does its allocations and locks the memory, smashes to
// itself don't affect anything we care about.
gMasterAllocator =
new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2);
gKeyValueAllocator =
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
ProtectedMemoryAllocator(sizeof(LongStringDictionary));
// Create a mutex for use in accessing the LongStringDictionary
int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL);
if (mutexResult == 0) {
// With the current compiler, gBreakpadAllocator is allocating 1444 bytes.
// Let's round up to the nearest page size.
//
int breakpad_pool_size = 4096;
/*
sizeof(Breakpad)
+ sizeof(google_breakpad::ExceptionHandler)
+ sizeof( STUFF ALLOCATED INSIDE ExceptionHandler )
*/
gBreakpadAllocator =
new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
ProtectedMemoryAllocator(breakpad_pool_size);
// Stack-based autorelease pool for Breakpad::Create() obj-c code.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
Breakpad* breakpad = Breakpad::Create(parameters);
if (breakpad) {
// Make read-only to protect against memory smashers
gMasterAllocator->Protect();
gKeyValueAllocator->Protect();
gBreakpadAllocator->Protect();
// Can uncomment this line to figure out how much space was actually
// allocated using this allocator
// printf("gBreakpadAllocator allocated size = %d\n",
// gBreakpadAllocator->GetAllocatedSize() );
[pool release];
return (BreakpadRef)breakpad;
}
[pool release];
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadCreate() : error\n");
}
if (gKeyValueAllocator) {
gKeyValueAllocator->~ProtectedMemoryAllocator();
gKeyValueAllocator = NULL;
}
if (gBreakpadAllocator) {
gBreakpadAllocator->~ProtectedMemoryAllocator();
gBreakpadAllocator = NULL;
}
delete gMasterAllocator;
gMasterAllocator = NULL;
return NULL;
}
//=============================================================================
void BreakpadRelease(BreakpadRef ref) {
try {
Breakpad* breakpad = (Breakpad*)ref;
if (gMasterAllocator) {
gMasterAllocator->Unprotect();
gKeyValueAllocator->Unprotect();
gBreakpadAllocator->Unprotect();
breakpad->~Breakpad();
// Unfortunately, it's not possible to deallocate this stuff
// because the exception handling thread is still finishing up
// asynchronously at this point... OK, it could be done with
// locks, etc. But since BreakpadRelease() should usually only
// be called right before the process exits, it's not worth
// deallocating this stuff.
#if 0
gKeyValueAllocator->~ProtectedMemoryAllocator();
gBreakpadAllocator->~ProtectedMemoryAllocator();
delete gMasterAllocator;
gMasterAllocator = NULL;
gKeyValueAllocator = NULL;
gBreakpadAllocator = NULL;
#endif
pthread_mutex_destroy(&gDictionaryMutex);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRelease() : error\n");
}
}
//=============================================================================
void BreakpadSetKeyValue(BreakpadRef ref, NSString* key, NSString* value) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
breakpad->SetKeyValue(key, value);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetKeyValue() : error\n");
}
}
void BreakpadAddUploadParameter(BreakpadRef ref,
NSString* key,
NSString* value) {
// The only difference, internally, between an upload parameter and
// a key value one that is set with BreakpadSetKeyValue is that we
// prepend the keyname with a special prefix. This informs the
// crash sender that the parameter should be sent along with the
// POST of the crash dump upload.
try {
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
NSString* prefixedKey = [@BREAKPAD_SERVER_PARAMETER_PREFIX
stringByAppendingString:key];
breakpad->SetKeyValue(prefixedKey, value);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadSetKeyValue() : error\n");
}
}
void BreakpadRemoveUploadParameter(BreakpadRef ref,
NSString* key) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
NSString* prefixedKey = [NSString stringWithFormat:@"%@%@",
@BREAKPAD_SERVER_PARAMETER_PREFIX, key];
breakpad->RemoveKeyValue(prefixedKey);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
}
}
//=============================================================================
NSString* BreakpadKeyValue(BreakpadRef ref, NSString* key) {
NSString* value = nil;
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad || !key || !gKeyValueAllocator)
return nil;
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
value = breakpad->KeyValue(key);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadKeyValue() : error\n");
}
return value;
}
//=============================================================================
void BreakpadRemoveKeyValue(BreakpadRef ref, NSString* key) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && key && gKeyValueAllocator) {
ProtectedMemoryLocker locker(&gDictionaryMutex, gKeyValueAllocator);
breakpad->RemoveKeyValue(key);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadRemoveKeyValue() : error\n");
}
}
//=============================================================================
int BreakpadGetCrashReportCount(BreakpadRef ref) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
return static_cast<int>([breakpad->CrashReportsToUpload() count]);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGetCrashReportCount() : error\n");
}
return false;
}
//=============================================================================
void BreakpadUploadNextReport(BreakpadRef ref) {
BreakpadUploadNextReportWithParameters(ref, nil, nullptr);
}
//=============================================================================
NSDictionary* BreakpadGetNextReportConfiguration(BreakpadRef ref) {
try {
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad)
return breakpad->NextCrashReportConfiguration();
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGetNextReportConfiguration() : error\n");
}
return nil;
}
//=============================================================================
NSDate* BreakpadGetDateOfMostRecentCrashReport(BreakpadRef ref) {
try {
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
return breakpad->DateOfMostRecentCrashReport();
}
} catch (...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGetDateOfMostRecentCrashReport() : error\n");
}
return nil;
}
//=============================================================================
void BreakpadUploadReportWithParametersAndConfiguration(
BreakpadRef ref,
NSDictionary* server_parameters,
NSDictionary* configuration,
BreakpadUploadCompletionCallback callback) {
try {
Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad || !configuration)
return;
breakpad->UploadReportWithConfiguration(configuration, server_parameters,
callback);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr,
"BreakpadUploadReportWithParametersAndConfiguration() : error\n");
}
}
//=============================================================================
void BreakpadUploadNextReportWithParameters(
BreakpadRef ref,
NSDictionary* server_parameters,
BreakpadUploadCompletionCallback callback) {
try {
Breakpad* breakpad = (Breakpad*)ref;
if (!breakpad)
return;
NSDictionary* configuration = breakpad->NextCrashReportConfiguration();
if (!configuration)
return;
return BreakpadUploadReportWithParametersAndConfiguration(
ref, server_parameters, configuration, callback);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadUploadNextReportWithParameters() : error\n");
}
}
void BreakpadHandleNetworkResponse(BreakpadRef ref,
NSDictionary* configuration,
NSData* data,
NSError* error) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad && configuration)
breakpad->HandleNetworkResponse(configuration,data, error);
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadHandleNetworkResponse() : error\n");
}
}
//=============================================================================
void BreakpadUploadData(BreakpadRef ref, NSData* data, NSString* name,
NSDictionary* server_parameters) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
breakpad->UploadData(data, name, server_parameters);
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadUploadData() : error\n");
}
}
//=============================================================================
NSDictionary* BreakpadGenerateReport(BreakpadRef ref,
NSDictionary* server_parameters) {
try {
// Not called at exception time
Breakpad* breakpad = (Breakpad*)ref;
if (breakpad) {
return breakpad->GenerateReport(server_parameters);
} else {
return nil;
}
} catch(...) { // don't let exceptions leave this C API
fprintf(stderr, "BreakpadGenerateReport() : error\n");
return nil;
}
}

View File

@ -0,0 +1,604 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
06D561E62700974500F9F2E8 /* encoding_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 06D561E42700974500F9F2E8 /* encoding_util.h */; };
06D561E72700974500F9F2E8 /* encoding_util.m in Sources */ = {isa = PBXBuildFile; fileRef = 06D561E52700974500F9F2E8 /* encoding_util.m */; };
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569320182CE29F0029C465 /* ucontext_compat.h */; };
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 14569322182CE2C10029C465 /* mach_vm_compat.h */; };
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */; };
16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */; };
16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C968147D4A4200776EAD /* BreakpadDefines.h */; };
16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7C96A147D4A4200776EAD /* Breakpad.h */; };
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7C96B147D4A4200776EAD /* Breakpad.mm */; };
16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CB9E147D4A4300776EAD /* ConfigFile.h */; };
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CB9F147D4A4300776EAD /* ConfigFile.mm */; };
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */; };
16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */; };
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBAF147D4A4300776EAD /* dynamic_images.cc */; };
16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB0147D4A4300776EAD /* dynamic_images.h */; };
16C7CDF9147D4A4300776EAD /* exception_handler.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBB1147D4A4300776EAD /* exception_handler.cc */; };
16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB2147D4A4300776EAD /* exception_handler.h */; };
16C7CDFC147D4A4300776EAD /* minidump_generator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBB4147D4A4300776EAD /* minidump_generator.cc */; };
16C7CDFD147D4A4300776EAD /* minidump_generator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBB5147D4A4300776EAD /* minidump_generator.h */; };
16C7CDFE147D4A4300776EAD /* protected_memory_allocator.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */; };
16C7CDFF147D4A4300776EAD /* protected_memory_allocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */; };
16C7CE08147D4A4300776EAD /* uploader.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CBEA147D4A4300776EAD /* uploader.h */; };
16C7CE09147D4A4300776EAD /* uploader.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CBEB147D4A4300776EAD /* uploader.mm */; };
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */; };
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */; };
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC06147D4A4300776EAD /* minidump_file_writer.h */; };
16C7CE40147D4A4300776EAD /* convert_UTF.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC4A147D4A4300776EAD /* convert_UTF.cc */; };
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC4B147D4A4300776EAD /* convert_UTF.h */; };
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC88147D4A4300776EAD /* GTMLogger.h */; };
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC89147D4A4300776EAD /* GTMLogger.m */; };
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */; };
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */; };
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC93147D4A4300776EAD /* file_id.cc */; };
16C7CE84147D4A4300776EAD /* file_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC94147D4A4300776EAD /* file_id.h */; };
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC95147D4A4300776EAD /* macho_id.cc */; };
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC96147D4A4300776EAD /* macho_id.h */; };
16C7CE8A147D4A4300776EAD /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9A147D4A4300776EAD /* macho_utilities.cc */; };
16C7CE8B147D4A4300776EAD /* macho_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC9B147D4A4300776EAD /* macho_utilities.h */; };
16C7CE8C147D4A4300776EAD /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9C147D4A4300776EAD /* macho_walker.cc */; };
16C7CE8D147D4A4300776EAD /* macho_walker.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CC9D147D4A4300776EAD /* macho_walker.h */; };
16C7CE8F147D4A4300776EAD /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CC9F147D4A4300776EAD /* string_utilities.cc */; };
16C7CE90147D4A4300776EAD /* string_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCA0147D4A4300776EAD /* string_utilities.h */; };
16C7CE93147D4A4300776EAD /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CCA4147D4A4300776EAD /* md5.cc */; };
16C7CE94147D4A4300776EAD /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCA5147D4A4300776EAD /* md5.h */; };
16C7CEA7147D4A4300776EAD /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = 16C7CCB9147D4A4300776EAD /* string_conversion.cc */; };
16C7CEA8147D4A4300776EAD /* string_conversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C7CCBA147D4A4300776EAD /* string_conversion.h */; };
16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */ = {isa = PBXBuildFile; fileRef = 16C92FAB150DF8330053D7BA /* BreakpadController.h */; };
16C92FAE150DF8330053D7BA /* BreakpadController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 16C92FAC150DF8330053D7BA /* BreakpadController.mm */; };
1EEEB60F1720821900F7E689 /* simple_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = 1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */; };
1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */; };
AA747D9F0F9514B9006C5449 /* Breakpad_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */; };
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; };
CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */ = {isa = PBXBuildFile; fileRef = CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */; };
CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */; };
E69213D8265202570071B04F /* HTTPRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = E69213D6265202570071B04F /* HTTPRequest.h */; };
E69213D9265202570071B04F /* HTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E69213D7265202570071B04F /* HTTPRequest.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
06D561E42700974500F9F2E8 /* encoding_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = encoding_util.h; sourceTree = "<group>"; };
06D561E52700974500F9F2E8 /* encoding_util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = encoding_util.m; sourceTree = "<group>"; };
14569320182CE29F0029C465 /* ucontext_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ucontext_compat.h; sourceTree = "<group>"; };
14569322182CE2C10029C465 /* mach_vm_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_vm_compat.h; sourceTree = "<group>"; };
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios_exception_minidump_generator.h; sourceTree = "<group>"; };
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios_exception_minidump_generator.mm; sourceTree = "<group>"; };
16C7C968147D4A4200776EAD /* BreakpadDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadDefines.h; sourceTree = "<group>"; };
16C7C96A147D4A4200776EAD /* Breakpad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpad.h; sourceTree = "<group>"; };
16C7C96B147D4A4200776EAD /* Breakpad.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Breakpad.mm; sourceTree = "<group>"; };
16C7CB9E147D4A4300776EAD /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigFile.h; sourceTree = "<group>"; };
16C7CB9F147D4A4300776EAD /* ConfigFile.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ConfigFile.mm; sourceTree = "<group>"; };
16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = breakpad_nlist_64.cc; sourceTree = "<group>"; };
16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = breakpad_nlist_64.h; sourceTree = "<group>"; };
16C7CBAF147D4A4300776EAD /* dynamic_images.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dynamic_images.cc; sourceTree = "<group>"; };
16C7CBB0147D4A4300776EAD /* dynamic_images.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dynamic_images.h; sourceTree = "<group>"; };
16C7CBB1147D4A4300776EAD /* exception_handler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = exception_handler.cc; sourceTree = "<group>"; };
16C7CBB2147D4A4300776EAD /* exception_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception_handler.h; sourceTree = "<group>"; };
16C7CBB4147D4A4300776EAD /* minidump_generator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_generator.cc; sourceTree = "<group>"; };
16C7CBB5147D4A4300776EAD /* minidump_generator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minidump_generator.h; sourceTree = "<group>"; };
16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = protected_memory_allocator.cc; sourceTree = "<group>"; };
16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = protected_memory_allocator.h; sourceTree = "<group>"; };
16C7CBEA147D4A4300776EAD /* uploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = uploader.h; sourceTree = "<group>"; };
16C7CBEB147D4A4300776EAD /* uploader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = uploader.mm; sourceTree = "<group>"; };
16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "minidump_file_writer-inl.h"; sourceTree = "<group>"; };
16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_file_writer.cc; sourceTree = "<group>"; };
16C7CC06147D4A4300776EAD /* minidump_file_writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = minidump_file_writer.h; sourceTree = "<group>"; };
16C7CC07147D4A4300776EAD /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump_file_writer_unittest.cc; sourceTree = "<group>"; };
16C7CC4A147D4A4300776EAD /* convert_UTF.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = convert_UTF.cc; sourceTree = "<group>"; };
16C7CC4B147D4A4300776EAD /* convert_UTF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = convert_UTF.h; sourceTree = "<group>"; };
16C7CC88147D4A4300776EAD /* GTMLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GTMLogger.h; sourceTree = "<group>"; };
16C7CC89147D4A4300776EAD /* GTMLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GTMLogger.m; sourceTree = "<group>"; };
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPMultipartUpload.h; sourceTree = "<group>"; };
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPMultipartUpload.m; sourceTree = "<group>"; };
16C7CC93147D4A4300776EAD /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_id.cc; sourceTree = "<group>"; };
16C7CC94147D4A4300776EAD /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_id.h; sourceTree = "<group>"; };
16C7CC95147D4A4300776EAD /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_id.cc; sourceTree = "<group>"; };
16C7CC96147D4A4300776EAD /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_id.h; sourceTree = "<group>"; };
16C7CC9A147D4A4300776EAD /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_utilities.cc; sourceTree = "<group>"; };
16C7CC9B147D4A4300776EAD /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_utilities.h; sourceTree = "<group>"; };
16C7CC9C147D4A4300776EAD /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = macho_walker.cc; sourceTree = "<group>"; };
16C7CC9D147D4A4300776EAD /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = macho_walker.h; sourceTree = "<group>"; };
16C7CC9F147D4A4300776EAD /* string_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_utilities.cc; sourceTree = "<group>"; };
16C7CCA0147D4A4300776EAD /* string_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_utilities.h; sourceTree = "<group>"; };
16C7CCA4147D4A4300776EAD /* md5.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = md5.cc; sourceTree = "<group>"; };
16C7CCA5147D4A4300776EAD /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; };
16C7CCB9147D4A4300776EAD /* string_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_conversion.cc; sourceTree = "<group>"; };
16C7CCBA147D4A4300776EAD /* string_conversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_conversion.h; sourceTree = "<group>"; };
16C92FAB150DF8330053D7BA /* BreakpadController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BreakpadController.h; sourceTree = "<group>"; };
16C92FAC150DF8330053D7BA /* BreakpadController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BreakpadController.mm; sourceTree = "<group>"; };
1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = simple_string_dictionary.cc; sourceTree = "<group>"; };
1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = simple_string_dictionary.h; sourceTree = "<group>"; };
AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Breakpad_Prefix.pch; sourceTree = SOURCE_ROOT; };
AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = long_string_dictionary.cc; sourceTree = "<group>"; };
CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = long_string_dictionary.h; sourceTree = "<group>"; };
D2AAC07E0554694100DB518D /* libBreakpad.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libBreakpad.a; sourceTree = BUILT_PRODUCTS_DIR; };
E69213D6265202570071B04F /* HTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequest.h; sourceTree = "<group>"; };
E69213D7265202570071B04F /* HTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HTTPRequest.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D2AAC07C0554694100DB518D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
034768DFFF38A50411DB9C8B /* Products */ = {
isa = PBXGroup;
children = (
D2AAC07E0554694100DB518D /* libBreakpad.a */,
);
name = Products;
sourceTree = "<group>";
};
0867D691FE84028FC02AAC07 /* Breakpad */ = {
isa = PBXGroup;
children = (
08FB77AEFE84172EC02AAC07 /* Classes */,
32C88DFF0371C24200C91783 /* Other Sources */,
0867D69AFE84028FC02AAC07 /* Frameworks */,
034768DFFF38A50411DB9C8B /* Products */,
);
name = Breakpad;
sourceTree = "<group>";
};
0867D69AFE84028FC02AAC07 /* Frameworks */ = {
isa = PBXGroup;
children = (
AACBBE490F95108600F1A2B1 /* Foundation.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
08FB77AEFE84172EC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
16C7C965147D4A4200776EAD /* client */,
16C7CC47147D4A4300776EAD /* common */,
);
name = Classes;
sourceTree = "<group>";
};
16BFA66A14E195E9009704F8 /* handler */ = {
isa = PBXGroup;
children = (
16BFA67114E1965A009704F8 /* ios_exception_minidump_generator.mm */,
16BFA66E14E195E9009704F8 /* ios_exception_minidump_generator.h */,
);
path = handler;
sourceTree = "<group>";
};
16C7C965147D4A4200776EAD /* client */ = {
isa = PBXGroup;
children = (
16C7C966147D4A4200776EAD /* apple */,
16C7C969147D4A4200776EAD /* ios */,
16C7C99E147D4A4200776EAD /* mac */,
16C7CC04147D4A4300776EAD /* minidump_file_writer-inl.h */,
16C7CC05147D4A4300776EAD /* minidump_file_writer.cc */,
16C7CC06147D4A4300776EAD /* minidump_file_writer.h */,
16C7CC07147D4A4300776EAD /* minidump_file_writer_unittest.cc */,
);
name = client;
path = ..;
sourceTree = SOURCE_ROOT;
};
16C7C966147D4A4200776EAD /* apple */ = {
isa = PBXGroup;
children = (
16C7C967147D4A4200776EAD /* Framework */,
);
path = apple;
sourceTree = "<group>";
};
16C7C967147D4A4200776EAD /* Framework */ = {
isa = PBXGroup;
children = (
16C7C968147D4A4200776EAD /* BreakpadDefines.h */,
);
path = Framework;
sourceTree = "<group>";
};
16C7C969147D4A4200776EAD /* ios */ = {
isa = PBXGroup;
children = (
16C92FAB150DF8330053D7BA /* BreakpadController.h */,
16C92FAC150DF8330053D7BA /* BreakpadController.mm */,
16BFA66A14E195E9009704F8 /* handler */,
16C7C96A147D4A4200776EAD /* Breakpad.h */,
16C7C96B147D4A4200776EAD /* Breakpad.mm */,
);
path = ios;
sourceTree = "<group>";
};
16C7C99E147D4A4200776EAD /* mac */ = {
isa = PBXGroup;
children = (
16C7CB9D147D4A4300776EAD /* crash_generation */,
16C7CBAA147D4A4300776EAD /* handler */,
16C7CBC8147D4A4300776EAD /* sender */,
);
path = mac;
sourceTree = "<group>";
};
16C7CB9D147D4A4300776EAD /* crash_generation */ = {
isa = PBXGroup;
children = (
16C7CB9E147D4A4300776EAD /* ConfigFile.h */,
16C7CB9F147D4A4300776EAD /* ConfigFile.mm */,
);
path = crash_generation;
sourceTree = "<group>";
};
16C7CBAA147D4A4300776EAD /* handler */ = {
isa = PBXGroup;
children = (
16C7CBAD147D4A4300776EAD /* breakpad_nlist_64.cc */,
16C7CBAE147D4A4300776EAD /* breakpad_nlist_64.h */,
16C7CBAF147D4A4300776EAD /* dynamic_images.cc */,
16C7CBB0147D4A4300776EAD /* dynamic_images.h */,
16C7CBB1147D4A4300776EAD /* exception_handler.cc */,
16C7CBB2147D4A4300776EAD /* exception_handler.h */,
14569322182CE2C10029C465 /* mach_vm_compat.h */,
16C7CBB4147D4A4300776EAD /* minidump_generator.cc */,
16C7CBB5147D4A4300776EAD /* minidump_generator.h */,
16C7CBBC147D4A4300776EAD /* protected_memory_allocator.cc */,
16C7CBBD147D4A4300776EAD /* protected_memory_allocator.h */,
14569320182CE29F0029C465 /* ucontext_compat.h */,
);
path = handler;
sourceTree = "<group>";
};
16C7CBC8147D4A4300776EAD /* sender */ = {
isa = PBXGroup;
children = (
16C7CBEA147D4A4300776EAD /* uploader.h */,
16C7CBEB147D4A4300776EAD /* uploader.mm */,
);
path = sender;
sourceTree = "<group>";
};
16C7CC47147D4A4300776EAD /* common */ = {
isa = PBXGroup;
children = (
CF706DC01F7C6EFB002C54C7 /* long_string_dictionary.h */,
CF6D547C1F9E6FFE00E95174 /* long_string_dictionary.cc */,
1EEEB60C1720821900F7E689 /* simple_string_dictionary.cc */,
1EEEB60D1720821900F7E689 /* simple_string_dictionary.h */,
16C7CC4A147D4A4300776EAD /* convert_UTF.cc */,
16C7CC4B147D4A4300776EAD /* convert_UTF.h */,
16C7CC82147D4A4300776EAD /* mac */,
16C7CCA4147D4A4300776EAD /* md5.cc */,
16C7CCA5147D4A4300776EAD /* md5.h */,
16C7CCB9147D4A4300776EAD /* string_conversion.cc */,
16C7CCBA147D4A4300776EAD /* string_conversion.h */,
);
name = common;
path = ../../common;
sourceTree = SOURCE_ROOT;
};
16C7CC82147D4A4300776EAD /* mac */ = {
isa = PBXGroup;
children = (
06D561E42700974500F9F2E8 /* encoding_util.h */,
06D561E52700974500F9F2E8 /* encoding_util.m */,
16C7CC88147D4A4300776EAD /* GTMLogger.h */,
16C7CC89147D4A4300776EAD /* GTMLogger.m */,
E69213D6265202570071B04F /* HTTPRequest.h */,
E69213D7265202570071B04F /* HTTPRequest.m */,
16C7CC8A147D4A4300776EAD /* HTTPMultipartUpload.h */,
16C7CC8B147D4A4300776EAD /* HTTPMultipartUpload.m */,
16C7CC93147D4A4300776EAD /* file_id.cc */,
16C7CC94147D4A4300776EAD /* file_id.h */,
16C7CC95147D4A4300776EAD /* macho_id.cc */,
16C7CC96147D4A4300776EAD /* macho_id.h */,
16C7CC9A147D4A4300776EAD /* macho_utilities.cc */,
16C7CC9B147D4A4300776EAD /* macho_utilities.h */,
16C7CC9C147D4A4300776EAD /* macho_walker.cc */,
16C7CC9D147D4A4300776EAD /* macho_walker.h */,
16C7CC9F147D4A4300776EAD /* string_utilities.cc */,
16C7CCA0147D4A4300776EAD /* string_utilities.h */,
);
path = mac;
sourceTree = "<group>";
};
32C88DFF0371C24200C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
AA747D9E0F9514B9006C5449 /* Breakpad_Prefix.pch */,
);
name = "Other Sources";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
D2AAC07A0554694100DB518D /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
AA747D9F0F9514B9006C5449 /* Breakpad_Prefix.pch in Headers */,
16C7CCCB147D4A4300776EAD /* BreakpadDefines.h in Headers */,
16C7CCCC147D4A4300776EAD /* Breakpad.h in Headers */,
16C7CDE8147D4A4300776EAD /* ConfigFile.h in Headers */,
14569321182CE29F0029C465 /* ucontext_compat.h in Headers */,
16C7CDF6147D4A4300776EAD /* breakpad_nlist_64.h in Headers */,
16C7CDF8147D4A4300776EAD /* dynamic_images.h in Headers */,
16C7CDFA147D4A4300776EAD /* exception_handler.h in Headers */,
16C7CDFD147D4A4300776EAD /* minidump_generator.h in Headers */,
16C7CDFF147D4A4300776EAD /* protected_memory_allocator.h in Headers */,
16C7CE08147D4A4300776EAD /* uploader.h in Headers */,
16C7CE18147D4A4300776EAD /* minidump_file_writer-inl.h in Headers */,
16C7CE1A147D4A4300776EAD /* minidump_file_writer.h in Headers */,
06D561E62700974500F9F2E8 /* encoding_util.h in Headers */,
16C7CE41147D4A4300776EAD /* convert_UTF.h in Headers */,
16C7CE78147D4A4300776EAD /* GTMLogger.h in Headers */,
E69213D8265202570071B04F /* HTTPRequest.h in Headers */,
16C7CE7A147D4A4300776EAD /* HTTPMultipartUpload.h in Headers */,
16C7CE84147D4A4300776EAD /* file_id.h in Headers */,
16C7CE86147D4A4300776EAD /* macho_id.h in Headers */,
16C7CE8B147D4A4300776EAD /* macho_utilities.h in Headers */,
16C7CE8D147D4A4300776EAD /* macho_walker.h in Headers */,
16C7CE90147D4A4300776EAD /* string_utilities.h in Headers */,
16C7CE94147D4A4300776EAD /* md5.h in Headers */,
16C7CEA8147D4A4300776EAD /* string_conversion.h in Headers */,
16BFA67014E195E9009704F8 /* ios_exception_minidump_generator.h in Headers */,
16C92FAD150DF8330053D7BA /* BreakpadController.h in Headers */,
CF706DC11F7C6EFB002C54C7 /* long_string_dictionary.h in Headers */,
1EEEB6101720821900F7E689 /* simple_string_dictionary.h in Headers */,
14569323182CE2C10029C465 /* mach_vm_compat.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
D2AAC07D0554694100DB518D /* Breakpad */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */;
buildPhases = (
D2AAC07A0554694100DB518D /* Headers */,
D2AAC07B0554694100DB518D /* Sources */,
D2AAC07C0554694100DB518D /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Breakpad;
productName = Breakpad;
productReference = D2AAC07E0554694100DB518D /* libBreakpad.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0510;
};
buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Breakpad" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
English,
Japanese,
French,
German,
da,
de,
es,
fr,
it,
ja,
nl,
no,
sl,
sv,
tr,
);
mainGroup = 0867D691FE84028FC02AAC07 /* Breakpad */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D2AAC07D0554694100DB518D /* Breakpad */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
D2AAC07B0554694100DB518D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
16C7CCCD147D4A4300776EAD /* Breakpad.mm in Sources */,
E69213D9265202570071B04F /* HTTPRequest.m in Sources */,
16C7CDE9147D4A4300776EAD /* ConfigFile.mm in Sources */,
16C7CDF5147D4A4300776EAD /* breakpad_nlist_64.cc in Sources */,
16C7CDF7147D4A4300776EAD /* dynamic_images.cc in Sources */,
16C7CDF9147D4A4300776EAD /* exception_handler.cc in Sources */,
16C7CDFC147D4A4300776EAD /* minidump_generator.cc in Sources */,
16C7CDFE147D4A4300776EAD /* protected_memory_allocator.cc in Sources */,
16C7CE09147D4A4300776EAD /* uploader.mm in Sources */,
CF6D547D1F9E6FFE00E95174 /* long_string_dictionary.cc in Sources */,
16C7CE19147D4A4300776EAD /* minidump_file_writer.cc in Sources */,
16C7CE40147D4A4300776EAD /* convert_UTF.cc in Sources */,
16C7CE79147D4A4300776EAD /* GTMLogger.m in Sources */,
06D561E72700974500F9F2E8 /* encoding_util.m in Sources */,
16C7CE7B147D4A4300776EAD /* HTTPMultipartUpload.m in Sources */,
16C7CE83147D4A4300776EAD /* file_id.cc in Sources */,
16C7CE85147D4A4300776EAD /* macho_id.cc in Sources */,
16C7CE8A147D4A4300776EAD /* macho_utilities.cc in Sources */,
16C7CE8C147D4A4300776EAD /* macho_walker.cc in Sources */,
16C7CE8F147D4A4300776EAD /* string_utilities.cc in Sources */,
16C7CE93147D4A4300776EAD /* md5.cc in Sources */,
16C7CEA7147D4A4300776EAD /* string_conversion.cc in Sources */,
16BFA67214E1965A009704F8 /* ios_exception_minidump_generator.mm in Sources */,
16C92FAE150DF8330053D7BA /* BreakpadController.mm in Sources */,
1EEEB60F1720821900F7E689 /* simple_string_dictionary.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
1DEB921F08733DC00010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LIBRARY = "libc++";
COPY_PHASE_STRIP = NO;
DSTROOT = /tmp/Breakpad.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Debug\"",
);
GCC_DYNAMIC_NO_PIC = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Breakpad_Prefix.pch;
INSTALL_PATH = /usr/local/lib;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Debug\"",
"\"$(SRCROOT)/../mac/gcov\"",
);
PRODUCT_NAME = Breakpad;
};
name = Debug;
};
1DEB922008733DC00010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LIBRARY = "libc++";
DSTROOT = /tmp/Breakpad.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Debug\"",
);
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Breakpad_Prefix.pch;
INSTALL_PATH = /usr/local/lib;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/Breakpad.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/breakpadUtilities.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/i386\"",
"\"$(SRCROOT)/../mac/build/Breakpad.build/Debug/gtest.build/Objects-normal/x86_64\"",
"\"$(SRCROOT)/../mac/build/Debug\"",
"\"$(SRCROOT)/../mac/gcov\"",
);
PRODUCT_NAME = Breakpad;
};
name = Release;
};
1DEB922308733DC00010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
../../,
../../client/apple/Framework,
../../common/mac,
);
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC";
SDKROOT = iphoneos;
WARNING_CFLAGS = "-Wundef";
};
name = Debug;
};
1DEB922408733DC00010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_SHADOW = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNKNOWN_PRAGMAS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
../../,
../../client/apple/Framework,
../../common/mac,
);
IPHONEOS_DEPLOYMENT_TARGET = 5.0;
OTHER_LDFLAGS = "-ObjC";
SDKROOT = iphoneos;
WARNING_CFLAGS = "-Wundef";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "Breakpad" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB921F08733DC00010E9CD /* Debug */,
1DEB922008733DC00010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "Breakpad" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB922308733DC00010E9CD /* Debug */,
1DEB922408733DC00010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
}

View File

@ -0,0 +1,154 @@
// 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 CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_
#define CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_
#import <Foundation/Foundation.h>
#import "client/ios/Breakpad.h"
// This class is used to offer a higher level API around BreakpadRef. It
// configures it, ensures thread-safety, and sends crash reports back to the
// collecting server. By default, no crash reports are sent, the user must call
// |setUploadingEnabled:YES| to start the uploading.
@interface BreakpadController : NSObject {
@private
// The dispatch queue that will own the breakpad reference.
dispatch_queue_t queue_;
// Instance of Breakpad crash reporter. This is owned by the queue, but can
// be created on the main thread at startup.
BreakpadRef breakpadRef_;
// The dictionary that contains configuration for breakpad. Modifying it
// should only happen when the controller is not started. The initial value
// is the infoDictionary of the bundle of the application.
NSMutableDictionary* configuration_;
// Whether or not crash reports should be uploaded.
BOOL enableUploads_;
// Whether the controller has been started on the main thread. This is only
// used to assert the initialization order is correct.
BOOL started_;
// The interval to wait between two uploads. Value is 0 if no upload must be
// done.
int uploadIntervalInSeconds_;
// The dictionary that contains additional server parameters to send when
// uploading crash reports.
NSDictionary* uploadTimeParameters_;
// The callback to call on report upload completion.
BreakpadUploadCompletionCallback uploadCompleteCallback_;
}
// Singleton.
+ (BreakpadController*)sharedInstance;
// Update the controller configuration. Merges its old configuration with the
// new one. Merge is done by replacing the old values by the new values.
- (void)updateConfiguration:(NSDictionary*)configuration;
// Reset the controller configuration to its initial value, which is the
// infoDictionary of the bundle of the application.
- (void)resetConfiguration;
// Configure the URL to upload the report to. This must be called at least once
// if the URL is not in the bundle information.
- (void)setUploadingURL:(NSString*)url;
// Set the minimal interval between two uploads in seconds. This must be called
// at least once if the interval is not in the bundle information. A value of 0
// will prevent uploads.
- (void)setUploadInterval:(int)intervalInSeconds;
// Set additional server parameters to send when uploading crash reports.
- (void)setParametersToAddAtUploadTime:(NSDictionary*)uploadTimeParameters;
// Specify an upload parameter that will be added to the crash report when a
// crash report is generated. See |BreakpadAddUploadParameter|.
- (void)addUploadParameter:(NSString*)value forKey:(NSString*)key;
// Sets the callback to be called after uploading a crash report to the server.
// Only the latest callback registered will be called.
- (void)setUploadCallback:(BreakpadUploadCompletionCallback)callback;
// Remove a previously-added parameter from the upload parameter set. See
// |BreakpadRemoveUploadParameter|.
- (void)removeUploadParameterForKey:(NSString*)key;
// Access the underlying BreakpadRef. This method is asynchronous, and will be
// executed on the thread owning the BreakpadRef variable. Moreover, if the
// controller is not started, the block will be called with a NULL parameter.
- (void)withBreakpadRef:(void(^)(BreakpadRef))callback;
// Starts the BreakpadController by registering crash handlers. If
// |onCurrentThread| is YES, all setup is done on the current thread, otherwise
// it is done on a private queue.
- (void)start:(BOOL)onCurrentThread;
// Unregisters the crash handlers.
- (void)stop;
// Returns whether or not the controller is started.
- (BOOL)isStarted;
// Enables or disables uploading of crash reports, but does not stop the
// BreakpadController.
- (void)setUploadingEnabled:(BOOL)enabled;
// Check if there is currently a crash report to upload.
- (void)hasReportToUpload:(void(^)(BOOL))callback;
// Get the number of crash reports waiting to upload.
- (void)getCrashReportCount:(void(^)(int))callback;
// Get the next report to upload.
// - If upload is disabled, callback will be called with (nil, -1).
// - If a delay is to be waited before sending, callback will be called with
// (nil, n), with n (> 0) being the number of seconds to wait.
// - if no delay is needed, callback will be called with (0, configuration),
// configuration being next report to upload, or nil if none is pending.
- (void)getNextReportConfigurationOrSendDelay:
(void(^)(NSDictionary*, int))callback;
// Get the date of the most recent crash report.
- (void)getDateOfMostRecentCrashReport:(void(^)(NSDate *))callback;
// Sends synchronously the report specified by |configuration|. This method is
// NOT thread safe and must be called from the breakpad thread.
- (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration
withBreakpadRef:(BreakpadRef)ref;
@end
#endif // CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_

View File

@ -0,0 +1,374 @@
// 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.
#import "BreakpadController.h"
#import <UIKit/UIKit.h>
#include <asl.h>
#include <execinfo.h>
#include <signal.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <common/scoped_ptr.h>
#pragma mark -
#pragma mark Private Methods
@interface BreakpadController ()
// Init the singleton instance.
- (id)initSingleton;
// Load a crash report and send it to the server.
- (void)sendStoredCrashReports;
// Returns when a report can be sent. |-1| means never, |0| means that a report
// can be sent immediately, a positive number is the number of seconds to wait
// before being allowed to upload a report.
- (int)sendDelay;
// Notifies that a report will be sent, and update the last sending time
// accordingly.
- (void)reportWillBeSent;
@end
#pragma mark -
#pragma mark Anonymous namespace
namespace {
// The name of the user defaults key for the last submission to the crash
// server.
NSString* const kLastSubmission = @"com.google.Breakpad.LastSubmission";
// Returns a NSString describing the current platform.
NSString* GetPlatform() {
// Name of the system call for getting the platform.
static const char kHwMachineSysctlName[] = "hw.machine";
NSString* result = nil;
size_t size = 0;
if (sysctlbyname(kHwMachineSysctlName, NULL, &size, NULL, 0) || size == 0)
return nil;
google_breakpad::scoped_array<char> machine(new char[size]);
if (sysctlbyname(kHwMachineSysctlName, machine.get(), &size, NULL, 0) == 0)
result = [NSString stringWithUTF8String:machine.get()];
return result;
}
} // namespace
#pragma mark -
#pragma mark BreakpadController Implementation
@implementation BreakpadController
+ (BreakpadController*)sharedInstance {
static dispatch_once_t onceToken;
static BreakpadController* sharedInstance ;
dispatch_once(&onceToken, ^{
sharedInstance = [[BreakpadController alloc] initSingleton];
});
return sharedInstance;
}
- (id)init {
return nil;
}
- (id)initSingleton {
self = [super init];
if (self) {
queue_ = dispatch_queue_create("com.google.BreakpadQueue", NULL);
enableUploads_ = NO;
started_ = NO;
[self resetConfiguration];
}
return self;
}
// Since this class is a singleton, this method is not expected to be called.
- (void)dealloc {
assert(!breakpadRef_);
dispatch_release(queue_);
[configuration_ release];
[uploadTimeParameters_ release];
[super dealloc];
}
#pragma mark -
- (void)start:(BOOL)onCurrentThread {
if (started_)
return;
started_ = YES;
void(^startBlock)() = ^{
assert(!breakpadRef_);
breakpadRef_ = BreakpadCreate(configuration_);
if (breakpadRef_) {
BreakpadAddUploadParameter(breakpadRef_, @"platform", GetPlatform());
}
};
if (onCurrentThread)
startBlock();
else
dispatch_async(queue_, startBlock);
}
- (void)stop {
if (!started_)
return;
started_ = NO;
dispatch_sync(queue_, ^{
if (breakpadRef_) {
BreakpadRelease(breakpadRef_);
breakpadRef_ = NULL;
}
});
}
- (BOOL)isStarted {
return started_;
}
// This method must be called from the breakpad queue.
- (void)threadUnsafeSendReportWithConfiguration:(NSDictionary*)configuration
withBreakpadRef:(BreakpadRef)ref {
NSAssert(started_, @"The controller must be started before "
"threadUnsafeSendReportWithConfiguration is called");
if (breakpadRef_) {
BreakpadUploadReportWithParametersAndConfiguration(
breakpadRef_, uploadTimeParameters_, configuration,
uploadCompleteCallback_);
}
}
- (void)setUploadingEnabled:(BOOL)enabled {
NSAssert(started_,
@"The controller must be started before setUploadingEnabled is called");
dispatch_async(queue_, ^{
if (enabled == enableUploads_)
return;
if (enabled) {
// Set this before calling doSendStoredCrashReport, because that
// calls sendDelay, which in turn checks this flag.
enableUploads_ = YES;
[self sendStoredCrashReports];
} else {
// disable the enableUpload_ flag.
// sendDelay checks this flag and disables the upload of logs by sendStoredCrashReports
enableUploads_ = NO;
}
});
}
- (void)updateConfiguration:(NSDictionary*)configuration {
NSAssert(!started_,
@"The controller must not be started when updateConfiguration is called");
[configuration_ addEntriesFromDictionary:configuration];
NSString *uploadInterval =
[configuration_ valueForKey:@BREAKPAD_REPORT_INTERVAL];
if (uploadInterval)
[self setUploadInterval:[uploadInterval intValue]];
}
- (void)resetConfiguration {
NSAssert(!started_,
@"The controller must not be started when resetConfiguration is called");
[configuration_ autorelease];
configuration_ = [[[NSBundle mainBundle] infoDictionary] mutableCopy];
NSString *uploadInterval =
[configuration_ valueForKey:@BREAKPAD_REPORT_INTERVAL];
[self setUploadInterval:[uploadInterval intValue]];
[self setParametersToAddAtUploadTime:nil];
}
- (void)setUploadingURL:(NSString*)url {
NSAssert(!started_,
@"The controller must not be started when setUploadingURL is called");
[configuration_ setValue:url forKey:@BREAKPAD_URL];
}
- (void)setUploadInterval:(int)intervalInSeconds {
NSAssert(!started_,
@"The controller must not be started when setUploadInterval is called");
[configuration_ removeObjectForKey:@BREAKPAD_REPORT_INTERVAL];
uploadIntervalInSeconds_ = intervalInSeconds;
if (uploadIntervalInSeconds_ < 0)
uploadIntervalInSeconds_ = 0;
}
- (void)setParametersToAddAtUploadTime:(NSDictionary*)uploadTimeParameters {
NSAssert(!started_, @"The controller must not be started when "
"setParametersToAddAtUploadTime is called");
[uploadTimeParameters_ autorelease];
uploadTimeParameters_ = [uploadTimeParameters copy];
}
- (void)addUploadParameter:(NSString*)value forKey:(NSString*)key {
NSAssert(started_,
@"The controller must be started before addUploadParameter is called");
dispatch_async(queue_, ^{
if (breakpadRef_)
BreakpadAddUploadParameter(breakpadRef_, key, value);
});
}
- (void)setUploadCallback:(BreakpadUploadCompletionCallback)callback {
NSAssert(started_,
@"The controller must not be started before setUploadCallback is "
"called");
dispatch_async(queue_, ^{
uploadCompleteCallback_ = callback;
});
}
- (void)removeUploadParameterForKey:(NSString*)key {
NSAssert(started_, @"The controller must be started before "
"removeUploadParameterForKey is called");
dispatch_async(queue_, ^{
if (breakpadRef_)
BreakpadRemoveUploadParameter(breakpadRef_, key);
});
}
- (void)withBreakpadRef:(void(^)(BreakpadRef))callback {
dispatch_async(queue_, ^{
callback(started_ ? breakpadRef_ : NULL);
});
}
- (void)hasReportToUpload:(void(^)(BOOL))callback {
NSAssert(started_, @"The controller must be started before "
"hasReportToUpload is called");
dispatch_async(queue_, ^{
callback(breakpadRef_ && (BreakpadGetCrashReportCount(breakpadRef_) > 0));
});
}
- (void)getCrashReportCount:(void(^)(int))callback {
NSAssert(started_, @"The controller must be started before "
"getCrashReportCount is called");
dispatch_async(queue_, ^{
callback(breakpadRef_ ? BreakpadGetCrashReportCount(breakpadRef_) : 0);
});
}
- (void)getNextReportConfigurationOrSendDelay:
(void(^)(NSDictionary*, int))callback {
NSAssert(started_, @"The controller must be started before "
"getNextReportConfigurationOrSendDelay is called");
dispatch_async(queue_, ^{
if (!breakpadRef_) {
callback(nil, -1);
return;
}
int delay = [self sendDelay];
if (delay != 0) {
callback(nil, delay);
return;
}
[self reportWillBeSent];
callback(BreakpadGetNextReportConfiguration(breakpadRef_), 0);
});
}
- (void)getDateOfMostRecentCrashReport:(void(^)(NSDate *))callback {
NSAssert(started_, @"The controller must be started before "
"getDateOfMostRecentCrashReport is called");
dispatch_async(queue_, ^{
if (!breakpadRef_) {
callback(nil);
return;
}
callback(BreakpadGetDateOfMostRecentCrashReport(breakpadRef_));
});
}
#pragma mark -
- (int)sendDelay {
if (!breakpadRef_ || uploadIntervalInSeconds_ <= 0 || !enableUploads_)
return -1;
// To prevent overloading the crash server, crashes are not sent than one
// report every |uploadIntervalInSeconds_|. A value in the user defaults is
// used to keep the time of the last upload.
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSNumber *lastTimeNum = [userDefaults objectForKey:kLastSubmission];
NSTimeInterval lastTime = lastTimeNum ? [lastTimeNum floatValue] : 0;
NSTimeInterval spanSeconds = CFAbsoluteTimeGetCurrent() - lastTime;
if (spanSeconds >= uploadIntervalInSeconds_)
return 0;
return uploadIntervalInSeconds_ - static_cast<int>(spanSeconds);
}
- (void)reportWillBeSent {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithDouble:CFAbsoluteTimeGetCurrent()]
forKey:kLastSubmission];
[userDefaults synchronize];
}
// This method must be called from the breakpad queue.
- (void)sendStoredCrashReports {
if (BreakpadGetCrashReportCount(breakpadRef_) == 0)
return;
int timeToWait = [self sendDelay];
// Unable to ever send report.
if (timeToWait == -1)
return;
// A report can be sent now.
if (timeToWait == 0) {
[self reportWillBeSent];
BreakpadUploadNextReportWithParameters(breakpadRef_, uploadTimeParameters_,
uploadCompleteCallback_);
// If more reports must be sent, make sure this method is called again.
if (BreakpadGetCrashReportCount(breakpadRef_) > 0)
timeToWait = uploadIntervalInSeconds_;
}
// A report must be sent later.
if (timeToWait > 0) {
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeToWait * NSEC_PER_SEC));
dispatch_after(delay, queue_, ^{
[self sendStoredCrashReports];
});
}
}
@end

View File

@ -0,0 +1,7 @@
//
// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project.
//
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#endif

Some files were not shown because too many files have changed in this diff Show More