123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100 |
- /* Target-dependent code for the NDS32 architecture, for GDB.
- Copyright (C) 2013-2022 Free Software Foundation, Inc.
- Contributed by Andes Technology Corporation.
- 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 "gdbcore.h"
- #include "value.h"
- #include "reggroups.h"
- #include "inferior.h"
- #include "osabi.h"
- #include "arch-utils.h"
- #include "regcache.h"
- #include "dis-asm.h"
- #include "user-regs.h"
- #include "elf-bfd.h"
- #include "dwarf2/frame.h"
- #include "remote.h"
- #include "target-descriptions.h"
- #include "nds32-tdep.h"
- #include "elf/nds32.h"
- #include "opcode/nds32.h"
- #include <algorithm>
- #include "features/nds32.c"
- /* Simple macros for instruction analysis. */
- #define CHOP_BITS(insn, n) (insn & ~__MASK (n))
- #define N32_LSMW_ENABLE4(insn) (((insn) >> 6) & 0xf)
- #define N32_SMW_ADM \
- N32_TYPE4 (LSMW, 0, 0, 0, 1, (N32_LSMW_ADM << 2) | N32_LSMW_LSMW)
- #define N32_LMW_BIM \
- N32_TYPE4 (LSMW, 0, 0, 0, 0, (N32_LSMW_BIM << 2) | N32_LSMW_LSMW)
- #define N32_FLDI_SP \
- N32_TYPE2 (LDC, 0, REG_SP, 0)
- /* Use an invalid address value as 'not available' marker. */
- enum { REG_UNAVAIL = (CORE_ADDR) -1 };
- /* Use an impossible value as invalid offset. */
- enum { INVALID_OFFSET = (CORE_ADDR) -1 };
- /* Instruction groups for NDS32 epilogue analysis. */
- enum
- {
- /* Instructions used everywhere, not only in epilogue. */
- INSN_NORMAL,
- /* Instructions used to reset sp for local vars, arguments, etc. */
- INSN_RESET_SP,
- /* Instructions used to recover saved regs and to recover padding. */
- INSN_RECOVER,
- /* Instructions used to return to the caller. */
- INSN_RETURN,
- /* Instructions used to recover saved regs and to return to the caller. */
- INSN_RECOVER_RETURN,
- };
- static const char *const nds32_register_names[] =
- {
- /* 32 GPRs. */
- "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
- "r24", "r25", "r26", "r27", "fp", "gp", "lp", "sp",
- /* PC. */
- "pc",
- };
- static const char *const nds32_fdr_register_names[] =
- {
- "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7",
- "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15",
- "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23",
- "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31"
- };
- static const char *const nds32_fsr_register_names[] =
- {
- "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
- "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15",
- "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23",
- "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31"
- };
- /* The number of registers for four FPU configuration options. */
- const int num_fdr_map[] = { 4, 8, 16, 32 };
- const int num_fsr_map[] = { 8, 16, 32, 32 };
- /* Aliases for registers. */
- static const struct
- {
- const char *name;
- const char *alias;
- } nds32_register_aliases[] =
- {
- {"r15", "ta"},
- {"r26", "p0"},
- {"r27", "p1"},
- {"fp", "r28"},
- {"gp", "r29"},
- {"lp", "r30"},
- {"sp", "r31"},
- {"cr0", "cpu_ver"},
- {"cr1", "icm_cfg"},
- {"cr2", "dcm_cfg"},
- {"cr3", "mmu_cfg"},
- {"cr4", "msc_cfg"},
- {"cr5", "core_id"},
- {"cr6", "fucop_exist"},
- {"cr7", "msc_cfg2"},
- {"ir0", "psw"},
- {"ir1", "ipsw"},
- {"ir2", "p_psw"},
- {"ir3", "ivb"},
- {"ir4", "eva"},
- {"ir5", "p_eva"},
- {"ir6", "itype"},
- {"ir7", "p_itype"},
- {"ir8", "merr"},
- {"ir9", "ipc"},
- {"ir10", "p_ipc"},
- {"ir11", "oipc"},
- {"ir12", "p_p0"},
- {"ir13", "p_p1"},
- {"ir14", "int_mask"},
- {"ir15", "int_pend"},
- {"ir16", "sp_usr"},
- {"ir17", "sp_priv"},
- {"ir18", "int_pri"},
- {"ir19", "int_ctrl"},
- {"ir20", "sp_usr1"},
- {"ir21", "sp_priv1"},
- {"ir22", "sp_usr2"},
- {"ir23", "sp_priv2"},
- {"ir24", "sp_usr3"},
- {"ir25", "sp_priv3"},
- {"ir26", "int_mask2"},
- {"ir27", "int_pend2"},
- {"ir28", "int_pri2"},
- {"ir29", "int_trigger"},
- {"mr0", "mmu_ctl"},
- {"mr1", "l1_pptb"},
- {"mr2", "tlb_vpn"},
- {"mr3", "tlb_data"},
- {"mr4", "tlb_misc"},
- {"mr5", "vlpt_idx"},
- {"mr6", "ilmb"},
- {"mr7", "dlmb"},
- {"mr8", "cache_ctl"},
- {"mr9", "hsmp_saddr"},
- {"mr10", "hsmp_eaddr"},
- {"mr11", "bg_region"},
- {"dr0", "bpc0"},
- {"dr1", "bpc1"},
- {"dr2", "bpc2"},
- {"dr3", "bpc3"},
- {"dr4", "bpc4"},
- {"dr5", "bpc5"},
- {"dr6", "bpc6"},
- {"dr7", "bpc7"},
- {"dr8", "bpa0"},
- {"dr9", "bpa1"},
- {"dr10", "bpa2"},
- {"dr11", "bpa3"},
- {"dr12", "bpa4"},
- {"dr13", "bpa5"},
- {"dr14", "bpa6"},
- {"dr15", "bpa7"},
- {"dr16", "bpam0"},
- {"dr17", "bpam1"},
- {"dr18", "bpam2"},
- {"dr19", "bpam3"},
- {"dr20", "bpam4"},
- {"dr21", "bpam5"},
- {"dr22", "bpam6"},
- {"dr23", "bpam7"},
- {"dr24", "bpv0"},
- {"dr25", "bpv1"},
- {"dr26", "bpv2"},
- {"dr27", "bpv3"},
- {"dr28", "bpv4"},
- {"dr29", "bpv5"},
- {"dr30", "bpv6"},
- {"dr31", "bpv7"},
- {"dr32", "bpcid0"},
- {"dr33", "bpcid1"},
- {"dr34", "bpcid2"},
- {"dr35", "bpcid3"},
- {"dr36", "bpcid4"},
- {"dr37", "bpcid5"},
- {"dr38", "bpcid6"},
- {"dr39", "bpcid7"},
- {"dr40", "edm_cfg"},
- {"dr41", "edmsw"},
- {"dr42", "edm_ctl"},
- {"dr43", "edm_dtr"},
- {"dr44", "bpmtc"},
- {"dr45", "dimbr"},
- {"dr46", "tecr0"},
- {"dr47", "tecr1"},
- {"hspr0", "hsp_ctl"},
- {"hspr1", "sp_bound"},
- {"hspr2", "sp_bound_priv"},
- {"pfr0", "pfmc0"},
- {"pfr1", "pfmc1"},
- {"pfr2", "pfmc2"},
- {"pfr3", "pfm_ctl"},
- {"pfr4", "pft_ctl"},
- {"dmar0", "dma_cfg"},
- {"dmar1", "dma_gcsw"},
- {"dmar2", "dma_chnsel"},
- {"dmar3", "dma_act"},
- {"dmar4", "dma_setup"},
- {"dmar5", "dma_isaddr"},
- {"dmar6", "dma_esaddr"},
- {"dmar7", "dma_tcnt"},
- {"dmar8", "dma_status"},
- {"dmar9", "dma_2dset"},
- {"dmar10", "dma_2dsctl"},
- {"dmar11", "dma_rcnt"},
- {"dmar12", "dma_hstatus"},
- {"racr0", "prusr_acc_ctl"},
- {"fucpr", "fucop_ctl"},
- {"idr0", "sdz_ctl"},
- {"idr1", "misc_ctl"},
- {"idr2", "ecc_misc"},
- {"secur0", "sfcr"},
- {"secur1", "sign"},
- {"secur2", "isign"},
- {"secur3", "p_isign"},
- };
- /* Value of a register alias. BATON is the regnum of the corresponding
- register. */
- static struct value *
- value_of_nds32_reg (struct frame_info *frame, const void *baton)
- {
- return value_of_register ((int) (intptr_t) baton, frame);
- }
- /* Implement the "frame_align" gdbarch method. */
- static CORE_ADDR
- nds32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
- {
- /* 8-byte aligned. */
- return align_down (sp, 8);
- }
- /* The same insn machine code is used for little-endian and big-endian. */
- constexpr gdb_byte nds32_break_insn[] = { 0xEA, 0x00 };
- typedef BP_MANIPULATION (nds32_break_insn) nds32_breakpoint;
- /* Implement the "dwarf2_reg_to_regnum" gdbarch method. */
- static int
- nds32_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
- {
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- const int FSR = 38;
- const int FDR = FSR + 32;
- if (num >= 0 && num < 32)
- {
- /* General-purpose registers (R0 - R31). */
- return num;
- }
- else if (num >= FSR && num < FSR + 32)
- {
- /* Single precision floating-point registers (FS0 - FS31). */
- return num - FSR + tdep->fs0_regnum;
- }
- else if (num >= FDR && num < FDR + 32)
- {
- /* Double precision floating-point registers (FD0 - FD31). */
- return num - FDR + NDS32_FD0_REGNUM;
- }
- /* No match, return a inaccessible register number. */
- return -1;
- }
- /* NDS32 register groups. */
- static const reggroup *nds32_cr_reggroup;
- static const reggroup *nds32_ir_reggroup;
- static const reggroup *nds32_mr_reggroup;
- static const reggroup *nds32_dr_reggroup;
- static const reggroup *nds32_pfr_reggroup;
- static const reggroup *nds32_hspr_reggroup;
- static const reggroup *nds32_dmar_reggroup;
- static const reggroup *nds32_racr_reggroup;
- static const reggroup *nds32_idr_reggroup;
- static const reggroup *nds32_secur_reggroup;
- static void
- nds32_init_reggroups (void)
- {
- nds32_cr_reggroup = reggroup_new ("cr", USER_REGGROUP);
- nds32_ir_reggroup = reggroup_new ("ir", USER_REGGROUP);
- nds32_mr_reggroup = reggroup_new ("mr", USER_REGGROUP);
- nds32_dr_reggroup = reggroup_new ("dr", USER_REGGROUP);
- nds32_pfr_reggroup = reggroup_new ("pfr", USER_REGGROUP);
- nds32_hspr_reggroup = reggroup_new ("hspr", USER_REGGROUP);
- nds32_dmar_reggroup = reggroup_new ("dmar", USER_REGGROUP);
- nds32_racr_reggroup = reggroup_new ("racr", USER_REGGROUP);
- nds32_idr_reggroup = reggroup_new ("idr", USER_REGGROUP);
- nds32_secur_reggroup = reggroup_new ("secur", USER_REGGROUP);
- }
- static void
- nds32_add_reggroups (struct gdbarch *gdbarch)
- {
- /* Add NDS32 register groups. */
- reggroup_add (gdbarch, nds32_cr_reggroup);
- reggroup_add (gdbarch, nds32_ir_reggroup);
- reggroup_add (gdbarch, nds32_mr_reggroup);
- reggroup_add (gdbarch, nds32_dr_reggroup);
- reggroup_add (gdbarch, nds32_pfr_reggroup);
- reggroup_add (gdbarch, nds32_hspr_reggroup);
- reggroup_add (gdbarch, nds32_dmar_reggroup);
- reggroup_add (gdbarch, nds32_racr_reggroup);
- reggroup_add (gdbarch, nds32_idr_reggroup);
- reggroup_add (gdbarch, nds32_secur_reggroup);
- }
- /* Implement the "register_reggroup_p" gdbarch method. */
- static int
- nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
- const struct reggroup *reggroup)
- {
- const char *reg_name;
- const char *group_name;
- int ret;
- if (reggroup == all_reggroup)
- return 1;
- /* General reggroup contains only GPRs and PC. */
- if (reggroup == general_reggroup)
- return regnum <= NDS32_PC_REGNUM;
- if (reggroup == float_reggroup || reggroup == save_reggroup
- || reggroup == restore_reggroup)
- {
- ret = tdesc_register_in_reggroup_p (gdbarch, regnum, reggroup);
- if (ret != -1)
- return ret;
- return default_register_reggroup_p (gdbarch, regnum, reggroup);
- }
- if (reggroup == system_reggroup)
- return (regnum > NDS32_PC_REGNUM)
- && !nds32_register_reggroup_p (gdbarch, regnum, float_reggroup);
- /* The NDS32 reggroup contains registers whose name is prefixed
- by reggroup name. */
- reg_name = gdbarch_register_name (gdbarch, regnum);
- group_name = reggroup->name ();
- return !strncmp (reg_name, group_name, strlen (group_name));
- }
- /* Implement the "pseudo_register_type" tdesc_arch_data method. */
- static struct type *
- nds32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
- {
- regnum -= gdbarch_num_regs (gdbarch);
- /* Currently, only FSRs could be defined as pseudo registers. */
- if (regnum < gdbarch_num_pseudo_regs (gdbarch))
- return arch_float_type (gdbarch, -1, "builtin_type_ieee_single",
- floatformats_ieee_single);
- warning (_("Unknown nds32 pseudo register %d."), regnum);
- return NULL;
- }
- /* Implement the "pseudo_register_name" tdesc_arch_data method. */
- static const char *
- nds32_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
- {
- regnum -= gdbarch_num_regs (gdbarch);
- /* Currently, only FSRs could be defined as pseudo registers. */
- if (regnum < gdbarch_num_pseudo_regs (gdbarch))
- return nds32_fsr_register_names[regnum];
- warning (_("Unknown nds32 pseudo register %d."), regnum);
- return NULL;
- }
- /* Implement the "pseudo_register_read" gdbarch method. */
- static enum register_status
- nds32_pseudo_register_read (struct gdbarch *gdbarch,
- readable_regcache *regcache, int regnum,
- gdb_byte *buf)
- {
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- gdb_byte reg_buf[8];
- int offset, fdr_regnum;
- enum register_status status;
- /* This function is registered in nds32_gdbarch_init only after these are
- set. */
- gdb_assert (tdep->fpu_freg != -1);
- gdb_assert (tdep->use_pseudo_fsrs != 0);
- regnum -= gdbarch_num_regs (gdbarch);
- /* Currently, only FSRs could be defined as pseudo registers. */
- if (regnum < gdbarch_num_pseudo_regs (gdbarch))
- {
- /* fs0 is always the most significant half of fd0. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- offset = (regnum & 1) ? 4 : 0;
- else
- offset = (regnum & 1) ? 0 : 4;
- fdr_regnum = NDS32_FD0_REGNUM + (regnum >> 1);
- status = regcache->raw_read (fdr_regnum, reg_buf);
- if (status == REG_VALID)
- memcpy (buf, reg_buf + offset, 4);
- return status;
- }
- gdb_assert_not_reached ("invalid pseudo register number");
- }
- /* Implement the "pseudo_register_write" gdbarch method. */
- static void
- nds32_pseudo_register_write (struct gdbarch *gdbarch,
- struct regcache *regcache, int regnum,
- const gdb_byte *buf)
- {
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- gdb_byte reg_buf[8];
- int offset, fdr_regnum;
- /* This function is registered in nds32_gdbarch_init only after these are
- set. */
- gdb_assert (tdep->fpu_freg != -1);
- gdb_assert (tdep->use_pseudo_fsrs != 0);
- regnum -= gdbarch_num_regs (gdbarch);
- /* Currently, only FSRs could be defined as pseudo registers. */
- if (regnum < gdbarch_num_pseudo_regs (gdbarch))
- {
- /* fs0 is always the most significant half of fd0. */
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- offset = (regnum & 1) ? 4 : 0;
- else
- offset = (regnum & 1) ? 0 : 4;
- fdr_regnum = NDS32_FD0_REGNUM + (regnum >> 1);
- regcache->raw_read (fdr_regnum, reg_buf);
- memcpy (reg_buf + offset, buf, 4);
- regcache->raw_write (fdr_regnum, reg_buf);
- return;
- }
- gdb_assert_not_reached ("invalid pseudo register number");
- }
- /* Helper function for NDS32 ABI. Return true if FPRs can be used
- to pass function arguments and return value. */
- static int
- nds32_abi_use_fpr (int elf_abi)
- {
- return elf_abi == E_NDS_ABI_V2FP_PLUS;
- }
- /* Helper function for NDS32 ABI. Return true if GPRs and stack
- can be used together to pass an argument. */
- static int
- nds32_abi_split (int elf_abi)
- {
- return elf_abi == E_NDS_ABI_AABI;
- }
- #define NDS32_NUM_SAVED_REGS (NDS32_LP_REGNUM + 1)
- struct nds32_frame_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;
- /* During prologue analysis, keep how far the SP and FP have been offset
- from the start of the stack frame (as defined by the previous frame's
- stack pointer).
- During epilogue analysis, keep how far the SP has been offset from the
- current stack pointer. */
- CORE_ADDR sp_offset;
- CORE_ADDR fp_offset;
- /* The address of the first instruction in this function. */
- CORE_ADDR pc;
- /* Saved registers. */
- CORE_ADDR saved_regs[NDS32_NUM_SAVED_REGS];
- };
- /* Allocate and initialize a frame cache. */
- static struct nds32_frame_cache *
- nds32_alloc_frame_cache (void)
- {
- struct nds32_frame_cache *cache;
- int i;
- cache = FRAME_OBSTACK_ZALLOC (struct nds32_frame_cache);
- /* Initialize fp_offset to check if FP is set in prologue. */
- cache->fp_offset = INVALID_OFFSET;
- /* Saved registers. We initialize these to -1 since zero is a valid
- offset. */
- for (i = 0; i < NDS32_NUM_SAVED_REGS; i++)
- cache->saved_regs[i] = REG_UNAVAIL;
- return cache;
- }
- /* Helper function for instructions used to push multiple words. */
- static void
- nds32_push_multiple_words (struct nds32_frame_cache *cache, int rb, int re,
- int enable4)
- {
- CORE_ADDR sp_offset = cache->sp_offset;
- int i;
- /* Check LP, GP, FP in enable4. */
- for (i = 1; i <= 3; i++)
- {
- if ((enable4 >> i) & 0x1)
- {
- sp_offset += 4;
- cache->saved_regs[NDS32_SP_REGNUM - i] = sp_offset;
- }
- }
- /* Skip case where re == rb == sp. */
- if ((rb < REG_FP) && (re < REG_FP))
- {
- for (i = re; i >= rb; i--)
- {
- sp_offset += 4;
- cache->saved_regs[i] = sp_offset;
- }
- }
- /* For sp, update the offset. */
- cache->sp_offset = sp_offset;
- }
- /* Analyze the instructions within the given address range. If CACHE
- is non-NULL, fill it in. Return the first address beyond the given
- address range. If CACHE is NULL, return the first address not
- recognized as a prologue instruction. */
- static CORE_ADDR
- nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc,
- CORE_ADDR limit_pc, struct nds32_frame_cache *cache)
- {
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int abi_use_fpr = nds32_abi_use_fpr (tdep->elf_abi);
- /* Current scanning status. */
- int in_prologue_bb = 0;
- int val_ta = 0;
- uint32_t insn, insn_len;
- for (; pc < limit_pc; pc += insn_len)
- {
- insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
- if ((insn & 0x80000000) == 0)
- {
- /* 32-bit instruction */
- insn_len = 4;
- if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_SP, 0))
- {
- /* addi $sp, $sp, imm15s */
- int imm15s = N32_IMM15S (insn);
- if (imm15s < 0)
- {
- if (cache != NULL)
- cache->sp_offset += -imm15s;
- in_prologue_bb = 1;
- continue;
- }
- }
- else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_FP, REG_SP, 0))
- {
- /* addi $fp, $sp, imm15s */
- int imm15s = N32_IMM15S (insn);
- if (imm15s > 0)
- {
- if (cache != NULL)
- cache->fp_offset = cache->sp_offset - imm15s;
- in_prologue_bb = 1;
- continue;
- }
- }
- else if ((insn & ~(__MASK (19) << 6)) == N32_SMW_ADM
- && N32_RA5 (insn) == REG_SP)
- {
- /* smw.adm Rb, [$sp], Re, enable4 */
- if (cache != NULL)
- nds32_push_multiple_words (cache, N32_RT5 (insn),
- N32_RB5 (insn),
- N32_LSMW_ENABLE4 (insn));
- in_prologue_bb = 1;
- continue;
- }
- else if (insn == N32_ALU1 (ADD, REG_SP, REG_SP, REG_TA)
- || insn == N32_ALU1 (ADD, REG_SP, REG_TA, REG_SP))
- {
- /* add $sp, $sp, $ta */
- /* add $sp, $ta, $sp */
- if (val_ta < 0)
- {
- if (cache != NULL)
- cache->sp_offset += -val_ta;
- in_prologue_bb = 1;
- continue;
- }
- }
- else if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_TA, 0))
- {
- /* movi $ta, imm20s */
- if (cache != NULL)
- val_ta = N32_IMM20S (insn);
- continue;
- }
- else if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_TA, 0))
- {
- /* sethi $ta, imm20u */
- if (cache != NULL)
- val_ta = N32_IMM20U (insn) << 12;
- continue;
- }
- else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_TA, REG_TA, 0))
- {
- /* ori $ta, $ta, imm15u */
- if (cache != NULL)
- val_ta |= N32_IMM15U (insn);
- continue;
- }
- else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_TA, REG_TA, 0))
- {
- /* addi $ta, $ta, imm15s */
- if (cache != NULL)
- val_ta += N32_IMM15S (insn);
- continue;
- }
- if (insn == N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP)
- || insn == N32_ALU1 (ADD, REG_GP, REG_GP, REG_TA))
- {
- /* add $gp, $ta, $gp */
- /* add $gp, $gp, $ta */
- in_prologue_bb = 1;
- continue;
- }
- else if (CHOP_BITS (insn, 20) == N32_TYPE1 (MOVI, REG_GP, 0))
- {
- /* movi $gp, imm20s */
- in_prologue_bb = 1;
- continue;
- }
- else if (CHOP_BITS (insn, 20) == N32_TYPE1 (SETHI, REG_GP, 0))
- {
- /* sethi $gp, imm20u */
- in_prologue_bb = 1;
- continue;
- }
- else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ORI, REG_GP, REG_GP, 0))
- {
- /* ori $gp, $gp, imm15u */
- in_prologue_bb = 1;
- continue;
- }
- else
- {
- /* Jump/Branch insns never appear in prologue basic block.
- The loop can be escaped early when these insns are met. */
- if (in_prologue_bb == 1)
- {
- int op = N32_OP6 (insn);
- if (op == N32_OP6_JI
- || op == N32_OP6_JREG
- || op == N32_OP6_BR1
- || op == N32_OP6_BR2
- || op == N32_OP6_BR3)
- break;
- }
- }
- if (abi_use_fpr && N32_OP6 (insn) == N32_OP6_SDC
- && __GF (insn, 12, 3) == 0)
- {
- /* For FPU insns, CP (bit [13:14]) should be CP0, and only
- normal form (bit [12] == 0) is used. */
- /* fsdi FDt, [$sp + (imm12s << 2)] */
- if (N32_RA5 (insn) == REG_SP)
- continue;
- }
- /* The optimizer might shove anything into the prologue, if
- we build up cache (cache != NULL) from analyzing prologue,
- we just skip what we don't recognize and analyze further to
- make cache as complete as possible. However, if we skip
- prologue, we'll stop immediately on unrecognized
- instruction. */
- if (cache == NULL)
- break;
- }
- else
- {
- /* 16-bit instruction */
- insn_len = 2;
- insn >>= 16;
- if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
- {
- /* addi10s.sp */
- int imm10s = N16_IMM10S (insn);
- if (imm10s < 0)
- {
- if (cache != NULL)
- cache->sp_offset += -imm10s;
- in_prologue_bb = 1;
- continue;
- }
- }
- else if (__GF (insn, 7, 8) == N16_T25_PUSH25)
- {
- /* push25 */
- if (cache != NULL)
- {
- int imm8u = (insn & 0x1f) << 3;
- int re = (insn >> 5) & 0x3;
- const int reg_map[] = { 6, 8, 10, 14 };
- /* Operation 1 -- smw.adm R6, [$sp], Re, #0xe */
- nds32_push_multiple_words (cache, 6, reg_map[re], 0xe);
- /* Operation 2 -- sp = sp - (imm5u << 3) */
- cache->sp_offset += imm8u;
- }
- in_prologue_bb = 1;
- continue;
- }
- else if (insn == N16_TYPE5 (ADD5PC, REG_GP))
- {
- /* add5.pc $gp */
- in_prologue_bb = 1;
- continue;
- }
- else if (CHOP_BITS (insn, 5) == N16_TYPE55 (MOVI55, REG_GP, 0))
- {
- /* movi55 $gp, imm5s */
- in_prologue_bb = 1;
- continue;
- }
- else
- {
- /* Jump/Branch insns never appear in prologue basic block.
- The loop can be escaped early when these insns are met. */
- if (in_prologue_bb == 1)
- {
- uint32_t insn5 = CHOP_BITS (insn, 5);
- uint32_t insn8 = CHOP_BITS (insn, 8);
- uint32_t insn38 = CHOP_BITS (insn, 11);
- if (insn5 == N16_TYPE5 (JR5, 0)
- || insn5 == N16_TYPE5 (JRAL5, 0)
- || insn5 == N16_TYPE5 (RET5, 0)
- || insn8 == N16_TYPE8 (J8, 0)
- || insn8 == N16_TYPE8 (BEQZS8, 0)
- || insn8 == N16_TYPE8 (BNEZS8, 0)
- || insn38 == N16_TYPE38 (BEQZ38, 0, 0)
- || insn38 == N16_TYPE38 (BNEZ38, 0, 0)
- || insn38 == N16_TYPE38 (BEQS38, 0, 0)
- || insn38 == N16_TYPE38 (BNES38, 0, 0))
- break;
- }
- }
- /* The optimizer might shove anything into the prologue, if
- we build up cache (cache != NULL) from analyzing prologue,
- we just skip what we don't recognize and analyze further to
- make cache as complete as possible. However, if we skip
- prologue, we'll stop immediately on unrecognized
- instruction. */
- if (cache == NULL)
- break;
- }
- }
- return pc;
- }
- /* Implement the "skip_prologue" gdbarch method.
- Find the end of function prologue. */
- static CORE_ADDR
- nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
- {
- CORE_ADDR func_addr, limit_pc;
- /* 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, NULL, &func_addr, NULL))
- {
- CORE_ADDR post_prologue_pc
- = skip_prologue_using_sal (gdbarch, func_addr);
- if (post_prologue_pc != 0)
- return std::max (pc, post_prologue_pc);
- }
- /* Can't determine prologue from the symbol table, need to examine
- instructions. */
- /* Find an upper limit on the function prologue using the debug
- information. If the debug information could not be used to provide
- that bound, then use an arbitrary large number as the upper bound. */
- limit_pc = skip_prologue_using_sal (gdbarch, pc);
- if (limit_pc == 0)
- limit_pc = pc + 128; /* Magic. */
- /* Find the end of prologue. */
- return nds32_analyze_prologue (gdbarch, pc, limit_pc, NULL);
- }
- /* Allocate and fill in *THIS_CACHE with information about the prologue of
- *THIS_FRAME. Do not do this if *THIS_CACHE was already allocated. Return
- a pointer to the current nds32_frame_cache in *THIS_CACHE. */
- static struct nds32_frame_cache *
- nds32_frame_cache (struct frame_info *this_frame, void **this_cache)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct nds32_frame_cache *cache;
- CORE_ADDR current_pc;
- ULONGEST prev_sp;
- ULONGEST this_base;
- int i;
- if (*this_cache)
- return (struct nds32_frame_cache *) *this_cache;
- cache = nds32_alloc_frame_cache ();
- *this_cache = cache;
- cache->pc = get_frame_func (this_frame);
- current_pc = get_frame_pc (this_frame);
- nds32_analyze_prologue (gdbarch, cache->pc, current_pc, cache);
- /* Compute the previous frame's stack pointer (which is also the
- frame's ID's stack address), and this frame's base pointer. */
- if (cache->fp_offset != INVALID_OFFSET)
- {
- /* FP is set in prologue, so it can be used to calculate other info. */
- this_base = get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM);
- prev_sp = this_base + cache->fp_offset;
- }
- else
- {
- this_base = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
- prev_sp = this_base + cache->sp_offset;
- }
- cache->prev_sp = prev_sp;
- cache->base = this_base;
- /* Adjust all the saved registers such that they contain addresses
- instead of offsets. */
- for (i = 0; i < NDS32_NUM_SAVED_REGS; i++)
- if (cache->saved_regs[i] != REG_UNAVAIL)
- cache->saved_regs[i] = cache->prev_sp - cache->saved_regs[i];
- return cache;
- }
- /* Implement the "this_id" frame_unwind method.
- Our frame ID for a normal frame is the current function's starting
- PC and the caller's SP when we were called. */
- static void
- nds32_frame_this_id (struct frame_info *this_frame,
- void **this_cache, struct frame_id *this_id)
- {
- struct nds32_frame_cache *cache = nds32_frame_cache (this_frame, this_cache);
- /* This marks the outermost frame. */
- if (cache->prev_sp == 0)
- return;
- *this_id = frame_id_build (cache->prev_sp, cache->pc);
- }
- /* Implement the "prev_register" frame_unwind method. */
- static struct value *
- nds32_frame_prev_register (struct frame_info *this_frame, void **this_cache,
- int regnum)
- {
- struct nds32_frame_cache *cache = nds32_frame_cache (this_frame, this_cache);
- if (regnum == NDS32_SP_REGNUM)
- return frame_unwind_got_constant (this_frame, regnum, cache->prev_sp);
- /* The PC of the previous frame is stored in the LP register of
- the current frame. */
- if (regnum == NDS32_PC_REGNUM)
- regnum = NDS32_LP_REGNUM;
- if (regnum < NDS32_NUM_SAVED_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 nds32_frame_unwind =
- {
- "nds32 prologue",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- nds32_frame_this_id,
- nds32_frame_prev_register,
- NULL,
- default_frame_sniffer,
- };
- /* Return the frame base address of *THIS_FRAME. */
- static CORE_ADDR
- nds32_frame_base_address (struct frame_info *this_frame, void **this_cache)
- {
- struct nds32_frame_cache *cache = nds32_frame_cache (this_frame, this_cache);
- return cache->base;
- }
- static const struct frame_base nds32_frame_base =
- {
- &nds32_frame_unwind,
- nds32_frame_base_address,
- nds32_frame_base_address,
- nds32_frame_base_address
- };
- /* Helper function for instructions used to pop multiple words. */
- static void
- nds32_pop_multiple_words (struct nds32_frame_cache *cache, int rb, int re,
- int enable4)
- {
- CORE_ADDR sp_offset = cache->sp_offset;
- int i;
- /* Skip case where re == rb == sp. */
- if ((rb < REG_FP) && (re < REG_FP))
- {
- for (i = rb; i <= re; i++)
- {
- cache->saved_regs[i] = sp_offset;
- sp_offset += 4;
- }
- }
- /* Check FP, GP, LP in enable4. */
- for (i = 3; i >= 1; i--)
- {
- if ((enable4 >> i) & 0x1)
- {
- cache->saved_regs[NDS32_SP_REGNUM - i] = sp_offset;
- sp_offset += 4;
- }
- }
- /* For sp, update the offset. */
- cache->sp_offset = sp_offset;
- }
- /* The instruction sequences in NDS32 epilogue are
- INSN_RESET_SP (optional)
- (If exists, this must be the first instruction in epilogue
- and the stack has not been destroyed.).
- INSN_RECOVER (optional).
- INSN_RETURN/INSN_RECOVER_RETURN (required). */
- /* Helper function for analyzing the given 32-bit INSN. If CACHE is non-NULL,
- the necessary information will be recorded. */
- static inline int
- nds32_analyze_epilogue_insn32 (int abi_use_fpr, uint32_t insn,
- struct nds32_frame_cache *cache)
- {
- if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_SP, 0)
- && N32_IMM15S (insn) > 0)
- /* addi $sp, $sp, imm15s */
- return INSN_RESET_SP;
- else if (CHOP_BITS (insn, 15) == N32_TYPE2 (ADDI, REG_SP, REG_FP, 0)
- && N32_IMM15S (insn) < 0)
- /* addi $sp, $fp, imm15s */
- return INSN_RESET_SP;
- else if ((insn & ~(__MASK (19) << 6)) == N32_LMW_BIM
- && N32_RA5 (insn) == REG_SP)
- {
- /* lmw.bim Rb, [$sp], Re, enable4 */
- if (cache != NULL)
- nds32_pop_multiple_words (cache, N32_RT5 (insn),
- N32_RB5 (insn), N32_LSMW_ENABLE4 (insn));
- return INSN_RECOVER;
- }
- else if (insn == N32_JREG (JR, 0, REG_LP, 0, 1))
- /* ret $lp */
- return INSN_RETURN;
- else if (insn == N32_ALU1 (ADD, REG_SP, REG_SP, REG_TA)
- || insn == N32_ALU1 (ADD, REG_SP, REG_TA, REG_SP))
- /* add $sp, $sp, $ta */
- /* add $sp, $ta, $sp */
- return INSN_RESET_SP;
- else if (abi_use_fpr
- && (insn & ~(__MASK (5) << 20 | __MASK (13))) == N32_FLDI_SP)
- {
- if (__GF (insn, 12, 1) == 0)
- /* fldi FDt, [$sp + (imm12s << 2)] */
- return INSN_RECOVER;
- else
- {
- /* fldi.bi FDt, [$sp], (imm12s << 2) */
- int offset = N32_IMM12S (insn) << 2;
- if (offset == 8 || offset == 12)
- {
- if (cache != NULL)
- cache->sp_offset += offset;
- return INSN_RECOVER;
- }
- }
- }
- return INSN_NORMAL;
- }
- /* Helper function for analyzing the given 16-bit INSN. If CACHE is non-NULL,
- the necessary information will be recorded. */
- static inline int
- nds32_analyze_epilogue_insn16 (uint32_t insn, struct nds32_frame_cache *cache)
- {
- if (insn == N16_TYPE5 (RET5, REG_LP))
- /* ret5 $lp */
- return INSN_RETURN;
- else if (CHOP_BITS (insn, 10) == N16_TYPE10 (ADDI10S, 0))
- {
- /* addi10s.sp */
- int imm10s = N16_IMM10S (insn);
- if (imm10s > 0)
- {
- if (cache != NULL)
- cache->sp_offset += imm10s;
- return INSN_RECOVER;
- }
- }
- else if (__GF (insn, 7, 8) == N16_T25_POP25)
- {
- /* pop25 */
- if (cache != NULL)
- {
- int imm8u = (insn & 0x1f) << 3;
- int re = (insn >> 5) & 0x3;
- const int reg_map[] = { 6, 8, 10, 14 };
- /* Operation 1 -- sp = sp + (imm5u << 3) */
- cache->sp_offset += imm8u;
- /* Operation 2 -- lmw.bim R6, [$sp], Re, #0xe */
- nds32_pop_multiple_words (cache, 6, reg_map[re], 0xe);
- }
- /* Operation 3 -- ret $lp */
- return INSN_RECOVER_RETURN;
- }
- return INSN_NORMAL;
- }
- /* Analyze a reasonable amount of instructions from the given PC to find
- the instruction used to return to the caller. Return 1 if the 'return'
- instruction could be found, 0 otherwise.
- If CACHE is non-NULL, fill it in. */
- static int
- nds32_analyze_epilogue (struct gdbarch *gdbarch, CORE_ADDR pc,
- struct nds32_frame_cache *cache)
- {
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int abi_use_fpr = nds32_abi_use_fpr (tdep->elf_abi);
- CORE_ADDR limit_pc;
- uint32_t insn, insn_len;
- int insn_type = INSN_NORMAL;
- if (abi_use_fpr)
- limit_pc = pc + 48;
- else
- limit_pc = pc + 16;
- for (; pc < limit_pc; pc += insn_len)
- {
- insn = read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
- if ((insn & 0x80000000) == 0)
- {
- /* 32-bit instruction */
- insn_len = 4;
- insn_type = nds32_analyze_epilogue_insn32 (abi_use_fpr, insn, cache);
- if (insn_type == INSN_RETURN)
- return 1;
- else if (insn_type == INSN_RECOVER)
- continue;
- }
- else
- {
- /* 16-bit instruction */
- insn_len = 2;
- insn >>= 16;
- insn_type = nds32_analyze_epilogue_insn16 (insn, cache);
- if (insn_type == INSN_RETURN || insn_type == INSN_RECOVER_RETURN)
- return 1;
- else if (insn_type == INSN_RECOVER)
- continue;
- }
- /* Stop the scan if this is an unexpected instruction. */
- break;
- }
- return 0;
- }
- /* Implement the "stack_frame_destroyed_p" gdbarch method. */
- static int
- nds32_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR addr)
- {
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int abi_use_fpr = nds32_abi_use_fpr (tdep->elf_abi);
- int insn_type = INSN_NORMAL;
- int ret_found = 0;
- uint32_t insn;
- insn = read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG);
- if ((insn & 0x80000000) == 0)
- {
- /* 32-bit instruction */
- insn_type = nds32_analyze_epilogue_insn32 (abi_use_fpr, insn, NULL);
- }
- else
- {
- /* 16-bit instruction */
- insn >>= 16;
- insn_type = nds32_analyze_epilogue_insn16 (insn, NULL);
- }
- if (insn_type == INSN_NORMAL || insn_type == INSN_RESET_SP)
- return 0;
- /* Search the required 'return' instruction within the following reasonable
- instructions. */
- ret_found = nds32_analyze_epilogue (gdbarch, addr, NULL);
- if (ret_found == 0)
- return 0;
- /* Scan backwards to make sure that the last instruction has adjusted
- stack. Both a 16-bit and a 32-bit instruction will be tried. This is
- just a heuristic, so the false positives will be acceptable. */
- insn = read_memory_unsigned_integer (addr - 2, 4, BFD_ENDIAN_BIG);
- /* Only 16-bit instructions are possible at addr - 2. */
- if ((insn & 0x80000000) != 0)
- {
- /* This may be a 16-bit instruction or part of a 32-bit instruction. */
- insn_type = nds32_analyze_epilogue_insn16 (insn >> 16, NULL);
- if (insn_type == INSN_RECOVER)
- return 1;
- }
- insn = read_memory_unsigned_integer (addr - 4, 4, BFD_ENDIAN_BIG);
- /* If this is a 16-bit instruction at addr - 4, then there must be another
- 16-bit instruction at addr - 2, so only 32-bit instructions need to
- be analyzed here. */
- if ((insn & 0x80000000) == 0)
- {
- /* This may be a 32-bit instruction or part of a 32-bit instruction. */
- insn_type = nds32_analyze_epilogue_insn32 (abi_use_fpr, insn, NULL);
- if (insn_type == INSN_RECOVER || insn_type == INSN_RESET_SP)
- return 1;
- }
- return 0;
- }
- /* Implement the "sniffer" frame_unwind method. */
- static int
- nds32_epilogue_frame_sniffer (const struct frame_unwind *self,
- struct frame_info *this_frame, void **this_cache)
- {
- if (frame_relative_level (this_frame) == 0)
- return nds32_stack_frame_destroyed_p (get_frame_arch (this_frame),
- get_frame_pc (this_frame));
- else
- return 0;
- }
- /* Allocate and fill in *THIS_CACHE with information needed to unwind
- *THIS_FRAME within epilogue. Do not do this if *THIS_CACHE was already
- allocated. Return a pointer to the current nds32_frame_cache in
- *THIS_CACHE. */
- static struct nds32_frame_cache *
- nds32_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
- {
- struct gdbarch *gdbarch = get_frame_arch (this_frame);
- struct nds32_frame_cache *cache;
- CORE_ADDR current_pc, current_sp;
- int i;
- if (*this_cache)
- return (struct nds32_frame_cache *) *this_cache;
- cache = nds32_alloc_frame_cache ();
- *this_cache = cache;
- cache->pc = get_frame_func (this_frame);
- current_pc = get_frame_pc (this_frame);
- nds32_analyze_epilogue (gdbarch, current_pc, cache);
- current_sp = get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM);
- cache->prev_sp = current_sp + cache->sp_offset;
- /* Adjust all the saved registers such that they contain addresses
- instead of offsets. */
- for (i = 0; i < NDS32_NUM_SAVED_REGS; i++)
- if (cache->saved_regs[i] != REG_UNAVAIL)
- cache->saved_regs[i] = current_sp + cache->saved_regs[i];
- return cache;
- }
- /* Implement the "this_id" frame_unwind method. */
- static void
- nds32_epilogue_frame_this_id (struct frame_info *this_frame,
- void **this_cache, struct frame_id *this_id)
- {
- struct nds32_frame_cache *cache
- = nds32_epilogue_frame_cache (this_frame, this_cache);
- /* This marks the outermost frame. */
- if (cache->prev_sp == 0)
- return;
- *this_id = frame_id_build (cache->prev_sp, cache->pc);
- }
- /* Implement the "prev_register" frame_unwind method. */
- static struct value *
- nds32_epilogue_frame_prev_register (struct frame_info *this_frame,
- void **this_cache, int regnum)
- {
- struct nds32_frame_cache *cache
- = nds32_epilogue_frame_cache (this_frame, this_cache);
- if (regnum == NDS32_SP_REGNUM)
- return frame_unwind_got_constant (this_frame, regnum, cache->prev_sp);
- /* The PC of the previous frame is stored in the LP register of
- the current frame. */
- if (regnum == NDS32_PC_REGNUM)
- regnum = NDS32_LP_REGNUM;
- if (regnum < NDS32_NUM_SAVED_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 nds32_epilogue_frame_unwind =
- {
- "nds32 epilogue",
- NORMAL_FRAME,
- default_frame_unwind_stop_reason,
- nds32_epilogue_frame_this_id,
- nds32_epilogue_frame_prev_register,
- NULL,
- nds32_epilogue_frame_sniffer
- };
- /* Floating type and struct type that has only one floating type member
- can pass value using FPU registers (when FPU ABI is used). */
- static int
- nds32_check_calling_use_fpr (struct type *type)
- {
- struct type *t;
- enum type_code typecode;
- t = type;
- while (1)
- {
- t = check_typedef (t);
- typecode = t->code ();
- if (typecode != TYPE_CODE_STRUCT)
- break;
- else if (t->num_fields () != 1)
- return 0;
- else
- t = t->field (0).type ();
- }
- return typecode == TYPE_CODE_FLT;
- }
- /* Implement the "push_dummy_call" gdbarch method. */
- static CORE_ADDR
- nds32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr,
- int nargs, struct value **args, CORE_ADDR sp,
- function_call_return_method return_method,
- CORE_ADDR struct_addr)
- {
- const int REND = 6; /* End for register offset. */
- int goff = 0; /* Current gpr offset for argument. */
- int foff = 0; /* Current fpr offset for argument. */
- int soff = 0; /* Current stack offset for argument. */
- int i;
- ULONGEST regval;
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- struct type *func_type = value_type (function);
- int abi_use_fpr = nds32_abi_use_fpr (tdep->elf_abi);
- int abi_split = nds32_abi_split (tdep->elf_abi);
- /* Set the return address. For the NDS32, the return breakpoint is
- always at BP_ADDR. */
- regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr);
- /* If STRUCT_RETURN is true, then the struct return address (in
- STRUCT_ADDR) will consume the first argument-passing register.
- Both adjust the register count and store that value. */
- if (return_method == return_method_struct)
- {
- regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_addr);
- goff++;
- }
- /* Now make sure there's space on the stack */
- for (i = 0; i < nargs; i++)
- {
- struct type *type = value_type (args[i]);
- int align = type_align (type);
- /* If align is zero, it may be an empty struct.
- Just ignore the argument of empty struct. */
- if (align == 0)
- continue;
- sp -= TYPE_LENGTH (type);
- sp = align_down (sp, align);
- }
- /* Stack must be 8-byte aligned. */
- sp = align_down (sp, 8);
- soff = 0;
- for (i = 0; i < nargs; i++)
- {
- const gdb_byte *val;
- int align, len;
- struct type *type;
- int calling_use_fpr;
- int use_fpr = 0;
- type = value_type (args[i]);
- calling_use_fpr = nds32_check_calling_use_fpr (type);
- len = TYPE_LENGTH (type);
- align = type_align (type);
- val = value_contents (args[i]).data ();
- /* The size of a composite type larger than 4 bytes will be rounded
- up to the nearest multiple of 4. */
- if (len > 4)
- len = align_up (len, 4);
- /* Variadic functions are handled differently between AABI and ABI2FP+.
- For AABI, the caller pushes arguments in registers, callee stores
- unnamed arguments in stack, and then va_arg fetch arguments in stack.
- Therefore, we don't have to handle variadic functions specially.
- For ABI2FP+, the caller pushes only named arguments in registers
- and pushes all unnamed arguments in stack. */
- if (abi_use_fpr && func_type->has_varargs ()
- && i >= func_type->num_fields ())
- goto use_stack;
- /* Try to use FPRs to pass arguments only when
- 1. The program is built using toolchain with FPU support.
- 2. The type of this argument can use FPR to pass value. */
- use_fpr = abi_use_fpr && calling_use_fpr;
- if (use_fpr)
- {
- if (tdep->fpu_freg == -1)
- goto error_no_fpr;
- /* Adjust alignment. */
- if ((align >> 2) > 0)
- foff = align_up (foff, align >> 2);
- if (foff < REND)
- {
- switch (len)
- {
- case 4:
- regcache->cooked_write (tdep->fs0_regnum + foff, val);
- foff++;
- break;
- case 8:
- regcache->cooked_write (NDS32_FD0_REGNUM + (foff >> 1), val);
- foff += 2;
- break;
- default:
- /* Long double? */
- internal_error (__FILE__, __LINE__,
- "Do not know how to handle %d-byte double.\n",
- len);
- break;
- }
- continue;
- }
- }
- else
- {
- /*
- When passing arguments using GPRs,
- * A composite type not larger than 4 bytes is passed in $rN.
- The format is as if the value is loaded with load instruction
- of corresponding size (e.g., LB, LH, LW).
- For example,
- r0
- 31 0
- LITTLE: [x x b a]
- BIG: [x x a b]
- * Otherwise, a composite type is passed in consecutive registers.
- The size is rounded up to the nearest multiple of 4.
- The successive registers hold the parts of the argument as if
- were loaded using lmw instructions.
- For example,
- r0 r1
- 31 0 31 0
- LITTLE: [d c b a] [x x x e]
- BIG: [a b c d] [e x x x]
- */
- /* Adjust alignment. */
- if ((align >> 2) > 0)
- goff = align_up (goff, align >> 2);
- if (len <= (REND - goff) * 4)
- {
- /* This argument can be passed wholly via GPRs. */
- while (len > 0)
- {
- regval = extract_unsigned_integer (val, (len > 4) ? 4 : len,
- byte_order);
- regcache_cooked_write_unsigned (regcache,
- NDS32_R0_REGNUM + goff,
- regval);
- len -= 4;
- val += 4;
- goff++;
- }
- continue;
- }
- else if (abi_split)
- {
- /* Some parts of this argument can be passed via GPRs. */
- while (goff < REND)
- {
- regval = extract_unsigned_integer (val, (len > 4) ? 4 : len,
- byte_order);
- regcache_cooked_write_unsigned (regcache,
- NDS32_R0_REGNUM + goff,
- regval);
- len -= 4;
- val += 4;
- goff++;
- }
- }
- }
- use_stack:
- /*
- When pushing (split parts of) an argument into stack,
- * A composite type not larger than 4 bytes is copied to different
- base address.
- In little-endian, the first byte of this argument is aligned
- at the low address of the next free word.
- In big-endian, the last byte of this argument is aligned
- at the high address of the next free word.
- For example,
- sp [ - ] [ c ] hi
- [ c ] [ b ]
- [ b ] [ a ]
- [ a ] [ - ] lo
- LITTLE BIG
- */
- /* Adjust alignment. */
- soff = align_up (soff, align);
- while (len > 0)
- {
- int rlen = (len > 4) ? 4 : len;
- if (byte_order == BFD_ENDIAN_BIG)
- write_memory (sp + soff + 4 - rlen, val, rlen);
- else
- write_memory (sp + soff, val, rlen);
- len -= 4;
- val += 4;
- soff += 4;
- }
- }
- /* Finally, update the SP register. */
- regcache_cooked_write_unsigned (regcache, NDS32_SP_REGNUM, sp);
- return sp;
- error_no_fpr:
- /* If use_fpr, but no floating-point register exists,
- then it is an error. */
- error (_("Fail to call. FPU registers are required."));
- }
- /* Read, for architecture GDBARCH, a function return value of TYPE
- from REGCACHE, and copy that into VALBUF. */
- static void
- nds32_extract_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, gdb_byte *valbuf)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int abi_use_fpr = nds32_abi_use_fpr (tdep->elf_abi);
- int calling_use_fpr;
- int len;
- calling_use_fpr = nds32_check_calling_use_fpr (type);
- len = TYPE_LENGTH (type);
- if (abi_use_fpr && calling_use_fpr)
- {
- if (len == 4)
- regcache->cooked_read (tdep->fs0_regnum, valbuf);
- else if (len == 8)
- regcache->cooked_read (NDS32_FD0_REGNUM, valbuf);
- else
- internal_error (__FILE__, __LINE__,
- _("Cannot extract return value of %d bytes "
- "long floating-point."), len);
- }
- else
- {
- /*
- When returning result,
- * A composite type not larger than 4 bytes is returned in $r0.
- The format is as if the result is loaded with load instruction
- of corresponding size (e.g., LB, LH, LW).
- For example,
- r0
- 31 0
- LITTLE: [x x b a]
- BIG: [x x a b]
- * Otherwise, a composite type not larger than 8 bytes is returned
- in $r0 and $r1.
- In little-endian, the first word is loaded in $r0.
- In big-endian, the last word is loaded in $r1.
- For example,
- r0 r1
- 31 0 31 0
- LITTLE: [d c b a] [x x x e]
- BIG: [x x x a] [b c d e]
- */
- ULONGEST tmp;
- if (len < 4)
- {
- /* By using store_unsigned_integer we avoid having to do
- anything special for small big-endian values. */
- regcache_cooked_read_unsigned (regcache, NDS32_R0_REGNUM, &tmp);
- store_unsigned_integer (valbuf, len, byte_order, tmp);
- }
- else if (len == 4)
- {
- regcache->cooked_read (NDS32_R0_REGNUM, valbuf);
- }
- else if (len < 8)
- {
- int len1, len2;
- len1 = byte_order == BFD_ENDIAN_BIG ? len - 4 : 4;
- len2 = len - len1;
- regcache_cooked_read_unsigned (regcache, NDS32_R0_REGNUM, &tmp);
- store_unsigned_integer (valbuf, len1, byte_order, tmp);
- regcache_cooked_read_unsigned (regcache, NDS32_R0_REGNUM + 1, &tmp);
- store_unsigned_integer (valbuf + len1, len2, byte_order, tmp);
- }
- else
- {
- regcache->cooked_read (NDS32_R0_REGNUM, valbuf);
- regcache->cooked_read (NDS32_R0_REGNUM + 1, valbuf + 4);
- }
- }
- }
- /* Write, for architecture GDBARCH, a function return value of TYPE
- from VALBUF into REGCACHE. */
- static void
- nds32_store_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, const gdb_byte *valbuf)
- {
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- nds32_gdbarch_tdep *tdep = (nds32_gdbarch_tdep *) gdbarch_tdep (gdbarch);
- int abi_use_fpr = nds32_abi_use_fpr (tdep->elf_abi);
- int calling_use_fpr;
- int len;
- calling_use_fpr = nds32_check_calling_use_fpr (type);
- len = TYPE_LENGTH (type);
- if (abi_use_fpr && calling_use_fpr)
- {
- if (len == 4)
- regcache->cooked_write (tdep->fs0_regnum, valbuf);
- else if (len == 8)
- regcache->cooked_write (NDS32_FD0_REGNUM, valbuf);
- else
- internal_error (__FILE__, __LINE__,
- _("Cannot store return value of %d bytes "
- "long floating-point."), len);
- }
- else
- {
- ULONGEST regval;
- if (len < 4)
- {
- regval = extract_unsigned_integer (valbuf, len, byte_order);
- regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, regval);
- }
- else if (len == 4)
- {
- regcache->cooked_write (NDS32_R0_REGNUM, valbuf);
- }
- else if (len < 8)
- {
- int len1, len2;
- len1 = byte_order == BFD_ENDIAN_BIG ? len - 4 : 4;
- len2 = len - len1;
- regval = extract_unsigned_integer (valbuf, len1, byte_order);
- regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, regval);
- regval = extract_unsigned_integer (valbuf + len1, len2, byte_order);
- regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM + 1,
- regval);
- }
- else
- {
- regcache->cooked_write (NDS32_R0_REGNUM, valbuf);
- regcache->cooked_write (NDS32_R0_REGNUM + 1, valbuf + 4);
- }
- }
- }
- /* Implement the "return_value" gdbarch method.
- Determine, for architecture GDBARCH, how a return value of TYPE
- should be returned. If it is supposed to be returned in registers,
- and READBUF is non-zero, read the appropriate value from REGCACHE,
- and copy it into READBUF. If WRITEBUF is non-zero, write the value
- from WRITEBUF into REGCACHE. */
- static enum return_value_convention
- nds32_return_value (struct gdbarch *gdbarch, struct value *func_type,
- struct type *type, struct regcache *regcache,
- gdb_byte *readbuf, const gdb_byte *writebuf)
- {
- if (TYPE_LENGTH (type) > 8)
- {
- return RETURN_VALUE_STRUCT_CONVENTION;
- }
- else
- {
- if (readbuf != NULL)
- nds32_extract_return_value (gdbarch, type, regcache, readbuf);
- if (writebuf != NULL)
- nds32_store_return_value (gdbarch, type, regcache, writebuf);
- return RETURN_VALUE_REGISTER_CONVENTION;
- }
- }
- /* Implement the "get_longjmp_target" gdbarch method. */
- static int
- nds32_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
- {
- gdb_byte buf[4];
- CORE_ADDR jb_addr;
- struct gdbarch *gdbarch = get_frame_arch (frame);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- jb_addr = get_frame_register_unsigned (frame, NDS32_R0_REGNUM);
- if (target_read_memory (jb_addr + 11 * 4, buf, 4))
- return 0;
- *pc = extract_unsigned_integer (buf, 4, byte_order);
- return 1;
- }
- /* Validate the given TDESC, and fixed-number some registers in it.
- Return 0 if the given TDESC does not contain the required feature
- or not contain required registers. */
- static int
- nds32_validate_tdesc_p (const struct target_desc *tdesc,
- struct tdesc_arch_data *tdesc_data,
- int *fpu_freg, int *use_pseudo_fsrs)
- {
- const struct tdesc_feature *feature;
- int i, valid_p;
- feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.core");
- if (feature == NULL)
- return 0;
- valid_p = 1;
- /* Validate and fixed-number R0-R10. */
- for (i = NDS32_R0_REGNUM; i <= NDS32_R0_REGNUM + 10; i++)
- valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
- nds32_register_names[i]);
- /* Validate R15. */
- valid_p &= tdesc_unnumbered_register (feature,
- nds32_register_names[NDS32_TA_REGNUM]);
- /* Validate and fixed-number FP, GP, LP, SP, PC. */
- for (i = NDS32_FP_REGNUM; i <= NDS32_PC_REGNUM; i++)
- valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
- nds32_register_names[i]);
- if (!valid_p)
- return 0;
- /* Fixed-number R11-R27. */
- for (i = NDS32_R0_REGNUM + 11; i <= NDS32_R0_REGNUM + 27; i++)
- tdesc_numbered_register (feature, tdesc_data, i, nds32_register_names[i]);
- feature = tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.fpu");
- if (feature != NULL)
- {
- int num_fdr_regs, num_fsr_regs, fs0_regnum, num_listed_fsr;
- int freg = -1;
- /* Guess FPU configuration via listed registers. */
- if (tdesc_unnumbered_register (feature, "fd31"))
- freg = 3;
- else if (tdesc_unnumbered_register (feature, "fd15"))
- freg = 2;
- else if (tdesc_unnumbered_register (feature, "fd7"))
- freg = 1;
- else if (tdesc_unnumbered_register (feature, "fd3"))
- freg = 0;
- if (freg == -1)
- /* Required FDR is not found. */
- return 0;
- else
- *fpu_freg = freg;
- /* Validate and fixed-number required FDRs. */
- num_fdr_regs = num_fdr_map[freg];
- for (i = 0; i < num_fdr_regs; i++)
- valid_p &= tdesc_numbered_register (feature, tdesc_data,
- NDS32_FD0_REGNUM + i,
- nds32_fdr_register_names[i]);
- if (!valid_p)
- return 0;
- /* Count the number of listed FSRs, and fixed-number them if present. */
- num_fsr_regs = num_fsr_map[freg];
- fs0_regnum = NDS32_FD0_REGNUM + num_fdr_regs;
- num_listed_fsr = 0;
- for (i = 0; i < num_fsr_regs; i++)
- num_listed_fsr += tdesc_numbered_register (feature, tdesc_data,
- fs0_regnum + i,
- nds32_fsr_register_names[i]);
- if (num_listed_fsr == 0)
- /* No required FSRs are listed explicitly, make them pseudo registers
- of FDRs. */
- *use_pseudo_fsrs = 1;
- else if (num_listed_fsr == num_fsr_regs)
- /* All required FSRs are listed explicitly. */
- *use_pseudo_fsrs = 0;
- else
- /* Some required FSRs are missing. */
- return 0;
- }
- return 1;
- }
- /* Initialize the current architecture based on INFO. If possible,
- re-use an architecture from ARCHES, which is a list of
- architectures already created during this debugging session.
- Called e.g. at program startup, when reading a core file, and when
- reading a binary file. */
- static struct gdbarch *
- nds32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
- {
- struct gdbarch *gdbarch;
- struct gdbarch_list *best_arch;
- tdesc_arch_data_up tdesc_data;
- const struct target_desc *tdesc = info.target_desc;
- int elf_abi = E_NDS_ABI_AABI;
- int fpu_freg = -1;
- int use_pseudo_fsrs = 0;
- int i, num_regs, maxregs;
- /* Extract the elf_flags if available. */
- if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
- elf_abi = elf_elfheader (info.abfd)->e_flags & EF_NDS_ABI;
- /* If there is already a candidate, use it. */
- for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
- best_arch != NULL;
- best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
- {
- nds32_gdbarch_tdep *idep
- = (nds32_gdbarch_tdep *) gdbarch_tdep (best_arch->gdbarch);
- if (idep->elf_abi != elf_abi)
- continue;
- /* Found a match. */
- break;
- }
- if (best_arch != NULL)
- return best_arch->gdbarch;
- if (!tdesc_has_registers (tdesc))
- tdesc = tdesc_nds32;
- tdesc_data = tdesc_data_alloc ();
- if (!nds32_validate_tdesc_p (tdesc, tdesc_data.get (), &fpu_freg,
- &use_pseudo_fsrs))
- return NULL;
- /* Allocate space for the new architecture. */
- nds32_gdbarch_tdep *tdep = new nds32_gdbarch_tdep;
- tdep->fpu_freg = fpu_freg;
- tdep->use_pseudo_fsrs = use_pseudo_fsrs;
- tdep->fs0_regnum = -1;
- tdep->elf_abi = elf_abi;
- gdbarch = gdbarch_alloc (&info, tdep);
- set_gdbarch_wchar_bit (gdbarch, 16);
- set_gdbarch_wchar_signed (gdbarch, 0);
- if (fpu_freg == -1)
- num_regs = NDS32_NUM_REGS;
- else if (use_pseudo_fsrs == 1)
- {
- set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read);
- set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write);
- set_tdesc_pseudo_register_name (gdbarch, nds32_pseudo_register_name);
- set_tdesc_pseudo_register_type (gdbarch, nds32_pseudo_register_type);
- set_gdbarch_num_pseudo_regs (gdbarch, num_fsr_map[fpu_freg]);
- num_regs = NDS32_NUM_REGS + num_fdr_map[fpu_freg];
- }
- else
- num_regs = NDS32_NUM_REGS + num_fdr_map[fpu_freg] + num_fsr_map[fpu_freg];
- set_gdbarch_num_regs (gdbarch, num_regs);
- tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
- /* Cache the register number of fs0. */
- if (fpu_freg != -1)
- tdep->fs0_regnum = user_reg_map_name_to_regnum (gdbarch, "fs0", -1);
- /* Add NDS32 register aliases. To avoid search in user register name space,
- user_reg_map_name_to_regnum is not used. */
- maxregs = gdbarch_num_cooked_regs (gdbarch);
- for (i = 0; i < ARRAY_SIZE (nds32_register_aliases); i++)
- {
- int regnum, j;
- regnum = -1;
- /* Search register name space. */
- for (j = 0; j < maxregs; j++)
- {
- const char *regname = gdbarch_register_name (gdbarch, j);
- if (regname != NULL
- && strcmp (regname, nds32_register_aliases[i].name) == 0)
- {
- regnum = j;
- break;
- }
- }
- /* Try next alias entry if the given name can not be found in register
- name space. */
- if (regnum == -1)
- continue;
- user_reg_add (gdbarch, nds32_register_aliases[i].alias,
- value_of_nds32_reg, (const void *) (intptr_t) regnum);
- }
- nds32_add_reggroups (gdbarch);
- /* Hook in ABI-specific overrides, if they have been registered. */
- info.tdesc_data = tdesc_data.get ();
- gdbarch_init_osabi (info, gdbarch);
- /* Override tdesc_register callbacks for system registers. */
- set_gdbarch_register_reggroup_p (gdbarch, nds32_register_reggroup_p);
- set_gdbarch_sp_regnum (gdbarch, NDS32_SP_REGNUM);
- set_gdbarch_pc_regnum (gdbarch, NDS32_PC_REGNUM);
- set_gdbarch_stack_frame_destroyed_p (gdbarch, nds32_stack_frame_destroyed_p);
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nds32_dwarf2_reg_to_regnum);
- set_gdbarch_push_dummy_call (gdbarch, nds32_push_dummy_call);
- set_gdbarch_return_value (gdbarch, nds32_return_value);
- set_gdbarch_skip_prologue (gdbarch, nds32_skip_prologue);
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_breakpoint_kind_from_pc (gdbarch,
- nds32_breakpoint::kind_from_pc);
- set_gdbarch_sw_breakpoint_from_kind (gdbarch,
- nds32_breakpoint::bp_from_kind);
- set_gdbarch_frame_align (gdbarch, nds32_frame_align);
- frame_base_set_default (gdbarch, &nds32_frame_base);
- /* Handle longjmp. */
- set_gdbarch_get_longjmp_target (gdbarch, nds32_get_longjmp_target);
- /* The order of appending is the order it check frame. */
- dwarf2_append_unwinders (gdbarch);
- frame_unwind_append_unwinder (gdbarch, &nds32_epilogue_frame_unwind);
- frame_unwind_append_unwinder (gdbarch, &nds32_frame_unwind);
- return gdbarch;
- }
- void _initialize_nds32_tdep ();
- void
- _initialize_nds32_tdep ()
- {
- /* Initialize gdbarch. */
- register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init);
- initialize_tdesc_nds32 ();
- nds32_init_reggroups ();
- }
|