更新breakpad代码

serial
Matthew 2 years ago
parent 56253ff351
commit 4a69a8c967

@ -43,6 +43,7 @@
android:label="@string/app_name" android:label="@string/app_name"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.MicroPhoto" android:theme="@style/Theme.MicroPhoto"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="28"> tools:targetApi="28">
<service <service
@ -67,6 +68,13 @@
</receiver> </receiver>
<receiver android:name=".BootBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</receiver>
<receiver android:name=".ScreenActionReceiver" <receiver android:name=".ScreenActionReceiver"
android:exported="true"> android:exported="true">
<intent-filter android:priority="90000"> <intent-filter android:priority="90000">

@ -5,8 +5,11 @@
cmake_minimum_required(VERSION 3.22.1) cmake_minimum_required(VERSION 3.22.1)
# enable_language(ASM)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
# set(CMAKE_ANDROID_ARM_MODE ON) # breakpad
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS}")
# SET_TARGET_PROPERTIES(microphoto PROPERTIES LINK_FLAGS "-Wl,-s,--gc-sections") # SET_TARGET_PROPERTIES(microphoto PROPERTIES LINK_FLAGS "-Wl,-s,--gc-sections")
@ -22,6 +25,7 @@ add_definitions(-DTERMINAL_CLIENT)
add_definitions(-DKEEP_FRAME_TYPE_ON_REVERSE) add_definitions(-DKEEP_FRAME_TYPE_ON_REVERSE)
add_definitions(-DBOOST_ALL_NO_LIB) add_definitions(-DBOOST_ALL_NO_LIB)
add_definitions(-DASIO_STANDALONE) add_definitions(-DASIO_STANDALONE)
# add_definitions(-DUSING_BREAK_PAD)
# set(OpenCV_DIR D:/Workspace/deps/OpenCV-android-sdk/sdk/native/jni/) # set(OpenCV_DIR D:/Workspace/deps/OpenCV-android-sdk/sdk/native/jni/)
set(OPENCV_EXTRA_MODULES_PATH D:/Workspace/Github/opencv_contrib/modules) set(OPENCV_EXTRA_MODULES_PATH D:/Workspace/Github/opencv_contrib/modules)
@ -97,7 +101,8 @@ file(GLOB BREAKPAD_SOURCES_COMMON
) )
file(GLOB BREAKPAD_ASM_SOURCE ${BREAKPAD_ROOT}/common/linux/breakpad_getcontext.S) file(GLOB BREAKPAD_ASM_SOURCE ${BREAKPAD_ROOT}/common/linux/breakpad_getcontext.S)
set_source_files_properties(${BREAKPAD_ASM_SOURCE} PROPERTIES LANGUAGE C) set_property(SOURCE ${BREAKPAD_ROOT}/common/linux/breakpad_getcontext.S PROPERTY LANGUAGE C)
# set_source_files_properties(${BREAKPAD_ASM_SOURCE} PROPERTIES LANGUAGE C)
# Creates and names a library, sets it as either STATIC # Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code. # or SHARED, and provides the relative paths to its source code.
@ -111,7 +116,9 @@ add_library( # Sets the name of the library.
STATIC STATIC
# Provides a relative path to your source file(s). # Provides a relative path to your source file(s).
${BREAKPAD_SOURCES_COMMON} ${BREAKPAD_ASM_SOURCE} ) ${BREAKPAD_SOURCES_COMMON}
${BREAKPAD_ASM_SOURCE}
)
INCLUDE_DIRECTORIES(${JSONCPP_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${JSONCPP_INCLUDE_DIR})
@ -322,7 +329,7 @@ target_link_libraries( # Specifies the target library.
jsoncpp jsoncpp
#breakpad # breakpad
# Links the target library to the log library # Links the target library to the log library
# included in the NDK. # included in the NDK.

@ -10,12 +10,27 @@
#include <camera/NdkCameraError.h> #include <camera/NdkCameraError.h>
#include <camera/NdkCameraManager.h> #include <camera/NdkCameraManager.h>
#ifdef USING_BREAK_PAD
#include "client/linux/handler/exception_handler.h"
#include "client/linux/handler/minidump_descriptor.h"
#endif
#include <android/native_window.h> #include <android/native_window.h>
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "Camera.h" #include "Camera.h"
#include "Camera2Reader.h" #include "Camera2Reader.h"
#ifdef USING_BREAK_PAD
bool DumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
LOGE("Dump path: %s\n", descriptor.path());
return succeeded;
}
#endif
bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread) bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread)
{ {
didAttachThread = false; didAttachThread = false;
@ -38,8 +53,19 @@ bool GetJniEnv(JavaVM *vm, JNIEnv **env, bool& didAttachThread)
return get_env_result == JNI_OK; return get_env_result == JNI_OK;
} }
// #include "client/linux/handler/exception_handler.h" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
// #include "client/linux/handler/minidump_descriptor.h" JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
#ifdef USING_BREAK_PAD
google_breakpad::MinidumpDescriptor descriptor("/sdcard/Android/data/com.xypower.mpapp/files/logs/");
google_breakpad::ExceptionHandler eh(descriptor, NULL, DumpCallback,
NULL, true, -1);
#endif
return JNI_VERSION_1_6;
}
extern "C" JNIEXPORT jstring JNICALL extern "C" JNIEXPORT jstring JNICALL
Java_com_xypower_mpapp_MainActivity_stringFromJNI( Java_com_xypower_mpapp_MainActivity_stringFromJNI(

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <signal.h> #include <signal.h>
#include <TargetConditionals.h> #include <TargetConditionals.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/crash_generation/crash_generation_client.h" #include "client/linux/crash_generation/crash_generation_client.h"
#include <stdio.h> #include <stdio.h>
@ -45,9 +49,11 @@ namespace {
class CrashGenerationClientImpl : public CrashGenerationClient { class CrashGenerationClientImpl : public CrashGenerationClient {
public: public:
explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {}
virtual ~CrashGenerationClientImpl() {} CrashGenerationClientImpl(const CrashGenerationClientImpl&) = delete;
void operator=(const CrashGenerationClientImpl&) = delete;
~CrashGenerationClientImpl() override = default;
virtual bool RequestDump(const void* blob, size_t blob_size) { bool RequestDump(const void* blob, size_t blob_size) override {
int fds[2]; int fds[2];
if (sys_pipe(fds) < 0) if (sys_pipe(fds) < 0)
return false; return false;
@ -88,8 +94,6 @@ class CrashGenerationClientImpl : public CrashGenerationClient {
private: private:
int server_fd_; int server_fd_;
DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl);
}; };
} // namespace } // namespace

@ -29,8 +29,6 @@
#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ #ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ #define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_
#include "common/basictypes.h"
#include <stddef.h> #include <stddef.h>
namespace google_breakpad { namespace google_breakpad {
@ -41,8 +39,10 @@ namespace google_breakpad {
// via a remote process. // via a remote process.
class CrashGenerationClient { class CrashGenerationClient {
public: public:
CrashGenerationClient() {} CrashGenerationClient() = default;
virtual ~CrashGenerationClient() {} CrashGenerationClient(const CrashGenerationClient&) = delete;
void operator=(const CrashGenerationClient&) = delete;
virtual ~CrashGenerationClient() = default;
// Request the crash server to generate a dump. |blob| is an opaque // Request the crash server to generate a dump. |blob| is an opaque
// CrashContext pointer from exception_handler.h. // CrashContext pointer from exception_handler.h.
@ -54,9 +54,6 @@ class CrashGenerationClient {
// The returned CrashGenerationClient* is owned by the caller of // The returned CrashGenerationClient* is owned by the caller of
// this function. // this function.
static CrashGenerationClient* TryCreate(int server_fd); static CrashGenerationClient* TryCreate(int server_fd);
private:
DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient);
}; };
} // namespace google_breakpad } // namespace google_breakpad

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h> #include <assert.h>
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/dump_writer_common/thread_info.h" #include "client/linux/dump_writer_common/thread_info.h"
#include <string.h> #include <string.h>
@ -318,23 +322,19 @@ void ThreadInfo::FillCPUContext(RawContextCPU* out) const {
out->t5 = mcontext.__gregs[30]; out->t5 = mcontext.__gregs[30];
out->t6 = mcontext.__gregs[31]; out->t6 = mcontext.__gregs[31];
# if __riscv_flen == 32 // Breakpad only supports RISCV32 with 32 bit floating point.
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) // Breakpad only supports RISCV64 with 64 bit floating point.
out->float_save.regs[i] = mcontext.__fpregs.__f.__f[i]; #if __riscv_xlen == 32
out->float_save.fpcsr = mcontext.__fpregs.__f.__fcsr; for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
# elif __riscv_flen == 64 out->fpregs[i] = mcontext.__fpregs.__f.__f[i];
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) out->fcsr = mcontext.__fpregs.__f.__fcsr;
out->float_save.regs[i] = mcontext.__fpregs.__d.__f[i]; #elif __riscv_xlen == 64
out->float_save.fpcsr = mcontext.__fpregs.__d.__fcsr; for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
# elif __riscv_flen == 128 out->fpregs[i] = mcontext.__fpregs.__d.__f[i];
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) { out->fcsr = mcontext.__fpregs.__d.__fcsr;
out->float_save.regs[i].high = mcontext.__fpregs.__q.__f[2*i]; #else
out->float_save.regs[i].low = mcontext.__fpregs.__q.__f[2*i+1]; #error "Unexpected __riscv_xlen"
} #endif
out->float_save.fpcsr = mcontext.__fpregs.__q.__fcsr;
# else
# error "Unexpected __riscv_flen"
# endif
} }
#endif // __riscv #endif // __riscv

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/dump_writer_common/ucontext_reader.h" #include "client/linux/dump_writer_common/ucontext_reader.h"
#include "common/linux/linux_libc_support.h" #include "common/linux/linux_libc_support.h"
@ -306,21 +310,19 @@ void UContextReader::FillCPUContext(RawContextCPU* out, const ucontext_t* uc) {
out->t5 = uc->uc_mcontext.__gregs[30]; out->t5 = uc->uc_mcontext.__gregs[30];
out->t6 = uc->uc_mcontext.__gregs[31]; out->t6 = uc->uc_mcontext.__gregs[31];
# if __riscv_flen == 32 // Breakpad only supports RISCV32 with 32 bit floating point.
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) // Breakpad only supports RISCV64 with 64 bit floating point.
out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__f.__f[i]; #if __riscv_xlen == 32
out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__f.__fcsr; for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
# elif __riscv_flen == 64 out->fpregs[i] = uc->uc_mcontext.__fpregs.__f.__f[i];
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) out->fcsr = uc->uc_mcontext.__fpregs.__f.__fcsr;
out->float_save.regs[i] = uc->uc_mcontext.__fpregs.__d.__f[i]; #elif __riscv_xlen == 64
out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__d.__fcsr; for (int i = 0; i < MD_CONTEXT_RISCV_FPR_COUNT; i++)
# elif __riscv_flen == 128 out->fpregs[i] = uc->uc_mcontext.__fpregs.__d.__f[i];
for(int i = 0; i < MD_FLOATINGSAVEAREA_RISCV_FPR_COUNT; i++) { out->fcsr = uc->uc_mcontext.__fpregs.__d.__fcsr;
out->float_save.regs[i].high = uc->uc_mcontext.__fpregs.__q.__f[2*i]; #else
out->float_save.regs[i].low = uc->uc_mcontext.__fpregs.__q.__f[2*i+1]; #error "Unexpected __riscv_xlen"
} #endif
out->float_save.fpcsr = uc->uc_mcontext.__fpregs.__q.__fcsr;
# endif
} }
#endif #endif

@ -62,6 +62,10 @@
// alternative malloc. Each function should have comment above it detailing the // alternative malloc. Each function should have comment above it detailing the
// context which it runs in. // context which it runs in.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/handler/exception_handler.h" #include "client/linux/handler/exception_handler.h"
#include <errno.h> #include <errno.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <poll.h> #include <poll.h>
#include <pthread.h> #include <pthread.h>
#include <stdint.h> #include <stdint.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdio.h> #include <stdio.h>
#include "client/linux/handler/minidump_descriptor.h" #include "client/linux/handler/minidump_descriptor.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/log/log.h" #include "client/linux/log/log.h"
#if defined(__ANDROID__) #if defined(__ANDROID__)

