Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit af2cb366 authored by Pavel Chupin's avatar Pavel Chupin
Browse files

Unwinding implementation via eh_frame sections for x86



Backtracing through eh_frame section is more effective allowing to reuse
ebp register for other purposes within routine. GCC with turned on
optimizations (-O1 and above) implicitly defines -fomit-frame-pointer
anyway. eh_frame sections are generated by default with GCC on any
optimization level.

This change implements remote unwinding (separate process unwinding).
Local unwinding is already implemented through _Unwind_Backtrace call
which is implemented in libgcc.

Change-Id: I1aea1ecd19c21710f9cf5f05dc272fc51b67b7aa
Signed-off-by: default avatarPavel Chupin <pavel.v.chupin@intel.com>
parent 3960ec22
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -101,6 +101,21 @@ int do_action_on_thread(const char* arg)
    return (int) result;
}

__attribute__((noinline)) int crash3(int a) {
   *((int*) 0xdead) = a;
   return a*4;
}

__attribute__((noinline)) int crash2(int a) {
   a = crash3(a) + 2;
   return a*3;
}

__attribute__((noinline)) int crash(int a) {
   a = crash2(a) + 1;
   return a*2;
}

int do_action(const char* arg)
{
    if(!strncmp(arg, "thread-", strlen("thread-"))) {
@@ -111,6 +126,7 @@ int do_action(const char* arg)
    if(!strcmp(arg,"nostack")) crashnostack();
    if(!strcmp(arg,"ctest")) return ctest();
    if(!strcmp(arg,"exit")) exit(1);
    if(!strcmp(arg,"crash")) return crash(42);
    if(!strcmp(arg,"abort")) maybeabort();

    pthread_t thr;
+716 −25

File changed.File mode changed from 100644 to 100755.

Preview size limit exceeded, changes collapsed.

+140 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Dwarf2 data encoding flags.
 */

#define DW_EH_PE_absptr         0x00
#define DW_EH_PE_omit           0xff
#define DW_EH_PE_uleb128        0x01
#define DW_EH_PE_udata2         0x02
#define DW_EH_PE_udata4         0x03
#define DW_EH_PE_udata8         0x04
#define DW_EH_PE_sleb128        0x09
#define DW_EH_PE_sdata2         0x0A
#define DW_EH_PE_sdata4         0x0B
#define DW_EH_PE_sdata8         0x0C
#define DW_EH_PE_signed         0x08
#define DW_EH_PE_pcrel          0x10
#define DW_EH_PE_textrel        0x20
#define DW_EH_PE_datarel        0x30
#define DW_EH_PE_funcrel        0x40
#define DW_EH_PE_aligned        0x50
#define DW_EH_PE_indirect       0x80

/*
 * Dwarf2 call frame instructions.
 */

typedef enum {
    DW_CFA_advance_loc = 0x40,
    DW_CFA_offset = 0x80,
    DW_CFA_restore = 0xc0,
    DW_CFA_nop = 0x00,
    DW_CFA_set_loc = 0x01,
    DW_CFA_advance_loc1 = 0x02,
    DW_CFA_advance_loc2 = 0x03,
    DW_CFA_advance_loc4 = 0x04,
    DW_CFA_offset_extended = 0x05,
    DW_CFA_restore_extended = 0x06,
    DW_CFA_undefined = 0x07,
    DW_CFA_same_value = 0x08,
    DW_CFA_register = 0x09,
    DW_CFA_remember_state = 0x0a,
    DW_CFA_restore_state = 0x0b,
    DW_CFA_def_cfa = 0x0c,
    DW_CFA_def_cfa_register = 0x0d,
    DW_CFA_def_cfa_offset = 0x0e
} dwarf_CFA;

/*
 * eh_frame_hdr information.
*/

typedef struct {
      uint8_t version;
      uint8_t eh_frame_ptr_enc;
      uint8_t fde_count_enc;
      uint8_t fde_table_enc;
      uintptr_t eh_frame_ptr;
      uint32_t fde_count;
} eh_frame_hdr_info_t;

/*
 * CIE information.
*/

typedef struct {
      uint8_t version;
      uint32_t code_align;
      uint32_t data_align;
      uint32_t reg;
      uint32_t aug_z;
      uint8_t aug_L;
      uint8_t aug_R;
      uint8_t aug_S;
      uint32_t aug_P;
} cie_info_t;

/*
 * FDE information.
*/

typedef struct {
      uint32_t start;
      uint32_t length; // number of instructions covered by FDE
      uint32_t aug_z;
      uint32_t aug_L;
} fde_info_t;

/*
 * Dwarf state.
*/

/* Stack of states: required for DW_CFA_remember_state/DW_CFA_restore_state
   30 should be enough */
#define DWARF_STATES_STACK 30

typedef struct {
    char rule;         // rule: o - offset(value); r - register(value)
    uint32_t value;    // value
} reg_rule_t;

/* Dwarf preserved number of registers for x86. */

#define DWARF_REGISTERS 17

typedef struct {
    uintptr_t loc;     // location (ip)
    uint8_t cfa_reg;   // index of register where CFA location stored
    intptr_t cfa_off;  // offset
    reg_rule_t regs[DWARF_REGISTERS]; // dwarf preserved registers for x86
} dwarf_state_t;

/* DWARF registers we are caring about. */

#define DWARF_EAX     0
#define DWARF_ECX     1
#define DWARF_EDX     2
#define DWARF_EBX     3
#define DWARF_ESP     4
#define DWARF_EBP     5
#define DWARF_ESI     6
#define DWARF_EDI     7
#define DWARF_EIP     8

+36 −3
Original line number Diff line number Diff line
@@ -19,11 +19,44 @@

#include "../ptrace-arch.h"

#include <stddef.h>
#include <elf.h>
#include <cutils/log.h>

void load_ptrace_map_info_data_arch(pid_t pid __attribute__((unused)),
                                    map_info_t* mi __attribute__((unused)),
                                    map_info_data_t* data __attribute__((unused))) {
static void load_eh_frame_hdr(pid_t pid, map_info_t* mi, uintptr_t *eh_frame_hdr) {
    uint32_t elf_phoff;
    uint32_t elf_phentsize_ehsize;
    uint32_t elf_shentsize_phnum;
    if (try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phoff), &elf_phoff)
            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_ehsize),
                    &elf_phentsize_ehsize)
            && try_get_word_ptrace(pid, mi->start + offsetof(Elf32_Ehdr, e_phnum),
                    &elf_shentsize_phnum)) {
        uint32_t elf_phentsize = elf_phentsize_ehsize >> 16;
        uint32_t elf_phnum = elf_shentsize_phnum & 0xffff;
        for (uint32_t i = 0; i < elf_phnum; i++) {
            uintptr_t elf_phdr = mi->start + elf_phoff + i * elf_phentsize;
            uint32_t elf_phdr_type;
            if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_type), &elf_phdr_type)) {
                break;
            }
            if (elf_phdr_type == PT_GNU_EH_FRAME) {
                uint32_t elf_phdr_offset;
                if (!try_get_word_ptrace(pid, elf_phdr + offsetof(Elf32_Phdr, p_offset),
                        &elf_phdr_offset)) {
                    break;
                }
                *eh_frame_hdr = mi->start + elf_phdr_offset;
                ALOGV("Parsed .eh_frame_hdr info for %s: start=0x%08x", mi->name, *eh_frame_hdr);
                return;
            }
        }
    }
    *eh_frame_hdr = 0;
}

void load_ptrace_map_info_data_arch(pid_t pid, map_info_t* mi, map_info_data_t* data) {
    load_eh_frame_hdr(pid, mi, &data->eh_frame_hdr);
}

void free_ptrace_map_info_data_arch(map_info_t* mi __attribute__((unused)),

libcorkscrew/ptrace-arch.h

100644 → 100755
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,8 @@ typedef struct {
#ifdef __arm__
    uintptr_t exidx_start;
    size_t exidx_size;
#elif __i386__
    uintptr_t eh_frame_hdr;
#endif
    symbol_table_t* symbol_table;
} map_info_data_t;