mirror of
https://git.freebsd.org/ports.git
synced 2025-06-20 20:20:30 -04:00
This includes an update to the bundled libc++ pretty printers with fixes for recent changes in libc++ to std::string and std::unordered_map. PR: 272922 Sponsored by: AFRL, DARPA Differential Revision: https://reviews.freebsd.org/D46232
266 lines
8 KiB
C
266 lines
8 KiB
C
/*-
|
|
* Copyright (c) 2017 John Baldwin <jhb@FreeBSD.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/* Target-dependent code for FreeBSD/aarch64 kernels. */
|
|
|
|
#include "defs.h"
|
|
|
|
#include "aarch64-tdep.h"
|
|
#include "frame-unwind.h"
|
|
#include "gdbarch.h"
|
|
#include "gdbcore.h"
|
|
#include "osabi.h"
|
|
#include "regcache.h"
|
|
#include "regset.h"
|
|
#include "solib.h"
|
|
#include "target.h"
|
|
#include "trad-frame.h"
|
|
|
|
#include "kgdb.h"
|
|
|
|
struct aarch64_fbsd_kern_info
|
|
{
|
|
LONGEST osreldate = 0;
|
|
};
|
|
|
|
/* Per-program-space data key. */
|
|
static const registry<program_space>::key<aarch64_fbsd_kern_info>
|
|
aarch64_fbsd_kern_pspace_data;
|
|
|
|
/* Get the current aarch64_fbsd_kern data. If none is found yet, add it
|
|
now. This function always returns a valid object. */
|
|
|
|
static struct aarch64_fbsd_kern_info *
|
|
get_aarch64_fbsd_kern_info (void)
|
|
{
|
|
struct aarch64_fbsd_kern_info *info;
|
|
|
|
info = aarch64_fbsd_kern_pspace_data.get (current_program_space);
|
|
if (info != nullptr)
|
|
return info;
|
|
|
|
info = aarch64_fbsd_kern_pspace_data.emplace (current_program_space);
|
|
info->osreldate = parse_and_eval_long ("osreldate");
|
|
return info;
|
|
}
|
|
|
|
static const struct regcache_map_entry aarch64_fbsd_pcbmap[] =
|
|
{
|
|
{ 11, AARCH64_X0_REGNUM + 19, 8 }, /* x19 ... x29 */
|
|
{ 1, AARCH64_PC_REGNUM, 8 },
|
|
{ 1, AARCH64_SP_REGNUM, 8 },
|
|
{ 0 }
|
|
};
|
|
|
|
static const struct regset aarch64_fbsd_pcbregset =
|
|
{
|
|
aarch64_fbsd_pcbmap,
|
|
regcache_supply_regset, regcache_collect_regset
|
|
};
|
|
|
|
/* In kernels prior to __FreeBSD_version 1400084, struct pcb used an
|
|
alternate layout. */
|
|
|
|
static const struct regcache_map_entry aarch64_fbsd13_pcbmap[] =
|
|
{
|
|
{ 30, AARCH64_X0_REGNUM, 8 }, /* x0 ... x29 */
|
|
{ 1, AARCH64_PC_REGNUM, 8 },
|
|
{ 1, REGCACHE_MAP_SKIP, 8 },
|
|
{ 1, AARCH64_SP_REGNUM, 8 },
|
|
{ 0 }
|
|
};
|
|
|
|
static const struct regset aarch64_fbsd13_pcbregset =
|
|
{
|
|
aarch64_fbsd13_pcbmap,
|
|
regcache_supply_regset, regcache_collect_regset
|
|
};
|
|
|
|
static void
|
|
aarch64_fbsd_supply_pcb(struct regcache *regcache, CORE_ADDR pcb_addr)
|
|
{
|
|
const struct regset *pcbregset;
|
|
struct aarch64_fbsd_kern_info *info = get_aarch64_fbsd_kern_info();
|
|
gdb_byte buf[8 * 33];
|
|
|
|
if (info->osreldate >= 1400084)
|
|
pcbregset = &aarch64_fbsd_pcbregset;
|
|
else
|
|
pcbregset = &aarch64_fbsd13_pcbregset;
|
|
if (target_read_memory (pcb_addr, buf, sizeof buf) == 0)
|
|
regcache_supply_regset (pcbregset, regcache, -1, buf,
|
|
sizeof (buf));
|
|
}
|
|
|
|
static const struct regcache_map_entry aarch64_fbsd_trapframe_map[] =
|
|
{
|
|
{ 1, AARCH64_SP_REGNUM, 8 },
|
|
{ 1, AARCH64_LR_REGNUM, 8 },
|
|
{ 1, AARCH64_PC_REGNUM, 8 },
|
|
{ 1, AARCH64_CPSR_REGNUM, 8 },
|
|
{ 1, REGCACHE_MAP_SKIP, 8 }, /* esr */
|
|
{ 1, REGCACHE_MAP_SKIP, 8 }, /* far */
|
|
{ 30, AARCH64_X0_REGNUM, 8 }, /* x0 ... x29 */
|
|
{ 0 }
|
|
};
|
|
|
|
/* In kernels prior to __FreeBSD_version 1400084, struct trapframe
|
|
used an alternate layout. */
|
|
|
|
static const struct regcache_map_entry aarch64_fbsd13_trapframe_map[] =
|
|
{
|
|
{ 1, AARCH64_SP_REGNUM, 8 },
|
|
{ 1, AARCH64_LR_REGNUM, 8 },
|
|
{ 1, AARCH64_PC_REGNUM, 8 },
|
|
{ 1, AARCH64_CPSR_REGNUM, 4 },
|
|
{ 1, REGCACHE_MAP_SKIP, 4 }, /* esr */
|
|
{ 30, AARCH64_X0_REGNUM, 8 }, /* x0 ... x29 */
|
|
{ 0 }
|
|
};
|
|
|
|
static struct trad_frame_cache *
|
|
aarch64_fbsd_trapframe_cache (const frame_info_ptr &this_frame,
|
|
void **this_cache)
|
|
{
|
|
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
|
struct aarch64_fbsd_kern_info *info = get_aarch64_fbsd_kern_info();
|
|
struct trad_frame_cache *cache;
|
|
CORE_ADDR func, offset, pc, sp;
|
|
const char *name;
|
|
int i, tf_size;
|
|
|
|
if (*this_cache != NULL)
|
|
return ((struct trad_frame_cache *)*this_cache);
|
|
|
|
const struct regcache_map_entry *trapframe_map;
|
|
if (info->osreldate >= 1400084)
|
|
trapframe_map = aarch64_fbsd_trapframe_map;
|
|
else
|
|
trapframe_map = aarch64_fbsd13_trapframe_map;
|
|
|
|
cache = trad_frame_cache_zalloc (this_frame);
|
|
*this_cache = cache;
|
|
|
|
sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
|
|
|
|
tf_size = regcache_map_entry_size (trapframe_map);
|
|
trad_frame_set_reg_regmap (cache, trapframe_map, sp, tf_size);
|
|
|
|
/* Read $PC from trap frame. */
|
|
func = get_frame_func (this_frame);
|
|
find_pc_partial_function (func, &name, NULL, NULL);
|
|
offset = regcache_map_offset (trapframe_map, AARCH64_PC_REGNUM, gdbarch);
|
|
pc = read_memory_unsigned_integer (sp + offset, 8, byte_order);
|
|
|
|
if (pc == 0 && strcmp(name, "fork_trampoline") == 0)
|
|
{
|
|
/* Initial frame of a kthread; terminate backtrace. */
|
|
trad_frame_set_id (cache, outer_frame_id);
|
|
}
|
|
else
|
|
{
|
|
/* Construct the frame ID using the function start. */
|
|
trad_frame_set_id (cache, frame_id_build (sp, func));
|
|
}
|
|
|
|
return cache;
|
|
}
|
|
|
|
static void
|
|
aarch64_fbsd_trapframe_this_id (const frame_info_ptr &this_frame,
|
|
void **this_cache, struct frame_id *this_id)
|
|
{
|
|
struct trad_frame_cache *cache =
|
|
aarch64_fbsd_trapframe_cache (this_frame, this_cache);
|
|
|
|
trad_frame_get_id (cache, this_id);
|
|
}
|
|
|
|
static struct value *
|
|
aarch64_fbsd_trapframe_prev_register (const frame_info_ptr &this_frame,
|
|
void **this_cache, int regnum)
|
|
{
|
|
struct trad_frame_cache *cache =
|
|
aarch64_fbsd_trapframe_cache (this_frame, this_cache);
|
|
|
|
return trad_frame_get_register (cache, this_frame, regnum);
|
|
}
|
|
|
|
static int
|
|
aarch64_fbsd_trapframe_sniffer (const struct frame_unwind *self,
|
|
const frame_info_ptr &this_frame,
|
|
void **this_prologue_cache)
|
|
{
|
|
const char *name;
|
|
|
|
find_pc_partial_function (get_frame_func (this_frame), &name, NULL, NULL);
|
|
return (name && ((strcmp (name, "handle_el1h_sync") == 0)
|
|
|| (strcmp (name, "handle_el1h_irq") == 0)
|
|
|| (strcmp (name, "handle_el0_sync") == 0)
|
|
|| (strcmp (name, "handle_el0_irq") == 0)
|
|
|| (strcmp (name, "handle_el0_error") == 0)
|
|
|| (strcmp (name, "fork_trampoline") == 0)));
|
|
}
|
|
|
|
static const struct frame_unwind aarch64_fbsd_trapframe_unwind = {
|
|
"aarch64 FreeBSD kernel trap",
|
|
SIGTRAMP_FRAME,
|
|
default_frame_unwind_stop_reason,
|
|
aarch64_fbsd_trapframe_this_id,
|
|
aarch64_fbsd_trapframe_prev_register,
|
|
NULL,
|
|
aarch64_fbsd_trapframe_sniffer
|
|
};
|
|
|
|
/* Implement the 'init_osabi' method of struct gdb_osabi_handler. */
|
|
|
|
static void
|
|
aarch64_fbsd_kernel_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|
{
|
|
aarch64_gdbarch_tdep *tdep = gdbarch_tdep<aarch64_gdbarch_tdep> (gdbarch);
|
|
|
|
frame_unwind_prepend_unwinder (gdbarch, &aarch64_fbsd_trapframe_unwind);
|
|
|
|
set_gdbarch_so_ops (gdbarch, &kld_so_ops);
|
|
|
|
/* Enable longjmp. */
|
|
tdep->jb_pc = 13;
|
|
|
|
fbsd_vmcore_set_supply_pcb (gdbarch, aarch64_fbsd_supply_pcb);
|
|
fbsd_vmcore_set_cpu_pcb_addr (gdbarch, kgdb_trgt_stop_pcb);
|
|
}
|
|
|
|
void _initialize_aarch64_kgdb_tdep ();
|
|
void
|
|
_initialize_aarch64_kgdb_tdep ()
|
|
{
|
|
gdbarch_register_osabi_sniffer(bfd_arch_aarch64,
|
|
bfd_target_elf_flavour,
|
|
fbsd_kernel_osabi_sniffer);
|
|
gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_FREEBSD_KERNEL,
|
|
aarch64_fbsd_kernel_init_abi);
|
|
}
|