/* Target-dependent code for PowerPC systems running FreeBSD.
Copyright (C) 2013-2019 Free Software Foundation, Inc.
This file is part of GDB.
This program 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 3 of the License, or
(at your option) any later version.
This program 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. If not, see . */
#include "defs.h"
#include "arch-utils.h"
#include "frame.h"
#include "gdbcore.h"
#include "frame-unwind.h"
#include "gdbtypes.h"
#include "osabi.h"
#include "regcache.h"
#include "regset.h"
#include "symtab.h"
#include "target.h"
#include "trad-frame.h"
#include "rs6000-tdep.h"
#include "ppc-tdep.h"
#include "ppc-tdep.h"
#include "ppc64-tdep.h"
#include "ppc-fbsd-tdep.h"
#include "morphos-tdep.h"
/* Calculate the destination of a branch/jump. Return -1 if not a branch. */
static CORE_ADDR
branch_dest (struct regcache *regcache, int opcode, int instr,
CORE_ADDR pc, CORE_ADDR safety)
{
struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR dest;
int immediate;
int absolute;
int ext_op;
absolute = (int) ((instr >> 1) & 1);
switch (opcode)
{
case 18:
immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */
if (absolute)
dest = immediate;
else
dest = pc + immediate;
break;
case 16:
immediate = ((instr & ~3) << 16) >> 16; /* br conditional */
if (absolute)
dest = immediate;
else
dest = pc + immediate;
break;
case 19:
#warning MorphOS: fix the calculation of destination of a branch/jump
ext_op = (instr >> 1) & 0x3ff;
if (ext_op == 16) /* br conditional register */
{
dest = regcache_raw_get_unsigned (regcache, tdep->ppc_lr_regnum) & ~3;
/*What if dest is out of the text segment? E.g. library call?
if (dest < MORPHOS_TEXT_SEGMENT_BASE)
{
dest =
}
*/
}
else if (ext_op == 528) /* br cond to count reg */
{
dest = regcache_raw_get_unsigned (regcache,
tdep->ppc_ctr_regnum) & ~3;
/*What if dest is out of the text segment? E.g. library call?
if (dest < MORPHOS_TEXT_SEGMENT_BASE)
{
dest =
}*/
}
else
return -1;
break;
default:
return -1;
}
return /*(dest < MORPHOS_TEXT_SEGMENT_BASE) ? safety :*/ dest;
}
static std::vector
rs6000_software_single_step (struct regcache *regcache)
{
struct gdbarch *gdbarch = regcache->arch ();
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int ii, insn;
CORE_ADDR loc;
CORE_ADDR breaks[2];
int opcode;
loc = regcache_read_pc (regcache);
insn = read_memory_integer (loc, 4, byte_order);
std::vector next_pcs = ppc_deal_with_atomic_sequence (regcache);
if (!next_pcs.empty ())
return next_pcs;
breaks[0] = loc + PPC_INSN_SIZE;
opcode = insn >> 26;
breaks[1] = branch_dest (regcache, opcode, insn, loc, breaks[0]);
/* Don't put two breakpoints on the same address. */
if (breaks[1] == breaks[0])
breaks[1] = -1;
for (ii = 0; ii < 2; ++ii)
{
/* ignore invalid breakpoint. */
if (breaks[ii] == -1)
continue;
next_pcs.push_back (breaks[ii]);
}
errno = 0; /* FIXME, don't ignore errors! */
/* What errors? {read,write}_memory call error(). */
return next_pcs;
}
static void
morphos_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* MorphOS does not support single stepping. Has to be simulated. */
set_gdbarch_software_single_step (gdbarch, rs6000_software_single_step);
/* Displaced stepping is currently not supported in combination with
software single-stepping. */
set_gdbarch_displaced_step_copy_insn (gdbarch, NULL);
set_gdbarch_displaced_step_fixup (gdbarch, NULL);
set_gdbarch_displaced_step_location (gdbarch, NULL);
/*
set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call);
set_gdbarch_return_value (gdbarch, rs6000_return_value);
set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
*/
}
void
_initialize_morphos_tdep (void)
{
gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_MORPHOS,
morphos_init_osabi);
gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_MORPHOS,
morphos_init_osabi);
}