Я загрузил исходный код Google breakpad, чтобы провести некоторое тестирование, демоверсия может нормально работать на X64 и ARM64, но на MIPS64 она не генерирует файл мини-дампов, и дочерний поток будет зависать после sys_clone в ExceptionHandler :: GenerateDump ();
Я проверил входной адрес дочернего потока, нашел, что адрес уменьшен на 16 байт, моя ревизия ядра:
[root@neo7 breakpad-master]# uname -r
3.10.0-514.26.2.ns7.030.mips64el
Мой тестовый код:
#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;
}
Я добавляю некоторые printf в ./src/client/linux/handler/exception_handler.cc, до sys_clone и после ThreadEntry, журнал выглядит так:
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)
если тип thread_arg имеет тип int *, проблем со смещением адресов нет. Если добавить префикс static для thread_arg, проблема смещения адреса также не возникает.
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)
И я пишу другой код для проверки sys_clone под функцией обработки сигналов:
#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;
}
Работает нормально:
thread_arg:ffcb9030
child:8447
arg:ffcb9030
thread_arg:ffcb9030
Интересно, почему передача содержимого стека в качестве параметров вызывает это
проблема несоответствия адресов в панели разбивки.