3

我下载了谷歌breakpad源码做一些测试,demo可以在X64和ARM64上正常工作,但是在MIPS64上它不会生成minidump文件,并且在ExceptionHandler::GenerateDump()下sys_clone后子线程会崩溃;我检查了子线程的输入地址,发现地址减少了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;
}

我在 ./src/client/linux/handler/exception_handler.cc 中添加了一些 printf,在 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 *,则不存在地址偏移问题。如果为thread_arg添加前缀static,也没有地址偏移问题。

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

我想知道为什么将堆栈的内容作为参数传递会导致 breakpad 中的地址不匹配问题。

4

0 回答 0