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

Commit 13e715b4 authored by Jeff Brown's avatar Jeff Brown
Browse files

Use libcorkscrew in debuggerd.

Change-Id: I5e3645a39d96c808f87075b49111d0262a19a0c8
parent 10484a06
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -5,12 +5,9 @@ ifneq ($(filter arm x86,$(TARGET_ARCH)),)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES:= debuggerd.c utility.c getevent.c $(TARGET_ARCH)/machine.c $(TARGET_ARCH)/unwind.c symbol_table.c
ifeq ($(TARGET_ARCH),arm)
LOCAL_SRC_FILES += $(TARGET_ARCH)/pr-support.c
endif
LOCAL_SRC_FILES:= debuggerd.c utility.c getevent.c $(TARGET_ARCH)/machine.c

LOCAL_CFLAGS := -Wall
LOCAL_CFLAGS := -Wall -Werror -std=gnu99
LOCAL_MODULE := debuggerd

ifeq ($(ARCH_ARM_HAVE_VFP),true)
@@ -20,7 +17,7 @@ ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
LOCAL_CFLAGS += -DWITH_VFP_D32
endif # ARCH_ARM_HAVE_VFP_D32

LOCAL_STATIC_LIBRARIES := libcutils libc
LOCAL_SHARED_LIBRARIES := libcutils libc libcorkscrew

include $(BUILD_EXECUTABLE)

+48 −284
Original line number Diff line number Diff line
@@ -34,10 +34,11 @@
#include <linux/input.h>
#include <linux/user.h>

#include "utility.h"
#include "../utility.h"
#include "../machine.h"

/* enable to dump memory pointed to by every register */
#define DUMP_MEM_FOR_ALL_REGS 1
#define DUMP_MEMORY_FOR_ALL_REGISTERS 1

#ifdef WITH_VFP
#ifdef WITH_VFP_D32
@@ -47,172 +48,22 @@
#endif
#endif

/* Main entry point to get the backtrace from the crashing process */
extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
                                        unsigned int sp_list[],
                                        int *frame0_pc_sane,
                                        bool at_fault);

/*
 * If this isn't clearly a null pointer dereference, dump the
 * /proc/maps entries near the fault address.
 *
 * This only makes sense to do on the thread that crashed.
 * If configured to do so, dump memory around *all* registers
 * for the crashing thread.
 */
static void show_nearby_maps(int tfd, int pid, mapinfo *map)
{
    siginfo_t si;

    memset(&si, 0, sizeof(si));
    if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) {
        _LOG(tfd, false, "cannot get siginfo for %d: %s\n",
            pid, strerror(errno));
        return;
    }
    if (!signal_has_address(si.si_signo))
        return;

    uintptr_t addr = (uintptr_t) si.si_addr;
    addr &= ~0xfff;     /* round to 4K page boundary */
    if (addr == 0)      /* null-pointer deref */
