12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112 |
- /* Target-dependent code for Moxie.
- Copyright (C) 2009-2022 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 <http://www.gnu.org/licenses/>. */
- #include "defs.h"
- #include "frame.h"
- #include "frame-unwind.h"
- #include "frame-base.h"
- #include "symtab.h"
- #include "gdbtypes.h"
- #include "gdbcmd.h"
- #include "gdbcore.h"
- #include "value.h"
- #include "inferior.h"
- #include "symfile.h"
- #include "objfiles.h"
- #include "osabi.h"
- #include "language.h"
- #include "arch-utils.h"
- #include "regcache.h"
- #include "trad-frame.h"
- #include "dis-asm.h"
- #include "record.h"
- #include "record-full.h"
- #include "moxie-tdep.h"
- #include <algorithm>
- /* Use an invalid address value as 'not available' marker. */
- enum { REG_UNAVAIL = (CORE_ADDR) -1 };
- struct moxie_frame_cache
- {
- /* Base address. */
- CORE_ADDR base;
- CORE_ADDR pc;
- LONGEST framesize;
- CORE_ADDR saved_regs[MOXIE_NUM_REGS];
- CORE_ADDR saved_sp;
- };
- /* Implement the "frame_align" gdbarch method. */
- static CORE_ADDR
- moxie_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
- {
- /* Align to the size of an instruction (so that they can safely be
- pushed onto the stack. */
- return sp & ~1;
- }
- constexpr gdb_byte moxie_break_insn[] = { 0x35, 0x00 };
- typedef BP_MANIPULATION (moxie_break_insn) moxie_breakpoint;
- /* Moxie register names. */
- static const char * const moxie_register_names[] = {
- "$fp", "$sp", "$r0", "$r1", "$r2",
- "$r3", "$r4", "$r5", "$r6", "$r7",
- "$r8", "$r9", "$r10", "$r11", "$r12",
- "$r13", "$pc", "$cc" };
- /* Implement the "register_name" gdbarch method. */
- static const char *
- moxie_register_name (struct gdbarch *gdbarch, int reg_nr)
- {
- if (reg_nr < 0)
- return NULL;
- if (reg_nr >= MOXIE_NUM_REGS)
- return NULL;
- return moxie_register_names[reg_nr];
- }
- /* Implement the "register_type" gdbarch method. */
- static struct type *
- moxie_register_type (struct gdbarch *gdbarch, int reg_nr)
- {
- if (reg_nr == MOXIE_PC_REGNUM)
- return builtin_type (gdbarch)->builtin_func_ptr;
- else if (reg_nr == MOXIE_SP_REGNUM || reg_nr == MOXIE_FP_REGNUM)
- return builtin_type (gdbarch)->builtin_data_ptr;
- else
- return builtin_type (gdbarch)->builtin_int32;
- }
- /* Write into appropriate registers a function return value
- of type TYPE, given in virtual format. */
- static void
- moxie_store_return_value (struct type *type, struct regcache *regcache,
- const gdb_byte *valbuf)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR regval;
- int len = TYPE_LENGTH (type);
- /* Things always get returned in RET1_REGNUM, RET2_REGNUM. */
- regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len, byte_order);
- regcache_cooked_write_unsigned (regcache, RET1_REGNUM, regval);
- if (len > 4)
- {
- regval = extract_unsigned_integer (valbuf + 4, len - 4, byte_order);
- regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval);
- }
- }
- /* Decode the instructions within the given address range. Decide
- when we must have reached the end of the function prologue. If a
- frame_info pointer is provided, fill in its saved_regs etc.
- Returns the address of the first instruction after the prologue. */
- static CORE_ADDR
- moxie_analyze_prologue (CORE_ADDR start_addr, CORE_ADDR end_addr,
- struct moxie_frame_cache *cache,
- struct gdbarch *gdbarch)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- CORE_ADDR next_addr;
- ULONGEST inst, inst2;
- LONGEST offset;
- int regnum;
- /* Record where the jsra instruction saves the PC and FP. */
- cache->saved_regs[MOXIE_PC_REGNUM] = -4;
- cache->saved_regs[MOXIE_FP_REGNUM] = 0;
- cache->framesize = 0;
- if (start_addr >= end_addr)
- return end_addr;
- for (next_addr = start_addr; next_addr < end_addr; )
- {
- inst = read_memory_unsigned_integer (next_addr, 2, byte_order);
- /* Match "push $sp $rN" where N is between 0 and 13 inclusive. */
- if (inst >= 0x0612 && inst <= 0x061f)
- {
- regnum = inst & 0x000f;
- cache->framesize += 4;
- cache->saved_regs[regnum] = cache->framesize;
- next_addr += 2;
- }
- else
- break;
- }
- inst = read_memory_unsigned_integer (next_addr, 2, byte_order);
- /* Optional stack allocation for args and local vars <= 4
- byte. */
- if (inst == 0x01e0) /* ldi.l $r12, X */
- {
- offset = read_memory_integer (next_addr + 2, 4, byte_order);
- inst2 = read_memory_unsigned_integer (next_addr + 6, 2, byte_order);
-
- if (inst2 == 0x291e) /* sub.l $sp, $r12 */
- {
- cache->framesize += offset;
- }
-
- return (next_addr + 8);
- }
- else if ((inst & 0xff00) == 0x9100) /* dec $sp, X */
- {
- cache->framesize += (inst & 0x00ff);
- next_addr += 2;
- while (next_addr < end_addr)
- {
- inst = read_memory_unsigned_integer (next_addr, 2, byte_order);
- if ((inst & 0xff00) != 0x9100) /* no more dec $sp, X */
- break;
- cache->framesize += (inst & 0x00ff);
- next_addr += 2;
- }
- }
- return next_addr;
- }
- /* Find the end of function prologue. */
- static CORE_ADDR
- moxie_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR func_addr = 0, func_end = 0;
- const char *func_name;
- /* See if we can determine the end of the prologue via the symbol table.
- If so, then return either PC, or the PC after the prologue, whichever
- is greater. */
- if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
- {
- CORE_ADDR post_prologue_pc
- = skip_prologue_using_sal (gdbarch, func_addr);
- if (post_prologue_pc != 0)
- return std::max (pc, post_prologue_pc);
- else
- {
- /* Can't determine prologue from the symbol table, need to examine
- instructions. */
- struct symtab_and_line sal;
- struct symbol *sym;
- struct moxie_frame_cache cache;
- CORE_ADDR plg_end;
-
- memset (&cache, 0, sizeof cache);
-
- plg_end = moxie_analyze_prologue (func_addr,
- func_end, &cache, gdbarch);
- /* Found a function. */
- sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL).symbol;
- /* Don't use line number debug info for assembly source
- files. */
- if (sym && sym->language () != language_asm)
- {
- sal = find_pc_line (func_addr, 0);
- if (sal.end && sal.end < func_end)
- {
- /* Found a line number, use it as end of
- prologue. */
- return sal.end;
- }
- }
- /* No useable line symbol. Use result of prologue parsing
- method. */
- return plg_end;
- }
- }
- /* No function symbol -- just return the PC. */
- return (CORE_ADDR) pc;
- }
- struct moxie_unwind_cache
- {
- /* The previous frame's inner most stack address. Used as this
- frame ID's stack_addr. */
- CORE_ADDR prev_sp;
- /* The frame's base, optionally used by the high-level debug info. */
- CORE_ADDR base;
- int size;
- /* How far the SP and r13 (FP) have been offset from the start of
- the stack frame (as defined by the previous frame's stack
- pointer). */
- LONGEST sp_offset;
- LONGEST r13_offset;
- int uses_frame;
- /* Table indicating the location of each and every register. */
- trad_frame_saved_reg *saved_regs;
- };
- /* Read an unsigned integer from the inferior, and adjust
- endianness. */
- static ULONGEST
- moxie_process_readu (CORE_ADDR addr, gdb_byte *buf,
- int length, enum bfd_endian byte_order)
- {
- if (target_read_memory (addr, buf, length))
- {
- if (record_debug)
- gdb_printf (gdb_stderr,
- _("Process record: error reading memory at "
- "addr 0x%s len = %d.\n"),
- paddress (target_gdbarch (), addr), length);
- return -1;
- }
- return extract_unsigned_integer (buf, length, byte_order);
- }
- /* Helper macro to extract the signed 10-bit offset from a 16-bit
- branch instruction. */
- #define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
- /* Insert a single step breakpoint. */
- static std::vector<CORE_ADDR>
- moxie_software_single_step (struct regcache *regcache)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- CORE_ADDR addr;
- gdb_byte buf[4];
- uint16_t inst;
- uint32_t tmpu32;
- ULONGEST fp;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- std::vector<CORE_ADDR> next_pcs;
- addr = regcache_read_pc (regcache);
- inst = (uint16_t) moxie_process_readu (addr, buf, 2, byte_order);
- /* Decode instruction. */
- if (inst & (1 << 15))
- {
- if (inst & (1 << 14))
- {
- /* This is a Form 3 instruction. */
- int opcode = (inst >> 10 & 0xf);
- switch (opcode)
- {
- case 0x00: /* beq */
- case 0x01: /* bne */
- case 0x02: /* blt */
- case 0x03: /* bgt */
- case 0x04: /* bltu */
- case 0x05: /* bgtu */
- case 0x06: /* bge */
- case 0x07: /* ble */
- case 0x08: /* bgeu */
- case 0x09: /* bleu */
- /* Insert breaks on both branches, because we can't currently tell
- which way things will go. */
- next_pcs.push_back (addr + 2);
- next_pcs.push_back (addr + 2 + INST2OFFSET(inst));
- break;
- default:
- {
- /* Do nothing. */
- break;
- }
- }
- }
- else
- {
- /* This is a Form 2 instruction. They are all 16 bits. */
- next_pcs.push_back (addr + 2);
- }
- }
- else
- {
- /* This is a Form 1 instruction. */
- int opcode = inst >> 8;
- switch (opcode)
- {
- /* 16-bit instructions. */
- case 0x00: /* bad */
- case 0x02: /* mov (register-to-register) */
- case 0x05: /* add.l */
- case 0x06: /* push */
- case 0x07: /* pop */
- case 0x0a: /* ld.l (register indirect) */
- case 0x0b: /* st.l */
- case 0x0e: /* cmp */
- case 0x0f: /* nop */
- case 0x10: /* sex.b */
- case 0x11: /* sex.s */
- case 0x12: /* zex.b */
- case 0x13: /* zex.s */
- case 0x14: /* umul.x */
- case 0x15: /* mul.x */
- case 0x16:
- case 0x17:
- case 0x18:
- case 0x1c: /* ld.b (register indirect) */
- case 0x1e: /* st.b */
- case 0x21: /* ld.s (register indirect) */
- case 0x23: /* st.s */
- case 0x26: /* and */
- case 0x27: /* lshr */
- case 0x28: /* ashl */
- case 0x29: /* sub.l */
- case 0x2a: /* neg */
- case 0x2b: /* or */
- case 0x2c: /* not */
- case 0x2d: /* ashr */
- case 0x2e: /* xor */
- case 0x2f: /* mul.l */
- case 0x31: /* div.l */
- case 0x32: /* udiv.l */
- case 0x33: /* mod.l */
- case 0x34: /* umod.l */
- next_pcs.push_back (addr + 2);
- break;
- /* 32-bit instructions. */
- case 0x0c: /* ldo.l */
- case 0x0d: /* sto.l */
- case 0x36: /* ldo.b */
- case 0x37: /* sto.b */
- case 0x38: /* ldo.s */
- case 0x39: /* sto.s */
- next_pcs.push_back (addr + 4);
- break;
- /* 48-bit instructions. */
- case 0x01: /* ldi.l (immediate) */
- case 0x08: /* lda.l */
- case 0x09: /* sta.l */
- case 0x1b: /* ldi.b (immediate) */
- case 0x1d: /* lda.b */
- case 0x1f: /* sta.b */
- case 0x20: /* ldi.s (immediate) */
- case 0x22: /* lda.s */
- case 0x24: /* sta.s */
- next_pcs.push_back (addr + 6);
- break;
- /* Control flow instructions. */
- case 0x03: /* jsra */
- case 0x1a: /* jmpa */
- next_pcs.push_back (moxie_process_readu (addr + 2, buf, 4,
- byte_order));
- break;
- case 0x04: /* ret */
- regcache_cooked_read_unsigned (regcache, MOXIE_FP_REGNUM, &fp);
- next_pcs.push_back (moxie_process_readu (fp + 4, buf, 4, byte_order));
- break;
- case 0x19: /* jsr */
- case 0x25: /* jmp */
- regcache->raw_read ((inst >> 4) & 0xf, (gdb_byte *) & tmpu32);
- next_pcs.push_back (tmpu32);
- break;
- case 0x30: /* swi */
- case 0x35: /* brk */
- /* Unsupported, for now. */
- break;
- }
- }
- return next_pcs;
- }
- /* Given a return value in `regbuf' with a type `valtype',
- extract and copy its value into `valbuf'. */
- static void
- moxie_extract_return_value (struct type *type, struct regcache *regcache,
- gdb_byte *dst)
- {
- struct gdbarch *gdbarch = regcache->arch ();
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- int len = TYPE_LENGTH (type);
- ULONGEST tmp;
- /* By using store_unsigned_integer we avoid having to do
- anything special for small big-endian values. */
- regcache_cooked_read_unsigned (regcache, RET1_REGNUM, &tmp);
- store_unsigned_integer (dst, (len > 4 ? len - 4 : len), byte_order, tmp);
- /* Ignore return values more than 8 bytes in size because the moxie
- returns anything more than 8 bytes in the stack. */
- if (len > 4)
- {
- regcache_cooked_read_unsigned (regcache, RET1_REGNUM + 1, &tmp);
- store_unsigned_integer (dst + len - 4, 4, byte_order, tmp);
- }
- }
- /* Implement the "return_value" gdbarch method. */
- static enum return_value_convention
- moxie_return_value (struct gdbarch *gdbarch, struct value *function,
- struct type *valtype, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- if (TYPE_LENGTH (valtype) > 8)
- return RETURN_VALUE_STRUCT_CONVENTION;
- else
- {
- if (readbuf != NULL)
- moxie_extract_return_value (valtype, regcache, readbuf);
- if (writebuf != NULL)
- moxie_store_return_value (valtype, regcache, writebuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- }
- /* Allocate and initialize a moxie_frame_cache object. */
- static struct moxie_frame_cache *
- moxie_alloc_frame_cache (void)
- {
- struct moxie_frame_cache *cache;
- int i;
- cache = FRAME_OBSTACK_ZALLOC (struct moxie_frame_cache);
- cache->base = 0;
- cache->saved_sp = 0;
- cache->pc = 0;
- cache->framesize = 0;
- for (i = 0; i < MOXIE_NUM_REGS; ++i)
- cache->saved_regs[i] = REG_UNAVAIL;
- return cache;
- }
- /* Populate a moxie_frame_cache object for this_frame. */
- static struct moxie_frame_cache *
- moxie_frame_cache (struct frame_info *this_frame, void **this_cache)
- {
- struct moxie_frame_cache *cache;
- CORE_ADDR current_pc;
- int i;
- if (*this_cache)
- return (struct moxie_frame_cache *) *this_cache;
- cache = moxie_alloc_frame_cache ();
- *this_cache = cache;
- cache->base = get_frame_register_unsigned (this_frame, MOXIE_FP_REGNUM);
- if (cache->base == 0)
- return cache;
- cache->pc = get_frame_func (this_frame);
- current_pc = get_frame_pc (this_frame);
- if (cache->pc)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- moxie_analyze_prologue (cache->pc, current_pc, cache, gdbarch);
- }
- cache->saved_sp = cache->base - cache->framesize;
- for (i = 0; i < MOXIE_NUM_REGS; ++i)
- if (cache->saved_regs[i] != REG_UNAVAIL)
- cache->saved_regs[i] = cache->base - cache->saved_regs[i];
- return cache;
- }
- /* Given a GDB frame, determine the address of the calling function's
- frame. This will be used to create a new GDB frame struct. */
- static void
- moxie_frame_this_id (struct frame_info *this_frame,
- void **this_prologue_cache, struct frame_id *this_id)
- {
- struct moxie_frame_cache *cache = moxie_frame_cache (this_frame,
- this_prologue_cache);
- /* This marks the outermost frame. */
- if (cache->base == 0)
- return;
- *this_id = frame_id_build (cache->saved_sp, cache->pc);
- }
- /* Get the value of register regnum in the previous stack frame. */
- static struct value *
- moxie_frame_prev_register (struct frame_info *this_frame,
- void **this_prologue_cache, int regnum)
- {
- struct moxie_frame_cache *cache = moxie_frame_cache (this_frame,
- this_prologue_cache);
- gdb_assert (regnum >= 0);
- if (regnum == MOXIE_SP_REGNUM && cache->saved_sp)
- return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
- if (regnum < MOXIE_NUM_REGS && cache->saved_regs[regnum] != REG_UNAVAIL)
- return frame_unwind_got_memory (this_frame, regnum,
- cache->saved_regs[regnum]);
- return frame_unwind_got_register (this_frame, regnum, regnum);
- }
- static const struct frame_unwind moxie_frame_unwind = {
- "moxie prologue",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- moxie_frame_this_id,
- moxie_frame_prev_register,
- NULL,
- default_frame_sniffer
- };
- /* Return the base address of this_frame. */
- static CORE_ADDR
- moxie_frame_base_address (struct frame_info *this_frame, void **this_cache)
- {
- struct moxie_frame_cache *cache = moxie_frame_cache (this_frame,
- this_cache);
- return cache->base;
- }
- static const struct frame_base moxie_frame_base = {
- &moxie_frame_unwind,
- moxie_frame_base_address,
- moxie_frame_base_address,
- moxie_frame_base_address
- };
- /* Parse the current instruction and record the values of the registers and
- memory that will be changed in current instruction to "record_arch_list".
- Return -1 if something wrong. */
- static int
- moxie_process_record (struct gdbarch *gdbarch, struct regcache *regcache,
- CORE_ADDR addr)
- {
- gdb_byte buf[4];
- uint16_t inst;
- uint32_t tmpu32;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- if (record_debug > 1)
- gdb_printf (gdb_stdlog, "Process record: moxie_process_record "
- "addr = 0x%s\n",
- paddress (target_gdbarch (), addr));
- inst = (uint16_t) moxie_process_readu (addr, buf, 2, byte_order);
- /* Decode instruction. */
- if (inst & (1 << 15))
- {
- if (inst & (1 << 14))
- {
- /* This is a Form 3 instruction. */
- int opcode = (inst >> 10 & 0xf);
-
- switch (opcode)
- {
- case 0x00: /* beq */
- case 0x01: /* bne */
- case 0x02: /* blt */
- case 0x03: /* bgt */
- case 0x04: /* bltu */
- case 0x05: /* bgtu */
- case 0x06: /* bge */
- case 0x07: /* ble */
- case 0x08: /* bgeu */
- case 0x09: /* bleu */
- /* Do nothing. */
- break;
- default:
- {
- /* Do nothing. */
- break;
- }
- }
- }
- else
- {
- /* This is a Form 2 instruction. */
- int opcode = (inst >> 12 & 0x3);
- switch (opcode)
- {
- case 0x00: /* inc */
- case 0x01: /* dec */
- case 0x02: /* gsr */
- {
- int reg = (inst >> 8) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x03: /* ssr */
- {
- /* Do nothing until GDB learns about moxie's special
- registers. */
- }
- break;
- default:
- /* Do nothing. */
- break;
- }
- }
- }
- else
- {
- /* This is a Form 1 instruction. */
- int opcode = inst >> 8;
- switch (opcode)
- {
- case 0x00: /* nop */
- /* Do nothing. */
- break;
- case 0x01: /* ldi.l (immediate) */
- case 0x02: /* mov (register-to-register) */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x03: /* jsra */
- {
- regcache->raw_read (
- MOXIE_SP_REGNUM, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- if (record_full_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
- || (record_full_arch_list_add_reg (regcache,
- MOXIE_SP_REGNUM))
- || record_full_arch_list_add_mem (tmpu32 - 12, 12))
- return -1;
- }
- break;
- case 0x04: /* ret */
- {
- if (record_full_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
- || (record_full_arch_list_add_reg (regcache,
- MOXIE_SP_REGNUM)))
- return -1;
- }
- break;
- case 0x05: /* add.l */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x06: /* push */
- {
- int reg = (inst >> 4) & 0xf;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- if (record_full_arch_list_add_reg (regcache, reg)
- || record_full_arch_list_add_mem (tmpu32 - 4, 4))
- return -1;
- }
- break;
- case 0x07: /* pop */
- {
- int a = (inst >> 4) & 0xf;
- int b = inst & 0xf;
- if (record_full_arch_list_add_reg (regcache, a)
- || record_full_arch_list_add_reg (regcache, b))
- return -1;
- }
- break;
- case 0x08: /* lda.l */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x09: /* sta.l */
- {
- tmpu32 = (uint32_t) moxie_process_readu (addr+2, buf,
- 4, byte_order);
- if (record_full_arch_list_add_mem (tmpu32, 4))
- return -1;
- }
- break;
- case 0x0a: /* ld.l (register indirect) */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x0b: /* st.l */
- {
- int reg = (inst >> 4) & 0xf;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- if (record_full_arch_list_add_mem (tmpu32, 4))
- return -1;
- }
- break;
- case 0x0c: /* ldo.l */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x0d: /* sto.l */
- {
- int reg = (inst >> 4) & 0xf;
- uint32_t offset = (((int16_t) moxie_process_readu (addr+2, buf, 2,
- byte_order)) << 16 ) >> 16;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- tmpu32 += offset;
- if (record_full_arch_list_add_mem (tmpu32, 4))
- return -1;
- }
- break;
- case 0x0e: /* cmp */
- {
- if (record_full_arch_list_add_reg (regcache, MOXIE_CC_REGNUM))
- return -1;
- }
- break;
- case 0x0f: /* nop */
- {
- /* Do nothing. */
- break;
- }
- case 0x10: /* sex.b */
- case 0x11: /* sex.s */
- case 0x12: /* zex.b */
- case 0x13: /* zex.s */
- case 0x14: /* umul.x */
- case 0x15: /* mul.x */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x16:
- case 0x17:
- case 0x18:
- {
- /* Do nothing. */
- break;
- }
- case 0x19: /* jsr */
- {
- regcache->raw_read (
- MOXIE_SP_REGNUM, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- if (record_full_arch_list_add_reg (regcache, MOXIE_FP_REGNUM)
- || (record_full_arch_list_add_reg (regcache,
- MOXIE_SP_REGNUM))
- || record_full_arch_list_add_mem (tmpu32 - 12, 12))
- return -1;
- }
- break;
- case 0x1a: /* jmpa */
- {
- /* Do nothing. */
- }
- break;
- case 0x1b: /* ldi.b (immediate) */
- case 0x1c: /* ld.b (register indirect) */
- case 0x1d: /* lda.b */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x1e: /* st.b */
- {
- int reg = (inst >> 4) & 0xf;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- if (record_full_arch_list_add_mem (tmpu32, 1))
- return -1;
- }
- break;
- case 0x1f: /* sta.b */
- {
- tmpu32 = moxie_process_readu (addr+2, buf, 4, byte_order);
- if (record_full_arch_list_add_mem (tmpu32, 1))
- return -1;
- }
- break;
- case 0x20: /* ldi.s (immediate) */
- case 0x21: /* ld.s (register indirect) */
- case 0x22: /* lda.s */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x23: /* st.s */
- {
- int reg = (inst >> 4) & 0xf;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- if (record_full_arch_list_add_mem (tmpu32, 2))
- return -1;
- }
- break;
- case 0x24: /* sta.s */
- {
- tmpu32 = moxie_process_readu (addr+2, buf, 4, byte_order);
- if (record_full_arch_list_add_mem (tmpu32, 2))
- return -1;
- }
- break;
- case 0x25: /* jmp */
- {
- /* Do nothing. */
- }
- break;
- case 0x26: /* and */
- case 0x27: /* lshr */
- case 0x28: /* ashl */
- case 0x29: /* sub */
- case 0x2a: /* neg */
- case 0x2b: /* or */
- case 0x2c: /* not */
- case 0x2d: /* ashr */
- case 0x2e: /* xor */
- case 0x2f: /* mul */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x30: /* swi */
- {
- /* We currently implement support for libgloss'
- system calls. */
- int inum = moxie_process_readu (addr+2, buf, 4, byte_order);
- switch (inum)
- {
- case 0x1: /* SYS_exit */
- {
- /* Do nothing. */
- }
- break;
- case 0x2: /* SYS_open */
- {
- if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
- return -1;
- }
- break;
- case 0x4: /* SYS_read */
- {
- uint32_t length, ptr;
- /* Read buffer pointer is in $r1. */
- regcache->raw_read (3, (gdb_byte *) & ptr);
- ptr = extract_unsigned_integer ((gdb_byte *) & ptr,
- 4, byte_order);
- /* String length is at 0x12($fp). */
- regcache->raw_read (
- MOXIE_FP_REGNUM, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- length = moxie_process_readu (tmpu32+20, buf, 4, byte_order);
- if (record_full_arch_list_add_mem (ptr, length))
- return -1;
- }
- break;
- case 0x5: /* SYS_write */
- {
- if (record_full_arch_list_add_reg (regcache, RET1_REGNUM))
- return -1;
- }
- break;
- default:
- break;
- }
- }
- break;
- case 0x31: /* div.l */
- case 0x32: /* udiv.l */
- case 0x33: /* mod.l */
- case 0x34: /* umod.l */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x35: /* brk */
- /* Do nothing. */
- break;
- case 0x36: /* ldo.b */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x37: /* sto.b */
- {
- int reg = (inst >> 4) & 0xf;
- uint32_t offset = (((int16_t) moxie_process_readu (addr+2, buf, 2,
- byte_order)) << 16 ) >> 16;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- tmpu32 += offset;
- if (record_full_arch_list_add_mem (tmpu32, 1))
- return -1;
- }
- break;
- case 0x38: /* ldo.s */
- {
- int reg = (inst >> 4) & 0xf;
- if (record_full_arch_list_add_reg (regcache, reg))
- return -1;
- }
- break;
- case 0x39: /* sto.s */
- {
- int reg = (inst >> 4) & 0xf;
- uint32_t offset = (((int16_t) moxie_process_readu (addr+2, buf, 2,
- byte_order)) << 16 ) >> 16;
- regcache->raw_read (reg, (gdb_byte *) & tmpu32);
- tmpu32 = extract_unsigned_integer ((gdb_byte *) & tmpu32,
- 4, byte_order);
- tmpu32 += offset;
- if (record_full_arch_list_add_mem (tmpu32, 2))
- return -1;
- }
- break;
- default:
- /* Do nothing. */
- break;
- }
- }
- if (record_full_arch_list_add_reg (regcache, MOXIE_PC_REGNUM))
- return -1;
- if (record_full_arch_list_add_end ())
- return -1;
- return 0;
- }
- /* Allocate and initialize the moxie gdbarch object. */
- static struct gdbarch *
- moxie_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
- {
- struct gdbarch *gdbarch;
- /* If there is already a candidate, use it. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return arches->gdbarch;
- /* Allocate space for the new architecture. */
- moxie_gdbarch_tdep *tdep = new moxie_gdbarch_tdep;
- gdbarch = gdbarch_alloc (&info, tdep);
- set_gdbarch_wchar_bit (gdbarch, 32);
- set_gdbarch_wchar_signed (gdbarch, 0);
- set_gdbarch_num_regs (gdbarch, MOXIE_NUM_REGS);
- set_gdbarch_sp_regnum (gdbarch, MOXIE_SP_REGNUM);
- set_gdbarch_pc_regnum (gdbarch, MOXIE_PC_REGNUM);
- set_gdbarch_register_name (gdbarch, moxie_register_name);
- set_gdbarch_register_type (gdbarch, moxie_register_type);
- set_gdbarch_return_value (gdbarch, moxie_return_value);
- set_gdbarch_skip_prologue (gdbarch, moxie_skip_prologue);
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_breakpoint_kind_from_pc (gdbarch,
- moxie_breakpoint::kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch,
- moxie_breakpoint::bp_from_kind);
- set_gdbarch_frame_align (gdbarch, moxie_frame_align);
- frame_base_set_default (gdbarch, &moxie_frame_base);
- /* Hook in ABI-specific overrides, if they have been registered. */
- gdbarch_init_osabi (info, gdbarch);
- /* Hook in the default unwinders. */
- frame_unwind_append_unwinder (gdbarch, &moxie_frame_unwind);
- /* Single stepping. */
- set_gdbarch_software_single_step (gdbarch, moxie_software_single_step);
- /* Support simple overlay manager. */
- set_gdbarch_overlay_update (gdbarch, simple_overlay_update);
- /* Support reverse debugging. */
- set_gdbarch_process_record (gdbarch, moxie_process_record);
- return gdbarch;
- }
- /* Register this machine's init routine. */
- void _initialize_moxie_tdep ();
- void
- _initialize_moxie_tdep ()
- {
- register_gdbarch_init (bfd_arch_moxie, moxie_gdbarch_init);
- }
|