I had download Google breakpad source to do some testing, the demo can work normal on X64 and ARM64, but on MIPS64 it does not generate minidump file and child thread will crash after sys_clone under ExceptionHandler::GenerateDump(); I checked the input address of the child thread, found the address is reduced by 16 bytes, my kernel revision is :
[root@neo7 breakpad-master]# uname -r
3.10.0-514.26.2.ns7.030.mips64el
My test code is :
#include "../src/client/linux/handler/exception_handler.h"
#include <pthread.h>
#include <iostream>
using namespace std;
static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
void *context,
bool succeeded)
{
printf("Dump path: %s\n", descriptor.path());
char cmd[512] = {0};
snprintf(cmd, sizeof(cmd), "echo %s > dump_name", descriptor.path());
system(cmd);
return succeeded;
}
void *TestThread(void* arg)
{
int input = *(int*)arg;
int *a = (int *)(NULL);
*a = 1;
}
int main(int argc, char *argv[])
{
google_breakpad::MinidumpDescriptor descriptor("/tmp");
google_breakpad::ExceptionHandler eh(descriptor,
NULL,
dumpCallback,
NULL,
true,
-1);
//crashHare();
pthread_t threadId;
int input = 12;
int ret = pthread_create(&threadId, NULL, TestThread, (void*)&input);
if(ret != 0)
{
cout<< "create thread error"<<endl;
}
cout<<"main thread running"<<endl;
pthread_join(threadId,NULL);
return 0;
}
I add some printf in ./src/client/linux/handler/exception_handler.cc, before sys_clone and after ThreadEntry, the log is :
struct ThreadArgument {
pid_t pid; // the crashing process
const MinidumpDescriptor* minidump_descriptor;
ExceptionHandler* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
ThreadArgument thread_arg;
thread_arg.handler = this;
thread_arg.minidump_descriptor = &minidump_descriptor_;
thread_arg.pid = getpid();
thread_arg.context = context;
thread_arg.context_size = sizeof(*context);
zzzzzzz &thread_arg:f10ee460 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 23889
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:f10ee450 (child thread)
if the type of thread_arg is a int *, there is no address offset problem. If add prefix static for thread_arg, there is no address offset problem too.
static ThreadArgument thread_arg; /* The same goes for malloc, but malloc is not safe */
zzzzzzz &thread_arg:20030060 (before sys_clone)
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
zzzzzzz child 22399
int ExceptionHandler::ThreadEntry(void *arg) {
zzzzzzz ThreadEntry
zzzzzzz arg:20030060 (child thread)
And I write an another code to test sys_clone under signal processing function:
#include <errno.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <sys/user.h>
#include <ucontext.h>
#include <algorithm>
#include <utility>
#include <vector>
#include "src/third_party/lss/linux_syscall_support.h"
#include "src/common/memory_allocator.h"
using namespace google_breakpad;
unsigned char *stack = NULL;
void my_memset(void* ip, char c, size_t len) {
char* p = (char *) ip;
while (len--)
*p++ = c;
}
struct ThreadArgument {
pid_t pid; // the crashing process
const void* minidump_descriptor;
void* handler;
const void* context; // a CrashContext structure
size_t context_size;
};
int ThreadEntry(void *arg) {
printf("arg:%x\n", arg);
const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
printf("thread_arg:%x\n", thread_arg);
return 0;
}
void GenerateDump(int signo) {
static const unsigned kChildStackSize = 16000;
PageAllocator allocator;
uint8_t* stack = reinterpret_cast<uint8_t*>(allocator.Alloc(kChildStackSize));
if (!stack)
return ;
stack += kChildStackSize;
my_memset(stack - 16, 0, 16);
ThreadArgument thread_arg;
thread_arg.handler = (void *) NULL;
thread_arg.minidump_descriptor = (void *) NULL;
thread_arg.pid = getpid();
thread_arg.context = (void *) NULL;
thread_arg.context_size = sizeof(void *);
printf("thread_arg:%x\n", &thread_arg);
const pid_t child = sys_clone(
ThreadEntry, stack, CLONE_FS | CLONE_UNTRACED, &thread_arg, NULL, NULL,
NULL);
printf("child:%d\n", child);
sleep(1);
return ;
}
int main(void)
{
signal(SIGSEGV, GenerateDump);
int *a = (int *)NULL;
*a = 1;
return 0;
}
It works normal:
thread_arg:ffcb9030
child:8447
arg:ffcb9030
thread_arg:ffcb9030
I wonder why passing the contents of the stack as parameters causes this address mismatch problem in breakpad.