static void dump_memory_and_code(int tfd, pid_t tid, bool at_fault) {
    struct pt_regs regs;
    if(ptrace(PTRACE_GETREGS, tid, 0, &regs)) {
        return;

    _LOG(tfd, false, "\nmemory map around addr %08x:\n", si.si_addr);

    /*
     * Search for a match, or for a hole where the match would be.  The list
     * is backward from the file content, so it starts at high addresses.
     */
    bool found = false;
    mapinfo *next = NULL;
    mapinfo *prev = NULL;
    while (map != NULL) {
        if (addr >= map->start && addr < map->end) {
            found = true;
            next = map->next;
            break;
        } else if (addr >= map->end) {
            /* map would be between "prev" and this entry */
            next = map;
            map = NULL;
            break;
        }

        prev = map;
        map = map->next;
    }

    /*
     * Show "next" then "match" then "prev" so that the addresses appear in
     * ascending order (like /proc/pid/maps).
     */
    if (next != NULL) {
        _LOG(tfd, false, "%08x-%08x %s\n", next->start, next->end, next->name);
    } else {
        _LOG(tfd, false, "(no map below)\n");
    }
    if (map != NULL) {
        _LOG(tfd, false, "%08x-%08x %s\n", map->start, map->end, map->name);
    } else {
        _LOG(tfd, false, "(no map for address)\n");
    }
    if (prev != NULL) {
        _LOG(tfd, false, "%08x-%08x %s\n", prev->start, prev->end, prev->name);
    } else {
        _LOG(tfd, false, "(no map above)\n");
    }
}

/*
 * Dumps a few bytes of memory, starting a bit before and ending a bit
 * after the specified address.
 */
static void dump_memory(int tfd, int pid, uintptr_t addr,
    bool only_in_tombstone)
{
    char code_buffer[64];       /* actual 8+1+((8+1)*4) + 1 == 45 */
    char ascii_buffer[32];      /* actual 16 + 1 == 17 */
    uintptr_t p, end;

    p = addr & ~3;
    p -= 32;
    if (p > addr) {
        /* catch underflow */
        p = 0;
    }
    end = p + 80;
    /* catch overflow; 'end - p' has to be multiples of 16 */
    while (end < p)
        end -= 16;

    /* Dump the code around PC as:
     *  addr     contents                             ascii
     *  00008d34 ef000000 e8bd0090 e1b00000 512fff1e  ............../Q
     *  00008d44 ea00b1f9 e92d0090 e3a070fc ef000000  ......-..p......
     */
    while (p < end) {
        char* asc_out = ascii_buffer;

        sprintf(code_buffer, "%08x ", p);

        int i;
        for (i = 0; i < 4; i++) {
            /*
             * If we see (data == -1 && errno != 0), we know that the ptrace
             * call failed, probably because we're dumping memory in an
             * unmapped or inaccessible page.  I don't know if there's
             * value in making that explicit in the output -- it likely
             * just complicates parsing and clarifies nothing for the
             * enlightened reader.
             */
            long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
            sprintf(code_buffer + strlen(code_buffer), "%08lx ", data);
    if (at_fault && DUMP_MEMORY_FOR_ALL_REGISTERS) {
        static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";

            int j;
            for (j = 0; j < 4; j++) {
                /*
                 * Our isprint() allows high-ASCII characters that display
                 * differently (often badly) in different viewers, so we
                 * just use a simpler test.
                 */
                char val = (data >> (j*8)) & 0xff;
                if (val >= 0x20 && val < 0x7f) {
                    *asc_out++ = val;
                } else {
                    *asc_out++ = '.';
                }
            }
            p += 4;
        }
        *asc_out = '\0';
        _LOG(tfd, only_in_tombstone, "%s %s\n", code_buffer, ascii_buffer);
    }

}

void dump_stack_and_code(int tfd, int pid, mapinfo *map,
                         int unwind_depth, unsigned int sp_list[],
                         bool at_fault)
{
    struct pt_regs r;
    int sp_depth;
    bool only_in_tombstone = !at_fault;

    if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return;

    if (DUMP_MEM_FOR_ALL_REGS && at_fault) {
        /*
         * If configured to do so, dump memory around *all* registers
         * for the crashing thread.
         *
         * TODO: remove duplicates.
         */
        static const char REG_NAMES[] = "R0R1R2R3R4R5R6R7R8R9SLFPIPSPLRPC";

        int reg;
        for (reg = 0; reg < 16; reg++) {
        for (int reg = 0; reg < 14; reg++) {
            /* this may not be a valid way to access, but it'll do for now */
            uintptr_t addr = r.uregs[reg];
            uintptr_t addr = regs.uregs[reg];

            /*
             * Don't bother if it looks like a small int or ~= null, or if
@@ -222,152 +73,65 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map,
                continue;
            }

            _LOG(tfd, only_in_tombstone, "\nmem near %.2s:\n",
                &REG_NAMES[reg*2]);
            dump_memory(tfd, pid, addr, false);
        }
    } else {
        unsigned int pc, lr;
        pc = r.ARM_pc;
        lr = r.ARM_lr;

        _LOG(tfd, only_in_tombstone, "\ncode around pc:\n");
        dump_memory(tfd, pid, (uintptr_t) pc, only_in_tombstone);

        if (lr != pc) {
            _LOG(tfd, only_in_tombstone, "\ncode around lr:\n");
            dump_memory(tfd, pid, (uintptr_t) lr, only_in_tombstone);
            _LOG(tfd, false, "\nmemory near %.2s:\n", &REG_NAMES[reg * 2]);
            dump_memory(tfd, tid, addr, at_fault);
        }
    }

    if (at_fault) {
        show_nearby_maps(tfd, pid, map);
    }

    unsigned int p, end;
    unsigned int sp = r.ARM_sp;

    p = sp - 64;
    if (p > sp)
        p = 0;
    p &= ~3;
    if (unwind_depth != 0) {
        if (unwind_depth < STACK_CONTENT_DEPTH) {
            end = sp_list[unwind_depth-1];
        }
        else {
            end = sp_list[STACK_CONTENT_DEPTH-1];
        }
    }
    else {
        end = p + 256;
        /* 'end - p' has to be multiples of 4 */
        if (end < p)
            end = ~7;
    }

    _LOG(tfd, only_in_tombstone, "\nstack:\n");

    /* If the crash is due to PC == 0, there will be two frames that
     * have identical SP value.
     */
    if (sp_list[0] == sp_list[1]) {
        sp_depth = 1;
    }
    else {
        sp_depth = 0;
    }
    _LOG(tfd, !at_fault, "\ncode around pc:\n");
    dump_memory(tfd, tid, (uintptr_t)regs.ARM_pc, at_fault);

    while (p <= end) {
         char *prompt;
         char level[16];
         long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
         if (p == sp_list[sp_depth]) {
             sprintf(level, "#%02d", sp_depth++);
             prompt = level;
    if (regs.ARM_pc != regs.ARM_lr) {
        _LOG(tfd, !at_fault, "\ncode around lr:\n");
        dump_memory(tfd, tid, (uintptr_t)regs.ARM_lr, at_fault);
    }
         else {
             prompt = "   ";
}

         /* Print the stack content in the log for the first 3 frames. For the
          * rest only print them in the tombstone file.
          */
         _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
              "%s %08x  %08x  %s\n", prompt, p, data,
              map_to_name(map, data, ""));
         p += 4;
    }
    /* print another 64-byte of stack data after the last frame */

    end = p+64;
    /* 'end - p' has to be multiples of 4 */
    if (end < p)
        end = ~7;

    while (p <= end) {
         long data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL);
         _LOG(tfd, (sp_depth > 2) || only_in_tombstone,
              "    %08x  %08x  %s\n", p, data,
              map_to_name(map, data, ""));
         p += 4;
    }
}

void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level,
                    bool at_fault)
{
    struct pt_regs r;

    if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
        _LOG(tfd, !at_fault, "tid %d not responding!\n", pid);
        return;
    }

    if (unwound_level == 0) {
        _LOG(tfd, !at_fault, "         #%02d  pc %08x  %s\n", 0, r.ARM_pc,
             map_to_name(map, r.ARM_pc, "<unknown>"));
    }
    _LOG(tfd, !at_fault, "         #%02d  lr %08x  %s\n", 1, r.ARM_lr,
            map_to_name(map, r.ARM_lr, "<unknown>"));
}

void dump_registers(int tfd, int pid, bool at_fault)
void dump_registers(ptrace_context_t* context __attribute((unused)),
        int tfd, pid_t tid, bool at_fault)
{
    struct pt_regs r;
    bool only_in_tombstone = !at_fault;

    if(ptrace(PTRACE_GETREGS, pid, 0, &r)) {
        _LOG(tfd, only_in_tombstone,
             "cannot get registers: %s\n", strerror(errno));
    if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
        _LOG(tfd, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
        return;
    }

    _LOG(tfd, only_in_tombstone, "    r0 %08x  r1 %08x  r2 %08x  r3 %08x\n",
         r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3);
            (uint32_t)r.ARM_r0, (uint32_t)r.ARM_r1, (uint32_t)r.ARM_r2, (uint32_t)r.ARM_r3);
    _LOG(tfd, only_in_tombstone, "    r4 %08x  r5 %08x  r6 %08x  r7 %08x\n",
         r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7);
    _LOG(tfd, only_in_tombstone, " r8 %08x  r9 %08x  10 %08x  fp %08x\n",
         r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp);
    _LOG(tfd, only_in_tombstone,
         " ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
         r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr);
            (uint32_t)r.ARM_r4, (uint32_t)r.ARM_r5, (uint32_t)r.ARM_r6, (uint32_t)r.ARM_r7);
    _LOG(tfd, only_in_tombstone, "    r8 %08x  r9 %08x  sl %08x  fp %08x\n",
            (uint32_t)r.ARM_r8, (uint32_t)r.ARM_r9, (uint32_t)r.ARM_r10, (uint32_t)r.ARM_fp);
    _LOG(tfd, only_in_tombstone, "    ip %08x  sp %08x  lr %08x  pc %08x  cpsr %08x\n",
            (uint32_t)r.ARM_ip, (uint32_t)r.ARM_sp, (uint32_t)r.ARM_lr,
            (uint32_t)r.ARM_pc, (uint32_t)r.ARM_cpsr);

#ifdef WITH_VFP
    struct user_vfp vfp_regs;
    int i;

    if(ptrace(PTRACE_GETVFPREGS, pid, 0, &vfp_regs)) {
        _LOG(tfd, only_in_tombstone,
             "cannot get registers: %s\n", strerror(errno));
    if(ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
        _LOG(tfd, only_in_tombstone, "cannot get registers: %s\n", strerror(errno));
        return;
    }

    for (i = 0; i < NUM_VFP_REGS; i += 2) {
        _LOG(tfd, only_in_tombstone,
             " d%-2d %016llx  d%-2d %016llx\n",
        _LOG(tfd, only_in_tombstone, "    d%-2d %016llx  d%-2d %016llx\n",
                i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
    }
    _LOG(tfd, only_in_tombstone, "    scr %08lx\n\n", vfp_regs.fpscr);
#endif
}

void dump_thread(ptrace_context_t* context, int tfd, pid_t tid, bool at_fault) {
    dump_registers(context, tfd, tid, at_fault);

    dump_backtrace_and_stack(context, tfd, tid, at_fault);

    if (at_fault) {
        dump_memory_and_code(tfd, tid, at_fault);
        dump_nearby_maps(context, tfd, tid);
    }
}

debuggerd/arm/pr-support.c

deleted100644 → 0
+0 −345
Original line number Diff line number Diff line
/* ARM EABI compliant unwinding routines
   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
   Contributed by Paul Brook
 
   This file is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   In addition to the permissions in the GNU General Public License, the
   Free Software Foundation gives you unlimited permission to link the
   compiled version of this file into combinations with other programs,
   and to distribute those combinations without any restriction coming
   from the use of this file.  (The General Public License restrictions
   do apply in other respects; for example, they cover modification of
   the file, and distribution when not linked into a combine
   executable.)

   This file is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.  */

/****************************************************************************
 * The functions here are derived from gcc/config/arm/pr-support.c from the 
 * 4.3.x release. The main changes here involve the use of ptrace to retrieve
 * memory/processor states from a remote process.
 ****************************************************************************/

#include <sys/types.h>
#include <unwind.h>

#include "utility.h"

/* We add a prototype for abort here to avoid creating a dependency on
   target headers.  */
extern void abort (void);

/* Derived from _Unwind_VRS_Pop to use ptrace */
extern _Unwind_VRS_Result 
unwind_VRS_Pop_with_ptrace (_Unwind_Context *context, 
                            _Unwind_VRS_RegClass regclass, 
                            _uw discriminator, 
                            _Unwind_VRS_DataRepresentation representation, 
                            pid_t pid);

typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */

/* Misc constants.  */
#define R_IP    12
#define R_SP    13
#define R_LR    14
#define R_PC    15

#define uint32_highbit (((_uw) 1) << 31)

void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp);

/* Unwind descriptors.  */

typedef struct
{
  _uw16 length;
  _uw16 offset;
} EHT16;

typedef struct
{
  _uw length;
  _uw offset;
} EHT32;

/* Personality routine helper functions.  */

#define CODE_FINISH (0xb0)

/* Derived from next_unwind_byte to use ptrace */
/* Return the next byte of unwinding information, or CODE_FINISH if there is
   no data remaining.  */
static inline _uw8
next_unwind_byte_with_ptrace (__gnu_unwind_state * uws, pid_t pid)
{
  _uw8 b;

  if (uws->bytes_left == 0)
    {
      /* Load another word */
      if (uws->words_left == 0)
	return CODE_FINISH; /* Nothing left.  */
      uws->words_left--;
      uws->data = get_remote_word(pid, uws->next);
      uws->next++;
      uws->bytes_left = 3;
    }
  else
    uws->bytes_left--;

  /* Extract the most significant byte.  */
  b = (uws->data >> 24) & 0xff;
  uws->data <<= 8;
  return b;
}

/* Execute the unwinding instructions described by UWS.  */
_Unwind_Reason_Code
unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws,
                           pid_t pid)
{
  _uw op;
  int set_pc;
  _uw reg;

  set_pc = 0;
  for (;;)
    {
      op = next_unwind_byte_with_ptrace (uws, pid);
      if (op == CODE_FINISH)
	{
	  /* If we haven't already set pc then copy it from lr.  */
	  if (!set_pc)
	    {
	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32,
			       &reg);
	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32,
			       &reg);
	      set_pc = 1;
	    }
	  /* Drop out of the loop.  */
	  break;
	}
      if ((op & 0x80) == 0)
	{
	  /* vsp = vsp +- (imm6 << 2 + 4).  */
	  _uw offset;

	  offset = ((op & 0x3f) << 2) + 4;
	  _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
	  if (op & 0x40)
	    reg -= offset;
	  else
	    reg += offset;
	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
	  continue;
	}
      
      if ((op & 0xf0) == 0x80)
	{
	  op = (op << 8) | next_unwind_byte_with_ptrace (uws, pid);
	  if (op == 0x8000)
	    {
	      /* Refuse to unwind.  */
	      return _URC_FAILURE;
	    }
	  /* Pop r4-r15 under mask.  */
	  op = (op << 4) & 0xfff0;
	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, _UVRSD_UINT32, 
                                      pid)
	      != _UVRSR_OK)
	    return _URC_FAILURE;
	  if (op & (1 << R_PC))
	    set_pc = 1;
	  continue;
	}
      if ((op & 0xf0) == 0x90)
	{
	  op &= 0xf;
	  if (op == 13 || op == 15)
	    /* Reserved.  */
	    return _URC_FAILURE;
	  /* vsp = r[nnnn].  */
	  _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, &reg);
	  _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, &reg);
	  continue;
	}
      if ((op & 0xf0) == 0xa0)
	{
	  /* Pop r4-r[4+nnn], [lr].  */
	  _uw mask;
	  
	  mask = (0xff0 >> (7 - (op & 7))) & 0xff0;
	  if (op & 8)
	    mask |= (1 << R_LR);
	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, mask, _UVRSD_UINT32,
                                      pid)
	      != _UVRSR_OK)
	    return _URC_FAILURE;
	  continue;
	}
      if ((op & 0xf0) == 0xb0)
	{
	  /* op == 0xb0 already handled.  */
	  if (op == 0xb1)
	    {
	      op = next_unwind_byte_with_ptrace (uws, pid);
	      if (op == 0 || ((op & 0xf0) != 0))
		/* Spare.  */
		return _URC_FAILURE;
	      /* Pop r0-r4 under mask.  */
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, 
                                          _UVRSD_UINT32, pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  if (op == 0xb2)
	    {
	      /* vsp = vsp + 0x204 + (uleb128 << 2).  */
	      int shift;

	      _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
			       &reg);
	      op = next_unwind_byte_with_ptrace (uws, pid);
	      shift = 2;
	      while (op & 0x80)
		{
		  reg += ((op & 0x7f) << shift);
		  shift += 7;
		  op = next_unwind_byte_with_ptrace (uws, pid);
		}
	      reg += ((op & 0x7f) << shift) + 0x204;
	      _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32,
			       &reg);
	      continue;
	    }
	  if (op == 0xb3)
	    {
	      /* Pop VFP registers with fldmx.  */
	      op = next_unwind_byte_with_ptrace (uws, pid);
	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, 
                                          pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  if ((op & 0xfc) == 0xb4)
	    {
	      /* Pop FPA E[4]-E[4+nn].  */
	      op = 0x40000 | ((op & 3) + 1);
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX, 
                                          pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  /* op & 0xf8 == 0xb8.  */
	  /* Pop VFP D[8]-D[8+nnn] with fldmx.  */
	  op = 0x80000 | ((op & 7) + 1);
	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, pid)
	      != _UVRSR_OK)
	    return _URC_FAILURE;
	  continue;
	}
      if ((op & 0xf0) == 0xc0)
	{
	  if (op == 0xc6)
	    {
	      /* Pop iWMMXt D registers.  */
	      op = next_unwind_byte_with_ptrace (uws, pid);
	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op, 
                                          _UVRSD_UINT64, pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  if (op == 0xc7)
	    {
	      op = next_unwind_byte_with_ptrace (uws, pid);
	      if (op == 0 || (op & 0xf0) != 0)
		/* Spare.  */
		return _URC_FAILURE;
	      /* Pop iWMMXt wCGR{3,2,1,0} under mask.  */
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXC, op, 
                                          _UVRSD_UINT32, pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  if ((op & 0xf8) == 0xc0)
	    {
	      /* Pop iWMMXt wR[10]-wR[10+nnn].  */
	      op = 0xa0000 | ((op & 0xf) + 1);
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op, 
                                          _UVRSD_UINT64, pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  if (op == 0xc8)
	    {
#ifndef __VFP_FP__
 	      /* Pop FPA registers.  */
 	      op = next_unwind_byte_with_ptrace (uws, pid);
	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
 	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX,
                                          pid)
 		  != _UVRSR_OK)
 		return _URC_FAILURE;
 	      continue;
#else
              /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm.  */
              op = next_unwind_byte_with_ptrace (uws, pid);
              op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1);
              if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, 
                                              _UVRSD_DOUBLE, pid)
                  != _UVRSR_OK)
                return _URC_FAILURE;
              continue;
#endif
	    }
	  if (op == 0xc9)
	    {
	      /* Pop VFP registers with fldmd.  */
	      op = next_unwind_byte_with_ptrace (uws, pid);
	      op = ((op & 0xf0) << 12) | ((op & 0xf) + 1);
	      if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, 
                                          _UVRSD_DOUBLE, pid)
		  != _UVRSR_OK)
		return _URC_FAILURE;
	      continue;
	    }
	  /* Spare.  */
	  return _URC_FAILURE;
	}
      if ((op & 0xf8) == 0xd0)
	{
	  /* Pop VFP D[8]-D[8+nnn] with fldmd.  */
	  op = 0x80000 | ((op & 7) + 1);
	  if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_DOUBLE, 
                                      pid)
	      != _UVRSR_OK)
	    return _URC_FAILURE;
	  continue;
	}
      /* Spare.  */
      return _URC_FAILURE;
    }
  return _URC_OK;
}

debuggerd/arm/unwind.c

deleted100644 → 0
+0 −667

File deleted.

Preview size limit exceeded, changes collapsed.

+128 −275

File changed.

Preview size limit exceeded, changes collapsed.

Loading