@ -29,6 +29,10 @@
// This translation unit generates microdumps into the console (logcat on // This translation unit generates microdumps into the console (logcat on
// Android). See crbug.com/410294 for more info and design docs. // Android). See crbug.com/410294 for more info and design docs.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/microdump_writer/microdump_writer.h" #include "client/linux/microdump_writer/microdump_writer.h"
#include <limits> #include <limits>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <ctype.h> #include <ctype.h>
#include <sys/syscall.h> #include <sys/syscall.h>
#include <sys/types.h> #include <sys/types.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
@ -35,7 +39,7 @@
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"
#include "client/linux/minidump_writer/cpu_set.h" #include "client/linux/minidump_writer/cpu_set.h"
#include "common/linux/tests/auto_testfile.h" #include "common/linux/scoped_tmpfile.h"
using namespace google_breakpad; using namespace google_breakpad;
@ -43,15 +47,6 @@ namespace {
typedef testing::Test CpuSetTest; typedef testing::Test CpuSetTest;
// Helper class to write test text file to a temporary file and return
// its file descriptor.
class ScopedTestFile : public AutoTestFile {
public:
explicit ScopedTestFile(const char* text)
: AutoTestFile("cpu_set", text) {
}
};
} }
TEST(CpuSetTest, EmptyCount) { TEST(CpuSetTest, EmptyCount) {
@ -60,8 +55,8 @@ TEST(CpuSetTest, EmptyCount) {
} }
TEST(CpuSetTest, OneCpu) { TEST(CpuSetTest, OneCpu) {
ScopedTestFile file("10"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("10"));
CpuSet set; CpuSet set;
ASSERT_TRUE(set.ParseSysFile(file.GetFd())); ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
@ -69,8 +64,8 @@ TEST(CpuSetTest, OneCpu) {
} }
TEST(CpuSetTest, OneCpuTerminated) { TEST(CpuSetTest, OneCpuTerminated) {
ScopedTestFile file("10\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("10\n"));
CpuSet set; CpuSet set;
ASSERT_TRUE(set.ParseSysFile(file.GetFd())); ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
@ -78,8 +73,8 @@ TEST(CpuSetTest, OneCpuTerminated) {
} }
TEST(CpuSetTest, TwoCpusWithComma) { TEST(CpuSetTest, TwoCpusWithComma) {
ScopedTestFile file("1,10"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("1,10"));
CpuSet set; CpuSet set;
ASSERT_TRUE(set.ParseSysFile(file.GetFd())); ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
@ -87,8 +82,8 @@ TEST(CpuSetTest, TwoCpusWithComma) {
} }
TEST(CpuSetTest, TwoCpusWithRange) { TEST(CpuSetTest, TwoCpusWithRange) {
ScopedTestFile file("1-2"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("1-2"));
CpuSet set; CpuSet set;
ASSERT_TRUE(set.ParseSysFile(file.GetFd())); ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
@ -96,8 +91,8 @@ TEST(CpuSetTest, TwoCpusWithRange) {
} }
TEST(CpuSetTest, TenCpusWithRange) { TEST(CpuSetTest, TenCpusWithRange) {
ScopedTestFile file("9-18"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("9-18"));
CpuSet set; CpuSet set;
ASSERT_TRUE(set.ParseSysFile(file.GetFd())); ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
@ -105,8 +100,8 @@ TEST(CpuSetTest, TenCpusWithRange) {
} }
TEST(CpuSetTest, MultiItems) { TEST(CpuSetTest, MultiItems) {
ScopedTestFile file("0, 2-4, 128"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("0, 2-4, 128"));
CpuSet set; CpuSet set;
ASSERT_TRUE(set.ParseSysFile(file.GetFd())); ASSERT_TRUE(set.ParseSysFile(file.GetFd()));
@ -114,14 +109,16 @@ TEST(CpuSetTest, MultiItems) {
} }
TEST(CpuSetTest, IntersectWith) { TEST(CpuSetTest, IntersectWith) {
ScopedTestFile file1("9-19"); ScopedTmpFile file1;
ASSERT_TRUE(file1.IsOk()); ASSERT_TRUE(file1.InitString("9-19"));
CpuSet set1; CpuSet set1;
ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
ASSERT_EQ(11, set1.GetCount()); ASSERT_EQ(11, set1.GetCount());
ScopedTestFile file2("16-24"); ScopedTmpFile file2;
ASSERT_TRUE(file2.IsOk()); ASSERT_TRUE(file2.InitString("16-24"));
CpuSet set2; CpuSet set2;
ASSERT_TRUE(set2.ParseSysFile(file2.GetFd())); ASSERT_TRUE(set2.ParseSysFile(file2.GetFd()));
ASSERT_EQ(9, set2.GetCount()); ASSERT_EQ(9, set2.GetCount());
@ -132,8 +129,9 @@ TEST(CpuSetTest, IntersectWith) {
} }
TEST(CpuSetTest, SelfIntersection) { TEST(CpuSetTest, SelfIntersection) {
ScopedTestFile file1("9-19"); ScopedTmpFile file1;
ASSERT_TRUE(file1.IsOk()); ASSERT_TRUE(file1.InitString("9-19"));
CpuSet set1; CpuSet set1;
ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
ASSERT_EQ(11, set1.GetCount()); ASSERT_EQ(11, set1.GetCount());
@ -143,14 +141,16 @@ TEST(CpuSetTest, SelfIntersection) {
} }
TEST(CpuSetTest, EmptyIntersection) { TEST(CpuSetTest, EmptyIntersection) {
ScopedTestFile file1("0-19"); ScopedTmpFile file1;
ASSERT_TRUE(file1.IsOk()); ASSERT_TRUE(file1.InitString("0-19"));
CpuSet set1; CpuSet set1;
ASSERT_TRUE(set1.ParseSysFile(file1.GetFd())); ASSERT_TRUE(set1.ParseSysFile(file1.GetFd()));
ASSERT_EQ(20, set1.GetCount()); ASSERT_EQ(20, set1.GetCount());
ScopedTestFile file2("20-39"); ScopedTmpFile file2;
ASSERT_TRUE(file2.IsOk()); ASSERT_TRUE(file2.InitString("20-39"));
CpuSet set2; CpuSet set2;
ASSERT_TRUE(set2.ParseSysFile(file2.GetFd())); ASSERT_TRUE(set2.ParseSysFile(file2.GetFd()));
ASSERT_EQ(20, set2.GetCount()); ASSERT_EQ(20, set2.GetCount());

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <set> #include <set>
#include <string> #include <string>

@ -26,13 +26,17 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include "client/linux/minidump_writer/line_reader.h" #include "client/linux/minidump_writer/line_reader.h"
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"
#include "common/linux/tests/auto_testfile.h" #include "common/linux/scoped_tmpfile.h"
using namespace google_breakpad; using namespace google_breakpad;
@ -40,22 +44,11 @@ namespace {
typedef testing::Test LineReaderTest; typedef testing::Test LineReaderTest;
class ScopedTestFile : public AutoTestFile {
public:
explicit ScopedTestFile(const char* text)
: AutoTestFile("line_reader", text) {
}
ScopedTestFile(const char* text, size_t text_len)
: AutoTestFile("line_reader", text, text_len) {
}
};
} }
TEST(LineReaderTest, EmptyFile) { TEST(LineReaderTest, EmptyFile) {
ScopedTestFile file(""); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString(""));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;
@ -64,8 +57,8 @@ TEST(LineReaderTest, EmptyFile) {
} }
TEST(LineReaderTest, OneLineTerminated) { TEST(LineReaderTest, OneLineTerminated) {
ScopedTestFile file("a\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("a\n"));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;
@ -80,8 +73,8 @@ TEST(LineReaderTest, OneLineTerminated) {
} }
TEST(LineReaderTest, OneLine) { TEST(LineReaderTest, OneLine) {
ScopedTestFile file("a"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("a"));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;
@ -96,8 +89,8 @@ TEST(LineReaderTest, OneLine) {
} }
TEST(LineReaderTest, TwoLinesTerminated) { TEST(LineReaderTest, TwoLinesTerminated) {
ScopedTestFile file("a\nb\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("a\nb\n"));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;
@ -118,8 +111,8 @@ TEST(LineReaderTest, TwoLinesTerminated) {
} }
TEST(LineReaderTest, TwoLines) { TEST(LineReaderTest, TwoLines) {
ScopedTestFile file("a\nb"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("a\nb"));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;
@ -142,8 +135,8 @@ TEST(LineReaderTest, TwoLines) {
TEST(LineReaderTest, MaxLength) { TEST(LineReaderTest, MaxLength) {
char l[LineReader::kMaxLineLen-1]; char l[LineReader::kMaxLineLen-1];
memset(l, 'a', sizeof(l)); memset(l, 'a', sizeof(l));
ScopedTestFile file(l, sizeof(l)); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitData(l, sizeof(l)));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;
@ -158,8 +151,8 @@ TEST(LineReaderTest, TooLong) {
// Note: this writes kMaxLineLen 'a' chars in the test file. // Note: this writes kMaxLineLen 'a' chars in the test file.
char l[LineReader::kMaxLineLen]; char l[LineReader::kMaxLineLen];
memset(l, 'a', sizeof(l)); memset(l, 'a', sizeof(l));
ScopedTestFile file(l, sizeof(l)); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitData(l, sizeof(l)));
LineReader reader(file.GetFd()); LineReader reader(file.GetFd());
const char* line; const char* line;

@ -29,6 +29,10 @@
// linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper. // linux_core_dumper.cc: Implement google_breakpad::LinuxCoreDumper.
// See linux_core_dumper.h for details. // See linux_core_dumper.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/minidump_writer/linux_core_dumper.h" #include "client/linux/minidump_writer/linux_core_dumper.h"
#include <asm/ptrace.h> #include <asm/ptrace.h>

@ -29,6 +29,10 @@
// linux_core_dumper_unittest.cc: // linux_core_dumper_unittest.cc:
// Unit tests for google_breakpad::LinuxCoreDumoer. // Unit tests for google_breakpad::LinuxCoreDumoer.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <string> #include <string>
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"

@ -34,6 +34,10 @@
// rules apply as detailed at the top of minidump_writer.h: no libc calls and // rules apply as detailed at the top of minidump_writer.h: no libc calls and
// use the alternative allocator. // use the alternative allocator.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/minidump_writer/linux_dumper.h" #include "client/linux/minidump_writer/linux_dumper.h"
#include <assert.h> #include <assert.h>
@ -342,7 +346,7 @@ LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
return false; return false;
bool filename_modified = HandleDeletedFileInMapping(filename); bool filename_modified = HandleDeletedFileInMapping(filename);
MemoryMappedFile mapped_file(filename, mapping.offset); MemoryMappedFile mapped_file(filename, 0);
if (!mapped_file.data() || mapped_file.size() < SELFMAG) if (!mapped_file.data() || mapped_file.size() < SELFMAG)
return false; return false;
@ -455,7 +459,7 @@ bool ElfFileSoName(const LinuxDumper& dumper,
if (!dumper.GetMappingAbsolutePath(mapping, filename)) if (!dumper.GetMappingAbsolutePath(mapping, filename))
return false; return false;
MemoryMappedFile mapped_file(filename, mapping.offset); MemoryMappedFile mapped_file(filename, 0);
if (!mapped_file.data() || mapped_file.size() < SELFMAG) { if (!mapped_file.data() || mapped_file.size() < SELFMAG) {
// mmap failed // mmap failed
return false; return false;

@ -30,6 +30,10 @@
// threads. The first word of each thread's stack is set to the thread // threads. The first word of each thread's stack is set to the thread
// id. // id.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <pthread.h> #include <pthread.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>

@ -35,6 +35,10 @@
// rules apply as detailed at the top of minidump_writer.h: no libc calls and // rules apply as detailed at the top of minidump_writer.h: no libc calls and
// use the alternative allocator. // use the alternative allocator.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/minidump_writer/linux_ptrace_dumper.h" #include "client/linux/minidump_writer/linux_ptrace_dumper.h"
#include <asm/ptrace.h> #include <asm/ptrace.h>
@ -175,6 +179,13 @@ bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) {
return false; return false;
} }
// When running on arm processors the binary may be built with softfp or
// hardfp. If built with softfp we have no hardware registers to read from,
// so the following read will always fail. gcc defines __SOFTFP__ macro,
// clang13 does not do so. see: https://reviews.llvm.org/D135680.
// If you are using clang and the macro is NOT defined, please include the
// macro define for applicable targets.
#if !defined(__SOFTFP__)
#if !(defined(__ANDROID__) && defined(__ARM_EABI__)) #if !(defined(__ANDROID__) && defined(__ARM_EABI__))
// When running an arm build on an arm64 device, attempting to get the // When running an arm build on an arm64 device, attempting to get the
// floating point registers fails. On Android, the floating point registers // floating point registers fails. On Android, the floating point registers
@ -186,6 +197,7 @@ bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) {
return false; return false;
} }
#endif // !(defined(__ANDROID__) && defined(__ARM_EABI__)) #endif // !(defined(__ANDROID__) && defined(__ARM_EABI__))
#endif // !defined(__SOFTFP__)
return true; return true;
#else // PTRACE_GETREGS #else // PTRACE_GETREGS
return false; return false;

@ -32,6 +32,10 @@
// This file was renamed from linux_dumper_unittest.cc and modified due // This file was renamed from linux_dumper_unittest.cc and modified due
// to LinuxDumper being splitted into two classes. // to LinuxDumper being splitted into two classes.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>

@ -42,6 +42,10 @@
// a canonical instance in the LinuxDumper object. We use the placement // a canonical instance in the LinuxDumper object. We use the placement
// new form to allocate objects and we don't delete them. // new form to allocate objects and we don't delete them.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/linux/handler/minidump_descriptor.h" #include "client/linux/handler/minidump_descriptor.h"
#include "client/linux/minidump_writer/minidump_writer.h" #include "client/linux/minidump_writer/minidump_writer.h"
#include "client/minidump_file_writer-inl.h" #include "client/minidump_file_writer-inl.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <sys/stat.h> #include <sys/stat.h>

@ -29,6 +29,10 @@
// minidump_writer_unittest_utils.cc: // minidump_writer_unittest_utils.cc:
// Shared routines used by unittests under client/linux/minidump_writer. // Shared routines used by unittests under client/linux/minidump_writer.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <string.h> #include <string.h>
#include "client/linux/minidump_writer/pe_file.h" #include "client/linux/minidump_writer/pe_file.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
@ -35,33 +39,19 @@
#include "client/linux/minidump_writer/proc_cpuinfo_reader.h" #include "client/linux/minidump_writer/proc_cpuinfo_reader.h"
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"
#include "common/linux/tests/auto_testfile.h" #include "common/linux/scoped_tmpfile.h"
using namespace google_breakpad; using namespace google_breakpad;
#if !defined(__ANDROID__)
#define TEMPDIR "/tmp"
#else
#define TEMPDIR "/data/local/tmp"
#endif
namespace { namespace {
typedef testing::Test ProcCpuInfoReaderTest; typedef testing::Test ProcCpuInfoReaderTest;
class ScopedTestFile : public AutoTestFile {
public:
explicit ScopedTestFile(const char* text)
: AutoTestFile("proc_cpuinfo_reader", text) {
}
};
} }
TEST(ProcCpuInfoReaderTest, EmptyFile) { TEST(ProcCpuInfoReaderTest, EmptyFile) {
ScopedTestFile file(""); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString(""));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -69,8 +59,8 @@ TEST(ProcCpuInfoReaderTest, EmptyFile) {
} }
TEST(ProcCpuInfoReaderTest, OneLineTerminated) { TEST(ProcCpuInfoReaderTest, OneLineTerminated) {
ScopedTestFile file("foo : bar\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("foo : bar\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -82,8 +72,8 @@ TEST(ProcCpuInfoReaderTest, OneLineTerminated) {
} }
TEST(ProcCpuInfoReaderTest, OneLine) { TEST(ProcCpuInfoReaderTest, OneLine) {
ScopedTestFile file("foo : bar"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("foo : bar"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -97,8 +87,8 @@ TEST(ProcCpuInfoReaderTest, OneLine) {
} }
TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) { TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) {
ScopedTestFile file("foo : bar\nzoo : tut\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("foo : bar\nzoo : tut\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -114,8 +104,8 @@ TEST(ProcCpuInfoReaderTest, TwoLinesTerminated) {
} }
TEST(ProcCpuInfoReaderTest, SkipMalformedLine) { TEST(ProcCpuInfoReaderTest, SkipMalformedLine) {
ScopedTestFile file("this line should have a column\nfoo : bar\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("this line should have a column\nfoo : bar\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -127,8 +117,8 @@ TEST(ProcCpuInfoReaderTest, SkipMalformedLine) {
} }
TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) { TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) {
ScopedTestFile file("\n\nfoo : bar\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("\n\nfoo : bar\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -140,8 +130,8 @@ TEST(ProcCpuInfoReaderTest, SkipOneEmptyLine) {
} }
TEST(ProcCpuInfoReaderTest, SkipEmptyField) { TEST(ProcCpuInfoReaderTest, SkipEmptyField) {
ScopedTestFile file(" : bar\nzoo : tut\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString(" : bar\nzoo : tut\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -153,8 +143,8 @@ TEST(ProcCpuInfoReaderTest, SkipEmptyField) {
} }
TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) { TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) {
ScopedTestFile file("foo : bar\n\n\nfoo : bar\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("foo : bar\n\n\nfoo : bar\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -170,8 +160,8 @@ TEST(ProcCpuInfoReaderTest, SkipTwoEmptyLines) {
} }
TEST(ProcCpuInfoReaderTest, FieldWithSpaces) { TEST(ProcCpuInfoReaderTest, FieldWithSpaces) {
ScopedTestFile file("foo bar : zoo\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("foo bar : zoo\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;
@ -183,8 +173,8 @@ TEST(ProcCpuInfoReaderTest, FieldWithSpaces) {
} }
TEST(ProcCpuInfoReaderTest, EmptyValue) { TEST(ProcCpuInfoReaderTest, EmptyValue) {
ScopedTestFile file("foo :\n"); ScopedTmpFile file;
ASSERT_TRUE(file.IsOk()); ASSERT_TRUE(file.InitString("foo :\n"));
ProcCpuInfoReader reader(file.GetFd()); ProcCpuInfoReader reader(file.GetFd());
const char* field; const char* field;

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/linux/google_crashdump_uploader.h" #include "common/linux/google_crashdump_uploader.h"
#include <string> #include <string>
#include <iostream> #include <iostream>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/mac/crash_generation/crash_generation_client.h" #include "client/mac/crash_generation/crash_generation_client.h"
#include "client/mac/crash_generation/crash_generation_server.h" #include "client/mac/crash_generation/crash_generation_server.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/mac/crash_generation/crash_generation_server.h" #include "client/mac/crash_generation/crash_generation_server.h"
#include <pthread.h> #include <pthread.h>

@ -65,6 +65,10 @@
* I've modified it to be compatible with 64-bit images. * I've modified it to be compatible with 64-bit images.
*/ */
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "breakpad_nlist_64.h" #include "breakpad_nlist_64.h"
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/mac/handler/dynamic_images.h" #include "client/mac/handler/dynamic_images.h"
extern "C" { // needed to compile on Leopard extern "C" { // needed to compile on Leopard

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <mach/exc.h> #include <mach/exc.h>
#include <mach/mig.h> #include <mach/mig.h>
#include <pthread.h> #include <pthread.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>

@ -30,6 +30,10 @@
// //
// See the header file for documentation // See the header file for documentation
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "protected_memory_allocator.h" #include "protected_memory_allocator.h"
#include <assert.h> #include <assert.h>

@ -33,6 +33,10 @@
// Copyright 2008 Google LLC // Copyright 2008 Google LLC
// //
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/mac/handler/testcases/DynamicImagesTests.h" #include "client/mac/handler/testcases/DynamicImagesTests.h"
#include "client/mac/handler/dynamic_images.h" #include "client/mac/handler/dynamic_images.h"

@ -33,6 +33,10 @@
// Copyright 2008 Google LLC // Copyright 2008 Google LLC
// //
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/mac/handler/testcases/breakpad_nlist_test.h" #include "client/mac/handler/testcases/breakpad_nlist_test.h"
#include <mach-o/nlist.h> #include <mach-o/nlist.h>
#include "client/mac/handler/breakpad_nlist_64.h" #include "client/mac/handler/breakpad_nlist_64.h"

@ -29,6 +29,10 @@
// crash_generation_server_test.cc // crash_generation_server_test.cc
// Unit tests for CrashGenerationServer // Unit tests for CrashGenerationServer
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <dirent.h> #include <dirent.h>
#include <glob.h> #include <glob.h>
#include <stdint.h> #include <stdint.h>

@ -28,6 +28,10 @@
// exception_handler_test.cc: Unit tests for google_breakpad::ExceptionHandler // exception_handler_test.cc: Unit tests for google_breakpad::ExceptionHandler
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <pthread.h> #include <pthread.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>

@ -28,6 +28,10 @@
// minidump_generator_test.cc: Unit tests for google_breakpad::MinidumpGenerator // minidump_generator_test.cc: Unit tests for google_breakpad::MinidumpGenerator
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <AvailabilityMacros.h> #include <AvailabilityMacros.h>
#ifndef MAC_OS_X_VERSION_10_6 #ifndef MAC_OS_X_VERSION_10_6
#define MAC_OS_X_VERSION_10_6 1060 #define MAC_OS_X_VERSION_10_6 1060

@ -30,6 +30,10 @@
// minidump_generator_test.cc can launch to test certain things // minidump_generator_test.cc can launch to test certain things
// that require a separate executable. // that require a separate executable.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <unistd.h> #include <unistd.h>
#include "client/mac/handler/exception_handler.h" #include "client/mac/handler/exception_handler.h"

@ -30,6 +30,10 @@
// //
// See minidump_file_writer.h for documentation. // See minidump_file_writer.h for documentation.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>

@ -36,6 +36,10 @@
-o minidump_file_writer_unittest -o minidump_file_writer_unittest
*/ */
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>

@ -28,6 +28,10 @@
// Author: Alfred Peng // Author: Alfred Peng
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <signal.h> #include <signal.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>

@ -28,6 +28,10 @@
// Author: Alfred Peng // Author: Alfred Peng
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>

@ -28,6 +28,10 @@
// Author: Alfred Peng // Author: Alfred Peng
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <fcntl.h> #include <fcntl.h>
#include <sys/frame.h> #include <sys/frame.h>
#include <sys/stat.h> #include <sys/stat.h>

@ -28,6 +28,10 @@
// Author: Alfred Peng // Author: Alfred Peng
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>

@ -28,6 +28,10 @@
// Author: Alfred Peng // Author: Alfred Peng
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <dirent.h> #include <dirent.h>
#include <elf.h> #include <elf.h>
#include <errno.h> #include <errno.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/crash_generation/client_info.h" #include "client/windows/crash_generation/client_info.h"
#include "client/windows/common/ipc_protocol.h" #include "client/windows/common/ipc_protocol.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/crash_generation/crash_generation_client.h" #include "client/windows/crash_generation/crash_generation_client.h"
#include <cassert> #include <cassert>
#include <utility> #include <utility>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/crash_generation/crash_generation_server.h" #include "client/windows/crash_generation/crash_generation_server.h"
#include <windows.h> #include <windows.h>
#include <cassert> #include <cassert>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/crash_generation/minidump_generator.h" #include "client/windows/crash_generation/minidump_generator.h"
#include <assert.h> #include <assert.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <objbase.h> #include <objbase.h>
#include <algorithm> #include <algorithm>

@ -29,6 +29,10 @@
// Disable exception handler warnings. // Disable exception handler warnings.
#pragma warning( disable : 4530 ) #pragma warning( disable : 4530 )
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <errno.h> #include <errno.h>
#include "client/windows/sender/crash_report_sender.h" #include "client/windows/sender/crash_report_sender.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/tests/crash_generation_app/abstract_class.h" #include "client/windows/tests/crash_generation_app/abstract_class.h"
namespace google_breakpad { namespace google_breakpad {

@ -29,6 +29,10 @@
// crash_generation_app.cpp : Defines the entry point for the application. // crash_generation_app.cpp : Defines the entry point for the application.
// //
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/tests/crash_generation_app/crash_generation_app.h" #include "client/windows/tests/crash_generation_app/crash_generation_app.h"
#include <windows.h> #include <windows.h>

@ -27,6 +27,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"
#include "client/windows/crash_generation/crash_generation_server.h" #include "client/windows/crash_generation/crash_generation_server.h"
#include "client/windows/common/ipc_protocol.h" #include "client/windows/common/ipc_protocol.h"

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <windows.h> #include <windows.h>
#include <objbase.h> #include <objbase.h>
#include <dbghelp.h> #include <dbghelp.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <windows.h> #include <windows.h>
#include <dbghelp.h> #include <dbghelp.h>
#include <strsafe.h> #include <strsafe.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <windows.h> #include <windows.h>
#include <string> #include <string>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "client/windows/unittests/exception_handler_test.h" #include "client/windows/unittests/exception_handler_test.h"
#include <windows.h> #include <windows.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <windows.h> #include <windows.h>
#include <objbase.h> #include <objbase.h>
#include <dbghelp.h> #include <dbghelp.h>

@ -29,14 +29,6 @@
#ifndef COMMON_BASICTYPES_H_ #ifndef COMMON_BASICTYPES_H_
#define COMMON_BASICTYPES_H_ #define COMMON_BASICTYPES_H_
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#ifndef DISALLOW_COPY_AND_ASSIGN
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif // DISALLOW_COPY_AND_ASSIGN
namespace google_breakpad { namespace google_breakpad {
// Used to explicitly mark the return value of a function as unused. If you are // Used to explicitly mark the return value of a function as unused. If you are

@ -31,6 +31,10 @@
// byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer // byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer
// and google_breakpad::ByteCursor. // and google_breakpad::ByteCursor.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <string> #include <string>
#include <string.h> #include <string.h>

@ -55,6 +55,10 @@ See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */ ------------------------------------------------------------------------ */
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "convert_UTF.h" #include "convert_UTF.h"
#ifdef CVTUTF_DEBUG #ifdef CVTUTF_DEBUG
#include <stdio.h> #include <stdio.h>

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>

@ -30,6 +30,10 @@
// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader // bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>

@ -31,6 +31,10 @@
// cfi_assembler.cc: Implementation of google_breakpad::CFISection class. // cfi_assembler.cc: Implementation of google_breakpad::CFISection class.
// See cfi_assembler.h for details. // See cfi_assembler.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/dwarf/cfi_assembler.h" #include "common/dwarf/cfi_assembler.h"
#include <assert.h> #include <assert.h>

@ -31,6 +31,10 @@
// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. // dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class.
// See dwarf2diehandler.h for details. // See dwarf2diehandler.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>

@ -32,6 +32,10 @@
// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. // dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>

@ -580,10 +580,10 @@ enum DwarfSectionId {
DW_SECT_TYPES = 2, DW_SECT_TYPES = 2,
DW_SECT_ABBREV = 3, DW_SECT_ABBREV = 3,
DW_SECT_LINE = 4, DW_SECT_LINE = 4,
DW_SECT_LOC = 5, DW_SECT_LOCLISTS = 5,
DW_SECT_STR_OFFSETS = 6, DW_SECT_STR_OFFSETS = 6,
DW_SECT_MACINFO = 7, DW_SECT_MACRO = 7,
DW_SECT_MACRO = 8 DW_SECT_RNGLISTS = 8
}; };
// Source languages. These are values for DW_AT_language. // Source languages. These are values for DW_AT_language.

@ -31,6 +31,10 @@
// Implementation of LineInfo, CompilationUnit, // Implementation of LineInfo, CompilationUnit,
// and CallFrameInfo. See dwarf2reader.h for details. // and CallFrameInfo. See dwarf2reader.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/dwarf/dwarf2reader.h" #include "common/dwarf/dwarf2reader.h"
#include <stdint.h> #include <stdint.h>
@ -76,9 +80,10 @@ CompilationUnit::CompilationUnit(const string& path,
str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), str_offsets_buffer_(NULL), str_offsets_buffer_length_(0),
addr_buffer_(NULL), addr_buffer_length_(0), addr_buffer_(NULL), addr_buffer_length_(0),
is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(),
skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), skeleton_dwo_id_(0), addr_base_(0),
str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), str_offsets_base_(0), have_checked_for_dwp_(false),
dwp_byte_reader_(), dwp_reader_() {} should_process_split_dwarf_(false), low_pc_(0),
has_source_line_info_(false), source_line_offset_(0) {}
// Initialize a compilation unit from a .dwo or .dwp file. // Initialize a compilation unit from a .dwo or .dwp file.
// In this case, we need the .debug_addr section from the // In this case, we need the .debug_addr section from the
@ -87,16 +92,10 @@ CompilationUnit::CompilationUnit(const string& path,
// the executable file, and call it as if we were still // the executable file, and call it as if we were still
// processing the original compilation unit. // processing the original compilation unit.
void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, void CompilationUnit::SetSplitDwarf(uint64_t addr_base,
uint64_t addr_buffer_length,
uint64_t addr_base,
uint64_t ranges_base,
uint64_t dwo_id) { uint64_t dwo_id) {
is_split_dwarf_ = true; is_split_dwarf_ = true;
addr_buffer_ = addr_buffer;
addr_buffer_length_ = addr_buffer_length;
addr_base_ = addr_base; addr_base_ = addr_base;
ranges_base_ = ranges_base;
skeleton_dwo_id_ = dwo_id; skeleton_dwo_id_ = dwo_id;
} }
@ -396,7 +395,13 @@ uint64_t CompilationUnit::Start() {
// Set up our buffer // Set up our buffer
buffer_ = iter->second.first + offset_from_section_start_; buffer_ = iter->second.first + offset_from_section_start_;
buffer_length_ = iter->second.second - offset_from_section_start_; if (is_split_dwarf_) {
iter = GetSectionByName(sections_, ".debug_info_offset");
assert(iter != sections_.end());
buffer_length_ = iter->second.second;
} else {
buffer_length_ = iter->second.second - offset_from_section_start_;
}
// Read the header // Read the header
ReadHeader(); ReadHeader();
@ -430,6 +435,12 @@ uint64_t CompilationUnit::Start() {
string_buffer_length_ = iter->second.second; string_buffer_length_ = iter->second.second;
} }
iter = GetSectionByName(sections_, ".debug_line");
if (iter != sections_.end()) {
line_buffer_ = iter->second.first;
line_buffer_length_ = iter->second.second;
}
// Set the line string section if we have one. // Set the line string section if we have one.
iter = GetSectionByName(sections_, ".debug_line_str"); iter = GetSectionByName(sections_, ".debug_line_str");
if (iter != sections_.end()) { if (iter != sections_.end()) {
@ -457,10 +468,8 @@ uint64_t CompilationUnit::Start() {
// If this is a skeleton compilation unit generated with split DWARF, // If this is a skeleton compilation unit generated with split DWARF,
// and the client needs the full debug info, we need to find the full // and the client needs the full debug info, we need to find the full
// compilation unit in a .dwo or .dwp file. // compilation unit in a .dwo or .dwp file.
if (!is_split_dwarf_ should_process_split_dwarf_ =
&& dwo_name_ != NULL !is_split_dwarf_ && dwo_name_ != NULL && handler_->NeedSplitDebugInfo();
&& handler_->NeedSplitDebugInfo())
ProcessSplitDwarf();
return ourlength; return ourlength;
} }
@ -881,7 +890,9 @@ const uint8_t* CompilationUnit::ProcessDIE(uint64_t dieoffset,
// DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must // DW_AT_str_offsets_base or DW_AT_addr_base. If it does, that attribute must
// be found and processed before trying to process the other attributes; // be found and processed before trying to process the other attributes;
// otherwise the string or address values will all come out incorrect. // otherwise the string or address values will all come out incorrect.
if (abbrev.tag == DW_TAG_compile_unit && header_.version == 5) { if ((abbrev.tag == DW_TAG_compile_unit ||
abbrev.tag == DW_TAG_skeleton_unit) &&
header_.version == 5) {
uint64_t dieoffset_copy = dieoffset; uint64_t dieoffset_copy = dieoffset;
const uint8_t* start_copy = start; const uint8_t* start_copy = start;
for (AttributeList::const_iterator i = abbrev.attributes.begin(); for (AttributeList::const_iterator i = abbrev.attributes.begin();
@ -990,66 +1001,69 @@ inline int GetElfWidth(const ElfReader& elf) {
return 0; return 0;
} }
void CompilationUnit::ProcessSplitDwarf() { bool CompilationUnit::ProcessSplitDwarf(std::string& split_file,
SectionMap& sections,
ByteReader& split_byte_reader,
uint64_t& cu_offset) {
if (!should_process_split_dwarf_)
return false;
struct stat statbuf; struct stat statbuf;
bool found_in_dwp = false;
if (!have_checked_for_dwp_) { if (!have_checked_for_dwp_) {
// Look for a .dwp file in the same directory as the executable. // Look for a .dwp file in the same directory as the executable.
have_checked_for_dwp_ = true; have_checked_for_dwp_ = true;
string dwp_suffix(".dwp"); string dwp_suffix(".dwp");
dwp_path_ = path_ + dwp_suffix; std::string dwp_path = path_ + dwp_suffix;
if (stat(dwp_path_.c_str(), &statbuf) != 0) { if (stat(dwp_path.c_str(), &statbuf) != 0) {
// Fall back to a split .debug file in the same directory. // Fall back to a split .debug file in the same directory.
string debug_suffix(".debug"); string debug_suffix(".debug");
dwp_path_ = path_; dwp_path = path_;
size_t found = path_.rfind(debug_suffix); size_t found = path_.rfind(debug_suffix);
if (found + debug_suffix.length() == path_.length()) if (found != string::npos &&
dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); found + debug_suffix.length() == path_.length())
dwp_path = dwp_path.replace(found, debug_suffix.length(), dwp_suffix);
} }
if (stat(dwp_path_.c_str(), &statbuf) == 0) { if (stat(dwp_path.c_str(), &statbuf) == 0) {
ElfReader* elf = new ElfReader(dwp_path_); split_elf_reader_ = std::make_unique<ElfReader>(dwp_path);
int width = GetElfWidth(*elf); int width = GetElfWidth(*split_elf_reader_.get());
if (width != 0) { if (width != 0) {
dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); split_byte_reader = ByteReader(reader_->GetEndianness());
dwp_byte_reader_->SetAddressSize(width); split_byte_reader.SetAddressSize(width);
dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); dwp_reader_ = std::make_unique<DwpReader>(split_byte_reader,
split_elf_reader_.get());
dwp_reader_->Initialize(); dwp_reader_->Initialize();
} else { // If we have a .dwp file, read the debug sections for the requested CU.
delete elf; dwp_reader_->ReadDebugSectionsForCU(dwo_id_, &sections);
if (!sections.empty()) {
SectionMap::const_iterator cu_iter =
GetSectionByName(sections, ".debug_info_offset");
SectionMap::const_iterator debug_info_iter =
GetSectionByName(sections, ".debug_info");
assert(cu_iter != sections.end());
assert(debug_info_iter != sections.end());
cu_offset = cu_iter->second.first - debug_info_iter->second.first;
found_in_dwp = true;
split_file = dwp_path;
}
} }
} }
} }
bool found_in_dwp = false;
if (dwp_reader_) {
// If we have a .dwp file, read the debug sections for the requested CU.
SectionMap sections;
dwp_reader_->ReadDebugSectionsForCU(dwo_id_, &sections);
if (!sections.empty()) {
found_in_dwp = true;
CompilationUnit dwp_comp_unit(dwp_path_, sections, 0,
dwp_byte_reader_.get(), handler_);
dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_,
ranges_base_, dwo_id_);
dwp_comp_unit.Start();
}
}
if (!found_in_dwp) { if (!found_in_dwp) {
// If no .dwp file, try to open the .dwo file. // If no .dwp file, try to open the .dwo file.
if (stat(dwo_name_, &statbuf) == 0) { if (stat(dwo_name_, &statbuf) == 0) {
ElfReader elf(dwo_name_); split_elf_reader_ = std::make_unique<ElfReader>(dwo_name_);
int width = GetElfWidth(elf); int width = GetElfWidth(*split_elf_reader_.get());
if (width != 0) { if (width != 0) {
ByteReader reader(ENDIANNESS_LITTLE); split_byte_reader = ByteReader(ENDIANNESS_LITTLE);
reader.SetAddressSize(width); split_byte_reader.SetAddressSize(width);
SectionMap sections; ReadDebugSectionsFromDwo(split_elf_reader_.get(), &sections);
ReadDebugSectionsFromDwo(&elf, &sections); if (!sections.empty()) {
CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, split_file = dwo_name_;
handler_); }
dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_,
addr_base_, ranges_base_, dwo_id_);
dwo_comp_unit.Start();
} }
} }
} }
return !split_file.empty();
} }
void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader,
@ -1084,10 +1098,6 @@ DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader)
abbrev_size_(0), info_data_(NULL), info_size_(0), abbrev_size_(0), info_data_(NULL), info_size_(0),
str_offsets_data_(NULL), str_offsets_size_(0) {} str_offsets_data_(NULL), str_offsets_size_(0) {}
DwpReader::~DwpReader() {
if (elf_reader_) delete elf_reader_;
}
void DwpReader::Initialize() { void DwpReader::Initialize() {
cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index",
&cu_index_size_); &cu_index_size_);
@ -1127,6 +1137,8 @@ void DwpReader::Initialize() {
info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_);
str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo",
&str_offsets_size_); &str_offsets_size_);
rnglist_data_ =
elf_reader_->GetSectionByName(".debug_rnglists.dwo", &rnglist_size_);
if (size_table_ >= cu_index_ + cu_index_size_) { if (size_table_ >= cu_index_ + cu_index_size_) {
version_ = 0; version_ = 0;
} }
@ -1227,13 +1239,24 @@ void DwpReader::ReadDebugSectionsForCU(uint64_t dwo_id,
} else if (section_id == DW_SECT_INFO) { } else if (section_id == DW_SECT_INFO) {
sections->insert(std::make_pair( sections->insert(std::make_pair(
".debug_info", ".debug_info",
std::make_pair(reinterpret_cast<const uint8_t*> (info_data_) std::make_pair(reinterpret_cast<const uint8_t*>(info_data_), 0)));
+ offset, size))); // .debug_info_offset will points the buffer for the CU with given
// dwo_id.
sections->insert(std::make_pair(
".debug_info_offset",
std::make_pair(
reinterpret_cast<const uint8_t*>(info_data_) + offset, size)));
} else if (section_id == DW_SECT_STR_OFFSETS) { } else if (section_id == DW_SECT_STR_OFFSETS) {
sections->insert(std::make_pair( sections->insert(std::make_pair(
".debug_str_offsets", ".debug_str_offsets",
std::make_pair(reinterpret_cast<const uint8_t*> (str_offsets_data_) std::make_pair(reinterpret_cast<const uint8_t*> (str_offsets_data_)
+ offset, size))); + offset, size)));
} else if (section_id == DW_SECT_RNGLISTS) {
sections->insert(std::make_pair(
".debug_rnglists",
std::make_pair(
reinterpret_cast<const uint8_t*>(rnglist_data_) + offset,
size)));
} }
} }
sections->insert(std::make_pair( sections->insert(std::make_pair(
@ -1819,6 +1842,11 @@ bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) {
return ReadDebugRngList(data); return ReadDebugRngList(data);
} }
} else if (form == DW_FORM_rnglistx) { } else if (form == DW_FORM_rnglistx) {
if (cu_info_->ranges_base_ == 0) {
// In split dwarf, there's no DW_AT_rnglists_base attribute, range_base
// will just be the first byte after the header.
cu_info_->ranges_base_ = reader_->OffsetSize() == 4? 12: 20;
}
offset_array_ = cu_info_->ranges_base_; offset_array_ = cu_info_->ranges_base_;
uint64_t index_offset = reader_->OffsetSize() * data; uint64_t index_offset = reader_->OffsetSize() * data;
uint64_t range_list_offset = uint64_t range_list_offset =

@ -469,8 +469,7 @@ class CompilationUnit {
// compilation unit. We also inherit the Dwarf2Handler from // compilation unit. We also inherit the Dwarf2Handler from
// the executable file, and call it as if we were still // the executable file, and call it as if we were still
// processing the original compilation unit. // processing the original compilation unit.
void SetSplitDwarf(const uint8_t* addr_buffer, uint64_t addr_buffer_length, void SetSplitDwarf(uint64_t addr_base, uint64_t dwo_id);
uint64_t addr_base, uint64_t ranges_base, uint64_t dwo_id);
// Begin reading a Dwarf2 compilation unit, and calling the // Begin reading a Dwarf2 compilation unit, and calling the
// callbacks in the Dwarf2Handler // callbacks in the Dwarf2Handler
@ -481,6 +480,36 @@ class CompilationUnit {
// start of the next compilation unit, if there is one. // start of the next compilation unit, if there is one.
uint64_t Start(); uint64_t Start();
// Process the actual debug information in a split DWARF file.
bool ProcessSplitDwarf(std::string& split_file,
SectionMap& sections,
ByteReader& split_byte_reader,
uint64_t& cu_offset);
const uint8_t* GetAddrBuffer() { return addr_buffer_; }
uint64_t GetAddrBufferLen() { return addr_buffer_length_; }
uint64_t GetAddrBase() { return addr_base_; }
uint64_t GetLowPC() { return low_pc_; }
uint64_t GetDWOID() { return dwo_id_; }
const uint8_t* GetLineBuffer() { return line_buffer_; }
uint64_t GetLineBufferLen() { return line_buffer_length_; }
const uint8_t* GetLineStrBuffer() { return line_string_buffer_; }
uint64_t GetLineStrBufferLen() { return line_string_buffer_length_; }
bool HasSourceLineInfo() { return has_source_line_info_; }
uint64_t GetSourceLineOffset() { return source_line_offset_; }
bool ShouldProcessSplitDwarf() { return should_process_split_dwarf_; }
private: private:
// This struct represents a single DWARF2/3 abbreviation // This struct represents a single DWARF2/3 abbreviation
@ -565,14 +594,12 @@ class CompilationUnit {
else if (attr == DW_AT_str_offsets_base) { else if (attr == DW_AT_str_offsets_base) {
str_offsets_base_ = data; str_offsets_base_ = data;
} }
else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) { else if (attr == DW_AT_low_pc) {
ranges_base_ = data; low_pc_ = data;
} }
// TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, else if (attr == DW_AT_stmt_list) {
// that base will apply to DW_AT_ranges attributes in the has_source_line_info_ = true;
// skeleton CU as well as in the .dwo/.dwp files. source_line_offset_ = data;
else if (attr == DW_AT_ranges && is_split_dwarf_) {
data += ranges_base_;
} }
handler_->ProcessAttributeUnsigned(offset, attr, form, data); handler_->ProcessAttributeUnsigned(offset, attr, form, data);
} }
@ -647,9 +674,6 @@ class CompilationUnit {
// new place to position the stream to. // new place to position the stream to.
const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form); const uint8_t* SkipAttribute(const uint8_t* start, enum DwarfForm form);
// Process the actual debug information in a split DWARF file.
void ProcessSplitDwarf();
// Read the debug sections from a .dwo file. // Read the debug sections from a .dwo file.
void ReadDebugSectionsFromDwo(ElfReader* elf_reader, void ReadDebugSectionsFromDwo(ElfReader* elf_reader,
SectionMap* sections); SectionMap* sections);
@ -658,7 +682,7 @@ class CompilationUnit {
const string path_; const string path_;
// Offset from section start is the offset of this compilation unit // Offset from section start is the offset of this compilation unit
// from the beginning of the .debug_info section. // from the beginning of the .debug_info/.debug_info.dwo section.
uint64_t offset_from_section_start_; uint64_t offset_from_section_start_;
// buffer is the buffer for our CU, starting at .debug_info + offset // buffer is the buffer for our CU, starting at .debug_info + offset
@ -688,7 +712,7 @@ class CompilationUnit {
const uint8_t* string_buffer_; const uint8_t* string_buffer_;
uint64_t string_buffer_length_; uint64_t string_buffer_length_;
// Similarly for .debug_line_string. // Similarly for .debug_line_str.
const uint8_t* line_string_buffer_; const uint8_t* line_string_buffer_;
uint64_t line_string_buffer_length_; uint64_t line_string_buffer_length_;
@ -702,6 +726,10 @@ class CompilationUnit {
const uint8_t* addr_buffer_; const uint8_t* addr_buffer_;
uint64_t addr_buffer_length_; uint64_t addr_buffer_length_;
// .debug_line section buffer and length.
const uint8_t* line_buffer_;
uint64_t line_buffer_length_;
// Flag indicating whether this compilation unit is part of a .dwo // Flag indicating whether this compilation unit is part of a .dwo
// or .dwp file. If true, we are reading this unit because a // or .dwp file. If true, we are reading this unit because a
// skeleton compilation unit in an executable file had a // skeleton compilation unit in an executable file had a
@ -730,10 +758,6 @@ class CompilationUnit {
// from the skeleton CU. // from the skeleton CU.
uint64_t skeleton_dwo_id_; uint64_t skeleton_dwo_id_;
// The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute,
// if any.
uint64_t ranges_base_;
// The value of the DW_AT_GNU_addr_base attribute, if any. // The value of the DW_AT_GNU_addr_base attribute, if any.
uint64_t addr_base_; uint64_t addr_base_;
@ -743,14 +767,20 @@ class CompilationUnit {
// True if we have already looked for a .dwp file. // True if we have already looked for a .dwp file.
bool have_checked_for_dwp_; bool have_checked_for_dwp_;
// Path to the .dwp file. // ElfReader for the dwo/dwo file.
string dwp_path_; std::unique_ptr<ElfReader> split_elf_reader_;
// ByteReader for the DWP file.
std::unique_ptr<ByteReader> dwp_byte_reader_;
// DWP reader. // DWP reader.
std::unique_ptr<DwpReader> dwp_reader_; std::unique_ptr<DwpReader> dwp_reader_;
bool should_process_split_dwarf_;
// The value of the DW_AT_low_pc attribute, if any.
uint64_t low_pc_;
// The value of DW_AT_stmt_list attribute if any.
bool has_source_line_info_;
uint64_t source_line_offset_;
}; };
// A Reader for a .dwp file. Supports the fetching of DWARF debug // A Reader for a .dwp file. Supports the fetching of DWARF debug
@ -770,8 +800,6 @@ class DwpReader {
public: public:
DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader);
~DwpReader();
// Read the CU index and initialize data members. // Read the CU index and initialize data members.
void Initialize(); void Initialize();
@ -839,6 +867,8 @@ class DwpReader {
size_t info_size_; size_t info_size_;
const char* str_offsets_data_; const char* str_offsets_data_;
size_t str_offsets_size_; size_t str_offsets_size_;
const char* rnglist_data_;
size_t rnglist_size_;
}; };
// This class is a reader for DWARF's Call Frame Information. CFI // This class is a reader for DWARF's Call Frame Information. CFI

@ -30,6 +30,10 @@
// dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo // dwarf2reader_cfi_unittest.cc: Unit tests for google_breakpad::CallFrameInfo
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>

@ -30,6 +30,10 @@
// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit // dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -329,7 +333,8 @@ struct DwarfFormsFixture: public DIEFixture {
uint64_t offset=0) { uint64_t offset=0) {
ByteReader byte_reader(params.endianness == kLittleEndian ? ByteReader byte_reader(params.endianness == kLittleEndian ?
ENDIANNESS_LITTLE : ENDIANNESS_BIG); ENDIANNESS_LITTLE : ENDIANNESS_BIG);
CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler); CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader,
&handler);
EXPECT_EQ(offset + parser.Start(), info_contents.size()); EXPECT_EQ(offset + parser.Start(), info_contents.size());
} }

@ -30,6 +30,10 @@
// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo // dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>

@ -32,6 +32,10 @@
// information generated when with splitting optimizations such as // information generated when with splitting optimizations such as
// -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc). // -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc).
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>

@ -30,6 +30,10 @@
#define _GNU_SOURCE // needed for pread() #define _GNU_SOURCE // needed for pread()
#endif #endif
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <string.h> #include <string.h>

@ -29,6 +29,10 @@
// This is a client for the dwarf2reader to extract function and line // This is a client for the dwarf2reader to extract function and line
// information from the debug info. // information from the debug info.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <assert.h> #include <assert.h>
#include <limits.h> #include <limits.h>
#include <stdio.h> #include <stdio.h>

@ -33,6 +33,10 @@
// Implementation of google_breakpad::DwarfCFIToModule. // Implementation of google_breakpad::DwarfCFIToModule.
// See dwarf_cfi_to_module.h for details. // See dwarf_cfi_to_module.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
@ -143,6 +147,29 @@ vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
} }
vector<string> DwarfCFIToModule::RegisterNames::RISCV() {
static const char *const names[] = {
"pc", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "",
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
};
return MakeVector(names, sizeof(names) / sizeof(names[0]));
}
bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length, bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length,
uint8_t version, const string& augmentation, uint8_t version, const string& augmentation,
unsigned return_address) { unsigned return_address) {

@ -114,6 +114,9 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
// MIPS. // MIPS.
static vector<string> MIPS(); static vector<string> MIPS();
// RISC-V.
static vector<string> RISCV();
private: private:
// Given STRINGS, an array of C strings with SIZE elements, return an // Given STRINGS, an array of C strings with SIZE elements, return an
// equivalent vector<string>. // equivalent vector<string>.

@ -30,6 +30,10 @@
// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. // dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <string> #include <string>
#include <vector> #include <vector>
@ -303,3 +307,15 @@ TEST(RegisterNames, X86_64) {
EXPECT_EQ("$rsp", names[7]); EXPECT_EQ("$rsp", names[7]);
EXPECT_EQ("$rip", names[16]); EXPECT_EQ("$rip", names[16]);
} }
TEST(RegisterNames, RISCV) {
vector<string> names = DwarfCFIToModule::RegisterNames::RISCV();
EXPECT_EQ("pc", names[0]);
EXPECT_EQ("t6", names[31]);
EXPECT_EQ("f0", names[32]);
EXPECT_EQ("f31", names[63]);
EXPECT_EQ("v0", names[96]);
EXPECT_EQ("v31", names[127]);
}

@ -35,6 +35,10 @@
#define __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS
#endif /* __STDC_FORMAT_MACROS */ #endif /* __STDC_FORMAT_MACROS */
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/dwarf_cu_to_module.h" #include "common/dwarf_cu_to_module.h"
#include <assert.h> #include <assert.h>
@ -165,19 +169,23 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference(
// parsing. This is for data shared across the CU's entire DIE tree, // parsing. This is for data shared across the CU's entire DIE tree,
// and parameters from the code invoking the CU parser. // and parameters from the code invoking the CU parser.
struct DwarfCUToModule::CUContext { struct DwarfCUToModule::CUContext {
CUContext(FileContext* file_context_arg, WarningReporter* reporter_arg, CUContext(FileContext* file_context_arg,
RangesHandler* ranges_handler_arg) WarningReporter* reporter_arg,
RangesHandler* ranges_handler_arg,
uint64_t low_pc,
uint64_t addr_base)
: version(0), : version(0),
file_context(file_context_arg), file_context(file_context_arg),
reporter(reporter_arg), reporter(reporter_arg),
ranges_handler(ranges_handler_arg), ranges_handler(ranges_handler_arg),
language(Language::CPlusPlus), language(Language::CPlusPlus),
low_pc(0), low_pc(low_pc),
high_pc(0), high_pc(0),
ranges_form(DW_FORM_sec_offset), ranges_form(DW_FORM_sec_offset),
ranges_data(0), ranges_data(0),
ranges_base(0), ranges_base(0),
str_offsets_base(0) { } addr_base(addr_base),
str_offsets_base(0) {}
~CUContext() { ~CUContext() {
for (vector<Module::Function*>::iterator it = functions.begin(); for (vector<Module::Function*>::iterator it = functions.begin();
@ -326,7 +334,10 @@ class DwarfCUToModule::GenericDIEHandler: public DIEHandler {
// Use this from EndAttributes member functions, not ProcessAttribute* // Use this from EndAttributes member functions, not ProcessAttribute*
// functions; only the former can be sure that all the DIE's attributes // functions; only the former can be sure that all the DIE's attributes
// have been seen. // have been seen.
StringView ComputeQualifiedName(); //
// On return, if has_qualified_name is non-NULL, *has_qualified_name is set to
// true if the DIE includes a fully-qualified name, false otherwise.
StringView ComputeQualifiedName(bool* has_qualified_name);
CUContext* cu_context_; CUContext* cu_context_;
DIEContext* parent_context_; DIEContext* parent_context_;
@ -462,7 +473,8 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
} }
} }
StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName(
bool* has_qualified_name) {
// Use the demangled name, if one is available. Demangled names are // Use the demangled name, if one is available. Demangled names are
// preferable to those inferred from the DWARF structure because they // preferable to those inferred from the DWARF structure because they
// include argument types. // include argument types.
@ -478,6 +490,15 @@ StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
StringView* unqualified_name = nullptr; StringView* unqualified_name = nullptr;
StringView* enclosing_name = nullptr; StringView* enclosing_name = nullptr;
if (!qualified_name) { if (!qualified_name) {
if (has_qualified_name) {
// dSYMs built with -gmlt do not include the DW_AT_linkage_name
// with the unmangled symbol, but rather include it in the
// LC_SYMTAB STABS, which end up in the externs of the module.
//
// Remember this so the Module can copy over the extern name later.
*has_qualified_name = false;
}
// Find the unqualified name. If the DIE has its own DW_AT_name // Find the unqualified name. If the DIE has its own DW_AT_name
// attribute, then use that; otherwise, check the specification. // attribute, then use that; otherwise, check the specification.
if (!name_attribute_.empty()) { if (!name_attribute_.empty()) {
@ -496,6 +517,10 @@ StringView DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
} else if (parent_context_) { } else if (parent_context_) {
enclosing_name = &parent_context_->name; enclosing_name = &parent_context_->name;
} }
} else {
if (has_qualified_name) {
*has_qualified_name = true;
}
} }
// Prepare the return value before upcoming mutations possibly invalidate the // Prepare the return value before upcoming mutations possibly invalidate the
@ -554,6 +579,7 @@ class DwarfCUToModule::InlineHandler : public GenericDIEHandler {
ranges_data_(0), ranges_data_(0),
call_site_line_(0), call_site_line_(0),
inline_nest_level_(inline_nest_level), inline_nest_level_(inline_nest_level),
has_range_data_(false),
inlines_(inlines) {} inlines_(inlines) {}
void ProcessAttributeUnsigned(enum DwarfAttribute attr, void ProcessAttributeUnsigned(enum DwarfAttribute attr,
@ -575,6 +601,7 @@ class DwarfCUToModule::InlineHandler : public GenericDIEHandler {
int call_site_line_; // DW_AT_call_line int call_site_line_; // DW_AT_call_line
int call_site_file_id_; // DW_AT_call_file int call_site_file_id_; // DW_AT_call_file
int inline_nest_level_; int inline_nest_level_;
bool has_range_data_;
// A vector of inlines in the same nest level. It's owned by its parent // A vector of inlines in the same nest level. It's owned by its parent
// function/inline. At Finish(), add this inline into the vector. // function/inline. At Finish(), add this inline into the vector.
vector<unique_ptr<Module::Inline>>& inlines_; vector<unique_ptr<Module::Inline>>& inlines_;
@ -595,6 +622,7 @@ void DwarfCUToModule::InlineHandler::ProcessAttributeUnsigned(
high_pc_ = data; high_pc_ = data;
break; break;
case DW_AT_ranges: case DW_AT_ranges:
has_range_data_ = true;
ranges_data_ = data; ranges_data_ = data;
ranges_form_ = form; ranges_form_ = form;
break; break;
@ -638,7 +666,7 @@ bool DwarfCUToModule::InlineHandler::EndAttributes() {
void DwarfCUToModule::InlineHandler::Finish() { void DwarfCUToModule::InlineHandler::Finish() {
vector<Module::Range> ranges; vector<Module::Range> ranges;
if (low_pc_ && high_pc_) { if (!has_range_data_) {
if (high_pc_form_ != DW_FORM_addr && if (high_pc_form_ != DW_FORM_addr &&
high_pc_form_ != DW_FORM_GNU_addr_index && high_pc_form_ != DW_FORM_GNU_addr_index &&
high_pc_form_ != DW_FORM_addrx && high_pc_form_ != DW_FORM_addrx &&
@ -675,11 +703,12 @@ void DwarfCUToModule::InlineHandler::Finish() {
// Every DW_TAG_inlined_subroutine should have a DW_AT_abstract_origin. // Every DW_TAG_inlined_subroutine should have a DW_AT_abstract_origin.
assert(specification_offset_ != 0); assert(specification_offset_ != 0);
cu_context_->file_context->module_->inline_origin_map.SetReference( Module::InlineOriginMap& inline_origin_map =
specification_offset_, specification_offset_); cu_context_->file_context->module_
->inline_origin_maps[cu_context_->file_context->filename_];
inline_origin_map.SetReference(specification_offset_, specification_offset_);
Module::InlineOrigin* origin = Module::InlineOrigin* origin =
cu_context_->file_context->module_->inline_origin_map inline_origin_map.GetOrCreateInlineOrigin(specification_offset_, name_);
.GetOrCreateInlineOrigin(specification_offset_, name_);
unique_ptr<Module::Inline> in( unique_ptr<Module::Inline> in(
new Module::Inline(origin, ranges, call_site_line_, call_site_file_id_, new Module::Inline(origin, ranges, call_site_line_, call_site_file_id_,
inline_nest_level_, std::move(child_inlines_))); inline_nest_level_, std::move(child_inlines_)));
@ -718,7 +747,9 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
ranges_form_(DW_FORM_sec_offset), ranges_form_(DW_FORM_sec_offset),
ranges_data_(0), ranges_data_(0),
inline_(false), inline_(false),
handle_inline_(handle_inline) {} handle_inline_(handle_inline),
has_qualified_name_(false),
has_range_data_(false) {}
void ProcessAttributeUnsigned(enum DwarfAttribute attr, void ProcessAttributeUnsigned(enum DwarfAttribute attr,
enum DwarfForm form, enum DwarfForm form,
@ -741,6 +772,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
bool inline_; bool inline_;
vector<unique_ptr<Module::Inline>> child_inlines_; vector<unique_ptr<Module::Inline>> child_inlines_;
bool handle_inline_; bool handle_inline_;
bool has_qualified_name_;
bool has_range_data_;
DIEContext child_context_; // A context for our children. DIEContext child_context_; // A context for our children.
}; };
@ -760,6 +793,7 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
high_pc_ = data; high_pc_ = data;
break; break;
case DW_AT_ranges: case DW_AT_ranges:
has_range_data_ = true;
ranges_data_ = data; ranges_data_ = data;
ranges_form_ = form; ranges_form_ = form;
break; break;
@ -804,7 +838,7 @@ DIEHandler* DwarfCUToModule::FuncHandler::FindChildHandler(
bool DwarfCUToModule::FuncHandler::EndAttributes() { bool DwarfCUToModule::FuncHandler::EndAttributes() {
// Compute our name, and record a specification, if appropriate. // Compute our name, and record a specification, if appropriate.
name_ = ComputeQualifiedName(); name_ = ComputeQualifiedName(&has_qualified_name_);
if (name_.empty() && abstract_origin_) { if (name_.empty() && abstract_origin_) {
name_ = abstract_origin_->name; name_ = abstract_origin_->name;
} }
@ -830,7 +864,7 @@ void DwarfCUToModule::FuncHandler::Finish() {
iter->second->name = name_; iter->second->name = name_;
} }
if (!ranges_data_) { if (!has_range_data_) {
// Make high_pc_ an address, if it isn't already. // Make high_pc_ an address, if it isn't already.
if (high_pc_form_ != DW_FORM_addr && if (high_pc_form_ != DW_FORM_addr &&
high_pc_form_ != DW_FORM_GNU_addr_index && high_pc_form_ != DW_FORM_GNU_addr_index &&
@ -877,6 +911,9 @@ void DwarfCUToModule::FuncHandler::Finish() {
scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_)); scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_));
func->ranges = ranges; func->ranges = ranges;
func->parameter_size = 0; func->parameter_size = 0;
// If the name was unqualified, prefer the Extern name if there's a mismatch
// (the Extern name will be fully-qualified in that case).
func->prefer_extern_name = !has_qualified_name_;
if (func->address) { if (func->address) {
// If the function address is zero this is a sign that this function // If the function address is zero this is a sign that this function
// description is just empty debug data and should just be discarded. // description is just empty debug data and should just be discarded.
@ -903,15 +940,16 @@ void DwarfCUToModule::FuncHandler::Finish() {
StringView name = name_.empty() ? name_omitted : name_; StringView name = name_.empty() ? name_omitted : name_;
uint64_t offset = uint64_t offset =
specification_offset_ != 0 ? specification_offset_ : offset_; specification_offset_ != 0 ? specification_offset_ : offset_;
cu_context_->file_context->module_->inline_origin_map.SetReference(offset_, Module::InlineOriginMap& inline_origin_map =
offset); cu_context_->file_context->module_
cu_context_->file_context->module_->inline_origin_map ->inline_origin_maps[cu_context_->file_context->filename_];
.GetOrCreateInlineOrigin(offset_, name); inline_origin_map.SetReference(offset_, offset);
inline_origin_map.GetOrCreateInlineOrigin(offset_, name);
} }
} }
bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
child_context_.name = ComputeQualifiedName(); child_context_.name = ComputeQualifiedName(NULL);
if (child_context_.name.empty() && no_specification) { if (child_context_.name.empty() && no_specification) {
cu_context_->reporter->UnknownSpecification(offset_, specification_offset_); cu_context_->reporter->UnknownSpecification(offset_, specification_offset_);
} }
@ -1041,12 +1079,21 @@ DwarfCUToModule::DwarfCUToModule(FileContext* file_context,
LineToModuleHandler* line_reader, LineToModuleHandler* line_reader,
RangesHandler* ranges_handler, RangesHandler* ranges_handler,
WarningReporter* reporter, WarningReporter* reporter,
bool handle_inline) bool handle_inline,
uint64_t low_pc,
uint64_t addr_base,
bool has_source_line_info,
uint64_t source_line_offset)
: RootDIEHandler(handle_inline), : RootDIEHandler(handle_inline),
line_reader_(line_reader), line_reader_(line_reader),
cu_context_(new CUContext(file_context, reporter, ranges_handler)), cu_context_(new CUContext(file_context,
reporter,
ranges_handler,
low_pc,
addr_base)),
child_context_(new DIEContext()), child_context_(new DIEContext()),
has_source_line_info_(false) {} has_source_line_info_(has_source_line_info),
source_line_offset_(source_line_offset) {}
DwarfCUToModule::~DwarfCUToModule() { DwarfCUToModule::~DwarfCUToModule() {
} }

@ -264,7 +264,11 @@ class DwarfCUToModule: public RootDIEHandler {
LineToModuleHandler* line_reader, LineToModuleHandler* line_reader,
RangesHandler* ranges_handler, RangesHandler* ranges_handler,
WarningReporter* reporter, WarningReporter* reporter,
bool handle_inline = false); bool handle_inline = false,
uint64_t low_pc = 0,
uint64_t addr_base = 0,
bool has_source_line_info = false,
uint64_t source_line_offset = 0);
~DwarfCUToModule(); ~DwarfCUToModule();
void ProcessAttributeSigned(enum DwarfAttribute attr, void ProcessAttributeSigned(enum DwarfAttribute attr,

@ -30,6 +30,10 @@
// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. // dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
@ -263,6 +267,10 @@ class CUFixtureBase {
void TestFunction(int i, const string& name, void TestFunction(int i, const string& name,
Module::Address address, Module::Address size); Module::Address address, Module::Address size);
// Test that the I'th function (ordered by address) in the module
// this.module_ has the given prefer_extern_name.
void TestFunctionPreferExternName(int i, bool prefer_extern_name);
// Test that the number of source lines owned by the I'th function // Test that the number of source lines owned by the I'th function
// in the module this.module_ is equal to EXPECTED. // in the module this.module_ is equal to EXPECTED.
void TestLineCount(int i, size_t expected); void TestLineCount(int i, size_t expected);
@ -611,6 +619,15 @@ void CUFixtureBase::TestFunction(int i, const string& name,
EXPECT_EQ(0U, function->parameter_size); EXPECT_EQ(0U, function->parameter_size);
} }
void CUFixtureBase::TestFunctionPreferExternName(int i,
bool prefer_extern_name) {
FillFunctions();
ASSERT_LT((size_t)i, functions_.size());
Module::Function* function = functions_[i];
EXPECT_EQ(prefer_extern_name, function->prefer_extern_name);
}
void CUFixtureBase::TestLineCount(int i, size_t expected) { void CUFixtureBase::TestLineCount(int i, size_t expected) {
FillFunctions(); FillFunctions();
ASSERT_LT((size_t) i, functions_.size()); ASSERT_LT((size_t) i, functions_.size());

@ -31,6 +31,10 @@
// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. // dwarf_line_to_module.cc: Implementation of DwarfLineToModule class.
// See dwarf_line_to_module.h for details. // See dwarf_line_to_module.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>

@ -30,6 +30,10 @@
// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. // dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <vector> #include <vector>
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"

@ -32,6 +32,10 @@
// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class. // dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class.
// See dwarf_range_list_handler.h for details. // See dwarf_range_list_handler.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <algorithm> #include <algorithm>
#include "common/dwarf_range_list_handler.h" #include "common/dwarf_range_list_handler.h"

@ -31,6 +31,10 @@
// language.cc: Subclasses and singletons for google_breakpad::Language. // language.cc: Subclasses and singletons for google_breakpad::Language.
// See language.h for details. // See language.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/language.h" #include "common/language.h"
#include <stdlib.h> #include <stdlib.h>

@ -0,0 +1,645 @@
// Copyright 2012 Google LLC
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google LLC nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// A minimalistic implementation of getcontext() to be used by
// Google Breakpad when getcontext() is not available in libc.
#include "common/linux/ucontext_constants.h"
/* int getcontext (ucontext_t* ucp) */
#if defined(__arm__)
.text
.global breakpad_getcontext
.hidden breakpad_getcontext
.type breakpad_getcontext, #function
.align 0
.fnstart
breakpad_getcontext:
/* First, save r4-r11 */
add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4)
stm r1, {r4-r11}
/* r12 is a scratch register, don't save it */
/* Save sp and lr explicitly. */
/* - sp can't be stored with stmia in Thumb-2 */
/* - STM instructions that store sp and pc are deprecated in ARM */
str sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)]
str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)]
/* Save the caller's address in 'pc' */
str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)]
/* Save ucontext_t* pointer across next call */
mov r4, r0
/* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
mov r0, #0 /* SIG_BLOCK */
mov r1, #0 /* NULL */
add r2, r4, #UCONTEXT_SIGMASK_OFFSET
bl sigprocmask(PLT)
/* Intentionally do not save the FPU state here. This is because on
* Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or
* ptrace(PTRACE_GETVFPREGS) to get it.
*
* Note that a real implementation of getcontext() would need to save
* this here to allow setcontext()/swapcontext() to work correctly.
*/
/* Restore the values of r4 and lr */
mov r0, r4
ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)]
ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)]
/* Return 0 */
mov r0, #0
bx lr
.fnend
.size breakpad_getcontext, . - breakpad_getcontext
#elif defined(__aarch64__)
#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT
// ENABLE_PAUTH must be defined to 1 since this value will be used in
// bitwise-shift later!
#define ENABLE_PAUTH 1
#if ((__ARM_FEATURE_PAC_DEFAULT&((1<<0)|(1<<1)))==0)
#error Pointer authentication defines no valid key!
#endif
#else
#define ENABLE_PAUTH 0
#endif
#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT==1)
// ENABLE_BTI must be defined to 1 since this value will be used in
// bitwise-shift later!
#define ENABLE_BTI 1
#else
#define ENABLE_BTI 0
#endif
// Although Pointer Authentication and Branch Target Instructions are technically
// seperate features they work together, i.e. the paciasp and pacibsp instructions
// serve as BTI landing pads.
// Therefore PA-instructions are enabled when PA _or_ BTI is enabled!
#if ENABLE_PAUTH || ENABLE_BTI
// See section "Pointer Authentication" of
// https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros
// for details how to interpret __ARM_FEATURE_PAC_DEFAULT
#if (__ARM_FEATURE_PAC_DEFAULT & (1<<0))
#define PAUTH_SIGN_SP paciasp
#define PAUTH_AUTH_SP autiasp
#else
#define PAUTH_SIGN_SP pacibsp
#define PAUTH_AUTH_SP autibsp
#endif
#else
#define PAUTH_SIGN_SP
#define PAUTH_AUTH_SP
#endif
#define _NSIG 64
#define __NR_rt_sigprocmask 135
.text
.global breakpad_getcontext
.hidden breakpad_getcontext
.type breakpad_getcontext, #function
.align 4
.cfi_startproc
breakpad_getcontext:
PAUTH_SIGN_SP
/* The saved context will return to the getcontext() call point
with a return value of 0 */
str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE]
stp x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE]
stp x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE]
stp x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE]
stp x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE]
stp x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE]
stp x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE]
str x30, [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE]
/* Place LR into the saved PC, this will ensure that when
switching to this saved context with setcontext() control
will pass back to the caller of getcontext(), we have
already arranged to return the appropriate return value in x0
above. */
str x30, [x0, MCONTEXT_PC_OFFSET]
/* Save the current SP */
mov x2, sp
str x2, [x0, MCONTEXT_SP_OFFSET]
/* Initialize the pstate. */
str xzr, [x0, MCONTEXT_PSTATE_OFFSET]
/* Figure out where to place the first context extension
block. */
add x2, x0, #MCONTEXT_EXTENSION_OFFSET
/* Write the context extension fpsimd header. */
mov w3, #(FPSIMD_MAGIC & 0xffff)
movk w3, #(FPSIMD_MAGIC >> 16), lsl #16
str w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET]
mov w3, #FPSIMD_CONTEXT_SIZE
str w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET]
/* Fill in the FP SIMD context. */
add x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE)
stp d8, d9, [x3], #(2 * SIMD_REGISTER_SIZE)
stp d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE)
stp d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE)
stp d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE)
add x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET
mrs x4, fpsr
str w4, [x3]
mrs x4, fpcr
str w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET]
/* Write the termination context extension header. */
add x2, x2, #FPSIMD_CONTEXT_SIZE
str xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET]
str xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET]
/* Grab the signal mask */
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
add x2, x0, #UCONTEXT_SIGMASK_OFFSET
mov x0, #0 /* SIG_BLOCK */
mov x1, #0 /* NULL */
mov x3, #(_NSIG / 8)
mov x8, #__NR_rt_sigprocmask
svc 0
/* Return x0 for success */
mov x0, 0
PAUTH_AUTH_SP
ret
.cfi_endproc
.size breakpad_getcontext, . - breakpad_getcontext
#elif defined(__i386__)
.text
.global breakpad_getcontext
.hidden breakpad_getcontext
.align 4
.type breakpad_getcontext, @function
breakpad_getcontext:
movl 4(%esp), %eax /* eax = uc */
/* Save register values */
movl %ecx, MCONTEXT_ECX_OFFSET(%eax)
movl %edx, MCONTEXT_EDX_OFFSET(%eax)
movl %ebx, MCONTEXT_EBX_OFFSET(%eax)
movl %edi, MCONTEXT_EDI_OFFSET(%eax)
movl %esi, MCONTEXT_ESI_OFFSET(%eax)
movl %ebp, MCONTEXT_EBP_OFFSET(%eax)
movl (%esp), %edx /* return address */
lea 4(%esp), %ecx /* exclude return address from stack */
mov %edx, MCONTEXT_EIP_OFFSET(%eax)
mov %ecx, MCONTEXT_ESP_OFFSET(%eax)
xorl %ecx, %ecx
movw %fs, %cx
mov %ecx, MCONTEXT_FS_OFFSET(%eax)
movl $0, MCONTEXT_EAX_OFFSET(%eax)
/* Save floating point state to fpregstate, then update
* the fpregs pointer to point to it */
leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx
fnstenv (%ecx)
fldenv (%ecx)
mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax)
/* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */
leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx
xorl %ecx, %ecx
push %edx /* &uc->uc_sigmask */
push %ecx /* NULL */
push %ecx /* SIGBLOCK == 0 on i386 */
call sigprocmask@PLT
addl $12, %esp
movl $0, %eax
ret
.size breakpad_getcontext, . - breakpad_getcontext
#elif defined(__mips__)
// This implementation is inspired by implementation of getcontext in glibc.
#include <asm-mips/asm.h>
#include <asm-mips/regdef.h>
#if _MIPS_SIM == _ABIO32
#include <asm-mips/fpregdef.h>
#endif
// from asm-mips/asm.h
#if _MIPS_SIM == _ABIO32
#define ALSZ 7
#define ALMASK ~7
#define SZREG 4
#else // _MIPS_SIM != _ABIO32
#define ALSZ 15
#define ALMASK ~15
#define SZREG 8
#endif
#include <asm/unistd.h> // for __NR_rt_sigprocmask
#define _NSIG8 128 / 8
#define SIG_BLOCK 1
.text
LOCALS_NUM = 1 // save gp on stack
FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK
GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
MCONTEXT_REG_SIZE = 8
#if _MIPS_SIM == _ABIO32
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
.mask 0x00000000, 0
.fmask 0x00000000, 0
.set noreorder
.cpload t9
.set reorder
move a2, sp
#define _SP a2
addiu sp, -FRAME_SIZE
.cprestore GP_FRAME_OFFSET
sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sw ra, MCONTEXT_PC_OFFSET(a0)
#ifdef __mips_hard_float
s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
cfc1 v1, fcr31
sw v1, MCONTEXT_FPC_CSR(a0)
#endif // __mips_hard_float
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
li a3, _NSIG8
addu a2, a0, UCONTEXT_SIGMASK_OFFSET
move a1, zero
li a0, SIG_BLOCK
li v0, __NR_rt_sigprocmask
syscall
addiu sp, FRAME_SIZE
jr ra
END (breakpad_getcontext)
#else
#ifndef NESTED
/*
* NESTED - declare nested routine entry point
*/
#define NESTED(symbol, framesize, rpc) \
.globl symbol; \
.align 2; \
.type symbol,@function; \
.ent symbol,0; \
symbol: .frame sp, framesize, rpc;
#endif
/*
* END - mark end of function
*/
#ifndef END
# define END(function) \
.end function; \
.size function,.-function
#endif
/* int getcontext (ucontext_t* ucp) */
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
.mask 0x10000000, 0
.fmask 0x00000000, 0
move a2, sp
#define _SP a2
move a3, gp
#define _GP a3
daddiu sp, -FRAME_SIZE
.cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext
/* Store a magic flag. */
li v1, 1
sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */
sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
sd ra, MCONTEXT_PC_OFFSET(a0)
#ifdef __mips_hard_float
s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
cfc1 v1, $31
sw v1, MCONTEXT_FPC_CSR(a0)
#endif /* __mips_hard_float */
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
li a3, _NSIG8
daddu a2, a0, UCONTEXT_SIGMASK_OFFSET
move a1, zero
li a0, SIG_BLOCK
li v0, __NR_rt_sigprocmask
syscall
.cpreturn
daddiu sp, FRAME_SIZE
move v0, zero
jr ra
END (breakpad_getcontext)
#endif // _MIPS_SIM == _ABIO32
#elif defined(__x86_64__)
/* The x64 implementation of breakpad_getcontext was derived in part
from the implementation of libunwind which requires the following
notice. */
/* 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>
This file is part of libunwind.
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. */
.text
.global breakpad_getcontext
.hidden breakpad_getcontext
.align 4
.type breakpad_getcontext, @function
breakpad_getcontext:
.cfi_startproc
/* Callee saved: RBX, RBP, R12-R15 */
movq %r12, MCONTEXT_GREGS_R12(%rdi)
movq %r13, MCONTEXT_GREGS_R13(%rdi)
movq %r14, MCONTEXT_GREGS_R14(%rdi)
movq %r15, MCONTEXT_GREGS_R15(%rdi)
movq %rbp, MCONTEXT_GREGS_RBP(%rdi)
movq %rbx, MCONTEXT_GREGS_RBX(%rdi)
/* Save argument registers (not strictly needed, but setcontext
restores them, so don't restore garbage). */
movq %r8, MCONTEXT_GREGS_R8(%rdi)
movq %r9, MCONTEXT_GREGS_R9(%rdi)
movq %rdi, MCONTEXT_GREGS_RDI(%rdi)
movq %rsi, MCONTEXT_GREGS_RSI(%rdi)
movq %rdx, MCONTEXT_GREGS_RDX(%rdi)
movq %rax, MCONTEXT_GREGS_RAX(%rdi)
movq %rcx, MCONTEXT_GREGS_RCX(%rdi)
/* Save fp state (not needed, except for setcontext not
restoring garbage). */
leaq MCONTEXT_FPREGS_MEM(%rdi),%r8
movq %r8, MCONTEXT_FPREGS_PTR(%rdi)
fnstenv (%r8)
stmxcsr FPREGS_OFFSET_MXCSR(%r8)
leaq 8(%rsp), %rax /* exclude this call. */
movq %rax, MCONTEXT_GREGS_RSP(%rdi)
movq 0(%rsp), %rax
movq %rax, MCONTEXT_GREGS_RIP(%rdi)
/* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */
leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3
xorq %rsi, %rsi // arg2 NULL
xorq %rdi, %rdi // arg1 SIGBLOCK == 0
call sigprocmask@PLT
/* Always return 0 for success, even if sigprocmask failed. */
xorl %eax, %eax
ret
.cfi_endproc
.size breakpad_getcontext, . - breakpad_getcontext
#elif defined(__riscv)
# define SIG_BLOCK 0
# define _NSIG8 8
# define __NR_rt_sigprocmask 135
.text
.globl breakpad_getcontext
.type breakpad_getcontext, @function
.align 0
.cfi_startproc
breakpad_getcontext:
REG_S ra, MCONTEXT_GREGS_PC(a0)
REG_S ra, MCONTEXT_GREGS_RA(a0)
REG_S sp, MCONTEXT_GREGS_SP(a0)
REG_S gp, MCONTEXT_GREGS_SP(a0)
REG_S tp, MCONTEXT_GREGS_TP(a0)
REG_S t0, MCONTEXT_GREGS_T0(a0)
REG_S t1, MCONTEXT_GREGS_T1(a0)
REG_S t2, MCONTEXT_GREGS_T2(a0)
REG_S s0, MCONTEXT_GREGS_S0(a0)
REG_S s1, MCONTEXT_GREGS_S1(a0)
REG_S a0, MCONTEXT_GREGS_A0(a0)
REG_S a1, MCONTEXT_GREGS_A1(a0)
REG_S a2, MCONTEXT_GREGS_A2(a0)
REG_S a3, MCONTEXT_GREGS_A3(a0)
REG_S a4, MCONTEXT_GREGS_A4(a0)
REG_S a5, MCONTEXT_GREGS_A5(a0)
REG_S a6, MCONTEXT_GREGS_A6(a0)
REG_S a7, MCONTEXT_GREGS_A7(a0)
REG_S s2, MCONTEXT_GREGS_S2(a0)
REG_S s3, MCONTEXT_GREGS_S3(a0)
REG_S s4, MCONTEXT_GREGS_S4(a0)
REG_S s5, MCONTEXT_GREGS_S5(a0)
REG_S s6, MCONTEXT_GREGS_S6(a0)
REG_S s7, MCONTEXT_GREGS_S7(a0)
REG_S s8, MCONTEXT_GREGS_S8(a0)
REG_S s9, MCONTEXT_GREGS_S9(a0)
REG_S s10, MCONTEXT_GREGS_S10(a0)
REG_S s11, MCONTEXT_GREGS_S11(a0)
REG_S t3, MCONTEXT_GREGS_T3(a0)
REG_S t4, MCONTEXT_GREGS_T4(a0)
REG_S t5, MCONTEXT_GREGS_T5(a0)
REG_S t6 , MCONTEXT_GREGS_T6(a0)
# ifndef __riscv_float_abi_soft
frsr a1
FREG_S ft0, MCONTEXT_FPREGS_FT0(a0)
FREG_S ft1, MCONTEXT_FPREGS_FT1(a0)
FREG_S ft2, MCONTEXT_FPREGS_FT2(a0)
FREG_S ft3, MCONTEXT_FPREGS_FT3(a0)
FREG_S ft4, MCONTEXT_FPREGS_FT4(a0)
FREG_S ft5, MCONTEXT_FPREGS_FT5(a0)
FREG_S ft6, MCONTEXT_FPREGS_FT6(a0)
FREG_S ft7, MCONTEXT_FPREGS_FT7(a0)
FREG_S fs0, MCONTEXT_FPREGS_FS0(a0)
FREG_S fs1, MCONTEXT_FPREGS_FS1(a0)
FREG_S fa0, MCONTEXT_FPREGS_FA0(a0)
FREG_S fa1, MCONTEXT_FPREGS_FA1(a0)
FREG_S fa2, MCONTEXT_FPREGS_FA2(a0)
FREG_S fa3, MCONTEXT_FPREGS_FA3(a0)
FREG_S fa4, MCONTEXT_FPREGS_FA4(a0)
FREG_S fa5, MCONTEXT_FPREGS_FA5(a0)
FREG_S fa6, MCONTEXT_FPREGS_FA6(a0)
FREG_S fa7, MCONTEXT_FPREGS_FA7(a0)
FREG_S fs2, MCONTEXT_FPREGS_FS2(a0)
FREG_S fs3, MCONTEXT_FPREGS_FS3(a0)
FREG_S fs4, MCONTEXT_FPREGS_FS4(a0)
FREG_S fs5, MCONTEXT_FPREGS_FS5(a0)
FREG_S fs6, MCONTEXT_FPREGS_FS6(a0)
FREG_S fs7, MCONTEXT_FPREGS_FS7(a0)
FREG_S fs8, MCONTEXT_FPREGS_FS8(a0)
FREG_S fs9, MCONTEXT_FPREGS_FS9(a0)
FREG_S fs10, MCONTEXT_FPREGS_FS10(a0)
FREG_S fs11, MCONTEXT_FPREGS_FS11(a0)
FREG_S ft8, MCONTEXT_FPREGS_FT8(a0)
FREG_S ft9, MCONTEXT_FPREGS_FT9(a0)
FREG_S ft10, MCONTEXT_FPREGS_FT10(a0)
FREG_S ft11, MCONTEXT_FPREGS_FT11(a0)
sw a1, MCONTEXT_FPC_CSR(a0)
# endif // __riscv_float_abi_soft
mv a1, zero
add a2, a0, UCONTEXT_SIGMASK_OFFSET
li a3, _NSIG8
mv a0, zero
li a7, __NR_rt_sigprocmask
ecall
mv a0, zero
ret
.cfi_endproc
.size breakpad_getcontext, . - breakpad_getcontext
#else
# error "This file has not been ported for your CPU!"
#endif
#if defined(__aarch64__)
// ENABLE_PAUTH and ENABLE_BTI would be enabled at the definition
// of AArch64 specific breakpad_getcontext function
#if ENABLE_PAUTH || ENABLE_BTI
// for further information on the .note.gnu.property section see
// https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#program-property
.pushsection .note.gnu.property, "a";
.balign 8
.long 4
.long 0x10
.long 0x5
.asciz "GNU"
.long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
.long 4
.long ((ENABLE_PAUTH)<<1) | ((ENABLE_BTI)<<0) /* PAuth and BTI */
.long 0
.popsection
#endif
#endif

@ -29,10 +29,6 @@
#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H #ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
#define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H #define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifndef HAVE_GETCONTEXT #ifndef HAVE_GETCONTEXT
#include <signal.h> #include <signal.h>

@ -29,6 +29,10 @@
// asm/sigcontext.h can't be included with signal.h on glibc or // asm/sigcontext.h can't be included with signal.h on glibc or
// musl, so only compare _libc_fpstate and _fpstate on Android. // musl, so only compare _libc_fpstate and _fpstate on Android.
#if defined(__ANDROID__) && defined(__x86_64__) #if defined(__ANDROID__) && defined(__x86_64__)
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <asm/sigcontext.h> #include <asm/sigcontext.h>
#endif #endif

@ -26,6 +26,10 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/linux/crc32.h" #include "common/linux/crc32.h"
namespace google_breakpad { namespace google_breakpad {

@ -31,6 +31,10 @@
// dump_symbols.cc: implement google_breakpad::WriteSymbolFile: // dump_symbols.cc: implement google_breakpad::WriteSymbolFile:
// Find all the debugging info in a file and dump it as a Breakpad symbol file. // Find all the debugging info in a file and dump it as a Breakpad symbol file.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/linux/dump_symbols.h" #include "common/linux/dump_symbols.h"
#include <assert.h> #include <assert.h>
@ -47,6 +51,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <zlib.h> #include <zlib.h>
#ifdef HAVE_LIBZSTD
#include <zstd.h>
#endif
#include <set> #include <set>
#include <string> #include <string>
@ -104,6 +111,11 @@ using google_breakpad::wasteful_vector;
#define EM_AARCH64 183 #define EM_AARCH64 183
#endif #endif
// Define ZStd compression if host machine does not include this define.
#ifndef ELFCOMPRESS_ZSTD
#define ELFCOMPRESS_ZSTD 2
#endif
// //
// FDWrapper // FDWrapper
// //
@ -301,7 +313,7 @@ uint32_t GetCompressionHeader(
return sizeof (*header); return sizeof (*header);
} }
std::pair<uint8_t *, uint64_t> UncompressSectionContents( std::pair<uint8_t *, uint64_t> UncompressZlibSectionContents(
const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) { const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) {
z_stream stream; z_stream stream;
memset(&stream, 0, sizeof stream); memset(&stream, 0, sizeof stream);
@ -330,6 +342,90 @@ std::pair<uint8_t *, uint64_t> UncompressSectionContents(
: std::make_pair(uncompressed_buffer.release(), uncompressed_size); : std::make_pair(uncompressed_buffer.release(), uncompressed_size);
} }
#ifdef HAVE_LIBZSTD
std::pair<uint8_t *, uint64_t> UncompressZstdSectionContents(
const uint8_t* compressed_buffer, uint64_t compressed_size,uint64_t uncompressed_size) {
google_breakpad::scoped_array<uint8_t> uncompressed_buffer(new uint8_t[uncompressed_size]);
size_t out_size = ZSTD_decompress(uncompressed_buffer.get(), uncompressed_size,
compressed_buffer, compressed_size);
if (ZSTD_isError(out_size)) {
return std::make_pair(nullptr, 0);
}
assert(out_size == uncompressed_size);
return std::make_pair(uncompressed_buffer.release(), uncompressed_size);
}
#endif
std::pair<uint8_t *, uint64_t> UncompressSectionContents(
uint64_t compression_type, const uint8_t* compressed_buffer,
uint64_t compressed_size, uint64_t uncompressed_size) {
if (compression_type == ELFCOMPRESS_ZLIB) {
return UncompressZlibSectionContents(compressed_buffer, compressed_size, uncompressed_size);
}
#ifdef HAVE_LIBZSTD
if (compression_type == ELFCOMPRESS_ZSTD) {
return UncompressZstdSectionContents(compressed_buffer, compressed_size, uncompressed_size);
}
#endif
return std::make_pair(nullptr, 0);
}
void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader,
Module* module,
google_breakpad::Endianness endianness,
bool handle_inter_cu_refs,
bool handle_inline) {
std::string split_file;
google_breakpad::SectionMap split_sections;
google_breakpad::ByteReader split_byte_reader(endianness);
uint64_t cu_offset = 0;
if (!reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader,
cu_offset))
return;
DwarfCUToModule::FileContext file_context(split_file, module,
handle_inter_cu_refs);
for (auto section : split_sections)
file_context.AddSectionToSectionMap(section.first, section.second.first,
section.second.second);
// Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str,
// its debug info will refer to .debug_addr/.debug_line in the main binary.
if (file_context.section_map().find(".debug_addr") ==
file_context.section_map().end())
file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(),
reader->GetAddrBufferLen());
if (file_context.section_map().find(".debug_line") ==
file_context.section_map().end())
file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(),
reader->GetLineBufferLen());
if (file_context.section_map().find(".debug_line_str") ==
file_context.section_map().end())
file_context.AddSectionToSectionMap(".debug_line_str",
reader->GetLineStrBuffer(),
reader->GetLineStrBufferLen());
DumperRangesHandler ranges_handler(&split_byte_reader);
DumperLineToModule line_to_module(&split_byte_reader);
DwarfCUToModule::WarningReporter reporter(split_file, cu_offset);
DwarfCUToModule root_handler(
&file_context, &line_to_module, &ranges_handler, &reporter, handle_inline,
reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(),
reader->GetSourceLineOffset());
google_breakpad::DIEDispatcher die_dispatcher(&root_handler);
google_breakpad::CompilationUnit split_reader(
split_file, file_context.section_map(), cu_offset, &split_byte_reader,
&die_dispatcher);
split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID());
split_reader.Start();
// Normally, it won't happen unless we have transitive reference.
if (split_reader.ShouldProcessSplitDwarf()) {
StartProcessSplitDwarf(&split_reader, module, endianness,
handle_inter_cu_refs, handle_inline);
}
}
template<typename ElfClass> template<typename ElfClass>
bool LoadDwarf(const string& dwarf_filename, bool LoadDwarf(const string& dwarf_filename,
const typename ElfClass::Ehdr* elf_header, const typename ElfClass::Ehdr* elf_header,
@ -380,7 +476,7 @@ bool LoadDwarf(const string& dwarf_filename,
size -= compression_header_size; size -= compression_header_size;
std::pair<uint8_t *, uint64_t> uncompressed = std::pair<uint8_t *, uint64_t> uncompressed =
UncompressSectionContents(contents, size, chdr.ch_size); UncompressSectionContents(chdr.ch_type, contents, size, chdr.ch_size);
if (uncompressed.first != nullptr && uncompressed.second != 0) { if (uncompressed.first != nullptr && uncompressed.second != 0) {
file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second); file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second);
@ -417,6 +513,11 @@ bool LoadDwarf(const string& dwarf_filename,
&die_dispatcher); &die_dispatcher);
// Process the entire compilation unit; get the offset of the next. // Process the entire compilation unit; get the offset of the next.
offset += reader.Start(); offset += reader.Start();
// Start to process split dwarf file.
if (reader.ShouldProcessSplitDwarf()) {
StartProcessSplitDwarf(&reader, module, endianness, handle_inter_cu_refs,
handle_inline);
}
} }
return true; return true;
} }
@ -445,6 +546,9 @@ bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header,
case EM_X86_64: case EM_X86_64:
*register_names = DwarfCFIToModule::RegisterNames::X86_64(); *register_names = DwarfCFIToModule::RegisterNames::X86_64();
return true; return true;
case EM_RISCV:
*register_names = DwarfCFIToModule::RegisterNames::RISCV();
return true;
default: default:
return false; return false;
} }
@ -522,7 +626,7 @@ bool LoadDwarfCFI(const string& dwarf_filename,
cfi_size -= compression_header_size; cfi_size -= compression_header_size;
std::pair<uint8_t *, uint64_t> uncompressed = std::pair<uint8_t *, uint64_t> uncompressed =
UncompressSectionContents(cfi, cfi_size, chdr.ch_size); UncompressSectionContents(chdr.ch_type, cfi, cfi_size, chdr.ch_size);
if (uncompressed.first == nullptr || uncompressed.second == 0) { if (uncompressed.first == nullptr || uncompressed.second == 0) {
fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str()); fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str());
@ -1018,6 +1122,7 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
case EM_SPARC: return "sparc"; case EM_SPARC: return "sparc";
case EM_SPARCV9: return "sparcv9"; case EM_SPARCV9: return "sparcv9";
case EM_X86_64: return "x86_64"; case EM_X86_64: return "x86_64";
case EM_RISCV: return "riscv";
default: return NULL; default: return NULL;
} }
} }

@ -31,6 +31,10 @@
// dump_symbols_unittest.cc: // dump_symbols_unittest.cc:
// Unittests for google_breakpad::DumpSymbols // Unittests for google_breakpad::DumpSymbols
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <elf.h> #include <elf.h>
#include <link.h> #include <link.h>
#include <stdio.h> #include <stdio.h>

@ -29,6 +29,10 @@
// elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. // elf_core_dump.cc: Implement google_breakpad::ElfCoreDump.
// See elf_core_dump.h for details. // See elf_core_dump.h for details.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/linux/elf_core_dump.h" #include "common/linux/elf_core_dump.h"
#include <stddef.h> #include <stddef.h>

@ -28,6 +28,10 @@
// elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. // elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump.
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include <sys/procfs.h> #include <sys/procfs.h>
#include <set> #include <set>

@ -30,6 +30,10 @@
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com> // Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
#ifdef HAVE_CONFIG_H
#include <config.h> // Must come first
#endif
#include "common/linux/elf_symbols_to_module.h" #include "common/linux/elf_symbols_to_module.h"
#include <cxxabi.h> #include <cxxabi.h>

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

Loading…
Cancel
Save